diff --git a/Applications/AppList.cmake b/Applications/AppList.cmake index c965a86005..2d8f662e70 100644 --- a/Applications/AppList.cmake +++ b/Applications/AppList.cmake @@ -1,22 +1,22 @@ # This file is included in the top-level MITK CMakeLists.txt file to # allow early dependency checking option(MITK_BUILD_APP_CoreApp "Build the MITK CoreApp" OFF) -option(MITK_BUILD_APP_ExtApp "Build the MITK ExtApp" ON) -option(MITK_BUILD_APP_mitkDiffusion "Build MITK Diffusion executable" OFF) +option(MITK_BUILD_APP_mitkWorkbench "Build the MITK Workbench executable" ON) +option(MITK_BUILD_APP_mitkDiffusion "Build the MITK Diffusion executable" OFF) # This variable is fed to ctkFunctionSetupPlugins() macro in the # top-level MITK CMakeLists.txt file. This allows to automatically # enable required plug-in runtime dependencies for applications using # the CTK DGraph executable and the ctkMacroValidateBuildOptions macro. # For this to work, directories containing executables must contain # a CMakeLists.txt file containing a "project(...)" command and a # target_libraries.cmake file setting a list named "target_libraries" # with required plug-in target names. set(MITK_APPS CoreApp^^MITK_BUILD_APP_CoreApp - ExtApp^^MITK_BUILD_APP_ExtApp + mitkWorkbench^^MITK_BUILD_APP_mitkWorkbench mitkDiffusion^^MITK_BUILD_APP_mitkDiffusion ) diff --git a/Applications/ExtApp/startExtApp.bat.in b/Applications/ExtApp/startExtApp.bat.in deleted file mode 100644 index 55a2217788..0000000000 --- a/Applications/ExtApp/startExtApp.bat.in +++ /dev/null @@ -1,2 +0,0 @@ -PATH=@MITK_RUNTIME_PATH@;%PATH% -@VS_BUILD_TYPE@\ExtApp.exe diff --git a/Applications/PluginGenerator/PluginTemplate/documentation/UserManual/Manual.dox b/Applications/PluginGenerator/PluginTemplate/documentation/UserManual/Manual.dox index aa3fb32a5d..c254a2ba83 100755 --- a/Applications/PluginGenerator/PluginTemplate/documentation/UserManual/Manual.dox +++ b/Applications/PluginGenerator/PluginTemplate/documentation/UserManual/Manual.dox @@ -1,19 +1,19 @@ /** -\bundlemainpage{$(plugin-target)} $(plugin-name) +\page $(plugin-target) $(plugin-name) \image html icon.xpm "Icon of $(plugin-name)" Available sections: - \ref $(plugin-target)Overview \section $(plugin-target)Overview Describe the features of your awesome plugin here */ diff --git a/Applications/PluginGenerator/ProjectTemplate/Apps/TemplateApp/TemplateApp.ini b/Applications/PluginGenerator/ProjectTemplate/Apps/TemplateApp/TemplateApp.ini index 083da5aae2..aaab82e17b 100644 --- a/Applications/PluginGenerator/ProjectTemplate/Apps/TemplateApp/TemplateApp.ini +++ b/Applications/PluginGenerator/ProjectTemplate/Apps/TemplateApp/TemplateApp.ini @@ -1,2 +1,3 @@ BlueBerry.home=@BLUEBERRY_BINARY_DIR@ BlueBerry.provisioning=@CMAKE_RUNTIME_OUTPUT_DIRECTORY@/@MY_APP_NAME@.provisioning +BlueBerry.qtplugin_path=@BLUEBERRY_QTPLUGIN_PATH@ diff --git a/Applications/ExtApp/CMakeLists.txt b/Applications/mitkWorkbench/CMakeLists.txt similarity index 77% rename from Applications/ExtApp/CMakeLists.txt rename to Applications/mitkWorkbench/CMakeLists.txt index 9d31b41f87..ace7c2d860 100644 --- a/Applications/ExtApp/CMakeLists.txt +++ b/Applications/mitkWorkbench/CMakeLists.txt @@ -1,40 +1,40 @@ -project(ExtApp) +project(mitkWorkbench) set(_app_options) if(MITK_SHOW_CONSOLE_WINDOW) list(APPEND _app_options SHOW_CONSOLE) endif() -MITK_USE_MODULE(qtsingleapplication) +MITK_USE_MODULE(qtsingleapplication Mitk) include_directories(${ALL_INCLUDE_DIRECTORIES}) # Create a cache entry for the provisioning file which is used to export # the file name in the MITKConfig.cmake file. This will keep external projects # which rely on this file happy. -set(MITK_EXTAPP_PROVISIONING_FILE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ExtApp.provisioning" CACHE INTERNAL "ExtApp provisioning file" FORCE) +set(MITK_EXTAPP_PROVISIONING_FILE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/mitkWorkbench.provisioning" CACHE INTERNAL "mitkWorkbench provisioning file" FORCE) # Plug-ins listed below will not be # - added as a build-time dependency to the executable # - listed in the provisioning file for the executable # - installed if they are external plug-ins set(_exclude_plugins org.blueberry.test org.blueberry.uitest org.mitk.gui.qt.coreapplication org.mitk.gui.qt.diffusionimagingapp ) FunctionCreateBlueBerryApplication( - NAME ExtApp - DESCRIPTION "MITK - ExtApp Application" + NAME mitkWorkbench + DESCRIPTION "MITK Workbench" EXCLUDE_PLUGINS ${_exclude_plugins} LINK_LIBRARIES ${ALL_LIBRARIES} ${_app_options} ) # Add a build time dependency to legacy BlueBerry bundles. if(MITK_MODULES_ENABLED_PLUGINS) - add_dependencies(ExtApp ${MITK_MODULES_ENABLED_PLUGINS}) + add_dependencies(mitkWorkbench ${MITK_MODULES_ENABLED_PLUGINS}) endif() diff --git a/Applications/mitkWorkbench/CPackOptions.cmake b/Applications/mitkWorkbench/CPackOptions.cmake new file mode 100644 index 0000000000..06935ce197 --- /dev/null +++ b/Applications/mitkWorkbench/CPackOptions.cmake @@ -0,0 +1,38 @@ +# Set MITK Workbench specific CPack options + +# set version +set(CPACK_PACKAGE_VERSION + "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") + +# determine possible system specific extension +set(extension "unkown-architecture") + +if(${CMAKE_SYSTEM_NAME} MATCHES Windows) + if(CMAKE_CL_64) + set(extension "win64") + elseif(MINGW) + set(extension "mingw32") + elseif(WIN32) + set(extension "win32") + endif() +endif(${CMAKE_SYSTEM_NAME} MATCHES Windows) + +if(${CMAKE_SYSTEM_NAME} MATCHES Linux) + if(${CMAKE_SYSTEM_PROCESSOR} MATCHES i686) + set(extension "linux32") + elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES x86_64) + if(${CMAKE_CXX_FLAGS} MATCHES " -m32 ") + set(extension "linux32") + else() + set(extension "linux64") + endif(${CMAKE_CXX_FLAGS} MATCHES " -m32 ") + else() + set(extension "linux") + endif() +endif(${CMAKE_SYSTEM_NAME} MATCHES Linux) + +if(${CMAKE_SYSTEM_NAME} MATCHES Darwin) + set(extension "mac64") +endif(${CMAKE_SYSTEM_NAME} MATCHES Darwin) + +set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${extension}") diff --git a/Applications/ExtApp/icons/icon.icns b/Applications/mitkWorkbench/icons/icon.icns similarity index 100% rename from Applications/ExtApp/icons/icon.icns rename to Applications/mitkWorkbench/icons/icon.icns diff --git a/Applications/ExtApp/icons/icon.ico b/Applications/mitkWorkbench/icons/icon.ico similarity index 100% rename from Applications/ExtApp/icons/icon.ico rename to Applications/mitkWorkbench/icons/icon.ico diff --git a/Applications/ExtApp/icons/icon.png b/Applications/mitkWorkbench/icons/icon.png similarity index 100% rename from Applications/ExtApp/icons/icon.png rename to Applications/mitkWorkbench/icons/icon.png diff --git a/Applications/ExtApp/icons/ExtApp.rc b/Applications/mitkWorkbench/icons/mitkWorkbench.rc similarity index 100% rename from Applications/ExtApp/icons/ExtApp.rc rename to Applications/mitkWorkbench/icons/mitkWorkbench.rc diff --git a/Applications/ExtApp/ExtApp.cpp b/Applications/mitkWorkbench/mitkWorkbench.cpp similarity index 72% rename from Applications/ExtApp/ExtApp.cpp rename to Applications/mitkWorkbench/mitkWorkbench.cpp index ba75c34645..dfe2379342 100644 --- a/Applications/ExtApp/ExtApp.cpp +++ b/Applications/mitkWorkbench/mitkWorkbench.cpp @@ -1,116 +1,143 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include +#include +#include + class QtSafeApplication : public QtSingleApplication { public: QtSafeApplication(int& argc, char** argv) : QtSingleApplication(argc, argv) {} /** * Reimplement notify to catch unhandled exceptions and open an error message. * * @param receiver * @param event * @return */ bool notify(QObject* receiver, QEvent* event) { QString msg; try { return QApplication::notify(receiver, event); } + catch (mitk::Exception& e) + { + msg = QString("MITK Exception:\n\n") + + QString("Desciption: ") + + QString(e.GetDescription()) + QString("\n\n") + + QString("Filename: ") + QString(e.GetFile()) + QString("\n\n") + + QString("Line: ") + QString::number(e.GetLine()); + } catch (Poco::Exception& e) { msg = QString::fromStdString(e.displayText()); } catch (std::exception& e) { msg = e.what(); } catch (...) { msg = "Unknown exception"; } + MITK_ERROR << "An error occurred: " << msg.toStdString(); + + QMessageBox msgBox; + msgBox.setText("An error occurred. You should save all data and quit the program to prevent possible data loss."); + msgBox.setDetailedText(msg); + msgBox.setIcon(QMessageBox::Critical); + msgBox.addButton(trUtf8("Exit immediately"), QMessageBox::YesRole); + msgBox.addButton(trUtf8("Ignore"), QMessageBox::NoRole); + + int ret = msgBox.exec(); + + switch(ret) + { + case 0: + MITK_ERROR << "The program was closed."; + this->closeAllWindows(); + break; + case 1: + MITK_ERROR << "The error was ignored by the user. The program may be in a corrupt state and don't behave like expected!"; + break; + } - QString text("An error occurred. You should save all data and quit the program to " - "prevent possible data loss.\nSee the error log for details.\n\n"); - text += msg; - - QMessageBox::critical(0, "Error", text); return false; } }; int main(int argc, char** argv) { // Create a QApplication instance first QtSafeApplication qSafeApp(argc, argv); - qSafeApp.setApplicationName("ExtApp"); + qSafeApp.setApplicationName("mitkWorkbench"); qSafeApp.setOrganizationName("DKFZ"); // This function checks if an instance is already running // and either sends a message to it (containing the command // line arguments) or checks if a new instance was forced by // providing the BlueBerry.newInstance command line argument. // In the latter case, a path to a temporary directory for // the new application's storage directory is returned. QString storageDir = handleNewAppInstance(&qSafeApp, argc, argv, "BlueBerry.newInstance"); // These paths replace the .ini file and are tailored for installation // packages created with CPack. If a .ini file is presented, it will // overwrite the settings in MapConfiguration Poco::Path basePath(argv[0]); basePath.setFileName(""); Poco::Path provFile(basePath); - provFile.setFileName("ExtApp.provisioning"); + provFile.setFileName("mitkWorkbench.provisioning"); Poco::Path extPath(basePath); extPath.pushDirectory("ExtBundles"); std::string pluginDirs = extPath.toString(); Poco::Util::MapConfiguration* extConfig(new Poco::Util::MapConfiguration()); if (!storageDir.isEmpty()) { extConfig->setString(berry::Platform::ARG_STORAGE_DIR, storageDir.toStdString()); } extConfig->setString(berry::Platform::ARG_PLUGIN_DIRS, pluginDirs); extConfig->setString(berry::Platform::ARG_PROVISIONING, provFile.toString()); extConfig->setString(berry::Platform::ARG_APPLICATION, "org.mitk.qt.extapplication"); // Preload the org.mitk.gui.qt.ext plug-in (and hence also QmitkExt) to speed // up a clean-cache start. This also works around bugs in older gcc and glibc implementations, // which have difficulties with multiple dynamic opening and closing of shared libraries with // many global static initializers. It also helps if dependent libraries have weird static // initialization methods and/or missing de-initialization code. - extConfig->setString(berry::Platform::ARG_PRELOAD_LIBRARY, "liborg_mitk_gui_qt_ext,libCTKDICOMCore"); + extConfig->setString(berry::Platform::ARG_PRELOAD_LIBRARY, "liborg_mitk_gui_qt_ext,libCTKDICOMCore:0.1"); return berry::Starter::Run(argc, argv, extConfig); } diff --git a/Applications/ExtApp/ExtApp.ini b/Applications/mitkWorkbench/mitkWorkbench.ini similarity index 74% rename from Applications/ExtApp/ExtApp.ini rename to Applications/mitkWorkbench/mitkWorkbench.ini index 911309235a..b73d1ab9b2 100644 --- a/Applications/ExtApp/ExtApp.ini +++ b/Applications/mitkWorkbench/mitkWorkbench.ini @@ -1,3 +1,4 @@ BlueBerry.home=@BLUEBERRY_BINARY_DIR@ BlueBerry.plugin_dirs=@MITK_MODULES_PLUGIN_OUTPUT_DIRS@ BlueBerry.provisioning=@MITK_EXTAPP_PROVISIONING_FILE@ +BlueBerry.qtplugin_path=@BLUEBERRY_QTPLUGIN_PATH@ diff --git a/Applications/mitkWorkbench/startMitkWorkbench.bat.in b/Applications/mitkWorkbench/startMitkWorkbench.bat.in new file mode 100644 index 0000000000..2240c0b2ef --- /dev/null +++ b/Applications/mitkWorkbench/startMitkWorkbench.bat.in @@ -0,0 +1,2 @@ +PATH=@MITK_RUNTIME_PATH@;%PATH% +@VS_BUILD_TYPE@\mitkWorkbench.exe diff --git a/Applications/ExtApp/target_libraries.cmake b/Applications/mitkWorkbench/target_libraries.cmake similarity index 100% rename from Applications/ExtApp/target_libraries.cmake rename to Applications/mitkWorkbench/target_libraries.cmake diff --git a/BlueBerry/BlueBerryConfig.cmake.in b/BlueBerry/BlueBerryConfig.cmake.in index 78ebbcace5..6568f028c1 100644 --- a/BlueBerry/BlueBerryConfig.cmake.in +++ b/BlueBerry/BlueBerryConfig.cmake.in @@ -1,85 +1,87 @@ # ------------------------------------------------------------------------- # Package requirements # ------------------------------------------------------------------------- set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "@BLUEBERRY_SOURCE_DIR@/CMake") set(CTK_DIR "@CTK_DIR@") find_package(CTK REQUIRED) set(mbilog_DIR "@mbilog_DIR@") find_package(mbilog REQUIRED) find_package(Poco REQUIRED) set(DOXYGEN_EXECUTABLE "@DOXYGEN_EXECUTABLE@") set(DOXYGEN_DOT_EXECUTABLE "@DOXYGEN_DOT_EXECUTABLE@") find_package(Doxygen) # ------------------------------------------------------------------------- # BlueBerry directory vars # ------------------------------------------------------------------------- set(BLUEBERRY_PLUGINS_SOURCE_DIR "@BLUEBERRY_PLUGINS_SOURCE_DIR@") set(BLUEBERRY_PLUGINS_BINARY_DIR "@BLUEBERRY_PLUGINS_BINARY_DIR@") set(BLUEBERRY_PLUGIN_SOURCE_DIRS "@BLUEBERRY_PLUGINS_SOURCE_DIR@") set(BLUEBERRY_SOURCE_DIR "@BLUEBERRY_SOURCE_DIR@") set(BlueBerry_SOURCE_DIR "@BLUEBERRY_SOURCE_DIR@") set(BLUEBERRY_BINARY_DIR "@BLUEBERRY_BINARY_DIR@") # ------------------------------------------------------------------------- # BlueBerry CMake file includes # ------------------------------------------------------------------------- set(BLUEBERRY_PLUGIN_USE_FILE @BB_PLUGIN_USE_FILE@) if(BLUEBERRY_PLUGIN_USE_FILE) if(EXISTS ${BLUEBERRY_PLUGIN_USE_FILE}) include(${BLUEBERRY_PLUGIN_USE_FILE}) endif() endif() if(NOT BB_PLUGIN_EXPORTS_FILE_INCLUDED AND NOT CMAKE_PROJECT_NAME STREQUAL "MITK") include("@BB_PLUGIN_EXPORTS_FILE@") set(BB_PLUGIN_EXPORTS_FILE_INCLUDED 1) endif() # ------------------------------------------------------------------------- # BlueBerry CMake variables # ------------------------------------------------------------------------- set(BLUEBERRY_DEBUG_POSTFIX @BLUEBERRY_DEBUG_POSTFIX@) set(BLUEBERRY_USE_QT_HELP @BLUEBERRY_USE_QT_HELP@) +set(BLUEBERRY_QTPLUGIN_PATH "@BLUEBERRY_QTPLUGIN_PATH@") + set(QT_HELPGENERATOR_EXECUTABLE "@QT_HELPGENERATOR_EXECUTABLE@") set(QT_COLLECTIONGENERATOR_EXECUTABLE "@QT_COLLECTIONGENERATOR_EXECUTABLE@") set(QT_ASSISTANT_EXECUTABLE "@QT_ASSISTANT_EXECUTABLE@") set(QT_XMLPATTERNS_EXECUTABLE "@QT_XMLPATTERNS_EXECUTABLE@") set(BLUEBERRY_PLUGIN_TARGETS @my_plugin_targets@) set(BLUEBERRY_PLUGIN_PROVISIONING_FILE "@BLUEBERRY_PROVISIONING_FILE@") set(BLUEBERRY_DOXYGEN_TAGFILE_NAME @BLUEBERRY_DOXYGEN_TAGFILE_NAME@) # ------------------------------------------------------------------------- # BlueBerry CMake macros # ------------------------------------------------------------------------- include(MacroParseArguments) include(MacroConvertSchema) include(MacroOrganizeSources) include(MacroCreateCTKPlugin) include(MacroCreateQtHelp) include(MacroInstallCTKPlugin) include(FunctionInstallThirdPartyCTKPlugins) include(FunctionCreateProvisioningFile) include(FunctionCreateBlueBerryApplication) diff --git a/BlueBerry/Bundles/org.blueberry.osgi/src/application/berryStarter.cpp b/BlueBerry/Bundles/org.blueberry.osgi/src/application/berryStarter.cpp index b09f344236..6a696134fe 100644 --- a/BlueBerry/Bundles/org.blueberry.osgi/src/application/berryStarter.cpp +++ b/BlueBerry/Bundles/org.blueberry.osgi/src/application/berryStarter.cpp @@ -1,175 +1,206 @@ /*=================================================================== 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 "berryLog.h" #include "berryStarter.h" #include "berryPlatform.h" #include "internal/berryInternalPlatform.h" #include "service/berryIExtensionPointService.h" #include "service/berryIConfigurationElement.h" #include "berryIApplication.h" #include #include namespace berry { const std::string Starter::XP_APPLICATIONS = "org.blueberry.osgi.applications"; int Starter::Run(int& argc, char** argv, Poco::Util::AbstractConfiguration* config) { // The CTK PluginFramework needs a QCoreApplication if (!qApp) { BERRY_FATAL << "No QCoreApplication instance found. You need to create one prior to calling Starter::Run()"; } InternalPlatform* platform = InternalPlatform::GetInstance(); int returnCode = 0; // startup the internal platform platform->Initialize(argc, argv, config); platform->Launch(); bool consoleLog = platform->ConsoleLog(); + // Add search paths for Qt plugins + foreach(QString qtPluginPath, QString::fromStdString(Platform::GetProperty(Platform::PROP_QTPLUGIN_PATH)).split(';', QString::SkipEmptyParts)) + { + if (QFile::exists(qtPluginPath)) + { + QCoreApplication::addLibraryPath(qtPluginPath); + } + else if (consoleLog) + { + BERRY_WARN << "Qt plugin path does not exist: " << qtPluginPath.toStdString(); + } + } + + // Add a default search path. It is assumed that installed applications + // provide their Qt plugins in that path. + static const QString defaultQtPluginPath = QCoreApplication::applicationDirPath() + "/plugins"; + if (QFile::exists(defaultQtPluginPath)) + { + QCoreApplication::addLibraryPath(defaultQtPluginPath); + } + + if (consoleLog) + { + std::string pathList; + foreach(QString libPath, QCoreApplication::libraryPaths()) + { + pathList += (pathList.empty() ? "" : ", ") + libPath.toStdString(); + } + BERRY_INFO << "Qt library search paths: " << pathList; + } + // run the application IExtensionPointService::Pointer service = platform->GetExtensionPointService(); if (service == 0) { platform->GetLogger()->log( Poco::Message( "Starter", "The extension point service could not be retrieved. This usually indicates that the BlueBerry OSGi plug-in could not be loaded.", Poco::Message::PRIO_FATAL)); std::unexpected(); returnCode = 1; } else { IConfigurationElement::vector extensions( service->GetConfigurationElementsFor(Starter::XP_APPLICATIONS)); IConfigurationElement::vector::iterator iter; for (iter = extensions.begin(); iter != extensions.end();) { if ((*iter)->GetName() != "application") iter = extensions.erase(iter); else ++iter; } std::string argApplication = Platform::GetConfiguration().getString( Platform::ARG_APPLICATION, ""); IApplication* app = 0; if (extensions.size() == 0) { BERRY_FATAL << "No extensions configured into extension-point '" << Starter::XP_APPLICATIONS << "' found. Aborting.\n"; returnCode = 0; } else if (extensions.size() == 1) { if (!argApplication.empty()) BERRY_INFO(consoleLog) << "One '" << Starter::XP_APPLICATIONS << "' extension found, ignoring " << Platform::ARG_APPLICATION << " argument.\n"; std::vector runs( extensions[0]->GetChildren("run")); app = runs.front()->CreateExecutableExtension ("class"); if (app == 0) { // support legacy BlueBerry extensions app = runs.front()->CreateExecutableExtension ("class", IApplication::GetManifestName()); } } else { if (argApplication.empty()) { BERRY_WARN << "You must provide an application id via \"" << Platform::ARG_APPLICATION << "=\""; BERRY_INFO << "Possible application ids are:"; for (iter = extensions.begin(); iter != extensions.end(); ++iter) { std::string appid; if ((*iter)->GetAttribute("id", appid) && !appid.empty()) { BERRY_INFO << appid; } } returnCode = 0; } else { for (iter = extensions.begin(); iter != extensions.end(); ++iter) { BERRY_INFO(consoleLog) << "Checking applications extension from: " << (*iter)->GetContributor() << std::endl; std::string appid; if ((*iter)->GetAttribute("id", appid)) { BERRY_INFO(consoleLog) << "Found id: " << appid << std::endl; if (appid.size() > 0 && appid == argApplication) { std::vector runs( (*iter)->GetChildren("run")); app = runs.front()->CreateExecutableExtension ("class"); if (app == 0) { // try legacy BlueBerry extensions app = runs.front()->CreateExecutableExtension ( "class", IApplication::GetManifestName()); } break; } } else throw CoreException("missing attribute", "id"); } } } if (app == 0) { BERRY_ERROR << "Could not create executable application extension for id: " << argApplication << std::endl; returnCode = 1; } else { returnCode = app->Start(); } } platform->Shutdown(); return returnCode; } } diff --git a/BlueBerry/Bundles/org.blueberry.osgi/src/berryPlatform.cpp b/BlueBerry/Bundles/org.blueberry.osgi/src/berryPlatform.cpp index e2c2c4d7ab..7d3086e7a0 100644 --- a/BlueBerry/Bundles/org.blueberry.osgi/src/berryPlatform.cpp +++ b/BlueBerry/Bundles/org.blueberry.osgi/src/berryPlatform.cpp @@ -1,229 +1,231 @@ /*=================================================================== 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 #include "berryPlatform.h" #include "service/berryIExtensionPointService.h" #include "internal/berryInternalPlatform.h" namespace berry { int Platform::OS_FREE_BSD = BERRY_OS_FREE_BSD; int Platform::OS_AIX = BERRY_OS_AIX; int Platform::OS_HPUX = BERRY_OS_HPUX; int Platform::OS_TRU64 = BERRY_OS_TRU64; int Platform::OS_LINUX = BERRY_OS_LINUX; int Platform::OS_MAC_OS_X = BERRY_OS_MAC_OS_X; int Platform::OS_NET_BSD = BERRY_OS_NET_BSD; int Platform::OS_OPEN_BSD = BERRY_OS_OPEN_BSD; int Platform::OS_IRIX = BERRY_OS_IRIX; int Platform::OS_SOLARIS = BERRY_OS_SOLARIS; int Platform::OS_QNX = BERRY_OS_QNX; int Platform::OS_VXWORKS = BERRY_OS_VXWORKS; int Platform::OS_CYGWIN = BERRY_OS_CYGWIN; int Platform::OS_UNKNOWN_UNIX = BERRY_OS_UNKNOWN_UNIX; int Platform::OS_WINDOWS_NT = BERRY_OS_WINDOWS_NT; int Platform::OS_WINDOWS_CE = BERRY_OS_WINDOWS_CE; int Platform::OS_VMS = BERRY_OS_VMS; int Platform::ARCH_ALPHA = BERRY_ARCH_ALPHA; int Platform::ARCH_IA32 = BERRY_ARCH_IA32; int Platform::ARCH_IA64 = BERRY_ARCH_IA64; int Platform::ARCH_MIPS = BERRY_ARCH_MIPS; int Platform::ARCH_HPPA = BERRY_ARCH_HPPA; int Platform::ARCH_PPC = BERRY_ARCH_PPC; int Platform::ARCH_POWER = BERRY_ARCH_POWER; int Platform::ARCH_SPARC = BERRY_ARCH_SPARC; int Platform::ARCH_AMD64 = BERRY_ARCH_AMD64; int Platform::ARCH_ARM = BERRY_ARCH_ARM; +std::string Platform::PROP_QTPLUGIN_PATH = "BlueBerry.qtplugin_path"; + std::string Platform::ARG_NEWINSTANCE = "BlueBerry.newInstance"; std::string Platform::ARG_CLEAN = "BlueBerry.clean"; std::string Platform::ARG_APPLICATION = "BlueBerry.application"; std::string Platform::ARG_HOME = "BlueBerry.home"; std::string Platform::ARG_STORAGE_DIR = "BlueBerry.storageDir"; std::string Platform::ARG_PLUGIN_CACHE = "BlueBerry.plugin_cache_dir"; std::string Platform::ARG_PLUGIN_DIRS = "BlueBerry.plugin_dirs"; std::string Platform::ARG_FORCE_PLUGIN_INSTALL = "BlueBerry.forcePlugins"; std::string Platform::ARG_PRELOAD_LIBRARY = "BlueBerry.preloadLibrary"; std::string Platform::ARG_PROVISIONING = "BlueBerry.provisioning"; std::string Platform::ARG_CONSOLELOG = "BlueBerry.consoleLog"; std::string Platform::ARG_TESTPLUGIN = "BlueBerry.testplugin"; std::string Platform::ARG_TESTAPPLICATION = "BlueBerry.testapplication"; std::string Platform::ARG_XARGS = "xargs"; const Poco::Path& Platform::GetConfigurationPath() { return InternalPlatform::GetInstance()->GetConfigurationPath(); } SmartPointer Platform::GetExtensionPointService() { return InternalPlatform::GetInstance()->GetExtensionPointService(); } PlatformEvents& Platform::GetEvents() { return InternalPlatform::GetInstance()->GetEvents(); } const Poco::Path& Platform::GetInstallPath() { return InternalPlatform::GetInstance()->GetInstallPath(); } const Poco::Path& Platform::GetInstancePath() { return InternalPlatform::GetInstance()->GetInstancePath(); } int Platform::GetOS() { return BERRY_OS; } int Platform::GetOSArch() { return BERRY_ARCH; } bool Platform::IsUnix() { #ifdef BERRY_OS_FAMILY_UNIX return true; #else return false; #endif } bool Platform::IsWindows() { #ifdef BERRY_OS_FAMILY_WINDOWS return true; #else return false; #endif } bool Platform::IsBSD() { #ifdef BERRY_OS_FAMILY_BSD return true; #else return false; #endif } bool Platform::IsLinux() { #ifdef BERRY_OS_FAMILY_LINUX return true; #else return false; #endif } bool Platform::IsVMS() { #ifdef BERRY_OS_FAMILY_VMS return true; #else return false; #endif } bool Platform::GetStatePath(Poco::Path& statePath, IBundle::Pointer bundle, bool create) { return InternalPlatform::GetInstance()->GetStatePath(statePath, bundle, create); } const Poco::Path& Platform::GetUserPath() { return InternalPlatform::GetInstance()->GetUserPath(); } -std::string Platform::GetProperty(const std::string& /*key*/) +std::string Platform::GetProperty(const std::string& key) { - return ""; + return GetConfiguration().getString(key, ""); } bool Platform::IsRunning() { return InternalPlatform::GetInstance()->IsRunning(); } int& Platform::GetRawApplicationArgs(char**& argv) { return InternalPlatform::GetInstance()->GetRawApplicationArgs(argv); } std::vector Platform::GetApplicationArgs() { return InternalPlatform::GetInstance()->GetApplicationArgs(); } std::string Platform::GetExtendedApplicationArgs() { return InternalPlatform::GetInstance()->GetConfiguration().getString(ARG_XARGS, ""); } void Platform::GetOptionSet(Poco::Util::OptionSet& os) { InternalPlatform::GetInstance()->defineOptions(os); } Poco::Util::LayeredConfiguration& Platform::GetConfiguration() { return InternalPlatform::GetInstance()->GetConfiguration(); } ServiceRegistry& Platform::GetServiceRegistry() { return InternalPlatform::GetInstance()->GetServiceRegistry(); } IBundle::Pointer Platform::GetBundle(const std::string& id) { return InternalPlatform::GetInstance()->GetBundle(id); } std::vector Platform::GetBundles() { return InternalPlatform::GetInstance()->GetBundles(); } QSharedPointer Platform::GetCTKPlugin(const QString& symbolicName) { QList > plugins = InternalPlatform::GetInstance()->GetCTKPluginFrameworkContext()->getPlugins(); foreach(QSharedPointer plugin, plugins) { if (plugin->getSymbolicName() == symbolicName) return plugin; } return QSharedPointer(0); } QSharedPointer Platform::GetCTKPlugin(long id) { return InternalPlatform::GetInstance()->GetCTKPluginFrameworkContext()->getPlugin(id); } } diff --git a/BlueBerry/Bundles/org.blueberry.osgi/src/berryPlatform.h b/BlueBerry/Bundles/org.blueberry.osgi/src/berryPlatform.h index 6bde5fcf81..361d5ea85a 100644 --- a/BlueBerry/Bundles/org.blueberry.osgi/src/berryPlatform.h +++ b/BlueBerry/Bundles/org.blueberry.osgi/src/berryPlatform.h @@ -1,359 +1,361 @@ /*=================================================================== 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 BERRY_Platform_INCLUDED #define BERRY_Platform_INCLUDED // // Platform Identification // #define BERRY_OS_FREE_BSD 0x0001 #define BERRY_OS_AIX 0x0002 #define BERRY_OS_HPUX 0x0003 #define BERRY_OS_TRU64 0x0004 #define BERRY_OS_LINUX 0x0005 #define BERRY_OS_MAC_OS_X 0x0006 #define BERRY_OS_NET_BSD 0x0007 #define BERRY_OS_OPEN_BSD 0x0008 #define BERRY_OS_IRIX 0x0009 #define BERRY_OS_SOLARIS 0x000a #define BERRY_OS_QNX 0x000b #define BERRY_OS_VXWORKS 0x000c #define BERRY_OS_CYGWIN 0x000d #define BERRY_OS_UNKNOWN_UNIX 0x00ff #define BERRY_OS_WINDOWS_NT 0x1001 #define BERRY_OS_WINDOWS_CE 0x1011 #define BERRY_OS_VMS 0x2001 #if defined(__FreeBSD__) #define BERRY_OS_FAMILY_UNIX 1 #define BERRY_OS_FAMILY_BSD 1 #define BERRY_OS BERRY_OS_FREE_BSD #elif defined(_AIX) || defined(__TOS_AIX__) #define BERRY_OS_FAMILY_UNIX 1 #define BERRY_OS BERRY_OS_AIX #elif defined(hpux) || defined(_hpux) #define BERRY_OS_FAMILY_UNIX 1 #define BERRY_OS BERRY_OS_HPUX #elif defined(__digital__) || defined(__osf__) #define BERRY_OS_FAMILY_UNIX 1 #define BERRY_OS BERRY_OS_TRU64 #elif defined(linux) || defined(__linux) || defined(__linux__) || defined(__TOS_LINUX__) #define BERRY_OS_FAMILY_UNIX 1 #define BERRY_OS BERRY_OS_LINUX #elif defined(__APPLE__) || defined(__TOS_MACOS__) #define BERRY_OS_FAMILY_UNIX 1 #define BERRY_OS_FAMILY_BSD 1 #define BERRY_OS BERRY_OS_MAC_OS_X #elif defined(__NetBSD__) #define BERRY_OS_FAMILY_UNIX 1 #define BERRY_OS_FAMILY_BSD 1 #define BERRY_OS BERRY_OS_NET_BSD #elif defined(__OpenBSD__) #define BERRY_OS_FAMILY_UNIX 1 #define BERRY_OS_FAMILY_BSD 1 #define BERRY_OS BERRY_OS_OPEN_BSD #elif defined(sgi) || defined(__sgi) #define BERRY_OS_FAMILY_UNIX 1 #define BERRY_OS BERRY_OS_IRIX #elif defined(sun) || defined(__sun) #define BERRY_OS_FAMILY_UNIX 1 #define BERRY_OS BERRY_OS_SOLARIS #elif defined(__QNX__) #define BERRY_OS_FAMILY_UNIX 1 #define BERRY_OS BERRY_OS_QNX #elif defined(unix) || defined(__unix) || defined(__unix__) #define BERRY_OS_FAMILY_UNIX 1 #define BERRY_OS BERRY_OS_UNKNOWN_UNIX #elif defined(_WIN32_WCE) #define BERRY_OS_FAMILY_WINDOWS 1 #define BERRY_OS BERRY_OS_WINDOWS_CE #elif defined(_WIN32) || defined(_WIN64) #define BERRY_OS_FAMILY_WINDOWS 1 #define BERRY_OS BERRY_OS_WINDOWS_NT #elif defined(__CYGWIN__) #define BERRY_OS_FAMILY_UNIX 1 #define BERRY_OS BERRY_OS_CYGWIN #elif defined(__VMS) #define BERRY_OS_FAMILY_VMS 1 #define BERRY_OS BERRY_OS_VMS #endif // // Hardware Architecture and Byte Order // #define BERRY_ARCH_ALPHA 0x01 #define BERRY_ARCH_IA32 0x02 #define BERRY_ARCH_IA64 0x03 #define BERRY_ARCH_MIPS 0x04 #define BERRY_ARCH_HPPA 0x05 #define BERRY_ARCH_PPC 0x06 #define BERRY_ARCH_POWER 0x07 #define BERRY_ARCH_SPARC 0x08 #define BERRY_ARCH_AMD64 0x09 #define BERRY_ARCH_ARM 0x0a #if defined(__ALPHA) || defined(__alpha) || defined(__alpha__) || defined(_M_ALPHA) #define BERRY_ARCH BERRY_ARCH_ALPHA #define BERRY_ARCH_LITTLE_ENDIAN 1 #elif defined(i386) || defined(__i386) || defined(__i386__) || defined(_M_IX86) #define BERRY_ARCH BERRY_ARCH_IA32 #define BERRY_ARCH_LITTLE_ENDIAN 1 #elif defined(_IA64) || defined(__IA64__) || defined(__ia64__) || defined(__ia64) || defined(_M_IA64) #define BERRY_ARCH BERRY_ARCH_IA64 #if defined(hpux) || defined(_hpux) #define BERRY_ARCH_BIG_ENDIAN 1 #else #define BERRY_ARCH_LITTLE_ENDIAN 1 #endif #elif defined(__x86_64__) #define BERRY_ARCH BERRY_ARCH_AMD64 #define BERRY_ARCH_LITTLE_ENDIAN 1 #elif defined(_M_X64) #define BERRY_ARCH BERRY_ARCH_AMD64 #define BERRY_ARCH_LITTLE_ENDIAN 1 #elif defined(__mips__) || defined(__mips) || defined(__MIPS__) || defined(_M_MRX000) #define BERRY_ARCH BERRY_ARCH_MIPS #define BERRY_ARCH_BIG_ENDIAN 1 #elif defined(__hppa) || defined(__hppa__) #define BERRY_ARCH BERRY_ARCH_HPPA #define BERRY_ARCH_BIG_ENDIAN 1 #elif defined(__PPC) || defined(__POWERPC__) || defined(__powerpc) || defined(__PPC__) || \ defined(__powerpc__) || defined(__ppc__) || defined(_ARCH_PPC) || defined(_M_PPC) #define BERRY_ARCH BERRY_ARCH_PPC #define BERRY_ARCH_BIG_ENDIAN 1 #elif defined(_POWER) || defined(_ARCH_PWR) || defined(_ARCH_PWR2) || defined(_ARCH_PWR3) || \ defined(_ARCH_PWR4) || defined(__THW_RS6000) #define BERRY_ARCH BERRY_ARCH_POWER #define BERRY_ARCH_BIG_ENDIAN 1 #elif defined(__sparc__) || defined(__sparc) || defined(sparc) #define BERRY_ARCH BERRY_ARCH_SPARC #define BERRY_ARCH_BIG_ENDIAN 1 #elif defined(__arm__) || defined(__arm) || defined(ARM) || defined(_ARM_) || defined(__ARM__) || defined(_M_ARM) #define BERRY_ARCH BERRY_ARCH_ARM #if defined(__ARMEB__) #define BERRY_ARCH_BIG_ENDIAN 1 #else #define BERRY_ARCH_LITTLE_ENDIAN 1 #endif #endif #include #include "event/berryPlatformEvents.h" #include "service/berryServiceRegistry.h" #include #include namespace berry { struct IExtensionPointService; /** * The central class of the BlueBerry Platform Runtime. This class cannot * be instantiated or subclassed by clients; all functionality is provided * by static methods. Features include: *
    *
  • the platform registry of installed plug-ins
  • *
  • the platform adapter manager
  • *
  • the platform log
  • *
*

* Most users don't have to worry about Platform's lifecycle. However, if your * code can call methods of this class when Platform is not running, it becomes * necessary to check {@link #IsRunning()} before making the call. A runtime * exception might be thrown or incorrect result might be returned if a method * from this class is called while Platform is not running. *

*/ class BERRY_OSGI Platform { public: static int OS_FREE_BSD; static int OS_AIX; static int OS_HPUX; static int OS_TRU64; static int OS_LINUX; static int OS_MAC_OS_X; static int OS_NET_BSD; static int OS_OPEN_BSD; static int OS_IRIX; static int OS_SOLARIS; static int OS_QNX; static int OS_VXWORKS; static int OS_CYGWIN; static int OS_UNKNOWN_UNIX; static int OS_WINDOWS_NT; static int OS_WINDOWS_CE; static int OS_VMS; static int ARCH_ALPHA; static int ARCH_IA32; static int ARCH_IA64; static int ARCH_MIPS; static int ARCH_HPPA; static int ARCH_PPC; static int ARCH_POWER; static int ARCH_SPARC; static int ARCH_AMD64; static int ARCH_ARM; + static std::string PROP_QTPLUGIN_PATH; + static std::string ARG_NEWINSTANCE; static std::string ARG_CLEAN; static std::string ARG_APPLICATION; static std::string ARG_HOME; static std::string ARG_STORAGE_DIR; static std::string ARG_PLUGIN_CACHE; static std::string ARG_PLUGIN_DIRS; static std::string ARG_FORCE_PLUGIN_INSTALL; static std::string ARG_PRELOAD_LIBRARY; static std::string ARG_PROVISIONING; static std::string ARG_CONSOLELOG; static std::string ARG_TESTPLUGIN; static std::string ARG_TESTAPPLICATION; static std::string ARG_XARGS; static SmartPointer GetExtensionPointService(); // static IPreferenceService GetPreferenceService(); static PlatformEvents& GetEvents(); /** * Returns the path of the configuration information * used to run this instance of the BlueBerry platform. * The configuration area typically * contains the list of plug-ins available for use, various settings * (those shared across different instances of the same configuration) * and any other such data needed by plug-ins. * An empty path is returned if the platform is running without a configuration location. * * @return the location of the platform's configuration data area */ static const Poco::Path& GetConfigurationPath(); /** * Returns the path of the base installation for the running platform * * @return the location of the platform's installation area or null if none */ static const Poco::Path& GetInstallPath(); /** * Returns the path of the platform's working directory (also known as the instance data area). * An empty path is returned if the platform is running without an instance location. * * @return the location of the platform's instance data area or null if none */ static const Poco::Path& GetInstancePath(); /** * Returns the path in the local file system of the * plug-in state area for the given bundle. * If the plug-in state area did not exist prior to this call, * it is created. *

* The plug-in state area is a file directory within the * platform's metadata area where a plug-in is free to create files. * The content and structure of this area is defined by the plug-in, * and the particular plug-in is solely responsible for any files * it puts there. It is recommended for plug-in preference settings and * other configuration parameters. *

* * @param bundle the bundle whose state location is returned * @return a local file system path * TODO Investigate the usage of a service factory */ static bool GetStatePath(Poco::Path& statePath, SmartPointer bundle, bool create = true); /** * Returns the path of the platform's user data area. The user data area is a location on the system * which is specific to the system's current user. By default it is located relative to the * location given by the System property "user.home". * An empty path is returned if the platform is running without an user location. * * @return the location of the platform's user data area or null if none */ static const Poco::Path& GetUserPath(); static int GetOS(); static int GetOSArch(); static bool IsUnix(); static bool IsWindows(); static bool IsBSD(); static bool IsLinux(); static bool IsVMS(); static std::string GetProperty(const std::string& key); static bool IsRunning(); static Poco::Util::LayeredConfiguration& GetConfiguration(); /** * Returns the unmodified, original command line arguments * */ static int& GetRawApplicationArgs(char**& argv); /** * Returns the applications command line arguments which * have not been consumed by the platform. */ static std::vector GetApplicationArgs(); /** * Returns the "extended" command line arguments. This is * just the string given as argument to the "--xargs" option. */ static std::string GetExtendedApplicationArgs(); static void GetOptionSet(Poco::Util::OptionSet &os); static ServiceRegistry& GetServiceRegistry(); /** * Returns the resolved bundle with the specified symbolic name that has the * highest version. If no resolved bundles are installed that have the * specified symbolic name then null is returned. * * @param id the symbolic name of the bundle to be returned. * @return the bundle that has the specified symbolic name with the * highest version, or null if no bundle is found. */ static IBundle::Pointer GetBundle(const std::string& id); static std::vector GetBundles(); static QSharedPointer GetCTKPlugin(const QString& symbolicName); static QSharedPointer GetCTKPlugin(long id); private: Platform(); }; } // namespace #endif // BERRY_Platform_INCLUDED diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditor.cpp b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditor.cpp index 0ba5a18a4d..60baf7429e 100644 --- a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditor.cpp +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditor.cpp @@ -1,328 +1,340 @@ /*=================================================================== 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 "berryHelpEditor.h" #include "berryHelpEditorInput.h" #include "berryHelpPluginActivator.h" #include "berryHelpPerspective.h" #include "berryHelpWebView.h" #include "berryQHelpEngineWrapper.h" #include "berryHelpEditorFindWidget.h" #include "berryHelpPluginActivator.h" #include "berryQHelpEngineWrapper.h" #include #include #include #include #include #include #include namespace berry { const std::string HelpEditor::EDITOR_ID = "org.blueberry.editors.help"; HelpEditor::HelpEditor() : m_ToolBar(0) , m_WebView(0) { } HelpEditor::~HelpEditor() { // we need to wrap the RemovePartListener call inside a // register/unregister block to prevent infinite recursion // due to the destruction of temporary smartpointer to this this->Register(); this->GetSite()->GetPage()->RemovePartListener(IPartListener::Pointer(this)); this->GetSite()->GetPage()->GetWorkbenchWindow()->RemovePerspectiveListener(IPerspectiveListener::Pointer(this)); this->UnRegister(false); } void HelpEditor::Init(berry::IEditorSite::Pointer site, berry::IEditorInput::Pointer input) { if (input.Cast().IsNull()) throw PartInitException("Invalid Input: Must be berry::HelpEditorInput"); this->SetSite(site); site->GetPage()->AddPartListener(IPartListener::Pointer(this)); site->GetPage()->GetWorkbenchWindow()->AddPerspectiveListener(IPerspectiveListener::Pointer(this)); m_WebView = new HelpWebView(site, 0); connect(m_WebView, SIGNAL(loadFinished(bool)), this, SLOT(InitializeTitle())); this->DoSetInput(input); } void HelpEditor::CreateQtPartControl(QWidget* parent) { QVBoxLayout* verticalLayout = new QVBoxLayout(parent); verticalLayout->setSpacing(0); verticalLayout->setContentsMargins(0, 0, 0, 0); m_ToolBar = new QToolBar(parent); m_ToolBar->setMaximumHeight(32); verticalLayout->addWidget(m_ToolBar); m_WebView->setParent(parent); m_WebView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); verticalLayout->addWidget(m_WebView); m_FindWidget = new HelpEditorFindWidget(parent); m_FindWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum); verticalLayout->addWidget(m_FindWidget); m_FindWidget->hide(); connect(m_FindWidget, SIGNAL(findNext()), this, SLOT(findNext())); connect(m_FindWidget, SIGNAL(findPrevious()), this, SLOT(findPrevious())); connect(m_FindWidget, SIGNAL(find(QString, bool)), this, SLOT(find(QString, bool))); connect(m_FindWidget, SIGNAL(escapePressed()), m_WebView, SLOT(setFocus())); // Fill the editor toolbar m_BackAction = m_ToolBar->addAction(QIcon(":/org.blueberry.ui.qt.help/go-previous.png"), "Go back", m_WebView, SLOT(backward())); m_ForwardAction = m_ToolBar->addAction(QIcon(":/org.blueberry.ui.qt.help/go-next.png"), "Go forward", m_WebView, SLOT(forward())); m_HomeAction = m_ToolBar->addAction(QIcon(":/org.blueberry.ui.qt.help/go-home.png"), "Go home", m_WebView, SLOT(home())); m_ToolBar->addSeparator(); m_FindAction = m_ToolBar->addAction(QIcon(":/org.blueberry.ui.qt.help/find.png"), "Find in text", this, SLOT(ShowTextSearch())); m_ToolBar->addSeparator(); m_ZoomIn = m_ToolBar->addAction(QIcon(":/org.blueberry.ui.qt.help/zoom-in.png"), "Zoom in", m_WebView, SLOT(scaleUp())); m_ZoomOut = m_ToolBar->addAction(QIcon(":/org.blueberry.ui.qt.help/zoom-out.png"), "Zoom out", m_WebView, SLOT(scaleDown())); m_ToolBar->addSeparator(); - m_OpenHelpMode = m_ToolBar->addAction("Switch to Help mode", this, SLOT(OpenHelpPerspective())); + m_OpenHelpMode = m_ToolBar->addAction("Open Help Perspective", this, SLOT(OpenHelpPerspective())); + m_CloseHelpMode = m_ToolBar->addAction("Close Help Perspective", this, SLOT(CloseHelpPerspective())); IPerspectiveDescriptor::Pointer currPersp = this->GetSite()->GetPage()->GetPerspective(); - m_OpenHelpMode->setEnabled(!(currPersp.IsNotNull() && currPersp->GetId() == HelpPerspective::ID)); + m_OpenHelpMode->setVisible(!(currPersp.IsNotNull() && currPersp->GetId() == HelpPerspective::ID)); + m_CloseHelpMode->setVisible((currPersp.IsNotNull() && currPersp->GetId() == HelpPerspective::ID)); connect(m_WebView, SIGNAL(backwardAvailable(bool)), m_BackAction, SLOT(setEnabled(bool))); connect(m_WebView, SIGNAL(forwardAvailable(bool)), m_ForwardAction, SLOT(setEnabled(bool))); m_BackAction->setEnabled(false); m_ForwardAction->setEnabled(false); m_HomeAction->setEnabled(!HelpPluginActivator::getInstance()->getQHelpEngine().homePage().isEmpty()); connect(&HelpPluginActivator::getInstance()->getQHelpEngine(), SIGNAL(homePageChanged(QString)), this, SLOT(HomePageChanged(QString))); } void HelpEditor::DoSetInput(IEditorInput::Pointer input) { if (input.IsNull()) { // close editor class CloseEditorRunnable : public Poco::Runnable { private: IEditorPart::Pointer editor; public: CloseEditorRunnable(IEditorPart::Pointer editor) : editor(editor) {} void run() { editor->GetSite()->GetPage()->CloseEditor(editor, false); delete this; } }; Display::GetDefault()->AsyncExec(new CloseEditorRunnable(IEditorPart::Pointer(this))); } else { // an empty url represents the home page HelpEditorInput::Pointer helpInput = input.Cast(); QString currHomePage = HelpPluginActivator::getInstance()->getQHelpEngine().homePage(); if (helpInput->GetUrl().isEmpty() && !currHomePage.isEmpty()) { helpInput = HelpEditorInput::Pointer(new HelpEditorInput(currHomePage)); } QtEditorPart::SetInput(helpInput); m_WebView->setSource(helpInput->GetUrl()); } } void HelpEditor::SetInputWithNotify(IEditorInput::Pointer input) { DoSetInput(input); FirePropertyChange(IWorkbenchPartConstants::PROP_INPUT); } void HelpEditor::SetInput(IEditorInput::Pointer input) { SetInputWithNotify(input); } void HelpEditor::HomePageChanged(const QString &page) { if (page.isEmpty()) { m_HomeAction->setEnabled(false); } m_HomeAction->setEnabled(true); if (this->GetEditorInput().Cast()->GetUrl().isEmpty()) { IEditorInput::Pointer newInput(new HelpEditorInput(page)); DoSetInput(newInput); } } void HelpEditor::OpenHelpPerspective() { PlatformUI::GetWorkbench()->ShowPerspective(HelpPerspective::ID, this->GetSite()->GetPage()->GetWorkbenchWindow()); } +void HelpEditor::CloseHelpPerspective() +{ + berry::IWorkbenchPage::Pointer + page = + berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage(); + page->ClosePerspective(page->GetPerspective(), true, true); +} + void HelpEditor::InitializeTitle() { std::string title = m_WebView->title().toStdString(); this->SetPartName(title); } void HelpEditor::ShowTextSearch() { m_FindWidget->show(); } void HelpEditor::SetFocus() { m_WebView->setFocus(); enableShortcuts(); } QWebPage *HelpEditor::GetQWebPage() const { return m_WebView->page(); } IPartListener::Events::Types HelpEditor::GetPartEventTypes() const { return IPartListener::Events::DEACTIVATED; } void HelpEditor::PartDeactivated(IWorkbenchPartReference::Pointer partRef) { if (partRef == GetSite()->GetPage()->GetReference(IWorkbenchPart::Pointer(this))) disableShortcuts(); } IPerspectiveListener::Events::Types HelpEditor::GetPerspectiveEventTypes() const { return IPerspectiveListener::Events::ACTIVATED | IPerspectiveListener::Events::DEACTIVATED; } void HelpEditor::PerspectiveActivated(SmartPointer page, IPerspectiveDescriptor::Pointer perspective) { if (perspective->GetId() == HelpPerspective::ID) { - m_OpenHelpMode->setEnabled(false); + m_OpenHelpMode->setVisible(false); + m_CloseHelpMode->setVisible(true); } } void HelpEditor::PerspectiveDeactivated(SmartPointer page, IPerspectiveDescriptor::Pointer perspective) { if (perspective->GetId() == HelpPerspective::ID) { - m_OpenHelpMode->setEnabled(true); + m_OpenHelpMode->setVisible(true); + m_CloseHelpMode->setVisible(false); } } void HelpEditor::findNext() { find(m_FindWidget->text(), true); } void HelpEditor::findPrevious() { find(m_FindWidget->text(), false); } void HelpEditor::find(const QString &ttf, bool forward) { bool found = findInWebPage(ttf, forward); if (!found && ttf.isEmpty()) found = true; // the line edit is empty, no need to mark it red... if (!m_FindWidget->isVisible()) m_FindWidget->show(); m_FindWidget->setPalette(found); } bool HelpEditor::findInWebPage(const QString &ttf, bool forward) { bool found = false; QWebPage::FindFlags options; if (!ttf.isEmpty()) { if (!forward) options |= QWebPage::FindBackward; if (m_FindWidget->caseSensitive()) options |= QWebPage::FindCaseSensitively; found = m_WebView->findText(ttf, options); if (!found) { options |= QWebPage::FindWrapsAroundDocument; found = m_WebView->findText(ttf, options); } } // force highlighting of all other matches, also when empty (clear) options = QWebPage::HighlightAllOccurrences; if (m_FindWidget->caseSensitive()) options |= QWebPage::FindCaseSensitively; m_WebView->findText(QLatin1String(""), options); m_WebView->findText(ttf, options); return found; } void HelpEditor::enableShortcuts() { m_BackAction->setShortcut(QKeySequence::Back); m_ForwardAction->setShortcut(QKeySequence::Forward); m_FindAction->setShortcut(QKeySequence::Find); m_ZoomIn->setShortcut(QKeySequence::ZoomIn); m_ZoomOut->setShortcut(QKeySequence::ZoomOut); } void HelpEditor::disableShortcuts() { m_BackAction->setShortcut(QKeySequence()); m_ForwardAction->setShortcut(QKeySequence()); m_FindAction->setShortcut(QKeySequence()); m_ZoomIn->setShortcut(QKeySequence()); m_ZoomOut->setShortcut(QKeySequence()); } } diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditor.h b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditor.h index 35ce350be5..29f869254b 100644 --- a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditor.h +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditor.h @@ -1,109 +1,111 @@ /*=================================================================== 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 BERRYHELPEDITOR_H_ #define BERRYHELPEDITOR_H_ #include #include #include #include class QToolBar; class QWebPage; namespace berry { class HelpWebView; class HelpEditorFindWidget; class HelpEditor : public QtEditorPart, public IReusableEditor, public IPartListener, public IPerspectiveListener { Q_OBJECT public: berryObjectMacro(HelpEditor) static const std::string EDITOR_ID; HelpEditor(); ~HelpEditor(); 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; } QWebPage* GetQWebPage() const; IPartListener::Events::Types GetPartEventTypes() const; void PartDeactivated(IWorkbenchPartReference::Pointer /*partRef*/); IPerspectiveListener::Events::Types GetPerspectiveEventTypes() const; void PerspectiveActivated(SmartPointer page, IPerspectiveDescriptor::Pointer perspective); void PerspectiveDeactivated(SmartPointer page, IPerspectiveDescriptor::Pointer perspective); protected: void CreateQtPartControl(QWidget* parent); void DoSetInput(IEditorInput::Pointer input); void SetInputWithNotify(IEditorInput::Pointer input); void SetInput(IEditorInput::Pointer input); private Q_SLOTS: void HomePageChanged(const QString& page); void OpenHelpPerspective(); + void CloseHelpPerspective(); void InitializeTitle(); void ShowTextSearch(); void findNext(); void findPrevious(); void find(const QString& ttf, bool forward); private: bool findInWebPage(const QString& ttf, bool forward); void enableShortcuts(); void disableShortcuts(); private: Q_DISABLE_COPY(HelpEditor) QToolBar* m_ToolBar; HelpWebView* m_WebView; HelpEditorFindWidget* m_FindWidget; QAction* m_BackAction; QAction* m_ForwardAction; QAction* m_FindAction; QAction* m_ZoomIn; QAction* m_ZoomOut; QAction* m_OpenHelpMode; + QAction* m_CloseHelpMode; QAction* m_HomeAction; }; } // end namespace berry #endif /*BERRYHELPEDITOR_H_*/ diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpPluginActivator.cpp b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpPluginActivator.cpp index 518d869e50..cca4a2e3b2 100644 --- a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpPluginActivator.cpp +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpPluginActivator.cpp @@ -1,465 +1,470 @@ /*=================================================================== 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 "berryHelpPluginActivator.h" #include "berryHelpContentView.h" #include "berryHelpIndexView.h" #include "berryHelpSearchView.h" #include "berryHelpEditor.h" #include "berryHelpEditorInput.h" #include "berryHelpPerspective.h" #include "berryQHelpEngineConfiguration.h" #include "berryQHelpEngineWrapper.h" #include #include #include #include #include namespace berry { class HelpPerspectiveListener : public IPerspectiveListener { public: Events::Types GetPerspectiveEventTypes() const; void PerspectiveOpened(SmartPointer page, IPerspectiveDescriptor::Pointer perspective); void PerspectiveChanged(SmartPointer page, IPerspectiveDescriptor::Pointer perspective, const std::string &changeId); }; class HelpWindowListener : public IWindowListener { public: HelpWindowListener(); ~HelpWindowListener(); void WindowClosed(IWorkbenchWindow::Pointer window); void WindowOpened(IWorkbenchWindow::Pointer window); private: // We use the same perspective listener for every window IPerspectiveListener::Pointer perspListener; }; HelpPluginActivator* HelpPluginActivator::instance = 0; HelpPluginActivator::HelpPluginActivator() : pluginListener(0) { this->instance = this; } HelpPluginActivator::~HelpPluginActivator() { instance = 0; } void HelpPluginActivator::start(ctkPluginContext* context) { BERRY_REGISTER_EXTENSION_CLASS(berry::HelpContentView, context) BERRY_REGISTER_EXTENSION_CLASS(berry::HelpIndexView, context) BERRY_REGISTER_EXTENSION_CLASS(berry::HelpSearchView, context) BERRY_REGISTER_EXTENSION_CLASS(berry::HelpEditor, context) BERRY_REGISTER_EXTENSION_CLASS(berry::HelpPerspective, context) QFileInfo qhcInfo = context->getDataFile("qthelpcollection.qhc"); helpEngine.reset(new QHelpEngineWrapper(qhcInfo.absoluteFilePath())); if (!helpEngine->setupData()) { BERRY_ERROR << "QHelpEngine set-up failed: " << helpEngine->error().toStdString(); return; } helpEngineConfiguration.reset(new QHelpEngineConfiguration(context, *helpEngine.data())); delete pluginListener; pluginListener = new QCHPluginListener(context, helpEngine.data()); context->connectPluginListener(pluginListener, SLOT(pluginChanged(ctkPluginEvent))); // register all QCH files from all the currently installed plugins pluginListener->processPlugins(); helpEngine->initialDocSetupDone(); // Register a wnd listener which registers a perspective listener for each // new window. The perspective listener opens the help home page in the window // if no other help page is opened yet. wndListener = IWindowListener::Pointer(new HelpWindowListener()); PlatformUI::GetWorkbench()->AddWindowListener(wndListener); // Register an event handler for CONTEXTHELP_REQUESTED events helpContextHandler.reset(new HelpContextHandler); ctkDictionary helpHandlerProps; helpHandlerProps.insert(ctkEventConstants::EVENT_TOPIC, "org/blueberry/ui/help/CONTEXTHELP_REQUESTED"); context->registerService(helpContextHandler.data(), helpHandlerProps); } void HelpPluginActivator::stop(ctkPluginContext* /*context*/) { delete pluginListener; pluginListener = 0; if (PlatformUI::IsWorkbenchRunning()) { PlatformUI::GetWorkbench()->RemoveWindowListener(wndListener); } wndListener = 0; } HelpPluginActivator *HelpPluginActivator::getInstance() { return instance; } QHelpEngineWrapper& HelpPluginActivator::getQHelpEngine() { return *helpEngine; } void HelpPluginActivator::linkActivated(IWorkbenchPage::Pointer page, const QUrl &link) { IEditorInput::Pointer input(new HelpEditorInput(link)); // see if an editor with the same input is already open IEditorPart::Pointer reuseEditor = page->FindEditor(input); if (reuseEditor) { // just activate it page->Activate(reuseEditor); } else { // reuse the currently active editor, if it is a HelpEditor reuseEditor = page->GetActiveEditor(); if (reuseEditor.IsNotNull() && page->GetReference(reuseEditor)->GetId() == HelpEditor::EDITOR_ID) { page->ReuseEditor(reuseEditor.Cast(), input); page->Activate(reuseEditor); } else { // get the last used HelpEditor instance std::vector editors = page->FindEditors(IEditorInput::Pointer(0), HelpEditor::EDITOR_ID, IWorkbenchPage::MATCH_ID); if (editors.empty()) { // no HelpEditor is currently open, create a new one page->OpenEditor(input, HelpEditor::EDITOR_ID); } else { // reuse an existing editor reuseEditor = editors.front()->GetEditor(false); page->ReuseEditor(reuseEditor.Cast(), input); page->Activate(reuseEditor); } } } } QCHPluginListener::QCHPluginListener(ctkPluginContext* context, QHelpEngine* helpEngine) : delayRegistration(true), context(context), helpEngine(helpEngine) {} void QCHPluginListener::processPlugins() { QMutexLocker lock(&mutex); processPlugins_unlocked(); } void QCHPluginListener::pluginChanged(const ctkPluginEvent& event) { QMutexLocker lock(&mutex); if (delayRegistration) { this->processPlugins_unlocked(); return; } /* Only should listen for RESOLVED and UNRESOLVED events. * * When a plugin is updated the Framework will publish an UNRESOLVED and * then a RESOLVED event which should cause the plugin to be removed * and then added back into the registry. * * When a plugin is uninstalled the Framework should publish an UNRESOLVED * event and then an UNINSTALLED event so the plugin will have been removed * by the UNRESOLVED event before the UNINSTALLED event is published. */ QSharedPointer plugin = event.getPlugin(); switch (event.getType()) { case ctkPluginEvent::RESOLVED : addPlugin(plugin); break; case ctkPluginEvent::UNRESOLVED : removePlugin(plugin); break; } } void QCHPluginListener::processPlugins_unlocked() { if (!delayRegistration) return; foreach (QSharedPointer plugin, context->getPlugins()) { if (isPluginResolved(plugin)) addPlugin(plugin); else removePlugin(plugin); } delayRegistration = false; } bool QCHPluginListener::isPluginResolved(QSharedPointer plugin) { return (plugin->getState() & (ctkPlugin::RESOLVED | ctkPlugin::ACTIVE | ctkPlugin::STARTING | ctkPlugin::STOPPING)) != 0; } void QCHPluginListener::removePlugin(QSharedPointer plugin) { // bail out if system plugin if (plugin->getPluginId() == 0) return; QFileInfo qchDirInfo = context->getDataFile("qch_files/" + QString::number(plugin->getPluginId())); if (qchDirInfo.exists()) { QDir qchDir(qchDirInfo.absoluteFilePath()); QStringList qchEntries = qchDir.entryList(QStringList("*.qch")); QStringList qchFiles; foreach(QString qchEntry, qchEntries) { qchFiles << qchDir.absoluteFilePath(qchEntry); } // unregister the cached qch files foreach(QString qchFile, qchFiles) { QString namespaceName = QHelpEngineCore::namespaceName(qchFile); if (namespaceName.isEmpty()) { BERRY_ERROR << "Could not get the namespace for qch file " << qchFile.toStdString(); continue; } else { if (!helpEngine->unregisterDocumentation(namespaceName)) { BERRY_ERROR << "Unregistering qch namespace " << namespaceName.toStdString() << " failed: " << helpEngine->error().toStdString(); } } } // clean the directory foreach(QString qchEntry, qchEntries) { qchDir.remove(qchEntry); } } } void QCHPluginListener::addPlugin(QSharedPointer plugin) { // bail out if system plugin if (plugin->getPluginId() == 0) return; QFileInfo qchDirInfo = context->getDataFile("qch_files/" + QString::number(plugin->getPluginId())); QUrl location(plugin->getLocation()); QFileInfo pluginFileInfo(location.toLocalFile()); if (!qchDirInfo.exists() || qchDirInfo.lastModified() < pluginFileInfo.lastModified()) { removePlugin(plugin); if (!qchDirInfo.exists()) { QDir().mkpath(qchDirInfo.absoluteFilePath()); } QStringList localQCHFiles; QStringList resourceList = plugin->findResources("/", "*.qch", true); foreach(QString resource, resourceList) { QByteArray content = plugin->getResource(resource); QFile localFile(qchDirInfo.absoluteFilePath() + "/" + resource.section('/', -1)); localFile.open(QIODevice::WriteOnly); localFile.write(content); localFile.close(); if (localFile.error() != QFile::NoError) { BERRY_WARN << "Error writing " << localFile.fileName().toStdString() << ": " << localFile.errorString().toStdString(); } else { localQCHFiles << localFile.fileName(); } } foreach(QString qchFile, localQCHFiles) { if (!helpEngine->registerDocumentation(qchFile)) { BERRY_ERROR << "Registering qch file " << qchFile.toStdString() << " failed: " << helpEngine->error().toStdString(); } } } } IPerspectiveListener::Events::Types HelpPerspectiveListener::GetPerspectiveEventTypes() const { return Events::OPENED | Events::CHANGED; } void HelpPerspectiveListener::PerspectiveOpened(SmartPointer page, IPerspectiveDescriptor::Pointer perspective) { // if no help editor is opened, open one showing the home page if (perspective->GetId() == HelpPerspective::ID && page->FindEditors(IEditorInput::Pointer(0), HelpEditor::EDITOR_ID, IWorkbenchPage::MATCH_ID).empty()) { IEditorInput::Pointer input(new HelpEditorInput()); page->OpenEditor(input, HelpEditor::EDITOR_ID); } } void HelpPerspectiveListener::PerspectiveChanged(SmartPointer page, IPerspectiveDescriptor::Pointer perspective, const std::string &changeId) { if (perspective->GetId() == HelpPerspective::ID && changeId == IWorkbenchPage::CHANGE_RESET) { PerspectiveOpened(page, perspective); } } HelpWindowListener::HelpWindowListener() : perspListener(new HelpPerspectiveListener()) { // Register perspective listener for already opened windows typedef std::vector WndVec; WndVec windows = PlatformUI::GetWorkbench()->GetWorkbenchWindows(); for (WndVec::iterator i = windows.begin(); i != windows.end(); ++i) { (*i)->AddPerspectiveListener(perspListener); } } HelpWindowListener::~HelpWindowListener() { typedef std::vector WndVec; WndVec windows = PlatformUI::GetWorkbench()->GetWorkbenchWindows(); for (WndVec::iterator i = windows.begin(); i != windows.end(); ++i) { (*i)->RemovePerspectiveListener(perspListener); } } void HelpWindowListener::WindowClosed(IWorkbenchWindow::Pointer window) { window->RemovePerspectiveListener(perspListener); } void HelpWindowListener::WindowOpened(IWorkbenchWindow::Pointer window) { window->AddPerspectiveListener(perspListener); } void HelpContextHandler::handleEvent(const ctkEvent &event) { struct _runner : public Poco::Runnable { _runner(const ctkEvent& ev) : ev(ev) {} void run() { QUrl helpUrl; if (ev.containsProperty("url")) { helpUrl = QUrl(ev.getProperty("url").toString()); } else { helpUrl = contextUrl(); } HelpPluginActivator::linkActivated(PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage(), helpUrl); delete this; } QUrl contextUrl() const { berry::IWorkbench* currentWorkbench = berry::PlatformUI::GetWorkbench(); if (currentWorkbench) { berry::IWorkbenchWindow::Pointer currentWorkbenchWindow = currentWorkbench->GetActiveWorkbenchWindow(); if (currentWorkbenchWindow) { berry::IWorkbenchPage::Pointer currentPage = currentWorkbenchWindow->GetActivePage(); if (currentPage) { berry::IWorkbenchPart::Pointer currentPart = currentPage->GetActivePart(); if (currentPart) { QString pluginID = QString::fromStdString(currentPart->GetSite()->GetPluginId()); QString viewID = QString::fromStdString(currentPart->GetSite()->GetId()); QString loc = "qthelp://" + pluginID + "/bundle/%1.html"; QHelpEngineWrapper& helpEngine = HelpPluginActivator::getInstance()->getQHelpEngine(); + // Get view help page if available QUrl contextUrl(loc.arg(viewID.replace(".", "_"))); QUrl url = helpEngine.findFile(contextUrl); if (url.isValid()) return url; else { BERRY_INFO << "Context help url invalid: " << contextUrl.toString().toStdString(); } + // If no view help exists get plugin help if available + QUrl pluginContextUrl(loc.arg(pluginID.replace(".", "_"))); + url = helpEngine.findFile(pluginContextUrl); + if (url.isValid()) return url; // Try to get the index.html file of the plug-in contributing the // currently active part. QUrl pluginIndexUrl(loc.arg("index")); url = helpEngine.findFile(pluginIndexUrl); if (url != pluginIndexUrl) { // Use the default page instead of another index.html // (merged via the virtual folder property). url = QUrl(); } return url; } } } } return QUrl(); } ctkEvent ev; }; // sync with GUI thread Display::GetDefault()->AsyncExec(new _runner(event)); } } Q_EXPORT_PLUGIN2(org_blueberry_ui_qt_help, berry::HelpPluginActivator) diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.log/documentation/UserManual/blueberrylogview.dox b/BlueBerry/Bundles/org.blueberry.ui.qt.log/documentation/UserManual/blueberrylogview.dox index 99acb16318..dbde26a7f5 100644 --- a/BlueBerry/Bundles/org.blueberry.ui.qt.log/documentation/UserManual/blueberrylogview.dox +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.log/documentation/UserManual/blueberrylogview.dox @@ -1,16 +1,16 @@ /** -\bundlemainpage{org_blueberry_ui_qt_log} The Logging Module +\page org_blueberry_ui_qt_log The Logging Module \image html Logging.png "Icon of the Module" The Plug-In "Logging Module" records all logging output of events and progress as specified in the source code with time of occurence, level of importance (Info, Warning, Error, Fatal, Debug), the message given and where it happens. The logging starts once you activate the Plug-In in your main application. A screenshot of the main view of the Logging Module is shown next. \image html LogView.png "Screenshot of the Logging Module" There are different features available in the view. The filter text field allows for searching all log events containing a certain substring. Using the button "Copy to clipboard" on the bottom right you can copy the current content of the logging view to your clipboard. This enables you to insert the logging information to any text processing application. You can also show more information on every logging message by activating the two checkboxes. In the simple view, leaving both checkboxes unchecked, you'll see logging messages and logging levels. A brief description of the logging levels can be found in the \ref LoggingPage "logging concept documentation". The checkbox "Category" adds a column for the category. The checkbox "Show Advanced Field" shows method, filename and linenumber where the logging message was emitted as well as the running time of the application. The next figure shows all information which can be shown in the Logging Module. \image html LogViewExplain.png "Details on the Vizualized Logging Information" */ \ No newline at end of file diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.log/manifest_headers.cmake b/BlueBerry/Bundles/org.blueberry.ui.qt.log/manifest_headers.cmake index 1b65ca4047..2e97a135f4 100644 --- a/BlueBerry/Bundles/org.blueberry.ui.qt.log/manifest_headers.cmake +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.log/manifest_headers.cmake @@ -1,6 +1,7 @@ set(Plugin-Name "BlueBerry Log Bundle") 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.blueberry.ui.qt) +set(Plugin-ActivationPolicy "eager") diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.log/src/internal/berryQtLogView.cpp b/BlueBerry/Bundles/org.blueberry.ui.qt.log/src/internal/berryQtLogView.cpp index 1e25b4c2cc..6d92f2a313 100644 --- a/BlueBerry/Bundles/org.blueberry.ui.qt.log/src/internal/berryQtLogView.cpp +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.log/src/internal/berryQtLogView.cpp @@ -1,150 +1,163 @@ /*=================================================================== 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. ===================================================================*/ #ifdef __MINGW32__ // We need to inlclude winbase.h here in order to declare // atomic intrinsics like InterlockedIncrement correctly. // Otherwhise, they would be declared wrong within qatomic_windows.h . #include #endif #include "berryQtLogView.h" #include "berryQtLogPlugin.h" #include #include #include #include #include #include #include namespace berry { QtLogView::QtLogView(QWidget *parent) : QWidget(parent) { berry::IPreferencesService::Pointer prefService = berry::Platform::GetServiceRegistry() .GetServiceById(berry::IPreferencesService::ID); berry::IBerryPreferences::Pointer prefs = (prefService->GetSystemPreferences()->Node("org_blueberry_ui_qt_log")) .Cast(); prefs->PutBool("ShowAdvancedFields", false); prefs->PutBool("ShowCategory", true); bool showAdvancedFields = false; ui.setupUi(this); model = QtLogPlugin::GetInstance()->GetLogModel(); model->SetShowAdvancedFiels( showAdvancedFields ); filterModel = new QSortFilterProxyModel(this); filterModel->setSourceModel(model); filterModel->setFilterKeyColumn(-1); ui.tableView->setModel(filterModel); - + ui.tableView->verticalHeader()->setVisible(false); ui.tableView->horizontalHeader()->setStretchLastSection(true); connect( ui.filterContent, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotFilterChange( const QString& ) ) ); connect( filterModel, SIGNAL( rowsInserted ( const QModelIndex &, int, int ) ), this, SLOT( slotRowAdded( const QModelIndex &, int , int ) ) ); - connect( ui.ShowCategory, SIGNAL( clicked(bool checked)),this, SLOT(on_ShowAdvancedFields_clicked(checked))); connect( ui.SaveToClipboard, SIGNAL( clicked()),this, SLOT(on_SaveToClipboard_clicked())); ui.ShowAdvancedFields->setChecked( showAdvancedFields ); } QtLogView::~QtLogView() { } void QtLogView::slotScrollDown( ) { ui.tableView->scrollToBottom(); } void QtLogView::slotFilterChange( const QString& q ) { filterModel->setFilterRegExp(QRegExp(q, Qt::CaseInsensitive, QRegExp::FixedString)); } + void QtLogView::slotRowAdded ( const QModelIndex & /*parent*/, int start, int end ) { - static int first=false; + ui.tableView->resizeRowsToContents(); - if(!first) - { - first=true; - ui.tableView->resizeColumnsToContents(); - ui.tableView->resizeRowsToContents(); - } - else - for(int r=start;r<=end;r++) + //only resize columns when first entry is added + static bool first = true; + if(first) { - ui.tableView->resizeRowToContents(r); + ui.tableView->resizeColumnsToContents(); + first = false; } QTimer::singleShot(0,this,SLOT( slotScrollDown() ) ); } +void QtLogView::showEvent( QShowEvent * event ) +{ + ui.tableView->resizeColumnsToContents(); + ui.tableView->resizeRowsToContents(); +} + void QtLogView::on_ShowAdvancedFields_clicked( bool checked ) { QtLogPlugin::GetInstance()->GetLogModel()->SetShowAdvancedFiels( checked ); ui.tableView->resizeColumnsToContents(); berry::IPreferencesService::Pointer prefService = berry::Platform::GetServiceRegistry() .GetServiceById(berry::IPreferencesService::ID); berry::IBerryPreferences::Pointer prefs = (prefService->GetSystemPreferences()->Node("org_blueberry_ui_qt_log")) .Cast(); prefs->PutBool("ShowAdvancedFields", checked); prefs->Flush(); } void QtLogView::on_ShowCategory_clicked( bool checked ) { QtLogPlugin::GetInstance()->GetLogModel()->SetShowCategory( checked ); ui.tableView->resizeColumnsToContents(); berry::IPreferencesService::Pointer prefService = berry::Platform::GetServiceRegistry() .GetServiceById(berry::IPreferencesService::ID); berry::IBerryPreferences::Pointer prefs = (prefService->GetSystemPreferences()->Node("org_blueberry_ui_qt_log")) .Cast(); prefs->PutBool("ShowCategory", checked); prefs->Flush(); } void QtLogView::on_SaveToClipboard_clicked() { QClipboard *clipboard = QApplication::clipboard(); - clipboard->setText(model->GetDataAsString()); + QString loggingMessagesAsText = QString(""); + for (int i=0; imodel()->rowCount(); i++) + { + for (int j=0; jmodel()->columnCount(); j++) + { + QModelIndex index = ui.tableView->model()->index(i, j); + loggingMessagesAsText += ui.tableView->model()->data(index, Qt::DisplayRole).toString() + " "; + } + loggingMessagesAsText += "\n"; + } + + clipboard->setText(loggingMessagesAsText); } } diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.log/src/internal/berryQtLogView.h b/BlueBerry/Bundles/org.blueberry.ui.qt.log/src/internal/berryQtLogView.h index 7b259e4bed..5dab3138c4 100644 --- a/BlueBerry/Bundles/org.blueberry.ui.qt.log/src/internal/berryQtLogView.h +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.log/src/internal/berryQtLogView.h @@ -1,54 +1,56 @@ /*=================================================================== 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 BERRYQTLOGVIEW_H #define BERRYQTLOGVIEW_H #include #include #include "ui_berryQtLogView.h" #include "berryQtPlatformLogModel.h" namespace berry { class QtLogView : public QWidget { Q_OBJECT public: QtLogView(QWidget *parent = 0); ~QtLogView(); QtPlatformLogModel *model; QSortFilterProxyModel *filterModel; private: Ui::QtLogViewClass ui; + + void showEvent ( QShowEvent * event ); protected slots: void slotFilterChange( const QString& ); void slotRowAdded( const QModelIndex & , int , int ); void slotScrollDown( ); void on_ShowAdvancedFields_clicked( bool checked = false ); void on_ShowCategory_clicked( bool checked = false ); void on_SaveToClipboard_clicked(); }; } #endif // BERRYQTLOGVIEW_H diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.log/src/internal/berryQtPlatformLogModel.cpp b/BlueBerry/Bundles/org.blueberry.ui.qt.log/src/internal/berryQtPlatformLogModel.cpp index 50d44e3585..189caab746 100644 --- a/BlueBerry/Bundles/org.blueberry.ui.qt.log/src/internal/berryQtPlatformLogModel.cpp +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.log/src/internal/berryQtPlatformLogModel.cpp @@ -1,329 +1,329 @@ /*=================================================================== 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. ===================================================================*/ #ifdef __MINGW32__ // We need to inlclude winbase.h here in order to declare // atomic intrinsics like InterlockedIncrement correctly. // Otherwhise, they would be declared wrong within qatomic_windows.h . #include #endif #include "berryQtPlatformLogModel.h" #include "berryPlatform.h" #include "event/berryPlatformEvents.h" #include #include #include #include #include #include "berryLog.h" #include #include #include namespace berry { const QString QtPlatformLogModel::Error = QString("Error"); const QString QtPlatformLogModel::Warn = QString("Warning"); const QString QtPlatformLogModel::Fatal = QString("Fatal"); const QString QtPlatformLogModel::Info = QString("Info"); const QString QtPlatformLogModel::Debug = QString("Debug"); void QtPlatformLogModel::slotFlushLogEntries() { m_Mutex.lock(); std::list *tmp=m_Active; m_Active=m_Pending; m_Pending=tmp; m_Mutex.unlock(); int num = static_cast(m_Pending->size()); if (num > 0) { int row = static_cast(m_Entries.size()); this->beginInsertRows(QModelIndex(), row, row+num-1); do { m_Entries.push_back(m_Pending->front()); m_Pending->pop_front(); } while(--num); this->endInsertRows(); } } void QtPlatformLogModel::addLogEntry(const mbilog::LogMessage &msg) { m_Mutex.lock(); //mbilog::BackendCout::FormatSmart(msg); FormatSmart is not static any more. So commented out this statement. Todo: fix m_Active->push_back(ExtendedLogMessage(msg)); m_Mutex.unlock(); emit signalFlushLogEntries(); } void QtPlatformLogModel::SetShowAdvancedFiels( bool showAdvancedFiels ) { if( m_ShowAdvancedFiels != showAdvancedFiels ) { m_ShowAdvancedFiels = showAdvancedFiels; this->reset(); } } void QtPlatformLogModel::SetShowCategory( bool showCategory ) { if( m_ShowCategory != showCategory ) { m_ShowCategory = showCategory; this->reset(); } } void QtPlatformLogModel::addLogEntry(const PlatformEvent& event) { const Poco::Message& entry = Poco::RefAnyCast(*event.GetData()); mbilog::LogMessage msg(mbilog::Info,"n/a",-1,"n/a"); msg.message += entry.getText(); msg.category = "BlueBerry."+entry.getSource(); msg.moduleName = "n/a"; addLogEntry(msg); } QtPlatformLogModel::QtPlatformLogModel(QObject* parent) : QAbstractTableModel(parent), m_ShowAdvancedFiels(false), m_ShowCategory(true) { m_Active=new std::list; m_Pending=new std::list; connect(this, SIGNAL(signalFlushLogEntries()), this, SLOT( slotFlushLogEntries() ), Qt::QueuedConnection ); Platform::GetEvents().logged += PlatformEventDelegate(this, &QtPlatformLogModel::addLogEntry); myBackend = new QtLogBackend(this); } QtPlatformLogModel::~QtPlatformLogModel() { disconnect(this, SIGNAL(signalFlushLogEntries()), this, SLOT( slotFlushLogEntries() )); // dont delete and unregister backend, only deactivate it to avoid thread syncronization issues cause mbilog::UnregisterBackend is not threadsafe // will be fixed. // delete myBackend; // delete m_Active; // delete m_Pending; m_Mutex.lock(); myBackend->Deactivate(); m_Mutex.unlock(); } // QT Binding int QtPlatformLogModel::rowCount(const QModelIndex&) const { return static_cast(m_Entries.size()); } int QtPlatformLogModel::columnCount(const QModelIndex&) const { int returnValue = 2; if( m_ShowAdvancedFiels ) returnValue += 7; if( m_ShowCategory ) returnValue += 1; return returnValue; } /* struct LogEntry { LogEntry(const std::string& msg, const std::string& src, std::time_t t) : message(msg.c_str()), moduleName(src.c_str()),time(std::clock()) { } QString message; clock_t time; QString level; QString filePath; QString lineNumber; QString moduleName; QString category; QString function; LogEntry(const mbilog::LogMessage &msg) { message = msg.message.c_str(); filePath = msg.filePath; std::stringstream out; out << msg.lineNumber; lineNumber = out.str().c_str(); moduleName = msg.moduleName; category = msg.category.c_str(); function = msg.functionName; time=std::clock(); } }; */ QVariant QtPlatformLogModel::data(const QModelIndex& index, int role) const { const ExtendedLogMessage *msg = &m_Entries[index.row()]; if (role == Qt::DisplayRole) { switch (index.column()) { case 0: if (m_ShowAdvancedFiels) return msg->getTime(); else return msg->getLevel(); case 1: if (m_ShowAdvancedFiels) return msg->getLevel(); else return msg->getMessage(); case 2: if (m_ShowAdvancedFiels) return msg->getMessage(); else return msg->getCategory(); case 3: if (m_ShowAdvancedFiels && m_ShowCategory) return msg->getCategory(); else if (m_ShowAdvancedFiels && !m_ShowCategory) return msg->getModuleName(); else break; case 4: if (m_ShowAdvancedFiels && m_ShowCategory) return msg->getModuleName(); else if (m_ShowAdvancedFiels && !m_ShowCategory) return msg->getFunctionName(); else break; case 5: if (m_ShowAdvancedFiels && m_ShowCategory) return msg->getFunctionName(); else if (m_ShowAdvancedFiels && !m_ShowCategory) return msg->getPath(); else break; case 6: if (m_ShowAdvancedFiels && m_ShowCategory) return msg->getPath(); else if (m_ShowAdvancedFiels && !m_ShowCategory) return msg->getLine(); else break; case 7: if (m_ShowAdvancedFiels && m_ShowCategory) return msg->getLine(); else break; } } else if( role == Qt::DecorationRole ) { if ( (m_ShowAdvancedFiels && index.column()==1) || (!m_ShowAdvancedFiels && index.column()==0) ) { QString file ( ":/org_blueberry_ui_qt_log/information.png" ); if( msg->message.level == mbilog::Error ) file = ":/org_blueberry_ui_qt_log/error.png"; else if( msg->message.level == mbilog::Warn ) file = ":/org_blueberry_ui_qt_log/warning.png"; else if( msg->message.level == mbilog::Debug ) file = ":/org_blueberry_ui_qt_log/debug.png"; else if( msg->message.level == mbilog::Fatal ) file = ":/org_blueberry_ui_qt_log/fatal.png"; QIcon icon(file); return QVariant(icon); } } return QVariant(); } QVariant QtPlatformLogModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { if( m_ShowAdvancedFiels && m_ShowCategory ) { switch (section) { case 0: return QVariant("Time"); case 1: return QVariant("Level"); case 2: return QVariant("Message"); case 3: return QVariant("Category"); case 4: return QVariant("Module"); case 5: return QVariant("Function"); case 6: return QVariant("File"); case 7: return QVariant("Line"); } } else if (m_ShowAdvancedFiels && !m_ShowCategory) { switch (section) { case 0: return QVariant("Time"); case 1: return QVariant("Level"); case 2: return QVariant("Message"); case 3: return QVariant("Module"); case 4: return QVariant("Function"); case 5: return QVariant("File"); case 6: return QVariant("Line"); } } else //!m_ShowAdvancedFiels, m_ShowCategory is not handled seperately because it only activates case 2 { switch (section) { - case 0: return QVariant("Severtiy"); + case 0: return QVariant("Level"); case 1: return QVariant("Message"); case 2: return QVariant("Category"); } } } return QVariant(); } QVariant QtPlatformLogModel::ExtendedLogMessage::getTime() const { std::stringstream ss; std::locale C("C"); ss.imbue(C); ss << std::setw(7) << std::setprecision(3) << std::fixed << ((double)this->time)/CLOCKS_PER_SEC; return QVariant(QString(ss.str().c_str())); } QString QtPlatformLogModel::GetDataAsString() { QString returnValue(""); for (int message=0; messagerowCount(QModelIndex()); message++) { for (int column=0; columncolumnCount(QModelIndex()); column++) { returnValue += " " + this->data(this->index(message,column),Qt::DisplayRole).toString(); } returnValue += "\n"; } return returnValue; } } diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.objectinspector/documentation/UserManual/blueberryobjectinspector.dox b/BlueBerry/Bundles/org.blueberry.ui.qt.objectinspector/documentation/UserManual/blueberryobjectinspector.dox index 1579fff5fa..260687c30b 100644 --- a/BlueBerry/Bundles/org.blueberry.ui.qt.objectinspector/documentation/UserManual/blueberryobjectinspector.dox +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.objectinspector/documentation/UserManual/blueberryobjectinspector.dox @@ -1,8 +1,8 @@ /** -\bundlemainpage{org_blueberry_ui_qt_objectinspector} The Object Browser +\page org_blueberry_ui_qt_objectinspector The Object Browser \image html ObjectBrowser.png "Icon of the Module" This view is only a debugging tool for berry::Object derived classes. */ \ No newline at end of file diff --git a/BlueBerry/CMake/MacroCreateCTKPlugin.cmake b/BlueBerry/CMake/MacroCreateCTKPlugin.cmake index 98751acb3f..cab79a716d 100644 --- a/BlueBerry/CMake/MacroCreateCTKPlugin.cmake +++ b/BlueBerry/CMake/MacroCreateCTKPlugin.cmake @@ -1,150 +1,189 @@ #! \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. macro(MACRO_CREATE_CTK_PLUGIN) - MACRO_PARSE_ARGUMENTS(_PLUGIN "EXPORT_DIRECTIVE;EXPORTED_INCLUDE_SUFFIXES" "TEST_PLUGIN;NO_QHP_TRANSFORM" ${ARGN}) + MACRO_PARSE_ARGUMENTS(_PLUGIN "EXPORT_DIRECTIVE;EXPORTED_INCLUDE_SUFFIXES;DOXYGEN_TAGFILES" "TEST_PLUGIN;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() - # Compute the plugin dependencies - ctkFunctionGetTargetLibraries(_PLUGIN_target_libraries) + #------------------------------------------------------------# + #------------------ 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) 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/BlueBerry/CMake/berryCTKQtHelpDoxygen.conf.in b/BlueBerry/CMake/berryCTKQtHelpDoxygen.conf.in index 509582be8f..6b29f8d63e 100644 --- a/BlueBerry/CMake/berryCTKQtHelpDoxygen.conf.in +++ b/BlueBerry/CMake/berryCTKQtHelpDoxygen.conf.in @@ -1,1553 +1,1802 @@ -# Doxyfile 1.6.3 +# Doxyfile 1.8.0 # This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project +# doxygen (www.doxygen.org) for a project. # -# All text after a hash (#) is considered a comment and will be ignored +# All text after a hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") +# Values that contain spaces should be placed between quotes (" "). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. PROJECT_NAME = "@Plugin-Name@" # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = "@PLUGIN_DOXYGEN_OUTPUT_DIR@" # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, -# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems +# (but less readable) file names. This can be useful if your file system # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = bundlemainpage{1}=\mainpage \ "isHtml=\if NO_SUCH_THING" \ "isHtmlend=\endif" +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO -# Doxygen selects the parser to use depending on the extension of the files it parses. -# With this tag you can assign which parser to use for a given extension. -# Doxygen has a built-in mapping, but you can override or extend it using this tag. -# The format is ext=language, where ext is a file extension, and language is one of -# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, -# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat -# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), -# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. EXTENSION_MAPPING = +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration +# func(std::string) {}). This also makes the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) -# will make doxygen to replace the get and set methods by a property in the +# will make doxygen replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time -# causing a significant performance penality. +# causing a significant performance penalty. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on -# a logarithmic scale so increasing the size by one will rougly double the +# a logarithmic scale so increasing the size by one will roughly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols +# corresponding to a cache size of 2^16 = 65536 symbols. SYMBOL_CACHE_SIZE = 0 +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default -# anonymous namespace are hidden. +# anonymous namespaces are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = NO # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = NO # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = NO # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= NO # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in +# the initial value of a variable or macro consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the +# The appearance of the initializer of individual variables and macros in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. # This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. -SHOW_NAMESPACES = YES +SHOW_NAMESPACES = NO # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by -# doxygen. The layout file controls the global structure of the generated output files -# in an output format independent way. The create the layout file that represents -# doxygen's defaults, run doxygen with the -l option. You can optionally specify a -# file name after the option, if omitted DoxygenLayout.xml will be used as the name -# of the layout file. +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. + +CITE_BIB_FILES = + #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES -# This WARN_NO_PARAMDOC option can be abled to get warnings for +# The WARN_NO_PARAMDOC option can be enabled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = "@PLUGIN_DOXYGEN_INPUT_DIR@" # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl FILE_PATTERNS = *.dox # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES -# The EXCLUDE tag can be used to specify files and/or directories that should +# The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. EXCLUDE = -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = "@PLUGIN_DOXYGEN_INPUT_DIR@" # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. # If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. # Doxygen will compare the file name with each pattern and apply the # filter if there is a match. # The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = YES # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. # Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 3 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a -# standard header. +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! +# style sheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER -# are set, an additional index file will be generated that can be used as input for -# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated -# HTML documentation. +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = YES # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = @Plugin-SymbolicName@ # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = bundle -# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. -# For more information please see +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = @PLUGIN_QHP_CUST_FILTER_NAME@ -# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see -# Qt Help Project / Custom Filters. +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = @PLUGIN_QHP_CUST_FILTER_ATTRS@ -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's # filter section matches. -# Qt Help Project / Filter Attributes. +# +# Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = @PLUGIN_QHP_SECT_FILTER_ATTRS@ # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help -# plugin. To install this plugin and make it available under the help contents +# plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as -# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before the help appears. +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. DISABLE_INDEX = YES -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - -ENUM_VALUES_PER_LINE = 4 - # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. GENERATE_TREEVIEW = NO +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + # By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, # and Class Hierarchy pages using a tree view instead of an ordered list. USE_INLINE_TREES = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 -# When the SEARCHENGINE tag is enabled doxygen will generate a search box for the HTML output. The underlying search engine uses javascript -# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) there is already a search function so this one should +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. +# However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = NO -# When the SERVER_BASED_SEARCH tag is enabled the search engine will be implemented using a PHP enabled web server instead of at the web client using Javascript. Doxygen will generate the search PHP script and index -# file to put on the web server. The advantage of the server based approach is that it scales better to large projects and allows full text search. The disadvances is that it is more difficult to setup +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup # and does not have live searching capabilities. SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and +# by the printer. Possible values are: a4, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO -# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER. +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO -# Load stylesheet definitions from file. Syntax is similar to doxygen's +# Load style sheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. # This is useful # if you want to understand what is going on. # On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. +# pointed to by INCLUDE_PATH will be searched when a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse -# the parser if not removed. +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: # # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # # TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. -TAGFILES = +TAGFILES = @PLUGIN_DOXYGEN_TAGFILES@ # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. -GENERATE_TAGFILE = "@PLUGIN_DOXYGEN_OUTPUT_DIR@/@Plugin-SymbolicName@.tag" +GENERATE_TAGFILE = "@PLUGIN_DOXYGEN_OUTPUT_DIR@/@PROJECT_NAME@.tag" # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more -# powerful graphs. +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO -# By default doxygen will write a font called FreeSans.ttf to the output -# directory and reference it in all dot files that doxygen generates. This -# font does not include all possible unicode characters however, so when you need -# these (or just want a differently looking font) you can specify the font name -# using DOT_FONTNAME. You need need to make sure dot is able to find the font, -# which can be done by putting it in a standard location or by setting the -# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory -# containing the font. +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. DOT_FONTNAME = FreeSans # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 -# By default doxygen will tell dot to use the output directory to look for the -# FreeSans.ttf font (which doxygen will put there itself). If you specify a -# different font using DOT_FONTNAME you can set the path where dot -# can find it using this tag. +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. +# CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. +# will generate a graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). DOT_IMAGE_FORMAT = png +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = YES # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES diff --git a/BlueBerry/CMakeLists.txt b/BlueBerry/CMakeLists.txt index 01c16652c0..fbd75a0416 100644 --- a/BlueBerry/CMakeLists.txt +++ b/BlueBerry/CMakeLists.txt @@ -1,276 +1,280 @@ project(BlueBerry) cmake_minimum_required(VERSION 2.8.4) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/CMake/") include(MacroParseArguments) include(MacroConvertSchema) include(MacroOrganizeSources) include(MacroCreateCTKPlugin) include(MacroCreateQtHelp) include(MacroInstallCTKPlugin) include(FunctionCreateProvisioningFile) if(MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4250 /wd4275 /wd4251 /wd4503") endif() if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) endif() find_package(mbilog REQUIRED) include_directories(${mbilog_INCLUDE_DIRS}) find_package(Qt4 4.6.2 REQUIRED) if(QT_QMAKE_CHANGED) set(QT_HELPGENERATOR_EXECUTABLE NOTFOUND) set(QT_COLLECTIONGENERATOR_EXECUTABLE NOTFOUND) set(QT_ASSISTANT_EXECUTABLE NOTFOUND) set(QT_XMLPATTERNS_EXECUTABLE NOTFOUND) endif() find_program(QT_HELPGENERATOR_EXECUTABLE NAMES qhelpgenerator qhelpgenerator-qt4 qhelpgenerator4 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) find_program(QT_COLLECTIONGENERATOR_EXECUTABLE NAMES qcollectiongenerator qcollectiongenerator-qt4 qcollectiongenerator4 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) find_program(QT_ASSISTANT_EXECUTABLE NAMES assistant-qt4 assistant4 assistant PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) find_program(QT_XMLPATTERNS_EXECUTABLE NAMES xmlpatterns PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) option(BLUEBERRY_USE_QT_HELP "Enable support for integrating bundle documentation into Qt Help" ON) mark_as_advanced(BLUEBERRY_USE_QT_HELP QT_HELPGENERATOR_EXECUTABLE QT_COLLECTIONGENERATOR_EXECUTABLE QT_ASSISTANT_EXECUTABLE QT_XMLPATTERNS_EXECUTABLE) set(_doxygen_too_old 1) if(BLUEBERRY_USE_QT_HELP) find_package(Doxygen) if(DOXYGEN_FOUND) execute_process(COMMAND ${DOXYGEN_EXECUTABLE} --version OUTPUT_VARIABLE _doxygen_version) if(${_doxygen_version} VERSION_GREATER 1.6.0 OR ${_doxygen_version} VERSION_EQUAL 1.6.0) set(_doxygen_too_old 0) endif() endif() if(_doxygen_too_old) message("Doxygen was not found or is too old. Version 1.6.0 or later is needed if BLUEBERRY_USE_QT_HELP is ON") set(BLUEBERRY_USE_QT_HELP OFF CACHE BOOL "Enable support for integrating bundle documentation into Qt Help" FORCE) endif() if(NOT QT_HELPGENERATOR_EXECUTABLE) message("You have enabled Qt Help support, but QT_HELPGENERATOR_EXECUTABLE is empty") set(BLUEBERRY_USE_QT_HELP OFF CACHE BOOL "Enable support for integrating bundle documentation into Qt Help" FORCE) endif() if(NOT QT_XMLPATTERNS_EXECUTABLE) message("You have enabled Qt Help support, but QT_XMLPATTERNS_EXECUTABLE is empty") set(BLUEBERRY_USE_QT_HELP OFF CACHE BOOL "Enable support for integrating bundle documentation into Qt Help" FORCE) endif() endif(BLUEBERRY_USE_QT_HELP) include(${QT_USE_FILE}) # ========= CTK specific CMake stuff ============ cmake_policy(SET CMP0012 NEW) find_package(CTK REQUIRED) # Extract all library names starting with org_blueberry_ macro(GetMyTargetLibraries all_target_libraries varname) set(re_ctkplugin "^org_blueberry_[a-zA-Z0-9_]+$") set(_tmp_list) list(APPEND _tmp_list ${all_target_libraries}) ctkMacroListFilter(_tmp_list re_ctkplugin OUTPUT_VARIABLE ${varname}) endmacro() # ================================================ option(BLUEBERRY_BUILD_ALL_PLUGINS "Build all BlueBerry plugins (overriding selection)" OFF) mark_as_advanced(BLUEBERRY_BUILD_ALL_PLUGINS) if(BLUEBERRY_BUILD_ALL_PLUGINS) set(BLUEBERRY_BUILD_ALL_PLUGINS_OPTION "FORCE_BUILD_ALL") endif() option(BLUEBERRY_STATIC "Build all plugins as static libraries" OFF) mark_as_advanced(BLUEBERRY_STATIC) option(BLUEBERRY_DEBUG_SMARTPOINTER "Enable code for debugging smart pointers" OFF) mark_as_advanced(BLUEBERRY_DEBUG_SMARTPOINTER) find_package(Poco REQUIRED) find_package(Ant) find_package(Eclipse) set(BLUEBERRY_SOURCE_DIR ${BlueBerry_SOURCE_DIR}) set(BLUEBERRY_BINARY_DIR ${BlueBerry_BINARY_DIR}) set(BLUEBERRY_PLUGINS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Bundles) set(BLUEBERRY_PLUGINS_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/Bundles) set(OSGI_APP solstice) set(OSGI_UI_APP solstice_ui) if(Eclipse_DIR) set(BLUEBERRY_DOC_TOOLS_DIR "${Eclipse_DIR}" CACHE PATH "Directory containing additional tools needed for generating the documentation") else() set(BLUEBERRY_DOC_TOOLS_DIR "" CACHE PATH "Directory containing additional tools needed for generating the documentation") endif() set(BLUEBERRY_DEBUG_POSTFIX d) # Testing options if(DEFINED BLUEBERRY_BUILD_TESTING) option(BLUEBERRY_BUILD_TESTING "Build the BlueBerry tests." ${BLUEBERRY_BUILD_TESTING}) else() option(BLUEBERRY_BUILD_TESTING "Build the BlueBerry tests." ${BUILD_TESTING}) endif() if(WIN32) set(_gui_testing_default "ON") else() set(_gui_testing_default "OFF") endif() option(BLUEBERRY_ENABLE_GUI_TESTING "Enable the BlueBerry GUI tests" ${_gui_testing_default}) mark_as_advanced(BLUEBERRY_ENABLE_GUI_TESTING) if(BLUEBERRY_BUILD_TESTING) enable_testing() endif() # Add CTK plugins set(_ctk_plugins Bundles/org.blueberry.osgi:ON Bundles/org.blueberry.compat:OFF Bundles/org.blueberry.core.runtime:OFF Bundles/org.blueberry.core.expressions:OFF Bundles/org.blueberry.solstice.common:OFF Bundles/org.blueberry.core.commands:OFF Bundles/org.blueberry.core.jobs:OFF Bundles/org.blueberry.ui:OFF Bundles/org.blueberry.ui.qt:OFF Bundles/org.blueberry.ui.qt.help:OFF Bundles/org.blueberry.ui.qt.log:ON Bundles/org.blueberry.ui.qt.objectinspector:OFF ) set(_ctk_test_plugins ) set(_ctk_plugins_include_dirs ${Poco_INCLUDE_DIRS} ) set(_ctk_plugins_link_dirs ${Poco_LIBRARY_DIR} ) include_directories(${_ctk_plugins_include_dirs}) link_directories(${_ctk_plugins_link_dirs}) if(BLUEBERRY_BUILD_TESTING) include(berryTestingHelpers) set(BLUEBERRY_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${OSGI_APP}") get_target_property(_is_macosx_bundle ${OSGI_APP} MACOSX_BUNDLE) if(APPLE AND _is_macosx_bundle) set(BLUEBERRY_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${OSGI_APP}.app/Contents/MacOS/${OSGI_APP}") endif() set(_ctk_testinfrastructure_plugins Bundles/org.blueberry.test:ON Bundles/org.blueberry.uitest:ON ) set(_ctk_test_plugins # Testing/org.blueberry.core.runtime.tests:ON # Testing/org.blueberry.osgi.tests:ON ) if(BLUEBERRY_ENABLE_GUI_TESTING) # list(APPEND _ctk_test_plugins Testing/org.blueberry.ui.tests:ON) set(BLUEBERRY_UI_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${OSGI_UI_APP}") get_target_property(_is_macosx_bundle ${OSGI_UI_APP} MACOSX_BUNDLE) if(APPLE AND _is_macosx_bundle) set(BLUEBERRY_UI_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${OSGI_UI_APP}.app/Contents/MacOS/${OSGI_UI_APP}") endif() endif() endif() set(BLUEBERRY_TESTING_PROVISIONING_FILE "${BlueBerry_BINARY_DIR}/BlueBerryTesting.provisioning") add_custom_target(BlueBerry) ctkMacroSetupPlugins(${_ctk_plugins} ${_ctk_testinfrastructure_plugins} ${_ctk_test_plugins} BUILD_OPTION_PREFIX BLUEBERRY_BUILD_ BUILD_ALL ${BLUEBERRY_BUILD_ALL_PLUGINS} COMPACT_OPTIONS) set(BLUEBERRY_PROVISIONING_FILE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/BlueBerry.provisioning") FunctionCreateProvisioningFile( FILE ${BLUEBERRY_PROVISIONING_FILE} PLUGINS ${_ctk_plugins} ) FunctionCreateProvisioningFile( FILE ${BLUEBERRY_TESTING_PROVISIONING_FILE} INCLUDE ${BLUEBERRY_PROVISIONING_FILE} PLUGINS ${_ctk_testinfrastructure_plugins} ${_ctk_test_plugins} ) if(${CMAKE_PROJECT_NAME}_PLUGIN_LIBRARIES) add_dependencies(BlueBerry ${${CMAKE_PROJECT_NAME}_PLUGIN_LIBRARIES}) endif() set_property(TARGET ${${CMAKE_PROJECT_NAME}_PLUGIN_LIBRARIES} PROPERTY LABELS BlueBerry) set(BB_PLUGIN_USE_FILE "${BlueBerry_BINARY_DIR}/BlueBerryPluginUseFile.cmake") if(${PROJECT_NAME}_PLUGIN_LIBRARIES) ctkFunctionGeneratePluginUseFile(${BB_PLUGIN_USE_FILE}) else() file(REMOVE ${BB_PLUGIN_USE_FILE}) set(BB_PLUGIN_USE_FILE ) endif() # CTK Plugin Exports set(BB_PLUGIN_EXPORTS_FILE "${CMAKE_CURRENT_BINARY_DIR}/BlueBerryPluginExports.cmake") GetMyTargetLibraries("${${PROJECT_NAME}_PLUGIN_LIBRARIES}" my_plugin_targets) set(additional_export_targets mbilog PocoFoundation PocoUtil PocoXML) if(BLUEBERRY_BUILD_TESTING) list(APPEND additional_export_targets CppUnit) endif() export(TARGETS ${my_plugin_targets} ${additional_export_targets} FILE ${BB_PLUGIN_EXPORTS_FILE}) add_subdirectory(Documentation) -configure_file(BlueBerryConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/BlueBerryConfig.cmake @ONLY) +set(BLUEBERRY_QTPLUGIN_PATH ) +if(CTK_QTDESIGNERPLUGINS_DIR AND EXISTS ${CTK_QTDESIGNERPLUGINS_DIR}) + set(BLUEBERRY_QTPLUGIN_PATH "${CTK_QTDESIGNERPLUGINS_DIR}") +endif() +configure_file(BlueBerryConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/BlueBerryConfig.cmake @ONLY) diff --git a/BlueBerry/Documentation/doxygen.conf.in b/BlueBerry/Documentation/doxygen.conf.in index daf8818a4a..7f59135730 100644 --- a/BlueBerry/Documentation/doxygen.conf.in +++ b/BlueBerry/Documentation/doxygen.conf.in @@ -1,1785 +1,1828 @@ -# Doxyfile 1.7.5.1 +# Doxyfile 1.8.0 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" "). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or sequence of words) that should # identify the project. Note that if you do not use Doxywizard you need # to put quotes around the project name if it contains spaces. PROJECT_NAME = BlueBerry # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = @BLUEBERRY_VERSION_STRING@ # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer # a quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = "A modular, cross-platform, C++ application framework" # With the PROJECT_LOGO tag one can specify an logo or icon that is # included in the documentation. The maximum height of the logo should not # exceed 55 pixels and the maximum width should not exceed 200 pixels. # Doxygen will copy the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = "@BLUEBERRY_DOXYGEN_OUTPUT_DIR@" # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful if your file system # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = "FIXME=\par Fix Me's:\n" +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given extension. # Doxygen has a built-in mapping, but you can override or extend it using this # tag. The format is ext=language, where ext is a file extension, and language # is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, # C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C # (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions # you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. EXTENSION_MAPPING = +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also makes the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = YES # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and # unions are shown inside the group in which they are included (e.g. using # @ingroup) instead of on a separate page (for HTML and Man pages) or # section (for LaTeX and RTF). INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and # unions with only public data fields will be shown inline in the documentation # of the scope in which they are defined (i.e. file, namespace, or group # documentation), provided this scope is documented. If set to NO (the default), # structs, classes, and unions are shown on a separate page (for HTML and Man # pages) or section (for LaTeX and RTF). INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penalty. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will roughly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols +# corresponding to a cache size of 2^16 = 65536 symbols. SYMBOL_CACHE_SIZE = 0 +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = NO # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespaces are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = YES # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to # do proper type resolution of all parameters of a function it will reject a # match between the prototype and the implementation of a member function even # if there is only one candidate or it is obvious which candidate to choose # by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen # will still accept a match between prototype and implementation in such cases. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or macro consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and macros in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 0 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. # This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. The create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files # containing the references data. This must be a list of .bib files. The # .bib extension is automatically appended if omitted. Using this command # requires the bibtex tool to be installed. See also # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style -# of the bibliography can be controlled using LATEX_BIB_STYLE. +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. CITE_BIB_FILES = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_NO_PARAMDOC option can be enabled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = ./ \ @BLUEBERRY_SOURCE_DIR@/Documentation/ \ @BLUEBERRY_SOURCE_DIR@/CMake/ \ @_doxygen_bundles@ \ @_doxygen_qt4bundles@ \ @_doxygen_binary_bundles@ \ @_doxygen_binary_qt4bundles@ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py # *.f90 *.f *.for *.vhd *.vhdl FILE_PATTERNS = *.h \ *.cpp \ *.dox \ *.txx \ *.cxx \ *.cmake # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES -# The EXCLUDE tag can be used to specify files and/or directories that should +# The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. -# Note that relative paths are relative to directory from which doxygen is run. +# Note that relative paths are relative to the directory from which doxygen is +# run. EXCLUDE = @BLUEBERRY_SOURCE_DIR@/CMake/BundleTemplate/ \ - @BLUEBERRY_SOURCE_DIR@/Documentation/snippets/ \ + @BLUEBERRY_SOURCE_DIR@/Documentation/snippets/ -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = moc_* \ Register* \ */files.cmake \ */.git/* \ @BLUEBERRY_BINARY_DIR@/*.cmake # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test -# Exclude private CMake macros and functions (CMake::_* did not work...) -EXCLUDE_SYMBOLS = _MACRO_* _FUNCTION_* +EXCLUDE_SYMBOLS = _MACRO_* \ + _FUNCTION_* # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = @BLUEBERRY_DOXYGEN_OUTPUT_DIR@/../extension-points \ - @BLUEBERRY_SOURCE_DIR@/Documentation/snippets/ \ + @BLUEBERRY_SOURCE_DIR@/Documentation/snippets/ # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = "@BLUEBERRY_SOURCE_DIR@" # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. # If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. # Doxygen will compare the file name with each pattern and apply the # filter if there is a match. # The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty or if # non of the patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = *.cmake=@CMakeDoxygenFilter_EXECUTABLE@ # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) # and it is also possible to disable source filtering for a specific pattern # using *.ext= (so without naming a filter). This option only has effect when # FILTER_SOURCE_FILES is enabled. FILTER_SOURCE_PATTERNS = #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. # Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 3 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. Note that when using a custom header you are responsible # for the proper inclusion of any scripts and style sheets that doxygen # needs, which is dependent on the configuration options used. -# It is adviced to generate a default header using "doxygen -w html +# It is advised to generate a default header using "doxygen -w html # header.html footer.html stylesheet.css YourConfigFile" and then modify # that header. Note that the header is subject to change so you typically # have to redo this when upgrading to a newer version of doxygen or when # changing the value of configuration settings such as GENERATE_TREEVIEW! HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! +# style sheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = @BLUEBERRY_DOXYGEN_STYLESHEET@ # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that # the files will be copied as-is; there are no commands or markers available. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. -# Doxygen will adjust the colors in the stylesheet and background images +# Doxygen will adjust the colors in the style sheet and background images # according to this color. Hue is specified as an angle on a colorwheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below # 100 gradually make the output lighter, whereas values above 100 make # the output darker. The value divided by 100 is the actual gamma applied, # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = YES # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated # that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to # add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see # # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's # filter section matches. # # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. DISABLE_INDEX = NO -# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values -# (range [0,1..20]) that doxygen will group on one line in the generated HTML -# documentation. Note that a value of 0 will completely suppress the enum -# values from appearing in the overview section. - -ENUM_VALUES_PER_LINE = 4 - # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. GENERATE_TREEVIEW = YES +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + # By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, # and Class Hierarchy pages using a tree view instead of an ordered list. USE_INLINE_TREES = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 300 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are # not supported properly for IE 6.0, but are supported on all modern browsers. # Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax # (see http://www.mathjax.org) which uses client side Javascript for the # rendering instead of using prerendered bitmaps. Use this if you do not # have LaTeX installed or if you want to formulas look prettier in the HTML -# output. When enabled you also need to install MathJax separately and +# output. When enabled you may also need to install MathJax separately and # configure the path to it using the MATHJAX_RELPATH option. USE_MATHJAX = NO # When MathJax is enabled you need to specify the location relative to the # HTML output directory using the MATHJAX_RELPATH option. The destination # directory should contain the MathJax.js script. For instance, if the mathjax # directory is located at the same level as the HTML output directory, then -# MATHJAX_RELPATH should be ../mathjax. The default value points to the -# mathjax.org site, so you can quickly see the result without installing -# MathJax, but it is strongly recommended to install a local copy of MathJax -# before deployment. +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. +# However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. MATHJAX_RELPATH = http://www.mathjax.org/mathjax # The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension # names that should be enabled during MathJax rendering. MATHJAX_EXTENSIONS = # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a PHP enabled web server instead of at the web client # using Javascript. Doxygen will generate the search PHP script and index # file to put on the web server. The advantage of the server # based approach is that it scales better to large projects and allows # full text search. The disadvantages are that it is more difficult to setup # and does not have live searching capabilities. SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for # the generated latex document. The footer should contain everything after # the last chapter. If it is left blank doxygen will generate a # standard footer. Notice: only use this tag if you know what you are doing! LATEX_FOOTER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See # http://en.wikipedia.org/wiki/BibTeX for more info. LATEX_BIB_STYLE = plain #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO -# Load stylesheet definitions from file. Syntax is similar to doxygen's +# Load style sheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. # This is useful # if you want to understand what is going on. # On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # pointed to by INCLUDE_PATH will be searched when a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = FREEVERSION \ ERROR_CHECKING \ HAS_TIFF \ HAS_JPEG \ HAS_NETLIB \ HAS_PNG \ HAS_ZLIB \ HAS_GLUT \ HAS_QT \ size_t=vcl_size_t \ DOXYGEN_SKIP # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition that # overrules the definition found in the source code. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all references to function-like macros # that are alone on a line, have an all uppercase name, and do not end with a # semicolon, because these will confuse the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: # # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # # TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = "@BLUEBERRY_DOXYGEN_TAGFILE_NAME@" # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option also works with HAVE_DOT disabled, but it is recommended to # install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = @HAVE_DOT@ # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is # allowed to run in parallel. When set to 0 (the default) doxygen will # base this on the number of processors available in the system. You can set it # explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. DOT_NUM_THREADS = 0 # By default doxygen will use the Helvetica font for all dot files that # doxygen generates. When you want a differently looking font you can specify # the font name using DOT_FONTNAME. You need to make sure dot is able to find # the font, which can be done by putting it in a standard location or by setting # the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the # directory containing the font. DOT_FONTNAME = FreeSans.ttf # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the Helvetica font. # If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to # set the path where dot can find it. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. +# CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will generate a graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are svg, png, jpg, or gif. # If left blank png will be used. If you choose svg you need to set # HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible in IE 9+ (other browsers do not have this requirement). DOT_IMAGE_FORMAT = png # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. # Note that this requires a modern browser other than Internet Explorer. # Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you # need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible. Older versions of IE do not have SVG support. INTERACTIVE_SVG = NO # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = "@DOXYGEN_DOT_PATH@" # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the # \mscfile command). MSCFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = YES # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES diff --git a/CMake/FindDCMTK.cmake b/CMake/FindDCMTK.cmake index bd1f3b7ab0..7f1000e9e7 100644 --- a/CMake/FindDCMTK.cmake +++ b/CMake/FindDCMTK.cmake @@ -1,157 +1,180 @@ # adapted version of FindDCMTK, better suited for super-builds # - find DCMTK libraries and applications # # DCMTK_INCLUDE_DIRS - Directories to include to use DCMTK # DCMTK_LIBRARIES - Files to link against to use DCMTK # DCMTK_FOUND - If false, don't try to use DCMTK # DCMTK_DIR - (optional) Source directory for DCMTK # # DCMTK_DIR can be used to make it simpler to find the various include # directories and compiled libraries if you've just compiled it in the # source tree. Just set it to the root of the tree where you extracted # the source (default to /usr/include/dcmtk/) #============================================================================= # Copyright 2004-2009 Kitware, Inc. # Copyright 2009-2010 Mathieu Malaterre # Copyright 2010 Thomas Sondergaard # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distributed this file outside of CMake, substitute the full # License text for the above reference.) # # Written for VXL by Amitha Perera. # Upgraded for GDCM by Mathieu Malaterre. # Modified for EasyViz by Thomas Sondergaard. # # prefer DCMTK_DIR over default system paths like /usr/lib set(CMAKE_PREFIX_PATH ${DCMTK_DIR}/lib ${CMAKE_PREFIX_PATH}) # this is given to FIND_LIBRARY or FIND_PATH if(NOT DCMTK_FOUND AND NOT DCMTK_DIR) set(DCMTK_DIR "/usr/include/dcmtk/" CACHE PATH "Root of DCMTK source tree (optional).") mark_as_advanced(DCMTK_DIR) endif() +# Find all libraries, store debug and release separately foreach(lib - dcmdata - dcmimage - dcmimgle - dcmjpeg - dcmnet dcmpstat - dcmqrdb - dcmsign dcmsr + dcmsign dcmtls + dcmqrdb + dcmnet + dcmjpeg + dcmimage + dcmimgle + dcmdata + oflog + ofstd ijg12 ijg16 ijg8 - oflog - ofstd) + ) - find_library(DCMTK_${lib}_LIBRARY + # Find Release libraries + find_library(DCMTK_${lib}_LIBRARY_RELEASE ${lib} PATHS ${DCMTK_DIR}/${lib}/libsrc ${DCMTK_DIR}/${lib}/libsrc/Release - ${DCMTK_DIR}/${lib}/libsrc/Debug ${DCMTK_DIR}/${lib}/Release - ${DCMTK_DIR}/${lib}/Debug ${DCMTK_DIR}/lib + ${DCMTK_DIR}/lib/Release + ${DCMTK_DIR}/dcmjpeg/lib${lib}/Release NO_DEFAULT_PATH ) - mark_as_advanced(DCMTK_${lib}_LIBRARY) - - #message("** DCMTKs ${lib} found at ${DCMTK_${lib}_LIBRARY}") - - if(DCMTK_${lib}_LIBRARY) - list(APPEND DCMTK_LIBRARIES ${DCMTK_${lib}_LIBRARY}) + # Find Debug libraries + find_library(DCMTK_${lib}_LIBRARY_DEBUG + ${lib} + PATHS + ${DCMTK_DIR}/${lib}/libsrc + ${DCMTK_DIR}/${lib}/libsrc/Debug + ${DCMTK_DIR}/${lib}/Debug + ${DCMTK_DIR}/lib + ${DCMTK_DIR}/lib/Debug + ${DCMTK_DIR}/dcmjpeg/lib${lib}/Debug + NO_DEFAULT_PATH + ) + + mark_as_advanced(DCMTK_${lib}_LIBRARY_RELEASE) + mark_as_advanced(DCMTK_${lib}_LIBRARY_DEBUG) + + # Add libraries to variable according to build type + set(DCMTK_${lib}_LIBRARY) + if(DCMTK_${lib}_LIBRARY_RELEASE) + list(APPEND DCMTK_LIBRARIES optimized ${DCMTK_${lib}_LIBRARY_RELEASE}) + list(APPEND DCMTK_${lib}_LIBRARY optimized ${DCMTK_${lib}_LIBRARY_RELEASE}) + endif() + + if(DCMTK_${lib}_LIBRARY_DEBUG) + list(APPEND DCMTK_LIBRARIES debug ${DCMTK_${lib}_LIBRARY_DEBUG}) + list(APPEND DCMTK_${lib}_LIBRARY debug ${DCMTK_${lib}_LIBRARY_DEBUG}) endif() endforeach() - set(DCMTK_config_TEST_HEADER osconfig.h) set(DCMTK_dcmdata_TEST_HEADER dctypes.h) set(DCMTK_dcmimage_TEST_HEADER dicoimg.h) set(DCMTK_dcmimgle_TEST_HEADER dcmimage.h) set(DCMTK_dcmjpeg_TEST_HEADER djdecode.h) set(DCMTK_dcmnet_TEST_HEADER assoc.h) set(DCMTK_dcmpstat_TEST_HEADER dcmpstat.h) set(DCMTK_dcmqrdb_TEST_HEADER dcmqrdba.h) set(DCMTK_dcmsign_TEST_HEADER sicert.h) set(DCMTK_dcmsr_TEST_HEADER dsrtree.h) set(DCMTK_dcmtls_TEST_HEADER tlslayer.h) set(DCMTK_ofstd_TEST_HEADER ofstdinc.h) foreach(dir config dcmdata dcmimage dcmimgle dcmjpeg dcmnet dcmpstat dcmqrdb dcmsign dcmsr dcmtls ofstd) find_path(DCMTK_${dir}_INCLUDE_DIR ${DCMTK_${dir}_TEST_HEADER} PATHS ${DCMTK_DIR}/${dir}/include ${DCMTK_DIR}/${dir} ${DCMTK_DIR}/include/dcmtk/${dir} ${DCMTK_DIR}/include/${dir}) mark_as_advanced(DCMTK_${dir}_INCLUDE_DIR) #message("** DCMTKs ${dir} found at ${DCMTK_${dir}_INCLUDE_DIR}") if(DCMTK_${dir}_INCLUDE_DIR) list(APPEND DCMTK_INCLUDE_DIRS ${DCMTK_${dir}_INCLUDE_DIR}) endif() endforeach() if(WIN32) list(APPEND DCMTK_LIBRARIES netapi32 wsock32) endif() if(DCMTK_ofstd_INCLUDE_DIR) get_filename_component(DCMTK_dcmtk_INCLUDE_DIR ${DCMTK_ofstd_INCLUDE_DIR} PATH CACHE) list(APPEND DCMTK_INCLUDE_DIRS ${DCMTK_dcmtk_INCLUDE_DIR}) mark_as_advanced(DCMTK_dcmtk_INCLUDE_DIR) endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(DCMTK DEFAULT_MSG DCMTK_config_INCLUDE_DIR DCMTK_ofstd_INCLUDE_DIR DCMTK_ofstd_LIBRARY DCMTK_dcmdata_INCLUDE_DIR DCMTK_dcmdata_LIBRARY DCMTK_dcmimgle_INCLUDE_DIR - DCMTK_dcmimgle_LIBRARY) + DCMTK_dcmimgle_LIBRARY + ) # Compatibility: This variable is deprecated set(DCMTK_INCLUDE_DIR ${DCMTK_INCLUDE_DIRS}) diff --git a/CMake/PackageDepends/MITK_DCMTK_Config.cmake b/CMake/PackageDepends/MITK_DCMTK_Config.cmake index 3f59479417..8221c975e4 100644 --- a/CMake/PackageDepends/MITK_DCMTK_Config.cmake +++ b/CMake/PackageDepends/MITK_DCMTK_Config.cmake @@ -1,48 +1,58 @@ if(MITK_USE_DCMTK) if(NOT DCMTK_DIR) set(DCMTK_DIR "$ENV{DCMTK_DIR}" CACHE PATH "Location of DCMTK") set(DCMTK_DIR "$ENV{DCMTK_DIR}") if(NOT DCMTK_DIR) message(FATAL_ERROR "DCMTK_DIR not set. Cannot proceed.") endif(NOT DCMTK_DIR) endif(NOT DCMTK_DIR) find_package(DCMTK) if(NOT DCMTK_FOUND) message(SEND_ERROR "DCMTK development files not found.\n Please check variables (e.g. DCMTK_DIR) for include directories and libraries.\nYou may set environment variable DCMTK_DIR before pressing 'configure'") endif(NOT DCMTK_FOUND) if( NOT WIN32 ) set(MISSING_LIBS_REQUIRED_BY_DCMTK wrap tiff z) endif( NOT WIN32 ) set(QT_USE_QTSQL 1) if(EXISTS ${DCMTK_config_INCLUDE_DIR}/osconfig.h) file(READ ${DCMTK_config_INCLUDE_DIR}/osconfig.h _osconfig_h) if(NOT _osconfig_h MATCHES "PACKAGE_VERSION_NUMBER \"354\"") # message(STATUS "Found DCMTK newer that 3.5.4 ...") set(MITK_USE_DCMTK_NEWER_THAN_3_5_4 TRUE) # assume the new oflog library is located next to the others # this can be removed if FindDCMTK is adapted for 3.5.5 - get_filename_component(_DCMTK_lib_dir ${DCMTK_ofstd_LIBRARY} PATH) - find_library(DCMTK_oflog_LIBRARY oflog ${_DCMTK_lib_dir} ) - list(APPEND DCMTK_LIBRARIES ${DCMTK_oflog_LIBRARY}) + # treat Debug and Release separately + get_filename_component(_DCMTK_lib_dir_release ${DCMTK_ofstd_LIBRARY_RELEASE} PATH) + get_filename_component(_DCMTK_lib_dir_debug ${DCMTK_ofstd_LIBRARY_DEBUG} PATH) + set(DCMTK_oflog_LIBRARY_RELEASE ) + set(DCMTK_oflog_LIBRARY_DEBUG ) + if(_DCMTK_lib_dir_release) + find_library(DCMTK_oflog_LIBRARY_RELEASE oflog ${_DCMTK_lib_dir_release} ) + list(APPEND DCMTK_LIBRARIES optimized ${DCMTK_oflog_LIBRARY_RELEASE} ) + endif() + if(_DCMTK_lib_dir_debug) + find_library(DCMTK_oflog_LIBRARY_DEBUG oflog ${_DCMTK_lib_dir_debug} ) + list(APPEND DCMTK_LIBRARIES debug ${DCMTK_oflog_LIBRARY_DEBUG} ) + endif() endif(NOT _osconfig_h MATCHES "PACKAGE_VERSION_NUMBER \"354\"") endif(EXISTS ${DCMTK_config_INCLUDE_DIR}/osconfig.h) # # Usually all code should be adapted to DCMTK 3.6 # If necessary you could configure the MITK_USE_DCMTK_NEWER_THAN_3_5_4 variable # to configure a header file for ifdefs: # configure_file( mitkDCMTKConfig.h.in mitkDCMTKConfig.h ) list(APPEND ALL_INCLUDE_DIRECTORIES ${DCMTK_INCLUDE_DIR} ${DCMTK_DIR}/include) list(APPEND ALL_LIBRARIES ${DCMTK_LIBRARIES} ${MISSING_LIBS_REQUIRED_BY_DCMTK}) #link_directories() endif(MITK_USE_DCMTK) diff --git a/CMake/QBundleTemplate/documentation/Manual/Manual.dox b/CMake/QBundleTemplate/documentation/Manual/Manual.dox index ef05c90079..abec43a1ef 100755 --- a/CMake/QBundleTemplate/documentation/Manual/Manual.dox +++ b/CMake/QBundleTemplate/documentation/Manual/Manual.dox @@ -1,13 +1,13 @@ /** -\bundlemainpage{@PLUGIN_ID@} @PLUGIN_NAME@ +\page @PLUGIN_ID@ @PLUGIN_NAME@ \image html icon.png "Icon of @PLUGIN_NAME@" Available sections: - \ref @PLUGIN_ID@Overview \section @PLUGIN_ID@Overview This is the description for the @PLUGIN_NAME@. */ diff --git a/CMake/mitkInstallRules.cmake b/CMake/mitkInstallRules.cmake index 0af9b7e741..976ba8459c 100644 --- a/CMake/mitkInstallRules.cmake +++ b/CMake/mitkInstallRules.cmake @@ -1,74 +1,109 @@ MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/mitk.ico ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/mitk.bmp ) #STATEMACHINE XML MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Core/Code/Interactions/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 e8a3ed57e7..2d377727f8 100644 --- a/CMake/mitkMacroCreateCTKPlugin.cmake +++ b/CMake/mitkMacroCreateCTKPlugin.cmake @@ -1,42 +1,50 @@ macro(MACRO_CREATE_MITK_CTK_PLUGIN) MACRO_PARSE_ARGUMENTS(_PLUGIN "EXPORT_DIRECTIVE;EXPORTED_INCLUDE_SUFFIXES;MODULE_DEPENDENCIES;SUBPROJECTS" "TEST_PLUGIN" ${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") else() set(is_test_plugin) endif() + set(_mitk_tagfile ) + + if(EXISTS ${MITK_DOXYGEN_TAGFILE_NAME}) + # Todo: Point to stable documentations for stable builds + set(_mitk_tagfile "${MITK_DOXYGEN_TAGFILE_NAME}=http://docs.mitk.org/nightly-qt4/") + endif() + MACRO_CREATE_CTK_PLUGIN(EXPORT_DIRECTIVE ${_PLUGIN_EXPORT_DIRECTIVE} EXPORTED_INCLUDE_SUFFIXES ${_PLUGIN_EXPORTED_INCLUDE_SUFFIXES} + DOXYGEN_TAGFILES ${_PLUGIN_DOXYGEN_TAGFILES} ${_mitk_tagfile} ${is_test_plugin}) target_link_libraries(${PLUGIN_TARGET} ${ALL_LIBRARIES}) 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() 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/mitkMacroInstall.cmake b/CMake/mitkMacroInstall.cmake index 27cf5421a7..cea1a32477 100644 --- a/CMake/mitkMacroInstall.cmake +++ b/CMake/mitkMacroInstall.cmake @@ -1,123 +1,127 @@ # # MITK specific install macro # # On Mac everything is installed for each bundle listed in MACOSX_BUNDLE_NAMES # by replacing the DESTINATION parameter. Everything else is passed to the CMake INSTALL command # # Usage: MITK_INSTALL( ) # macro(MITK_INSTALL) set(ARGS ${ARGN}) set(install_directories "") list(FIND ARGS DESTINATION _destination_index) # set(_install_DESTINATION "") if(_destination_index GREATER -1) message(SEND_ERROR "MITK_INSTALL macro must not be called with a DESTINATION parameter.") ### This code was a try to replace a given DESTINATION #math(EXPR _destination_index ${_destination_index} + 1) #list(GET ARGS ${_destination_index} _install_DESTINATION) #string(REGEX REPLACE ^bin "" _install_DESTINATION ${_install_DESTINATION}) else() if(NOT MACOSX_BUNDLE_NAMES) install(${ARGS} DESTINATION bin) else() foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) install(${ARGS} DESTINATION ${bundle_name}.app/Contents/MacOS/${_install_DESTINATION}) endforeach() endif() endif() endmacro() # Fix _target_location # This is used in several install macros macro(_fixup_target) install(CODE " macro(gp_item_default_embedded_path_override item default_embedded_path_var) get_filename_component(_item_name \"\${item}\" NAME) get_filename_component(_item_path \"\${item}\" PATH) # We have to fix all path references to build trees for plugins if(NOT _item_path MATCHES \"\${CMAKE_INSTALL_PREFIX}/${_bundle_dest_dir}\") # item with relative path or embedded path pointing to some build dir set(full_path \"full_path-NOTFOUND\") file(GLOB_RECURSE full_path \${CMAKE_INSTALL_PREFIX}/${_bundle_dest_dir}/\${_item_name} ) + list(LENGTH full_path full_path_length) + if(full_path_length GREATER 1) + list(GET full_path 0 full_path) + endif() get_filename_component(_item_path \"\${full_path}\" PATH) endif() if(_item_path STREQUAL \"\${CMAKE_INSTALL_PREFIX}/${_bundle_dest_dir}/plugins\" OR _item_name MATCHES \"liborg\" # this is for legacy BlueBerry bundle support ) # Only fix plugins message(\"override: \${item}\") message(\"found file: \${_item_path}/\${_item_name}\") if(APPLE) string(REPLACE \${CMAKE_INSTALL_PREFIX}/${_bundle_dest_dir} @executable_path \${default_embedded_path_var} \"\${_item_path}\" ) else() set(\${default_embedded_path_var} \"\${_item_path}\") endif() message(\"override result: \${\${default_embedded_path_var}}\") endif() endmacro(gp_item_default_embedded_path_override) macro(gp_resolved_file_type_override file type) if(NOT APPLE) get_filename_component(_file_path \"\${file}\" PATH) get_filename_component(_file_name \"\${file}\" NAME) if(_file_path MATCHES \"^\${CMAKE_INSTALL_PREFIX}\") set(\${type} \"local\") endif() if(_file_name MATCHES gdiplus) set(\${type} \"system\") endif(_file_name MATCHES gdiplus) endif() endmacro(gp_resolved_file_type_override) - if(NOT APPLE AND (UNIX OR MINGW)) + if(NOT APPLE) macro(gp_resolve_item_override context item exepath dirs resolved_item_var resolved_var) if(\${item} MATCHES \"blueberry_osgi\") get_filename_component(_item_name \${item} NAME) set(\${resolved_item_var} \"\${exepath}/plugins/\${_item_name}\") set(\${resolved_var} 1) endif() endmacro() endif() if(\"${_install_GLOB_PLUGINS}\" STREQUAL \"TRUE\") file(GLOB_RECURSE GLOBBED_BLUEBERRY_PLUGINS # glob for all blueberry bundles of this application \"\${CMAKE_INSTALL_PREFIX}/${_bundle_dest_dir}/liborg*${CMAKE_SHARED_LIBRARY_SUFFIX}\") endif() file(GLOB_RECURSE GLOBBED_QT_PLUGINS # glob for Qt plugins \"\${CMAKE_INSTALL_PREFIX}/${${_target_location}_qt_plugins_install_dir}/plugins/*${CMAKE_SHARED_LIBRARY_SUFFIX}\") # use custom version of BundleUtilities message(\"globbed plugins: \${GLOBBED_QT_PLUGINS} \${GLOBBED_BLUEBERRY_PLUGINS}\") set(PLUGIN_DIRS) set(PLUGINS ${_install_PLUGINS} \${GLOBBED_QT_PLUGINS} \${GLOBBED_BLUEBERRY_PLUGINS}) if(PLUGINS) list(REMOVE_DUPLICATES PLUGINS) endif(PLUGINS) foreach(_plugin \${GLOBBED_BLUEBERRY_PLUGINS}) get_filename_component(_pluginpath \${_plugin} PATH) list(APPEND PLUGIN_DIRS \${_pluginpath}) endforeach(_plugin) set(DIRS ${DIRS}) list(APPEND DIRS \${PLUGIN_DIRS}) list(REMOVE_DUPLICATES DIRS) # use custom version of BundleUtilities set(CMAKE_MODULE_PATH ${MITK_SOURCE_DIR}/CMake ${CMAKE_MODULE_PATH} ) include(BundleUtilities) fixup_bundle(\"\${CMAKE_INSTALL_PREFIX}/${_target_location}\" \"\${PLUGINS}\" \"\${DIRS}\") ") endmacro() diff --git a/CMakeExternals/CTK.cmake b/CMakeExternals/CTK.cmake index 88b5da01f4..a647402efb 100644 --- a/CMakeExternals/CTK.cmake +++ b/CMakeExternals/CTK.cmake @@ -1,79 +1,81 @@ #----------------------------------------------------------------------------- # 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 2b5ab7c4) + set(revision_tag f8d63311) #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 ) 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 2352b3078d045387232ac148c63b1c3a + URL_MD5 cbd57918a076d6c3830313c01724ceaf 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/DCMTK.cmake b/CMakeExternals/DCMTK.cmake index f6bc6d3f64..217b581134 100644 --- a/CMakeExternals/DCMTK.cmake +++ b/CMakeExternals/DCMTK.cmake @@ -1,63 +1,65 @@ #----------------------------------------------------------------------------- # 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(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 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_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/MITKData.cmake b/CMakeExternals/MITKData.cmake index 993e0b4fc9..66eb308a2e 100644 --- a/CMakeExternals/MITKData.cmake +++ b/CMakeExternals/MITKData.cmake @@ -1,38 +1,39 @@ #----------------------------------------------------------------------------- # MITK Data #----------------------------------------------------------------------------- # Sanity checks if(DEFINED MITK_DATA_DIR AND NOT EXISTS ${MITK_DATA_DIR}) message(FATAL_ERROR "MITK_DATA_DIR variable is defined but corresponds to non-existing directory") endif() set(proj MITK-Data) set(proj_DEPENDENCIES) set(MITK-Data_DEPENDS ${proj}) if(BUILD_TESTING) - set(revision_tag c3794753) + set(revision_tag a9c994aa) + #if(${proj}_REVISION_TAG) # set(revision_tag ${${proj}_REVISION_TAG}) #endif() ExternalProject_Add(${proj} URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/MITK-Data_${revision_tag}.tar.gz UPDATE_COMMAND "" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" DEPENDS ${proj_DEPENDENCIES} ) set(MITK_DATA_DIR ${ep_source_dir}/${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif(BUILD_TESTING) diff --git a/CMakeLists.txt b/CMakeLists.txt index 90917a7706..75a1ae56f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,916 +1,916 @@ 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_Python "Use Python wrapping in MITK" OFF) set(MITK_USE_CableSwig ${MITK_USE_Python}) 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(mitkFunctionCreateWindowsBatchScript) include(mitkFunctionInstallProvisioningFiles) 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 ExtApp +# 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) #----------------------------------------------------------------------------- # 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}") include(mitkSetupC++0xVariables) set(cflags ) if(WIN32) set(cflags "${cflags} -DPOCO_NO_UNWINDOWS -DWIN32_LEAN_AND_MEAN") endif() if(CMAKE_COMPILER_IS_GNUCXX) set(cflags "${cflags} -Wall -Wextra -Wpointer-arith -Winvalid-pch -Wcast-align -Wwrite-strings") mitkFunctionCheckCompilerFlags("-fdiagnostics-show-option" cflags) mitkFunctionCheckCompilerFlags("-Wl,--no-undefined" cflags) mitkFunctionCheckCompilerFlags("-Wl,--as-needed" cflags) 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) 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}") 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}") #----------------------------------------------------------------------------- # 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() 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(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MITK_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${MITK_CXX_FLAGS_RELEASE}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${MITK_C_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) 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() 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() # 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 #----------------------------------------------------------------------------- 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) endif() #----------------------------------------------------------------------------- # Documentation #----------------------------------------------------------------------------- add_subdirectory(Documentation) #----------------------------------------------------------------------------- # Installation #----------------------------------------------------------------------------- # set MITK cpack variables # These are the default variables, which can be overwritten ( see below ) include(mitkSetupCPack) set(use_default_config ON) # MITK_APPS is set in Applications/AppList.cmake (included somewhere above # if MITK_USE_BLUEBERRY is set to ON). if(MITK_APPS) set(activated_apps_no 0) list(LENGTH MITK_APPS app_count) # Check how many apps have been enabled # If more than one app has been activated, the we use the # default CPack configuration. Otherwise that apps configuration # will be used, if present. foreach(mitk_app ${MITK_APPS}) # extract option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 1 option_name) # check if the application is enabled if(${option_name} OR MITK_BUILD_ALL_APPS) MATH(EXPR activated_apps_no "${activated_apps_no} + 1") endif() endforeach() if(app_count EQUAL 1 AND (activated_apps_no EQUAL 1 OR MITK_BUILD_ALL_APPS)) # Corner case if there is only one app in total set(use_project_cpack ON) elseif(activated_apps_no EQUAL 1 AND NOT MITK_BUILD_ALL_APPS) # Only one app is enabled (no "build all" flag set) set(use_project_cpack ON) else() # Less or more then one app is enabled set(use_project_cpack OFF) endif() foreach(mitk_app ${MITK_APPS}) # extract target_dir and option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 0 target_dir) list(GET target_info_list 1 option_name) # check if the application is enabled if(${option_name} OR MITK_BUILD_ALL_APPS) # check whether application specific configuration files will be used if(use_project_cpack) # use files if they exist if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/Applications/${target_dir}/CPackOptions.cmake") include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/${target_dir}/CPackOptions.cmake") endif() if(EXISTS "${PROJECT_SOURCE_DIR}/Applications/${target_dir}/CPackConfig.cmake.in") set(CPACK_PROJECT_CONFIG_FILE "${PROJECT_BINARY_DIR}/Applications/${target_dir}/CPackConfig.cmake") configure_file(${PROJECT_SOURCE_DIR}/Applications/${target_dir}/CPackConfig.cmake.in ${CPACK_PROJECT_CONFIG_FILE} @ONLY) set(use_default_config OFF) endif() endif() # add link to the list list(APPEND CPACK_CREATE_DESKTOP_LINKS "${target_dir}") endif() endforeach() endif() # if no application specific configuration file was used, use default if(use_default_config) configure_file(${MITK_SOURCE_DIR}/MITKCPackOptions.cmake.in ${MITK_BINARY_DIR}/MITKCPackOptions.cmake @ONLY) set(CPACK_PROJECT_CONFIG_FILE "${MITK_BINARY_DIR}/MITKCPackOptions.cmake") endif() # include CPack model once all variables are set include(CPack) # Additional installation rules include(mitkInstallRules) #----------------------------------------------------------------------------- # Last configuration steps #----------------------------------------------------------------------------- set(MITK_EXPORTS_FILE "${MITK_BINARY_DIR}/MitkExports.cmake") file(REMOVE ${MITK_EXPORTS_FILE}) if(MITK_USE_BLUEBERRY) # This is for installation support of external projects depending on # MITK plugins. 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). if(MITK_PLUGIN_LIBRARIES) export(TARGETS ${MITK_PLUGIN_LIBRARIES} APPEND FILE ${MITK_EXPORTS_FILE}) endif() endif() 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/Core/Code/Algorithms/mitkExtractSliceFilter.h b/Core/Code/Algorithms/mitkExtractSliceFilter.h index a36c7ab9b0..58a410b446 100644 --- a/Core/Code/Algorithms/mitkExtractSliceFilter.h +++ b/Core/Code/Algorithms/mitkExtractSliceFilter.h @@ -1,184 +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. ===================================================================*/ #ifndef mitkExtractSliceFilter_h_Included #define mitkExtractSliceFilter_h_Included #include "MitkExports.h" #include "mitkImageToImageFilter.h" #include #include #include #include #include #include #include namespace mitk { /** \brief ExtractSliceFilter extracts a 2D abitrary oriented slice from a 3D volume. - The filter can reslice in all orthogonal planes such as sagittal, coronal and transversal, + The filter can reslice in all orthogonal planes such as sagittal, coronal and axial, and is also able to reslice a abitrary oriented oblique plane. Curved planes are specified via an AbstractTransformGeometry as the input worldgeometry. The convinient workflow is: 1. Set an image as input. 2. Set the worldGeometry2D. This defines a grid where the slice is being extracted 3. And then start the pipeline. There are a few more properties that can be set to modify the behavior of the slicing. The properties are: - interpolation mode either Nearestneighbor, Linear or Cubic. - a transform this is a convinient way to adapt the reslice axis for the case that the image is transformed e.g. rotated. - time step the time step in a timesliced volume. - resample by geometry wether the resampling grid corresponds to the specs of the worldgeometry or is directly derived from the input image By default the properties are set to: - interpolation mode Nearestneighbor. - a transform NULL (No transform is set). - time step 0. - resample by geometry false (Corresponds to input image). */ class MITK_CORE_EXPORT ExtractSliceFilter : public ImageToImageFilter { public: mitkClassMacro(ExtractSliceFilter, ImageToImageFilter); itkNewMacro(ExtractSliceFilter); mitkNewMacro1Param(Self, vtkImageReslice*); /** \brief Set the axis where to reslice at.*/ void SetWorldGeometry(const Geometry2D* geometry ){ this->m_WorldGeometry = geometry; } /** \brief Set the time step in the 4D volume */ void SetTimeStep( unsigned int timestep){ this->m_TimeStep = timestep; } unsigned int GetTimeStep(){ return this->m_TimeStep; } /** \brief Set a transform for the reslice axes. * This transform is needed if the image volume itself is transformed. (Effects the reslice axis) */ void SetResliceTransformByGeometry(const Geometry3D* transform){ this->m_ResliceTransform = transform; } /** \brief Resampling grid corresponds to: false->image true->worldgeometry*/ void SetInPlaneResampleExtentByGeometry(bool inPlaneResampleExtentByGeometry){ this->m_InPlaneResampleExtentByGeometry = inPlaneResampleExtentByGeometry; } /** \brief Sets the output dimension of the slice*/ void SetOutputDimensionality(unsigned int dimension){ this->m_OutputDimension = dimension; } /** \brief Set the spacing in z direction manually. * Required if the outputDimension is > 2. */ void SetOutputSpacingZDirection(double zSpacing){ this->m_ZSpacing = zSpacing; } /** \brief Set the extent in pixel for direction z manualy. Required if the output dimension is > 2. */ void SetOutputExtentZDirection(int zMin, int zMax) { this->m_ZMin = zMin; this->m_ZMax = zMax; } /** \brief Get the bounding box of the slice [xMin, xMax, yMin, yMax, zMin, zMax] * The method uses the input of the filter to calculate the bounds. * It is recommended to use * GetClippedPlaneBounds(const Geometry3D*, const PlaneGeometry*, vtkFloatingPointType*) * if you are not sure about the input. */ bool GetClippedPlaneBounds(double bounds[6]); /** \brief Get the bounding box of the slice [xMin, xMax, yMin, yMax, zMin, zMax]*/ bool GetClippedPlaneBounds( const Geometry3D *boundingGeometry, const PlaneGeometry *planeGeometry, vtkFloatingPointType *bounds ); /** \brief Get the spacing of the slice. returns mitk::ScalarType[2] */ mitk::ScalarType* GetOutputSpacing(); /** \brief Get Output as vtkImageData. * Note: * SetVtkOutputRequest(true) has to be called at least once before * GetVtkOutput(). Otherwise the output is empty for the first update step. */ vtkImageData* GetVtkOutput(){ m_VtkOutputRequested = true; return m_Reslicer->GetOutput(); } /** Set VtkOutPutRequest to suppress the convertion of the image. * It is suggested to use this with GetVtkOutput(). * Note: * SetVtkOutputRequest(true) has to be called at least once before * GetVtkOutput(). Otherwise the output is empty for the first update step. */ void SetVtkOutputRequest(bool isRequested){ m_VtkOutputRequested = isRequested; } /** \brief Get the reslices axis matrix. * Note: the axis are recalculated when calling SetResliceTransformByGeometry. */ vtkMatrix4x4* GetResliceAxes(){ return this->m_Reslicer->GetResliceAxes(); } enum ResliceInterpolation { RESLICE_NEAREST, RESLICE_LINEAR, RESLICE_CUBIC }; void SetInterpolationMode( ExtractSliceFilter::ResliceInterpolation interpolation){ this->m_InterpolationMode = interpolation; } protected: ExtractSliceFilter(vtkImageReslice* reslicer = NULL); virtual ~ExtractSliceFilter(); virtual void GenerateData(); virtual void GenerateOutputInformation(); virtual void GenerateInputRequestedRegion(); const Geometry2D* m_WorldGeometry; vtkSmartPointer m_Reslicer; unsigned int m_TimeStep; unsigned int m_OutputDimension; double m_ZSpacing; int m_ZMin; int m_ZMax; ResliceInterpolation m_InterpolationMode; Geometry3D::ConstPointer m_ResliceTransform; bool m_InPlaneResampleExtentByGeometry;//Resampling grid corresponds to: false->image true->worldgeometry mitk::ScalarType* m_OutPutSpacing; bool m_VtkOutputRequested; /** \brief Internal helper method for intersection testing used only in CalculateClippedPlaneBounds() */ bool LineIntersectZero( vtkPoints *points, int p1, int p2, vtkFloatingPointType *bounds ); /** \brief Calculate the bounding box of the resliced image. This is necessary for * arbitrarily rotated planes in an image volume. A rotated plane (e.g. in swivel mode) * will have a new bounding box, which needs to be calculated. */ bool CalculateClippedPlaneBounds( const Geometry3D *boundingGeometry, const PlaneGeometry *planeGeometry, vtkFloatingPointType *bounds ); }; } #endif // mitkExtractSliceFilter_h_Included diff --git a/Core/Code/Algorithms/mitkRGBToRGBACastImageFilter.cpp b/Core/Code/Algorithms/mitkRGBToRGBACastImageFilter.cpp index dff950eadf..0de74adc2c 100644 --- a/Core/Code/Algorithms/mitkRGBToRGBACastImageFilter.cpp +++ b/Core/Code/Algorithms/mitkRGBToRGBACastImageFilter.cpp @@ -1,229 +1,232 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkRGBToRGBACastImageFilter.h" #include "mitkImageTimeSelector.h" #include "mitkProperties.h" #include "mitkImageAccessByItk.h" #include "mitkImageToItk.h" #include #include #include #include mitk::RGBToRGBACastImageFilter::RGBToRGBACastImageFilter() { this->SetNumberOfInputs(1); this->SetNumberOfRequiredInputs(1); m_InputTimeSelector = mitk::ImageTimeSelector::New(); m_OutputTimeSelector = mitk::ImageTimeSelector::New(); } mitk::RGBToRGBACastImageFilter::~RGBToRGBACastImageFilter() { } bool mitk::RGBToRGBACastImageFilter::IsRGBImage( const mitk::Image *image ) { const mitk::PixelType &inputPixelType = image->GetPixelType(); - if ( (inputPixelType == typeid( UCRGBPixelType) ) - || (inputPixelType == typeid( USRGBPixelType) ) - || (inputPixelType == typeid( FloatRGBPixelType) ) - || (inputPixelType == typeid( DoubleRGBPixelType) ) ) + if ( (inputPixelType.GetPixelTypeId() == itk::ImageIOBase::RGB ) + && ( (inputPixelType.GetTypeId() == typeid( unsigned char) ) + || (inputPixelType.GetTypeId() == typeid( unsigned short) ) + || (inputPixelType.GetTypeId() == typeid( float) ) + || (inputPixelType.GetTypeId() == typeid( double) ) + ) + ) { return true; } return false; } void mitk::RGBToRGBACastImageFilter::GenerateInputRequestedRegion() { Superclass::GenerateInputRequestedRegion(); mitk::Image* output = this->GetOutput(); mitk::Image* input = const_cast< mitk::Image * > ( this->GetInput() ); if ( !output->IsInitialized() ) { return; } input->SetRequestedRegionToLargestPossibleRegion(); //GenerateTimeInInputRegion(output, input); } void mitk::RGBToRGBACastImageFilter::GenerateOutputInformation() { mitk::Image::ConstPointer input = this->GetInput(); mitk::Image::Pointer output = this->GetOutput(); if ((output->IsInitialized()) && (this->GetMTime() <= m_TimeOfHeaderInitialization.GetMTime())) return; itkDebugMacro(<<"GenerateOutputInformation()"); // Initialize RGBA output with same pixel type as input image const mitk::PixelType &inputPixelType = input->GetPixelType(); typedef itk::Image< UCRGBPixelType > UCRGBItkImageType; typedef itk::Image< USRGBPixelType > USRGBItkImageType; typedef itk::Image< FloatRGBPixelType > FloatCRGBItkImageType; typedef itk::Image< DoubleRGBPixelType > DoubleRGBItkImageType; - if ( inputPixelType == typeid( UCRGBPixelType ) ) + if ( inputPixelType == mitk::MakePixelType< UCRGBItkImageType>() ) { const mitk::PixelType refPtype = MakePixelType(); output->Initialize( refPtype, *input->GetTimeSlicedGeometry() ); } - else if ( inputPixelType == typeid( USRGBPixelType ) ) + else if ( inputPixelType == mitk::MakePixelType< USRGBItkImageType>( ) ) { const mitk::PixelType refPtype = MakePixelType(); output->Initialize( refPtype, *input->GetTimeSlicedGeometry() ); } - else if ( inputPixelType == typeid( FloatRGBPixelType ) ) + else if ( inputPixelType == mitk::MakePixelType< FloatCRGBItkImageType>( ) ) { const mitk::PixelType refPtype = MakePixelType(); output->Initialize( refPtype, *input->GetTimeSlicedGeometry() ); } - else if ( inputPixelType == typeid( DoubleRGBPixelType ) ) + else if ( inputPixelType == mitk::MakePixelType< DoubleRGBItkImageType>( ) ) { const mitk::PixelType refPtype = MakePixelType(); output->Initialize( refPtype, *input->GetTimeSlicedGeometry() ); } output->SetPropertyList(input->GetPropertyList()->Clone()); m_TimeOfHeaderInitialization.Modified(); } void mitk::RGBToRGBACastImageFilter::GenerateData() { mitk::Image::ConstPointer input = this->GetInput(); mitk::Image::Pointer output = this->GetOutput(); if( !output->IsInitialized() ) { return; } m_InputTimeSelector->SetInput(input); m_OutputTimeSelector->SetInput(this->GetOutput()); mitk::Image::RegionType outputRegion = output->GetRequestedRegion(); const mitk::TimeSlicedGeometry *outputTimeGeometry = output->GetTimeSlicedGeometry(); const mitk::TimeSlicedGeometry *inputTimeGeometry = input->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(); mitk::Image *image = m_InputTimeSelector->GetOutput(); const mitk::PixelType &pixelType = image->GetPixelType(); // Check if the pixel type is supported - if ( pixelType == typeid( UCRGBPixelType ) ) + if ( pixelType == MakePixelType< itk::Image >() ) { AccessFixedPixelTypeByItk_2( image, InternalCast, (UCRGBPixelType), this, 255 ); } - else if ( pixelType == typeid( USRGBPixelType ) ) + else if ( pixelType == MakePixelType< itk::Image< USRGBPixelType> >() ) { AccessFixedPixelTypeByItk_2( image, InternalCast, (USRGBPixelType), this, 65535 ); } - else if ( pixelType == typeid( FloatRGBPixelType ) ) + else if ( pixelType == MakePixelType< itk::Image< FloatRGBPixelType> >() ) { AccessFixedPixelTypeByItk_2( image, InternalCast, (FloatRGBPixelType), this, 1.0 ); } - else if ( pixelType == typeid( DoubleRGBPixelType ) ) + else if ( pixelType == MakePixelType< itk::Image< DoubleRGBPixelType> >() ) { AccessFixedPixelTypeByItk_2( image, InternalCast, (DoubleRGBPixelType), this, 1.0 ); } else { // Otherwise, write warning and graft input to output // ...TBD... } } m_TimeOfHeaderInitialization.Modified(); } template < typename TPixel, unsigned int VImageDimension > void mitk::RGBToRGBACastImageFilter::InternalCast( itk::Image< TPixel, VImageDimension > *inputItkImage, mitk::RGBToRGBACastImageFilter *addComponentFilter, typename TPixel::ComponentType defaultAlpha ) { typedef TPixel InputPixelType; typedef itk::RGBAPixel< typename TPixel::ComponentType > OutputPixelType; typedef itk::Image< InputPixelType, VImageDimension > InputImageType; typedef itk::Image< OutputPixelType, VImageDimension > OutputImageType; typedef itk::ImageRegionConstIterator< InputImageType > InputImageIteratorType; typedef itk::ImageRegionIteratorWithIndex< OutputImageType > OutputImageIteratorType; typename mitk::ImageToItk< OutputImageType >::Pointer outputimagetoitk = mitk::ImageToItk< OutputImageType >::New(); outputimagetoitk->SetInput(addComponentFilter->m_OutputTimeSelector->GetOutput()); outputimagetoitk->Update(); typename OutputImageType::Pointer outputItkImage = outputimagetoitk->GetOutput(); // create the iterators typename InputImageType::RegionType inputRegionOfInterest = inputItkImage->GetLargestPossibleRegion(); InputImageIteratorType inputIt( inputItkImage, inputRegionOfInterest ); OutputImageIteratorType outputIt( outputItkImage, inputRegionOfInterest ); for ( inputIt.GoToBegin(), outputIt.GoToBegin(); !inputIt.IsAtEnd(); ++inputIt, ++outputIt ) { typename InputPixelType::Iterator pixelInputIt = inputIt.Get().Begin(); typename OutputPixelType::Iterator pixelOutputIt = outputIt.Get().Begin(); *pixelOutputIt++ = *pixelInputIt++; *pixelOutputIt++ = *pixelInputIt++; *pixelOutputIt++ = *pixelInputIt++; *pixelOutputIt = defaultAlpha; } } diff --git a/Core/Code/Common/mitkCommon.h b/Core/Code/Common/mitkCommon.h index 42bbcc65d5..3c4dadbc64 100644 --- a/Core/Code/Common/mitkCommon.h +++ b/Core/Code/Common/mitkCommon.h @@ -1,122 +1,122 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITK_COMMON_H_DEFINED #define MITK_COMMON_H_DEFINED #ifdef _MSC_VER // This warns about truncation to 255 characters in debug/browse info #pragma warning (disable : 4786) #pragma warning (disable : 4068 ) /* disable unknown pragma warnings */ #endif //add only those headers here that are really necessary for all classes! #include "itkObject.h" #include "mitkConfig.h" #include "mitkLogMacros.h" #include "mitkExportMacros.h" #include "mitkExceptionMacro.h" #ifndef MITK_UNMANGLE_IPPIC #define mitkIpPicDescriptor mitkIpPicDescriptor #endif typedef unsigned int MapperSlotId; #define mitkClassMacro(className,SuperClassName) \ typedef className Self; \ typedef SuperClassName Superclass; \ typedef itk::SmartPointer Pointer; \ typedef itk::SmartPointer ConstPointer; \ itkTypeMacro(className,SuperClassName) /** * Macro for Constructors with one parameter for classes derived from itk::Lightobject **/ #define mitkNewMacro1Param(classname,type) \ static Pointer New(type _arg) \ { \ Pointer smartPtr = new classname ( _arg ); \ smartPtr->UnRegister(); \ return smartPtr; \ } \ /** * Macro for Constructors with two parameters for classes derived from itk::Lightobject **/ #define mitkNewMacro2Param(classname,typea,typeb) \ static Pointer New(typea _arga, typeb _argb) \ { \ Pointer smartPtr = new classname ( _arga, _argb ); \ smartPtr->UnRegister(); \ return smartPtr; \ } \ /** * Macro for Constructors with three parameters for classes derived from itk::Lightobject **/ #define mitkNewMacro3Param(classname,typea,typeb,typec) \ static Pointer New(typea _arga, typeb _argb, typec _argc) \ { \ Pointer smartPtr = new classname ( _arga, _argb, _argc ); \ smartPtr->UnRegister(); \ return smartPtr; \ } \ /** * Macro for Constructors with three parameters for classes derived from itk::Lightobject **/ #define mitkNewMacro4Param(classname,typea,typeb,typec,typed) \ static Pointer New(typea _arga, typeb _argb, typec _argc, typed _argd) \ { \ Pointer smartPtr = new classname ( _arga, _argb, _argc, _argd ); \ smartPtr->UnRegister(); \ return smartPtr; \ } \ /** Get a smart const pointer to an object. Creates the member * Get"name"() (e.g., GetPoints()). */ #define mitkGetObjectMacroConst(name,type) \ virtual type * Get##name () const \ { \ itkDebugMacro("returning " #name " address " << this->m_##name ); \ return this->m_##name.GetPointer(); \ } /** Creates a Clone() method for "Classname". Returns a smartPtr of a clone of the calling object*/ #define mitkCloneMacro(classname) \ virtual Pointer Clone() const \ { \ Pointer smartPtr = new classname(*this); \ smartPtr->UnRegister(); \ return smartPtr; \ } /** cross-platform deprecation macro \todo maybe there is something in external toolkits (ITK, VTK,...) that we could reulse -- would be much preferable */ #ifdef __GNUC__ - #define DEPRECATED(func) func __attribute__ ((deprecated)) + #define DEPRECATED(...) __VA_ARGS__ __attribute__ ((deprecated)) #elif defined(_MSC_VER) - #define DEPRECATED(func) __declspec(deprecated) func + #define DEPRECATED(...) __declspec(deprecated) ##__VA_ARGS__ #else #pragma message("WARNING: You need to implement DEPRECATED for your compiler!") #define DEPRECATED(func) func #endif #endif // MITK_COMMON_H_DEFINED diff --git a/Core/Code/Common/mitkException.h b/Core/Code/Common/mitkException.h index 206eecdcdc..d2eca21bdf 100644 --- a/Core/Code/Common/mitkException.h +++ b/Core/Code/Common/mitkException.h @@ -1,113 +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. ===================================================================*/ #ifndef MITKEXCEPTION_H_INCLUDED #define MITKEXCEPTION_H_INCLUDED #include #include #include namespace mitk { /**Documentation * \brief An object of this class represents an exception of MITK. * Please don't instantiate exceptions manually, but use the * exception macros (file mitkExceptionMacro.h) instead. * Simple use in your code is: * * mitkThrow() << "optional exception message"; * * You can also define specialized exceptions which must inherit * from this class. Please always use the mitkExceptionClassMacro * when implementing specialized exceptions. A simple implementation * can look like: * * class MyException : public mitk::Exception * { * public: * mitkExceptionClassMacro(MyException,mitk::Exception); * }; * * You can then throw your specialized exceptions by using the macro * * mitkThrowException(MyException) << "optional exception message"; */ class MITK_CORE_EXPORT Exception : public itk::ExceptionObject { public: Exception(const char *file, unsigned int lineNumber=0, const char *desc="None", const char *loc="Unknown") : itk::ExceptionObject(file,lineNumber,desc,loc){} virtual ~Exception() throw() {} itkTypeMacro(ClassName, SuperClassName); /** \brief Adds rethrow data to this exception. */ void AddRethrowData(const char *file, unsigned int lineNumber, const char *message); /** \return Returns how often the exception was rethrown. */ int GetNumberOfRethrows(); /** @return Returns the rethrow data of the specified rethrow number. Returns empty data, if the rethrowNumber doesn't exist. * @param rethrowNumber The internal number of the rethrow. * @param file (returnvalue) This varaiable will be filled with the file of the specified rethrow. * @param file (returnvalue) This varaiable will be filled with the line of the specified rethrow. * @param file (returnvalue) This varaiable will be filled with the message of the specified rethrow. */ void GetRethrowData(int rethrowNumber, std::string &file, int &line, std::string &message); /** \brief Definition of the bit shift operator for this class.*/ template inline Exception& operator<<(const T& data) { std::stringstream ss; ss << this->GetDescription() << data; this->SetDescription(ss.str()); return *this; } /** \brief Definition of the bit shift operator for this class (for non const data).*/ template inline Exception& operator<<(T& data) { std::stringstream ss; ss << this->GetDescription() << data; this->SetDescription(ss.str()); return *this; } /** \brief Definition of the bit shift operator for this class (for functions).*/ inline Exception& operator<<(std::ostream& (*func)(std::ostream&)) { std::stringstream ss; ss << this->GetDescription() << func; this->SetDescription(ss.str()); return *this; } protected: struct ReThrowData { std::string RethrowClassname; - int RethrowLine; + unsigned int RethrowLine; std::string RethrowMessage; }; std::vector m_RethrowData; }; } // namespace mitk #endif diff --git a/Core/Code/Controllers/mitkRenderingManager.cpp b/Core/Code/Controllers/mitkRenderingManager.cpp index d7d6fe8fd3..b5011143dc 100644 --- a/Core/Code/Controllers/mitkRenderingManager.cpp +++ b/Core/Code/Controllers/mitkRenderingManager.cpp @@ -1,1044 +1,1032 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkRenderingManagerFactory.h" #include "mitkBaseRenderer.h" #include "mitkGlobalInteraction.h" #include #include #include "mitkVector.h" #include #include #include #include namespace mitk { RenderingManager::Pointer RenderingManager::s_Instance = 0; RenderingManagerFactory *RenderingManager::s_RenderingManagerFactory = 0; RenderingManager ::RenderingManager() : m_UpdatePending( false ), m_MaxLOD( 1 ), m_LODIncreaseBlocked( false ), m_LODAbortMechanismEnabled( false ), m_ClippingPlaneEnabled( false ), - m_TimeNavigationController( NULL ), + m_TimeNavigationController( SliceNavigationController::New("dummy") ), m_DataStorage( NULL ), m_ConstrainedPaddingZooming ( true ) { m_ShadingEnabled.assign( 3, false ); m_ShadingValues.assign( 4, 0.0 ); m_GlobalInteraction = mitk::GlobalInteraction::GetInstance(); InitializePropertyList(); } RenderingManager ::~RenderingManager() { // Decrease reference counts of all registered vtkRenderWindows for // proper destruction RenderWindowVector::iterator it; for ( it = m_AllRenderWindows.begin(); it != m_AllRenderWindows.end(); ++it ) { (*it)->UnRegister( NULL ); RenderWindowCallbacksList::iterator callbacks_it = this->m_RenderWindowCallbacksList.find(*it); if (callbacks_it != this->m_RenderWindowCallbacksList.end()) { (*it)->RemoveObserver(callbacks_it->second.commands[0u]); (*it)->RemoveObserver(callbacks_it->second.commands[1u]); (*it)->RemoveObserver(callbacks_it->second.commands[2u]); } } } void RenderingManager ::SetFactory( RenderingManagerFactory *factory ) { s_RenderingManagerFactory = factory; } const RenderingManagerFactory * RenderingManager ::GetFactory() { return s_RenderingManagerFactory; } bool RenderingManager ::HasFactory() { if ( RenderingManager::s_RenderingManagerFactory ) { return true; } else { return false; } } RenderingManager::Pointer RenderingManager ::New() { const RenderingManagerFactory* factory = GetFactory(); if(factory == NULL) return NULL; return factory->CreateRenderingManager(); } RenderingManager * RenderingManager ::GetInstance() { if ( !RenderingManager::s_Instance ) { if ( s_RenderingManagerFactory ) { s_Instance = s_RenderingManagerFactory->CreateRenderingManager(); } } return s_Instance; } bool RenderingManager ::IsInstantiated() { if ( RenderingManager::s_Instance ) return true; else return false; } void RenderingManager ::AddRenderWindow( vtkRenderWindow *renderWindow ) { if ( renderWindow && (m_RenderWindowList.find( renderWindow ) == m_RenderWindowList.end()) ) { m_RenderWindowList[renderWindow] = RENDERING_INACTIVE; m_AllRenderWindows.push_back( renderWindow ); if ( m_DataStorage.IsNotNull() ) mitk::BaseRenderer::GetInstance( renderWindow )->SetDataStorage( m_DataStorage.GetPointer() ); // Register vtkRenderWindow instance renderWindow->Register( NULL ); typedef itk::MemberCommand< RenderingManager > MemberCommandType; // Add callbacks for rendering abort mechanism //BaseRenderer *renderer = BaseRenderer::GetInstance( renderWindow ); vtkCallbackCommand *startCallbackCommand = vtkCallbackCommand::New(); startCallbackCommand->SetCallback( RenderingManager::RenderingStartCallback ); renderWindow->AddObserver( vtkCommand::StartEvent, startCallbackCommand ); vtkCallbackCommand *progressCallbackCommand = vtkCallbackCommand::New(); progressCallbackCommand->SetCallback( RenderingManager::RenderingProgressCallback ); renderWindow->AddObserver( vtkCommand::AbortCheckEvent, progressCallbackCommand ); vtkCallbackCommand *endCallbackCommand = vtkCallbackCommand::New(); endCallbackCommand->SetCallback( RenderingManager::RenderingEndCallback ); renderWindow->AddObserver( vtkCommand::EndEvent, endCallbackCommand ); RenderWindowCallbacks callbacks; callbacks.commands[0u] = startCallbackCommand; callbacks.commands[1u] = progressCallbackCommand; callbacks.commands[2u] = endCallbackCommand; this->m_RenderWindowCallbacksList[renderWindow] = callbacks; //Delete vtk variables correctly startCallbackCommand->Delete(); progressCallbackCommand->Delete(); endCallbackCommand->Delete(); } } void RenderingManager ::RemoveRenderWindow( vtkRenderWindow *renderWindow ) { if (m_RenderWindowList.erase( renderWindow )) { RenderWindowCallbacksList::iterator callbacks_it = this->m_RenderWindowCallbacksList.find(renderWindow); if(callbacks_it != this->m_RenderWindowCallbacksList.end()) { renderWindow->RemoveObserver(callbacks_it->second.commands[0u]); renderWindow->RemoveObserver(callbacks_it->second.commands[1u]); renderWindow->RemoveObserver(callbacks_it->second.commands[2u]); this->m_RenderWindowCallbacksList.erase(callbacks_it); } RenderWindowVector::iterator rw_it = std::find( m_AllRenderWindows.begin(), m_AllRenderWindows.end(), renderWindow ); if(rw_it != m_AllRenderWindows.end()) { // Decrease reference count for proper destruction (*rw_it)->UnRegister(NULL); m_AllRenderWindows.erase( rw_it ); } } } const RenderingManager::RenderWindowVector& RenderingManager ::GetAllRegisteredRenderWindows() { return m_AllRenderWindows; } void RenderingManager ::RequestUpdate( vtkRenderWindow *renderWindow ) { // If the renderWindow is not valid, we do not want to inadvertantly create // an entry in the m_RenderWindowList map. It is possible if the user is // regularly calling AddRenderer and RemoveRenderer for a rendering update // to come into this method with a renderWindow pointer that is valid in the // sense that the window does exist within the application, but that // renderWindow has been temporarily removed from this RenderingManager for // performance reasons. if (m_RenderWindowList.find( renderWindow ) == m_RenderWindowList.end()) { return; } m_RenderWindowList[renderWindow] = RENDERING_REQUESTED; if ( !m_UpdatePending ) { m_UpdatePending = true; this->GenerateRenderingRequestEvent(); } } void RenderingManager ::ForceImmediateUpdate( vtkRenderWindow *renderWindow ) { // If the renderWindow is not valid, we do not want to inadvertantly create // an entry in the m_RenderWindowList map. It is possible if the user is // regularly calling AddRenderer and RemoveRenderer for a rendering update // to come into this method with a renderWindow pointer that is valid in the // sense that the window does exist within the application, but that // renderWindow has been temporarily removed from this RenderingManager for // performance reasons. if (m_RenderWindowList.find( renderWindow ) == m_RenderWindowList.end()) { return; } // Erase potentially pending requests for this window m_RenderWindowList[renderWindow] = RENDERING_INACTIVE; m_UpdatePending = false; // Immediately repaint this window (implementation platform specific) // If the size is 0 it crahses int *size = renderWindow->GetSize(); if ( 0 != size[0] && 0 != size[1] ) { //prepare the camera etc. before rendering //Note: this is a very important step which should be called before the VTK render! //If you modify the camera anywhere else or after the render call, the scene cannot be seen. mitk::VtkPropRenderer *vPR = dynamic_cast(mitk::BaseRenderer::GetInstance( renderWindow )); if(vPR) vPR->PrepareRender(); // Execute rendering renderWindow->Render(); } } void RenderingManager ::RequestUpdateAll( RequestType type ) { RenderWindowList::iterator it; for ( it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it ) { int id = BaseRenderer::GetInstance(it->first)->GetMapperID(); if ( (type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2)) ) { this->RequestUpdate( it->first ); } } } void RenderingManager ::ForceImmediateUpdateAll( RequestType type ) { RenderWindowList::iterator it; for ( it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it ) { int id = BaseRenderer::GetInstance(it->first)->GetMapperID(); if ( (type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2)) ) { // Immediately repaint this window (implementation platform specific) // If the size is 0, it crashes this->ForceImmediateUpdate(it->first); // int *size = it->first->GetSize(); // if ( 0 != size[0] && 0 != size[1] ) // { // //prepare the camera before rendering // //Note: this is a very important step which should be called before the VTK render! // //If you modify the camera anywhere else or after the render call, the scene cannot be seen. // mitk::VtkPropRenderer *vPR = // dynamic_cast(mitk::BaseRenderer::GetInstance( it->first )); // if(vPR) // vPR->PrepareRender(); // // Execute rendering // it->first->Render(); // } // it->second = RENDERING_INACTIVE; } } //m_UpdatePending = false; } //bool RenderingManager::InitializeViews( const mitk::DataStorage * storage, const DataNode* node = NULL, RequestType type, bool preserveRoughOrientationInWorldSpace ) //{ // mitk::Geometry3D::Pointer geometry; // if ( storage != NULL ) // { // geometry = storage->ComputeVisibleBoundingGeometry3D(node, "visible", NULL, "includeInBoundingBox" ); // // if ( geometry.IsNotNull() ) // { // // let's see if we have data with a limited live-span ... // mitk::TimeBounds timebounds = geometry->GetTimeBounds(); // if ( timebounds[1] < mitk::ScalarTypeNumericTraits::max() ) // { // mitk::ScalarType duration = timebounds[1]-timebounds[0]; // // mitk::TimeSlicedGeometry::Pointer timegeometry = // mitk::TimeSlicedGeometry::New(); // timegeometry->InitializeEvenlyTimed( // geometry, (unsigned int) duration ); // timegeometry->SetTimeBounds( timebounds ); // // timebounds[1] = timebounds[0] + 1.0; // geometry->SetTimeBounds( timebounds ); // // geometry = timegeometry; // } // } // } // // // Use geometry for initialization // return this->InitializeViews( geometry.GetPointer(), type ); //} bool RenderingManager ::InitializeViews( const Geometry3D * dataGeometry, RequestType type, bool preserveRoughOrientationInWorldSpace ) { MITK_DEBUG << "initializing views"; bool boundingBoxInitialized = false; Geometry3D::ConstPointer geometry = dataGeometry; if (dataGeometry && preserveRoughOrientationInWorldSpace) { // clone the input geometry Geometry3D::Pointer modifiedGeometry = dynamic_cast( dataGeometry->Clone().GetPointer() ); assert(modifiedGeometry.IsNotNull()); // construct an affine transform from it AffineGeometryFrame3D::TransformType::Pointer transform = AffineGeometryFrame3D::TransformType::New(); assert( modifiedGeometry->GetIndexToWorldTransform() ); transform->SetMatrix( modifiedGeometry->GetIndexToWorldTransform()->GetMatrix() ); transform->SetOffset( modifiedGeometry->GetIndexToWorldTransform()->GetOffset() ); // get transform matrix AffineGeometryFrame3D::TransformType::MatrixType::InternalMatrixType& oldMatrix = const_cast< AffineGeometryFrame3D::TransformType::MatrixType::InternalMatrixType& > ( transform->GetMatrix().GetVnlMatrix() ); AffineGeometryFrame3D::TransformType::MatrixType::InternalMatrixType newMatrix(oldMatrix); // get offset and bound Vector3D offset = modifiedGeometry->GetIndexToWorldTransform()->GetOffset(); Geometry3D::BoundsArrayType oldBounds = modifiedGeometry->GetBounds(); Geometry3D::BoundsArrayType newBounds = modifiedGeometry->GetBounds(); // get rid of rotation other than pi/2 degree for ( unsigned int i = 0; i < 3; ++i ) { // i-th column of the direction matrix Vector3D currentVector; currentVector[0] = oldMatrix(0,i); currentVector[1] = oldMatrix(1,i); currentVector[2] = oldMatrix(2,i); // matchingRow will store the row that holds the biggest // value in the column unsigned int matchingRow = 0; // maximum value in the column float max = std::numeric_limits::min(); // sign of the maximum value (-1 or 1) int sign = 1; // iterate through the column vector for (unsigned int dim = 0; dim < 3; ++dim) { if ( fabs(currentVector[dim]) > max ) { matchingRow = dim; max = fabs(currentVector[dim]); if(currentVector[dim]<0) sign = -1; else sign = 1; } } // in case we found a negative maximum, // we negate the column and adjust the offset // (in order to run through the dimension in the opposite direction) if(sign == -1) { currentVector *= sign; offset += modifiedGeometry->GetAxisVector(i); } // matchingRow is now used as column index to place currentVector // correctly in the new matrix vnl_vector newMatrixColumn(3); newMatrixColumn[0] = currentVector[0]; newMatrixColumn[1] = currentVector[1]; newMatrixColumn[2] = currentVector[2]; newMatrix.set_column( matchingRow, newMatrixColumn ); // if a column is moved, we also have to adjust the bounding // box accordingly, this is done here newBounds[2*matchingRow ] = oldBounds[2*i ]; newBounds[2*matchingRow+1] = oldBounds[2*i+1]; } // set the newly calculated bounds array modifiedGeometry->SetBounds(newBounds); // set new offset and direction matrix AffineGeometryFrame3D::TransformType::MatrixType newMatrixITK( newMatrix ); transform->SetMatrix( newMatrixITK ); transform->SetOffset( offset ); modifiedGeometry->SetIndexToWorldTransform( transform ); geometry = modifiedGeometry; } int warningLevel = vtkObject::GetGlobalWarningDisplay(); vtkObject::GlobalWarningDisplayOff(); if ( (geometry.IsNotNull() ) && (const_cast< mitk::BoundingBox * >( geometry->GetBoundingBox())->GetDiagonalLength2() > mitk::eps) ) { boundingBoxInitialized = true; } if (geometry.IsNotNull() ) {// make sure bounding box has an extent bigger than zero in any direction // clone the input geometry Geometry3D::Pointer modifiedGeometry = dynamic_cast( dataGeometry->Clone().GetPointer() ); assert(modifiedGeometry.IsNotNull()); Geometry3D::BoundsArrayType newBounds = modifiedGeometry->GetBounds(); for( unsigned int dimension = 0; ( 2 * dimension ) < newBounds.Size() ; dimension++ ) { //check for equality but for an epsilon if( Equal( newBounds[ 2 * dimension ], newBounds[ 2 * dimension + 1 ] ) ) { newBounds[ 2 * dimension + 1 ] += 1; } } // set the newly calculated bounds array modifiedGeometry->SetBounds(newBounds); geometry = modifiedGeometry; } RenderWindowList::iterator it; for ( it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it ) { mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance( it->first ); baseRenderer->GetDisplayGeometry()->SetConstrainZoomingAndPanning(m_ConstrainedPaddingZooming); int id = baseRenderer->GetMapperID(); if ( ((type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2))) ) { this->InternalViewInitialization( baseRenderer, geometry, boundingBoxInitialized, id ); } } - if ( m_TimeNavigationController != NULL ) + if ( boundingBoxInitialized ) { - if ( boundingBoxInitialized ) - { - m_TimeNavigationController->SetInputWorldGeometry( geometry ); - } - m_TimeNavigationController->Update(); + m_TimeNavigationController->SetInputWorldGeometry( geometry ); } + m_TimeNavigationController->Update(); this->RequestUpdateAll( type ); vtkObject::SetGlobalWarningDisplay( warningLevel ); // Inform listeners that views have been initialized this->InvokeEvent( mitk::RenderingManagerViewsInitializedEvent() ); return boundingBoxInitialized; } bool RenderingManager ::InitializeViews( RequestType type ) { RenderWindowList::iterator it; for ( it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it ) { mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance( it->first ); int id = baseRenderer->GetMapperID(); if ( (type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2)) ) { mitk::SliceNavigationController *nc = baseRenderer->GetSliceNavigationController(); // Re-initialize view direction nc->SetViewDirectionToDefault(); // Update the SNC nc->Update(); } } this->RequestUpdateAll( type ); return true; } //bool RenderingManager::InitializeView( vtkRenderWindow * renderWindow, const DataStorage* ds, const DataNode node = NULL, bool initializeGlobalTimeSNC ) //{ // mitk::Geometry3D::Pointer geometry; // if ( ds != NULL ) // { // geometry = ds->ComputeVisibleBoundingGeometry3D(node, NULL, "includeInBoundingBox" ); // // if ( geometry.IsNotNull() ) // { // // let's see if we have data with a limited live-span ... // mitk::TimeBounds timebounds = geometry->GetTimeBounds(); // if ( timebounds[1] < mitk::ScalarTypeNumericTraits::max() ) // { // mitk::ScalarType duration = timebounds[1]-timebounds[0]; // // mitk::TimeSlicedGeometry::Pointer timegeometry = // mitk::TimeSlicedGeometry::New(); // timegeometry->InitializeEvenlyTimed( // geometry, (unsigned int) duration ); // timegeometry->SetTimeBounds( timebounds ); // // timebounds[1] = timebounds[0] + 1.0; // geometry->SetTimeBounds( timebounds ); // // geometry = timegeometry; // } // } // } // // // Use geometry for initialization // return this->InitializeView( renderWindow, // geometry.GetPointer(), initializeGlobalTimeSNC ); //} bool RenderingManager::InitializeView( vtkRenderWindow * renderWindow, const Geometry3D * geometry, bool initializeGlobalTimeSNC ) { bool boundingBoxInitialized = false; int warningLevel = vtkObject::GetGlobalWarningDisplay(); vtkObject::GlobalWarningDisplayOff(); if ( (geometry != NULL ) && (const_cast< mitk::BoundingBox * >( geometry->GetBoundingBox())->GetDiagonalLength2() > mitk::eps) ) { boundingBoxInitialized = true; } mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance( renderWindow ); int id = baseRenderer->GetMapperID(); this->InternalViewInitialization( baseRenderer, geometry, boundingBoxInitialized, id ); - if ( m_TimeNavigationController != NULL ) + if ( boundingBoxInitialized && initializeGlobalTimeSNC ) { - if ( boundingBoxInitialized && initializeGlobalTimeSNC ) - { - m_TimeNavigationController->SetInputWorldGeometry( geometry ); - } - m_TimeNavigationController->Update(); + m_TimeNavigationController->SetInputWorldGeometry( geometry ); } + m_TimeNavigationController->Update(); this->RequestUpdate( renderWindow ); vtkObject::SetGlobalWarningDisplay( warningLevel ); return boundingBoxInitialized; } bool RenderingManager::InitializeView( vtkRenderWindow * renderWindow ) { mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance( renderWindow ); mitk::SliceNavigationController *nc = baseRenderer->GetSliceNavigationController(); // Re-initialize view direction nc->SetViewDirectionToDefault(); // Update the SNC nc->Update(); this->RequestUpdate( renderWindow ); return true; } void RenderingManager::InternalViewInitialization(mitk::BaseRenderer *baseRenderer, const mitk::Geometry3D *geometry, bool boundingBoxInitialized, int mapperID ) { mitk::SliceNavigationController *nc = baseRenderer->GetSliceNavigationController(); // Re-initialize view direction nc->SetViewDirectionToDefault(); if ( boundingBoxInitialized ) { // Set geometry for NC nc->SetInputWorldGeometry( geometry ); nc->Update(); if ( mapperID == 1 ) { // For 2D SNCs, steppers are set so that the cross is centered // in the image nc->GetSlice()->SetPos( nc->GetSlice()->GetSteps() / 2 ); } // Fit the render window DisplayGeometry baseRenderer->GetDisplayGeometry()->Fit(); baseRenderer->GetCameraController()->SetViewToAnterior(); } else { nc->Update(); } } -void RenderingManager::SetTimeNavigationController( SliceNavigationController *nc ) -{ - m_TimeNavigationController = nc; -} - - const SliceNavigationController* RenderingManager::GetTimeNavigationController() const { - return m_TimeNavigationController; + return m_TimeNavigationController.GetPointer(); } SliceNavigationController* RenderingManager::GetTimeNavigationController() { - return m_TimeNavigationController; + return m_TimeNavigationController.GetPointer(); } void RenderingManager::ExecutePendingRequests() { m_UpdatePending = false; // Satisfy all pending update requests RenderWindowList::iterator it; int i = 0; for ( it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it, ++i ) { if ( it->second == RENDERING_REQUESTED ) { this->ForceImmediateUpdate( it->first ); } } } void RenderingManager::RenderingStartCallback( vtkObject *caller, unsigned long , void *, void * ) { vtkRenderWindow *renderWindow = dynamic_cast< vtkRenderWindow * >( caller ); mitk::RenderingManager* renman = mitk::BaseRenderer::GetInstance(renderWindow)->GetRenderingManager(); RenderWindowList &renderWindowList = renman->m_RenderWindowList; if ( renderWindow ) { renderWindowList[renderWindow] = RENDERING_INPROGRESS; } renman->m_UpdatePending = false; } void RenderingManager ::RenderingProgressCallback( vtkObject *caller, unsigned long , void *, void * ) { vtkRenderWindow *renderWindow = dynamic_cast< vtkRenderWindow * >( caller ); mitk::RenderingManager* renman = mitk::BaseRenderer::GetInstance(renderWindow)->GetRenderingManager(); if ( renman->m_LODAbortMechanismEnabled ) { vtkRenderWindow *renderWindow = dynamic_cast< vtkRenderWindow * >( caller ); if ( renderWindow ) { BaseRenderer *renderer = BaseRenderer::GetInstance( renderWindow ); if ( renderer && (renderer->GetNumberOfVisibleLODEnabledMappers() > 0) ) { renman->DoMonitorRendering(); } } } } void RenderingManager ::RenderingEndCallback( vtkObject *caller, unsigned long , void *, void * ) { vtkRenderWindow *renderWindow = dynamic_cast< vtkRenderWindow * >( caller ); mitk::RenderingManager* renman = mitk::BaseRenderer::GetInstance(renderWindow)->GetRenderingManager(); RenderWindowList &renderWindowList = renman->m_RenderWindowList; RendererIntMap &nextLODMap = renman->m_NextLODMap; if ( renderWindow ) { BaseRenderer *renderer = BaseRenderer::GetInstance( renderWindow ); if ( renderer ) { renderWindowList[renderer->GetRenderWindow()] = RENDERING_INACTIVE; // Level-of-Detail handling if ( renderer->GetNumberOfVisibleLODEnabledMappers() > 0 ) { if(nextLODMap[renderer]==0) renman->StartOrResetTimer(); else nextLODMap[renderer] = 0; } } } } bool RenderingManager ::IsRendering() const { RenderWindowList::const_iterator it; for ( it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it ) { if ( it->second == RENDERING_INPROGRESS ) { return true; } } return false; } void RenderingManager ::AbortRendering() { RenderWindowList::iterator it; for ( it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it ) { if ( it->second == RENDERING_INPROGRESS ) { it->first->SetAbortRender( true ); m_RenderingAbortedMap[BaseRenderer::GetInstance(it->first)] = true; } } } int RenderingManager ::GetNextLOD( BaseRenderer *renderer ) { if ( renderer != NULL ) { return m_NextLODMap[renderer]; } else { return 0; } } void RenderingManager ::ExecutePendingHighResRenderingRequest() { RenderWindowList::iterator it; for ( it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it ) { BaseRenderer *renderer = BaseRenderer::GetInstance( it->first ); if(renderer->GetNumberOfVisibleLODEnabledMappers()>0) { if(m_NextLODMap[renderer]==0) { m_NextLODMap[renderer]=1; RequestUpdate( it->first ); } } } } void RenderingManager ::SetMaximumLOD( unsigned int max ) { m_MaxLOD = max; } //enable/disable shading void RenderingManager ::SetShading(bool state, unsigned int lod) { if(lod>m_MaxLOD) { itkWarningMacro(<<"LOD out of range requested: " << lod << " maxLOD: " << m_MaxLOD); return; } m_ShadingEnabled[lod] = state; } bool RenderingManager ::GetShading(unsigned int lod) { if(lod>m_MaxLOD) { itkWarningMacro(<<"LOD out of range requested: " << lod << " maxLOD: " << m_MaxLOD); return false; } return m_ShadingEnabled[lod]; } //enable/disable the clipping plane void RenderingManager ::SetClippingPlaneStatus(bool status) { m_ClippingPlaneEnabled = status; } bool RenderingManager ::GetClippingPlaneStatus() { return m_ClippingPlaneEnabled; } void RenderingManager ::SetShadingValues(float ambient, float diffuse, float specular, float specpower) { m_ShadingValues[0] = ambient; m_ShadingValues[1] = diffuse; m_ShadingValues[2] = specular; m_ShadingValues[3] = specpower; } RenderingManager::FloatVector & RenderingManager ::GetShadingValues() { return m_ShadingValues; } void RenderingManager::SetDepthPeelingEnabled( bool enabled ) { RenderWindowList::iterator it; for ( it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it ) { mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance( it->first ); baseRenderer->SetDepthPeelingEnabled(enabled); } } void RenderingManager::SetMaxNumberOfPeels( int maxNumber ) { RenderWindowList::iterator it; for ( it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it ) { mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance( it->first ); baseRenderer->SetMaxNumberOfPeels(maxNumber); } } void RenderingManager::InitializePropertyList() { if (m_PropertyList.IsNull()) { m_PropertyList = PropertyList::New(); } this->SetProperty("coupled-zoom", BoolProperty::New(false)); this->SetProperty("coupled-plane-rotation", BoolProperty::New(false)); this->SetProperty("MIP-slice-rendering", BoolProperty::New(false)); } PropertyList::Pointer RenderingManager::GetPropertyList() const { return m_PropertyList; } BaseProperty* RenderingManager::GetProperty(const char *propertyKey) const { return m_PropertyList->GetProperty(propertyKey); } void RenderingManager::SetProperty(const char *propertyKey, BaseProperty* propertyValue) { m_PropertyList->SetProperty(propertyKey, propertyValue); } void RenderingManager::SetDataStorage( DataStorage* storage ) { if ( storage != NULL ) { m_DataStorage = storage; RenderingManager::RenderWindowVector::iterator iter; for ( iter = m_AllRenderWindows.begin(); iterSetDataStorage( m_DataStorage.GetPointer() ); } } } mitk::DataStorage* RenderingManager::GetDataStorage() { return m_DataStorage; } void RenderingManager::SetGlobalInteraction( mitk::GlobalInteraction* globalInteraction ) { if ( globalInteraction != NULL ) { m_GlobalInteraction = globalInteraction; } } mitk::GlobalInteraction* RenderingManager::GetGlobalInteraction() { return m_GlobalInteraction; } // Create and register generic RenderingManagerFactory. TestingRenderingManagerFactory renderingManagerFactory; } // namespace diff --git a/Core/Code/Controllers/mitkRenderingManager.h b/Core/Code/Controllers/mitkRenderingManager.h index 956e553f02..c30d993e70 100644 --- a/Core/Code/Controllers/mitkRenderingManager.h +++ b/Core/Code/Controllers/mitkRenderingManager.h @@ -1,419 +1,414 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 MITKRENDERINGMANAGER_H_HEADER_INCLUDED_C135A197 #define MITKRENDERINGMANAGER_H_HEADER_INCLUDED_C135A197 #include #include #include #include #include #include "mitkPropertyList.h" #include "mitkProperties.h" class vtkRenderWindow; class vtkObject; namespace mitk { class RenderingManager; class RenderingManagerFactory; class Geometry3D; class SliceNavigationController; class BaseRenderer; class DataStorage; class GlobalInteraction; /** * \brief Manager for coordinating the rendering process. * * RenderingManager is a central instance retrieving and executing * RenderWindow update requests. Its main purpose is to coordinate * distributed requests which cannot be aware of each other - lacking the * knowledge of whether they are really necessary or not. For example, two * objects might determine that a specific RenderWindow needs to be updated. * This would result in one unnecessary update, if both executed the update * on their own. * * The RenderingManager addresses this by letting each such object * request an update, and waiting for other objects to possibly * issue the same request. The actual update will then only be executed at a * well-defined point in the main event loop (this may be each time after * event processing is done). * * Convinience methods for updating all RenderWindows which have been * registered with the RenderingManager exist. If theses methods are not * used, it is not required to register (add) RenderWindows prior to using * the RenderingManager. * * The methods #ForceImmediateUpdate() and #ForceImmediateUpdateAll() can * be used to force the RenderWindow update execution without any delay, * bypassing the request functionality. * * The interface of RenderingManager is platform independent. Platform * specific subclasses have to be implemented, though, to supply an * appropriate event issueing for controlling the update execution process. * See method documentation for a description of how this can be done. * * \sa TestingRenderingManager An "empty" RenderingManager implementation which * can be used in tests etc. * */ class MITK_CORE_EXPORT RenderingManager : public itk::Object { public: mitkClassMacro(RenderingManager,itk::Object); typedef std::vector< vtkRenderWindow* > RenderWindowVector; typedef std::vector< float > FloatVector; typedef std::vector< bool > BoolVector; typedef itk::SmartPointer< DataStorage > DataStoragePointer; typedef itk::SmartPointer< GlobalInteraction > GlobalInteractionPointer; enum RequestType { REQUEST_UPDATE_ALL = 0, REQUEST_UPDATE_2DWINDOWS, REQUEST_UPDATE_3DWINDOWS }; static Pointer New(); /** Set the object factory which produces the desired platform specific * RenderingManager singleton instance. */ static void SetFactory( RenderingManagerFactory *factory ); /** Get the object factory which produces the platform specific * RenderingManager instances. */ static const RenderingManagerFactory *GetFactory(); /** Returns true if a factory has already been set. */ static bool HasFactory(); /** Get the RenderingManager singleton instance. */ static RenderingManager *GetInstance(); /** Returns true if the singleton instance does already exist. */ static bool IsInstantiated(); /** Adds a RenderWindow. This is required if the methods #RequestUpdateAll * or #ForceImmediateUpdate are to be used. */ void AddRenderWindow( vtkRenderWindow *renderWindow ); /** Removes a RenderWindow. */ void RemoveRenderWindow( vtkRenderWindow *renderWindow ); /** Get a list of all registered RenderWindows */ const RenderWindowVector &GetAllRegisteredRenderWindows(); /** Requests an update for the specified RenderWindow, to be executed as * soon as the main loop is ready for rendering. */ void RequestUpdate( vtkRenderWindow *renderWindow ); /** Immediately executes an update of the specified RenderWindow. */ void ForceImmediateUpdate( vtkRenderWindow *renderWindow ); /** Requests all currently registered RenderWindows to be updated. * If only 2D or 3D windows should be updated, this can be specified * via the parameter requestType. */ void RequestUpdateAll( RequestType type = REQUEST_UPDATE_ALL ); /** Immediately executes an update of all registered RenderWindows. * If only 2D or 3D windows should be updated, this can be specified * via the parameter requestType. */ void ForceImmediateUpdateAll( RequestType type = REQUEST_UPDATE_ALL ); /** Initializes the windows specified by requestType to the geometry of the * given DataStorage. */ //virtual bool InitializeViews( const DataStorage *storage, const DataNode* node = NULL, // RequestType type = REQUEST_UPDATE_ALL, bool preserveRoughOrientationInWorldSpace = false ); /** Initializes the windows specified by requestType to the given * geometry. PLATFORM SPECIFIC. TODO: HOW IS THIS PLATFORM SPECIFIC? */ virtual bool InitializeViews( const Geometry3D *geometry, RequestType type = REQUEST_UPDATE_ALL, bool preserveRoughOrientationInWorldSpace = false ); /** Initializes the windows to the default viewing direction * (geomtry information is NOT changed). PLATFORM SPECIFIC. */ virtual bool InitializeViews( RequestType type = REQUEST_UPDATE_ALL ); /** Initializes the specified window to the geometry of the given * DataNode. Set "initializeGlobalTimeSNC" to true in order to use this * geometry as global TimeSlicedGeometry. PLATFORM SPECIFIC. */ //virtual bool InitializeView( vtkRenderWindow *renderWindow, const DataStorage* ds, const DataNode* node = NULL, bool initializeGlobalTimeSNC = false ); /** Initializes the specified window to the given geometry. Set * "initializeGlobalTimeSNC" to true in order to use this geometry as * global TimeSlicedGeometry. PLATFORM SPECIFIC. */ virtual bool InitializeView( vtkRenderWindow *renderWindow, const Geometry3D *geometry, bool initializeGlobalTimeSNC = false); /** Initializes the specified window to the default viewing direction * (geomtry information is NOT changed). PLATFORM SPECIFIC. */ virtual bool InitializeView( vtkRenderWindow *renderWindow ); - - /** Sets the (global) SliceNavigationController responsible for - * time-slicing. */ - void SetTimeNavigationController( SliceNavigationController *nc ); - /** Gets the (global) SliceNavigationController responsible for * time-slicing. */ const SliceNavigationController *GetTimeNavigationController() const; /** Gets the (global) SliceNavigationController responsible for * time-slicing. */ SliceNavigationController *GetTimeNavigationController(); virtual ~RenderingManager(); /** Executes all pending requests. This method has to be called by the * system whenever a RenderingManager induced request event occurs in * the system pipeline (see concrete RenderingManager implementations). */ virtual void ExecutePendingRequests(); bool IsRendering() const; void AbortRendering(); /** En-/Disable LOD increase globally. */ itkSetMacro( LODIncreaseBlocked, bool ); /** En-/Disable LOD increase globally. */ itkGetMacro( LODIncreaseBlocked, bool ); /** En-/Disable LOD increase globally. */ itkBooleanMacro( LODIncreaseBlocked ); /** En-/Disable LOD abort mechanism. */ itkSetMacro( LODAbortMechanismEnabled, bool ); /** En-/Disable LOD abort mechanism. */ itkGetMacro( LODAbortMechanismEnabled, bool ); /** En-/Disable LOD abort mechanism. */ itkBooleanMacro( LODAbortMechanismEnabled ); /** En-/Disable depth peeling for all renderers */ void SetDepthPeelingEnabled(bool enabled); /** Set maximum number of peels for all renderers */ void SetMaxNumberOfPeels(int maxNumber); /** Force a sub-class to start a timer for a pending hires-rendering request */ virtual void StartOrResetTimer() {}; /** To be called by a sub-class from a timer callback */ void ExecutePendingHighResRenderingRequest(); virtual void DoStartRendering() {}; virtual void DoMonitorRendering() {}; virtual void DoFinishAbortRendering() {}; int GetNextLOD( BaseRenderer* renderer ); /** Set current LOD (NULL means all renderers)*/ void SetMaximumLOD( unsigned int max ); void SetShading( bool state, unsigned int lod ); bool GetShading( unsigned int lod ); void SetClippingPlaneStatus( bool status ); bool GetClippingPlaneStatus(); void SetShadingValues( float ambient, float diffuse, float specular, float specpower ); FloatVector &GetShadingValues(); /** Returns a property list */ PropertyList::Pointer GetPropertyList() const; /** Returns a property from m_PropertyList */ BaseProperty* GetProperty(const char *propertyKey) const; /** Sets or adds (if not present) a property in m_PropertyList */ void SetProperty(const char *propertyKey, BaseProperty* propertyValue); /** * \brief Setter / Getter for internal DataStorage * * Sets / returns the mitk::DataStorage that is used internally. This instance holds all mitk::DataNodes that are * rendered by the registered BaseRenderers. * * If this DataStorage is changed at runtime by calling SetDataStorage(), * all currently registered BaseRenderers are automatically given the correct instance. * When a new BaseRenderer is added, it is automatically initialized with the currently active DataStorage. */ void SetDataStorage( mitk::DataStorage* storage ); /** * \brief Setter / Getter for internal DataStorage * * Sets / returns the mitk::DataStorage that is used internally. This instance holds all mitk::DataNodes that are * rendered by the registered BaseRenderers. * * If this DataStorage is changed at runtime by calling SetDataStorage(), * all currently registered BaseRenderers are automatically given the correct instance. * When a new BaseRenderer is added, it is automatically initialized with the currently active DataStorage. */ mitk::DataStorage* GetDataStorage(); /** * \brief Setter / Getter for internal GloabInteraction * * Sets / returns the instance of mitk::GlobalInteraction that is internally held. * It'S not actually used by this class but offers it to all registered BaseRenderers. * These need it for their own internal initialization of the FocusManager and the corresponding EventMappers. */ void SetGlobalInteraction( mitk::GlobalInteraction* globalInteraction ); /** * \brief Setter / Getter for internal GloabInteraction * * Sets / returns the instance of mitk::GlobalInteraction that is internally held. * It'S not actually used by this class but offers it to all registered BaseRenderers. * These need it for their own internal initialization of the FocusManager and the corresponding EventMappers. */ mitk::GlobalInteraction* GetGlobalInteraction(); itkSetMacro(ConstrainedPaddingZooming, bool); protected: enum { RENDERING_INACTIVE = 0, RENDERING_REQUESTED, RENDERING_INPROGRESS }; RenderingManager(); /** Abstract method for generating a system specific event for rendering * request. This method is called whenever an update is requested */ virtual void GenerateRenderingRequestEvent() = 0; virtual void InitializePropertyList(); bool m_UpdatePending; typedef std::map< BaseRenderer *, unsigned int > RendererIntMap; typedef std::map< BaseRenderer *, bool > RendererBoolMap; RendererBoolMap m_RenderingAbortedMap; RendererIntMap m_NextLODMap; unsigned int m_MaxLOD; bool m_LODIncreaseBlocked; bool m_LODAbortMechanismEnabled; BoolVector m_ShadingEnabled; bool m_ClippingPlaneEnabled; FloatVector m_ShadingValues; static void RenderingStartCallback( vtkObject *caller, unsigned long eid, void *clientdata, void *calldata ); static void RenderingProgressCallback( vtkObject *caller, unsigned long eid, void *clientdata, void *calldata ); static void RenderingEndCallback( vtkObject *caller, unsigned long eid, void *clientdata, void *calldata ); typedef std::map< vtkRenderWindow *, int > RenderWindowList; RenderWindowList m_RenderWindowList; RenderWindowVector m_AllRenderWindows; struct RenderWindowCallbacks { vtkCallbackCommand* commands[3u]; }; typedef std::map RenderWindowCallbacksList; RenderWindowCallbacksList m_RenderWindowCallbacksList; - SliceNavigationController *m_TimeNavigationController; + itk::SmartPointer m_TimeNavigationController; static RenderingManager::Pointer s_Instance; static RenderingManagerFactory *s_RenderingManagerFactory; PropertyList::Pointer m_PropertyList; DataStoragePointer m_DataStorage; GlobalInteractionPointer m_GlobalInteraction; bool m_ConstrainedPaddingZooming; private: void InternalViewInitialization( mitk::BaseRenderer *baseRenderer, const mitk::Geometry3D *geometry, bool boundingBoxInitialized, int mapperID ); }; #pragma GCC visibility push(default) itkEventMacro( RenderingManagerEvent, itk::AnyEvent ); itkEventMacro( RenderingManagerViewsInitializedEvent, RenderingManagerEvent ); #pragma GCC visibility pop /** * Generic RenderingManager implementation for "non-rendering-plattform", * e.g. for tests. Its factory (TestingRenderingManagerFactory) is * automatically on start-up and is used by default if not other * RenderingManagerFactory is instantiated explicitly thereafter. * (see mitkRenderingManager.cpp) */ class MITK_CORE_EXPORT TestingRenderingManager : public RenderingManager { public: mitkClassMacro(TestingRenderingManager,RenderingManager); itkNewMacro(Self); protected: virtual void GenerateRenderingRequestEvent() { ForceImmediateUpdateAll(); }; }; } // namespace mitk #endif /* MITKRenderingManager_H_HEADER_INCLUDED_C135A197 */ diff --git a/Core/Code/Controllers/mitkSliceNavigationController.cpp b/Core/Code/Controllers/mitkSliceNavigationController.cpp index 149ddf05b5..83bc346826 100644 --- a/Core/Code/Controllers/mitkSliceNavigationController.cpp +++ b/Core/Code/Controllers/mitkSliceNavigationController.cpp @@ -1,726 +1,726 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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( Transversal ), - m_DefaultViewDirection( Transversal ), + 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 == Transversal ) + if ( m_ViewDirection == Axial ) { - this->Update( Transversal, false, false, true ); + 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 Transversal: no "break" here!! + //else: use Axial: no "break" here!! - case Transversal: + case Axial: slicedWorldGeometry = SlicedGeometry3D::New(); slicedWorldGeometry->InitializePlanes( - m_InputWorldGeometry, PlaneGeometry::Transversal, + 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(); } 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 = new mitk::PointOperation(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) { stream<<"; Time: " << baseRenderer->GetTime() << " ms; Pixelvalue: "<GetPixelValueByIndex(p, baseRenderer->GetTimeStep())<<" "; } else { stream<<"; Time: " << baseRenderer->GetTime() << " ms; Pixelvalue: "<GetPixelValueByIndex(p, baseRenderer->GetTimeStep())<<" "; } } 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/Controllers/mitkSliceNavigationController.h b/Core/Code/Controllers/mitkSliceNavigationController.h index 1f70623b30..4a932958a9 100644 --- a/Core/Code/Controllers/mitkSliceNavigationController.h +++ b/Core/Code/Controllers/mitkSliceNavigationController.h @@ -1,510 +1,545 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 SLICENAVIGATIONCONTROLLER_H_HEADER_INCLUDED_C1C55A2F #define SLICENAVIGATIONCONTROLLER_H_HEADER_INCLUDED_C1C55A2F #include #include "mitkBaseController.h" #include "mitkRenderingManager.h" #include "mitkTimeSlicedGeometry.h" #include "mitkMessage.h" #pragma GCC visibility push(default) #include #pragma GCC visibility pop #include #include #include "mitkRestorePlanePositionOperation.h" namespace mitk { #define mitkTimeSlicedGeometryEventMacro( classname , super ) \ class MITK_CORE_EXPORT classname : public super { \ public: \ typedef classname Self; \ typedef super Superclass; \ classname(TimeSlicedGeometry* aTimeSlicedGeometry, unsigned int aPos) \ : Superclass(aTimeSlicedGeometry, aPos) {} \ virtual ~classname() {} \ virtual const char * GetEventName() const { return #classname; } \ virtual bool CheckEvent(const ::itk::EventObject* e) const \ { return dynamic_cast(e); } \ virtual ::itk::EventObject* MakeObject() const \ { return new Self(GetTimeSlicedGeometry(), GetPos()); } \ private: \ void operator=(const Self&); \ } class PlaneGeometry; class Geometry3D; class BaseRenderer; /** * \brief Controls the selection of the slice the associated BaseRenderer * will display * * A SliceNavigationController takes a Geometry3D as input world geometry * (TODO what are the exact requirements?) and generates a TimeSlicedGeometry * as output. The TimeSlicedGeometry holds a number of SlicedGeometry3Ds and * these in turn hold a series of Geometry2Ds. One of these Geometry2Ds is * selected as world geometry for the BaseRenderers associated to 2D views. * * The SliceNavigationController holds has Steppers (one for the slice, a * second for the time step), which control the selection of a single * Geometry2D from the TimeSlicedGeometry. SliceNavigationController generates * ITK events to tell observers, like a BaseRenderer, when the selected slice * or timestep changes. * * SliceNavigationControllers are registered as listeners to GlobalInteraction * by the QmitkStdMultiWidget. In ExecuteAction, the controllers react to * PositionEvents by setting the steppers to the slice which is nearest to the * point of the PositionEvent. * * Example: * \code * // Initialization * sliceCtrl = mitk::SliceNavigationController::New(); * * // Tell the navigator the geometry to be sliced (with geometry a * // Geometry3D::ConstPointer) * sliceCtrl->SetInputWorldGeometry(geometry.GetPointer()); * * // Tell the navigator in which direction it shall slice the data - * sliceCtrl->SetViewDirection(mitk::SliceNavigationController::Transversal); + * sliceCtrl->SetViewDirection(mitk::SliceNavigationController::Axial); * * // Connect one or more BaseRenderer to this navigator, i.e.: events sent * // by the navigator when stepping through the slices (e.g. by * // sliceCtrl->GetSlice()->Next()) will be received by the BaseRenderer * // (in this example only slice-changes, see also ConnectGeometryTimeEvent * // and ConnectGeometryEvents.) * sliceCtrl->ConnectGeometrySliceEvent(renderer.GetPointer()); * * //create a world geometry and send the information to the connected renderer(s) * sliceCtrl->Update(); * \endcode * * * You can connect visible navigators to a SliceNavigationController, e.g., a * QmitkSliderNavigator (for Qt): * * \code * // Create the visible navigator (a slider with a spin-box) * QmitkSliderNavigator* navigator = * new QmitkSliderNavigator(parent, "slidernavigator"); * * // Connect the navigator to the slice-stepper of the * // SliceNavigationController. For initialization (position, mininal and * // maximal values) the values of the SliceNavigationController are used. * // Thus, accessing methods of a navigator is normally not necessary, since * // everything can be set via the (Qt-independent) SliceNavigationController. * // The QmitkStepperAdapter converts the Qt-signals to Qt-independent * // itk-events. * new QmitkStepperAdapter(navigator, sliceCtrl->GetSlice(), "navigatoradaptor"); * \endcode * * If you do not want that all renderwindows are updated when a new slice is * selected, you can use a specific RenderingManager, which updates only those * renderwindows that should be updated. This is sometimes useful when a 3D view * does not need to be updated when the slices in some 2D views are changed. * QmitkSliderNavigator (for Qt): * * \code * // create a specific RenderingManager * mitk::RenderingManager::Pointer myManager = mitk::RenderingManager::New(); * * // tell the RenderingManager to update only renderwindow1 and renderwindow2 * myManager->AddRenderWindow(renderwindow1); * myManager->AddRenderWindow(renderwindow2); * * // tell the SliceNavigationController of renderwindow1 and renderwindow2 * // to use the specific RenderingManager instead of the global one * renderwindow1->GetSliceNavigationController()->SetRenderingManager(myManager); * renderwindow2->GetSliceNavigationController()->SetRenderingManager(myManager); * \endcode * * \todo implement for non-evenly-timed geometry! * \ingroup NavigationControl */ class MITK_CORE_EXPORT SliceNavigationController : public BaseController { public: mitkClassMacro(SliceNavigationController,BaseController); itkNewMacro(Self); mitkNewMacro1Param(Self, const char *); /** * \brief Possible view directions, \a Original will uses * the Geometry2D instances in a SlicedGeometry3D provided * as input world geometry (by SetInputWorldGeometry). */ - enum ViewDirection{Transversal, Sagittal, Frontal, Original}; + enum ViewDirection + { +#ifdef _MSC_VER + Transversal, // deprecated +#endif + Axial = 0, + Sagittal, + Frontal, + Original + }; + +#ifdef __GNUC__ + __attribute__ ((deprecated)) static const ViewDirection Transversal = ViewDirection(Axial); +#endif /** * \brief Set the input world geometry out of which the * geometries for slicing will be created. */ void SetInputWorldGeometry(const mitk::Geometry3D* geometry); itkGetConstObjectMacro(InputWorldGeometry, mitk::Geometry3D); /** * \brief Access the created geometry */ itkGetConstObjectMacro(CreatedWorldGeometry, mitk::Geometry3D); /** * \brief Set the desired view directions * * \sa ViewDirection * \sa Update(ViewDirection viewDirection, bool top = true, * bool frontside = true, bool rotated = false) */ itkSetEnumMacro(ViewDirection, ViewDirection); itkGetEnumMacro(ViewDirection, ViewDirection); /** * \brief Set the default view direction * * This is used to re-initialize the view direction of the SNC to the * default value with SetViewDirectionToDefault() * * \sa ViewDirection * \sa Update(ViewDirection viewDirection, bool top = true, * bool frontside = true, bool rotated = false) */ itkSetEnumMacro(DefaultViewDirection, ViewDirection); itkGetEnumMacro(DefaultViewDirection, ViewDirection); virtual void SetViewDirectionToDefault(); /** * \brief Do the actual creation and send it to the connected * observers (renderers) * */ virtual void Update(); /** * \brief Extended version of Update, additionally allowing to * specify the direction/orientation of the created geometry. * */ virtual void Update(ViewDirection viewDirection, bool top = true, bool frontside = true, bool rotated = false); /** * \brief Send the created geometry to the connected * observers (renderers) * * Called by Update(). */ virtual void SendCreatedWorldGeometry(); /** * \brief Tell observers to re-read the currently selected 2D geometry * * Called by mitk::SlicesRotator during rotation. */ virtual void SendCreatedWorldGeometryUpdate(); /** * \brief Send the currently selected slice to the connected * observers (renderers) * * Called by Update(). */ virtual void SendSlice(); /** * \brief Send the currently selected time to the connected * observers (renderers) * * Called by Update(). */ virtual void SendTime(); /** * \brief Set the RenderingManager to be used * * If \a NULL, the default RenderingManager will be used. */ itkSetObjectMacro(RenderingManager, RenderingManager); mitk::RenderingManager* GetRenderingManager() const; #pragma GCC visibility push(default) itkEventMacro( UpdateEvent, itk::AnyEvent ); #pragma GCC visibility pop class MITK_CORE_EXPORT TimeSlicedGeometryEvent : public itk::AnyEvent { public: typedef TimeSlicedGeometryEvent Self; typedef itk::AnyEvent Superclass; TimeSlicedGeometryEvent( TimeSlicedGeometry* aTimeSlicedGeometry, unsigned int aPos) : m_TimeSlicedGeometry(aTimeSlicedGeometry), m_Pos(aPos) {} virtual ~TimeSlicedGeometryEvent() {} virtual const char * GetEventName() const { return "TimeSlicedGeometryEvent"; } virtual bool CheckEvent(const ::itk::EventObject* e) const { return dynamic_cast(e); } virtual ::itk::EventObject* MakeObject() const { return new Self(m_TimeSlicedGeometry, m_Pos); } TimeSlicedGeometry* GetTimeSlicedGeometry() const { return m_TimeSlicedGeometry; } unsigned int GetPos() const { return m_Pos; } private: TimeSlicedGeometry::Pointer m_TimeSlicedGeometry; unsigned int m_Pos; // TimeSlicedGeometryEvent(const Self&); void operator=(const Self&); //just hide }; mitkTimeSlicedGeometryEventMacro( GeometrySendEvent,TimeSlicedGeometryEvent ); mitkTimeSlicedGeometryEventMacro( GeometryUpdateEvent, TimeSlicedGeometryEvent ); mitkTimeSlicedGeometryEventMacro( GeometryTimeEvent, TimeSlicedGeometryEvent ); mitkTimeSlicedGeometryEventMacro( GeometrySliceEvent, TimeSlicedGeometryEvent ); template void ConnectGeometrySendEvent(T* receiver) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::SetGeometry); - AddObserver(GeometrySendEvent(NULL,0), eventReceptorCommand); + unsigned long tag = AddObserver(GeometrySendEvent(NULL,0), eventReceptorCommand); + m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); } template void ConnectGeometryUpdateEvent(T* receiver) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::UpdateGeometry); - AddObserver(GeometryUpdateEvent(NULL,0), eventReceptorCommand); + unsigned long tag = AddObserver(GeometryUpdateEvent(NULL,0), eventReceptorCommand); + m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); } template void ConnectGeometrySliceEvent(T* receiver, bool connectSendEvent=true) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::SetGeometrySlice); - AddObserver(GeometrySliceEvent(NULL,0), eventReceptorCommand); + unsigned long tag = AddObserver(GeometrySliceEvent(NULL,0), eventReceptorCommand); + m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); if(connectSendEvent) ConnectGeometrySendEvent(receiver); } template void ConnectGeometryTimeEvent(T* receiver, bool connectSendEvent=true) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::SetGeometryTime); - AddObserver(GeometryTimeEvent(NULL,0), eventReceptorCommand); + unsigned long tag = AddObserver(GeometryTimeEvent(NULL,0), eventReceptorCommand); + m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); if(connectSendEvent) ConnectGeometrySendEvent(receiver); } template void ConnectGeometryEvents(T* receiver) { //connect sendEvent only once ConnectGeometrySliceEvent(receiver, false); ConnectGeometryTimeEvent(receiver); } + // use a templated method to get the right offset when casting to void* + template + void Disconnect(T* receiver) + { + ObserverTagsMapType::iterator i = m_ReceiverToObserverTagsMap.find(static_cast(receiver)); + if (i == m_ReceiverToObserverTagsMap.end()) return; + const std::list& tags = i->second; + for (std::list::const_iterator tagIter = tags.begin(); + tagIter != tags.end(); ++tagIter) + { + RemoveObserver(*tagIter); + } + m_ReceiverToObserverTagsMap.erase(i); + } + Message<> crosshairPositionEvent; /** * \brief To connect multiple SliceNavigationController, we can * act as an observer ourselves: implemented interface * \warning not implemented */ virtual void SetGeometry(const itk::EventObject & geometrySliceEvent); /** * \brief To connect multiple SliceNavigationController, we can * act as an observer ourselves: implemented interface */ virtual void SetGeometrySlice(const itk::EventObject & geometrySliceEvent); /** * \brief To connect multiple SliceNavigationController, we can * act as an observer ourselves: implemented interface */ virtual void SetGeometryTime(const itk::EventObject & geometryTimeEvent); /** \brief Positions the SNC according to the specified point */ void SelectSliceByPoint( const mitk::Point3D &point ); /** \brief Returns the TimeSlicedGeometry created by the SNC. */ const mitk::TimeSlicedGeometry *GetCreatedWorldGeometry(); /** \brief Returns the Geometry3D of the currently selected time step. */ const mitk::Geometry3D *GetCurrentGeometry3D(); /** \brief Returns the currently selected Plane in the current * Geometry3D (if existent). */ const mitk::PlaneGeometry *GetCurrentPlaneGeometry(); /** \brief Sets the BaseRenderer associated with this SNC (if any). While * the BaseRenderer is not directly used by SNC, this is a convenience * method to enable BaseRenderer access via the SNC. */ void SetRenderer( BaseRenderer *renderer ); /** \brief Gets the BaseRenderer associated with this SNC (if any). While * the BaseRenderer is not directly used by SNC, this is a convenience * method to enable BaseRenderer access via the SNC. Returns NULL if no * BaseRenderer has been specified*/ BaseRenderer *GetRenderer() const; /** \brief Re-orients the slice stack to include the plane specified by * the given point an normal vector. */ void ReorientSlices( const mitk::Point3D &point, const mitk::Vector3D &normal ); virtual bool ExecuteAction( Action* action, mitk::StateEvent const* stateEvent); void ExecuteOperation(Operation* operation); /** * \brief Feature option to lock planes during mouse interaction. * This option flag disables the mouse event which causes the center * cross to move near by. */ itkSetMacro(SliceLocked, bool); itkGetMacro(SliceLocked, bool); itkBooleanMacro(SliceLocked); /** * \brief Feature option to lock slice rotation. * * This option flag disables separately the rotation of a slice which is * implemented in mitkSliceRotator. */ itkSetMacro(SliceRotationLocked, bool); itkGetMacro(SliceRotationLocked, bool); itkBooleanMacro(SliceRotationLocked); /** * \brief Adjusts the numerical range of the slice stepper according to * the current geometry orientation of this SNC's SlicedGeometry. */ void AdjustSliceStepperRange(); protected: SliceNavigationController(const char * type = NULL); virtual ~SliceNavigationController(); /* template static void buildstring( mitkIpPicDescriptor *pic, itk::Point p, std::string &s, T = 0) { std::string value; std::stringstream stream; stream.imbue(std::locale::classic()); stream<=0 && p[1] >=0 && p[2]>=0) && (unsigned int)p[0] < pic->n[0] && (unsigned int)p[1] < pic->n[1] && (unsigned int)p[2] < pic->n[2] ) { if(pic->bpe!=24) { stream<<(((T*) pic->data)[ p[0] + p[1]*pic->n[0] + p[2]*pic->n[0]*pic->n[1] ]); } else { stream<<(((T*) pic->data)[p[0]*3 + 0 + p[1]*pic->n[0]*3 + p[2]*pic->n[0]*pic->n[1]*3 ]); stream<<(((T*) pic->data)[p[0]*3 + 1 + p[1]*pic->n[0]*3 + p[2]*pic->n[0]*pic->n[1]*3 ]); stream<<(((T*) pic->data)[p[0]*3 + 2 + p[1]*pic->n[0]*3 + p[2]*pic->n[0]*pic->n[1]*3 ]); } s = stream.str(); } else { s+= "point out of data"; } }; */ mitk::Geometry3D::ConstPointer m_InputWorldGeometry; mitk::Geometry3D::Pointer m_ExtendedInputWorldGeometry; mitk::TimeSlicedGeometry::Pointer m_CreatedWorldGeometry; ViewDirection m_ViewDirection; ViewDirection m_DefaultViewDirection; mitk::RenderingManager::Pointer m_RenderingManager; mitk::BaseRenderer *m_Renderer; itkSetMacro(Top, bool); itkGetMacro(Top, bool); itkBooleanMacro(Top); itkSetMacro(FrontSide, bool); itkGetMacro(FrontSide, bool); itkBooleanMacro(FrontSide); itkSetMacro(Rotated, bool); itkGetMacro(Rotated, bool); itkBooleanMacro(Rotated); bool m_Top; bool m_FrontSide; bool m_Rotated; bool m_BlockUpdate; bool m_SliceLocked; bool m_SliceRotationLocked; unsigned int m_OldPos; + + typedef std::map > ObserverTagsMapType; + ObserverTagsMapType m_ReceiverToObserverTagsMap; }; } // namespace mitk #endif /* SLICENAVIGATIONCONTROLLER_H_HEADER_INCLUDED_C1C55A2F */ diff --git a/Core/Code/DataManagement/mitkImageAccessByItk.h b/Core/Code/DataManagement/mitkImageAccessByItk.h index 8fc5ae80ca..4dd691e82f 100644 --- a/Core/Code/DataManagement/mitkImageAccessByItk.h +++ b/Core/Code/DataManagement/mitkImageAccessByItk.h @@ -1,619 +1,620 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 MITKIMAGEACCESSBYITK_H_HEADER_INCLUDED #define MITKIMAGEACCESSBYITK_H_HEADER_INCLUDED #include #include #include #include #include #include #include #include #include #include #include namespace mitk { /** * \brief Exception class thrown in #AccessByItk macros. * * This exception can be thrown by the invocation of the #AccessByItk macros, * if the MITK image is of non-expected dimension or pixel type. * * \ingroup Adaptor */ class AccessByItkException : public virtual std::runtime_error { public: AccessByItkException(const std::string& msg) : std::runtime_error(msg) {} ~AccessByItkException() throw() {} }; } #ifndef DOXYGEN_SKIP #define _accessByItkPixelTypeException(pixelType, pixelTypeSeq) \ { \ std::string msg("Pixel type "); \ msg.append(pixelType.GetItkTypeAsString()); \ msg.append(" is not in " MITK_PP_STRINGIZE(pixelTypeSeq)); \ throw mitk::AccessByItkException(msg); \ } #define _accessByItkDimensionException(dim, validDims) \ { \ std::stringstream msg; \ msg << "Dimension " << (dim) << " is not in " << validDims ; \ throw mitk::AccessByItkException(msg.str()); \ } #define _checkSpecificDimensionIter(r, mitkImage, dim) \ if (mitkImage->GetDimension() == dim); else #define _checkSpecificDimension(mitkImage, dimSeq) \ MITK_PP_SEQ_FOR_EACH(_checkSpecificDimensionIter, mitkImage, dimSeq) \ _accessByItkDimensionException(mitkImage->GetDimension(), MITK_PP_STRINGIZE(dimSeq)) #define _msvc_expand_bug(macro, arg) MITK_PP_EXPAND(macro arg) //-------------------------------- 0-Arg Versions -------------------------------------- #define _accessByItk(itkImageTypeFunction, pixeltype, dimension) \ - if ( pixelType == typeid(pixeltype) && constImage->GetDimension() == dimension) \ - { \ - typedef itk::Image ImageType; \ + if ( pixelType == mitk::MakePixelType< itk::Image >() && constImage->GetDimension() == dimension) \ + {\ + typedef itk::Image ImageType; \ typedef mitk::ImageToItk ImageToItkType; \ itk::SmartPointer imagetoitk = ImageToItkType::New(); \ imagetoitk->SetInput(constImage); \ imagetoitk->Update(); \ itkImageTypeFunction(imagetoitk->GetOutput()); \ } else #define _accessByItkArgs(itkImageTypeFunction, type) \ (itkImageTypeFunction, MITK_PP_TUPLE_REM(2)type) // product will be of the form (itkImageTypeFunction)(short)(2) for pixel type short and dimension 2 #ifdef _MSC_VER #define _accessByItkProductIter(r, product) \ _msvc_expand_bug(_accessByItk, _msvc_expand_bug(_accessByItkArgs, (MITK_PP_SEQ_HEAD(product), MITK_PP_SEQ_TO_TUPLE(MITK_PP_SEQ_TAIL(product))))) #else #define _accessByItkProductIter(r, product) \ MITK_PP_EXPAND(_accessByItk _accessByItkArgs(MITK_PP_SEQ_HEAD(product), MITK_PP_SEQ_TO_TUPLE(MITK_PP_SEQ_TAIL(product)))) #endif #define _accessFixedTypeByItk(itkImageTypeFunction, pixelTypeSeq, dimSeq) \ MITK_PP_SEQ_FOR_EACH_PRODUCT(_accessByItkProductIter, ((itkImageTypeFunction))(pixelTypeSeq)(dimSeq)) //-------------------------------- n-Arg Versions -------------------------------------- #define _accessByItk_n(itkImageTypeFunction, pixeltype, dimension, args) \ - if ( pixelType == typeid(pixeltype) && constImage->GetDimension() == dimension) \ - { \ - typedef itk::Image ImageType; \ + if ( pixelType == mitk::MakePixelType< itk::Image >() && constImage->GetDimension() == dimension) \ + {\ + typedef itk::Image ImageType; \ typedef mitk::ImageToItk ImageToItkType; \ itk::SmartPointer imagetoitk = ImageToItkType::New(); \ imagetoitk->SetInput(constImage); \ imagetoitk->Update(); \ itkImageTypeFunction(imagetoitk->GetOutput(), MITK_PP_TUPLE_REM(MITK_PP_SEQ_HEAD(args))MITK_PP_SEQ_TAIL(args)); \ } else #define _accessByItkArgs_n(itkImageTypeFunction, type, args) \ (itkImageTypeFunction, MITK_PP_TUPLE_REM(2) type, args) // product will be of the form ((itkImageTypeFunction)(3)(a,b,c))(short)(2) // for the variable argument list a,b,c and for pixel type short and dimension 2 #ifdef _MSC_VER #define _accessByItkProductIter_n(r, product) \ _msvc_expand_bug(_accessByItk_n, _msvc_expand_bug(_accessByItkArgs_n, (MITK_PP_SEQ_HEAD(MITK_PP_SEQ_HEAD(product)), MITK_PP_SEQ_TO_TUPLE(MITK_PP_SEQ_TAIL(product)), MITK_PP_SEQ_TAIL(MITK_PP_SEQ_HEAD(product))))) #else #define _accessByItkProductIter_n(r, product) \ MITK_PP_EXPAND(_accessByItk_n _accessByItkArgs_n(MITK_PP_SEQ_HEAD(MITK_PP_SEQ_HEAD(product)), MITK_PP_SEQ_TO_TUPLE(MITK_PP_SEQ_TAIL(product)), MITK_PP_SEQ_TAIL(MITK_PP_SEQ_HEAD(product)))) #endif #define _accessFixedTypeByItk_n(itkImageTypeFunction, pixelTypeSeq, dimSeq, va_tuple) \ MITK_PP_SEQ_FOR_EACH_PRODUCT(_accessByItkProductIter_n, (((itkImageTypeFunction)(MITK_PP_ARG_COUNT va_tuple) va_tuple))(pixelTypeSeq)(dimSeq)) #endif //DOXYGEN_SKIP /** * \brief Access a MITK image by an ITK image * * Define a templated function or method (\a itkImageTypeFunction) * within which the mitk-image (\a mitkImage) is accessed: * \code * template < typename TPixel, unsigned int VImageDimension > * void ExampleFunction( itk::Image* itkImage ); * \endcode * * The itk::Image passed to the function/method has the same * data-pointer as the mitk-image. So you have full read- and write- * access to the data vector of the mitk-image using the itk-image. * Call by: * \code * mitk::Image* inputMitkImage = ... * try * { * AccessByItk(inputMitkImage, ExampleFunction); * } * catch (const mitk::AccessByItkException& e) * { * // mitk::Image is of wrong pixel type or dimension, * // insert error handling here * } * \endcode * * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * \note If your inputMitkImage is an mitk::Image::Pointer, use * inputMitkImage.GetPointer() * \note If you need to pass additional parameters to your * access-function (\a itkImageTypeFunction), use #AccessByItk_n. * \note If you know the dimension of your input mitk-image, * it is better to use AccessFixedDimensionByItk (less code * is generated). * \sa AccessFixedDimensionByItk * \sa AccessFixedTypeByItk * \sa AccessFixedPixelTypeByItk * \sa AccessByItk_n * * \ingroup Adaptor */ #define AccessByItk(mitkImage, itkImageTypeFunction) \ AccessFixedTypeByItk(mitkImage, itkImageTypeFunction, MITK_ACCESSBYITK_PIXEL_TYPES_SEQ, MITK_ACCESSBYITK_DIMENSIONS_SEQ) /** * \brief Access a mitk-image with known pixeltype (but unknown dimension) by an itk-image. * * For usage, see #AccessByItk. * * \param pixelTypeSeq A sequence of pixel types, like (short)(char)(int) * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * If the image has a different pixel type, a mitk::AccessByItkException exception is * thrown. If you do not know the pixel type for sure, use #AccessByItk. * * \sa AccessByItk * \sa AccessFixedDimensionByItk * \sa AccessFixedTypeByItk * \sa AccessFixedPixelTypeByItk_n * * \ingroup Adaptor */ #define AccessFixedPixelTypeByItk(mitkImage, itkImageTypeFunction, pixelTypeSeq) \ AccessFixedTypeByItk(mitkImage, itkImageTypeFunction, pixelTypeSeq, MITK_ACCESSBYITK_DIMENSIONS_SEQ) /** * \brief Access a mitk-image with an integral pixel type by an itk-image * * See #AccessByItk for details. * * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * \sa AccessFixedPixelTypeByItk * \sa AccessByItk * \sa AccessIntegralPixelTypeByItk_n */ #define AccessIntegralPixelTypeByItk(mitkImage, itkImageTypeFunction) \ AccessFixedTypeByItk(mitkImage, itkImageTypeFunction, MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES_SEQ, MITK_ACCESSBYITK_DIMENSIONS_SEQ) /** * \brief Access a mitk-image with a floating point pixel type by an ITK image * * See #AccessByItk for details. * * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * \sa AccessFixedPixelTypeByItk * \sa AccessByItk * \sa AccessFloatingPixelTypeByItk_n */ #define AccessFloatingPixelTypeByItk(mitkImage, itkImageTypeFunction) \ AccessFixedTypeByItk(mitkImage, itkImageTypeFunction, MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES_SEQ, MITK_ACCESSBYITK_DIMENSIONS_SEQ) /** * \brief Access a mitk-image with known dimension by an itk-image * * For usage, see #AccessByItk. * * \param dimension Dimension of the mitk-image. If the image has a different dimension, * a mitk::AccessByItkException exception is thrown. * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * \note If you do not know the dimension for sure, use #AccessByItk. * * \sa AccessByItk * \sa AccessFixedDimensionByItk_n * \sa AccessFixedTypeByItk * \sa AccessFixedPixelTypeByItk * * \ingroup Adaptor */ #define AccessFixedDimensionByItk(mitkImage, itkImageTypeFunction, dimension) \ AccessFixedTypeByItk(mitkImage, itkImageTypeFunction, MITK_ACCESSBYITK_PIXEL_TYPES_SEQ, (dimension)) /** * \brief Access a mitk-image with known type (pixel type and dimension) by an itk-image. * * The provided mitk-image must be in the set of types created by taking the * cartesian product of the pixel type sequence and the dimension sequence. * For example, a call to * \code * AccessFixedTypeByItk(myMitkImage, MyAccessFunction, (short)(int), (2)(3)) * \endcode * asserts that the type of myMitkImage (pixeltype,dim) is in the set {(short,2),(short,3),(int,2),(int,3)}. * For more information, see #AccessByItk. * * \param pixelTypeSeq A sequence of pixel types, like (short)(char)(int). * \param dimension A sequence of dimensions, like (2)(3). * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * If the image has a different dimension or pixel type, * a mitk::AccessByItkException exception is thrown. * * \note If you do not know the dimension for sure, use #AccessByItk. * * \sa AccessByItk * \sa AccessFixedDimensionByItk * \sa AccessFixedTypeByItk_n * \sa AccessFixedPixelTypeByItk * * \ingroup Adaptor */ #define AccessFixedTypeByItk(mitkImage, itkImageTypeFunction, pixelTypeSeq, dimSeq) \ { \ const mitk::PixelType& pixelType = mitkImage->GetPixelType(); \ const mitk::Image* constImage = mitkImage; \ const_cast(constImage)->Update(); \ _checkSpecificDimension(mitkImage, dimSeq); \ _accessFixedTypeByItk(itkImageTypeFunction, pixelTypeSeq, dimSeq) \ _accessByItkPixelTypeException(mitkImage->GetPixelType(), pixelTypeSeq) \ } //------------------------------ n-Arg Access Macros ----------------------------------- /** * \brief Access a MITK image by an ITK image with one or more parameters. * * Define a templated function or method (\a itkImageTypeFunction) with one ore more * additional parameters, within which the mitk-image (\a mitkImage) is accessed: * \code * template < typename TPixel, unsigned int VImageDimension > * void ExampleFunction( itk::Image* itkImage, SomeType param); * \endcode * * The itk::Image passed to the function/method has the same * data-pointer as the mitk-image. So you have full read- and write- * access to the data vector of the mitk-image using the itk-image. * Call by: * \code * SomeType param = ... * mitk::Image* inputMitkImage = ... * try * { * AccessByItk_n(inputMitkImage, ExampleFunction, (param)); * } * catch (const mitk::AccessByItkException& e) * { * // mitk::Image is of wrong pixel type or dimension, * // insert error handling here * } * \endcode * * \param va_tuple A variable length tuple containing the arguments to be passed * to the access function itkImageTypeFunction, e.g. ("first", 2, THIRD). * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * \note If your inputMitkImage is an mitk::Image::Pointer, use * inputMitkImage.GetPointer() * \note If you know the dimension of your input mitk-image, * it is better to use AccessFixedDimensionByItk_n (less code * is generated). * \sa AccessFixedDimensionByItk_n * \sa AccessFixedTypeByItk_n * \sa AccessFixedPixelTypeByItk_n * \sa AccessByItk * * \ingroup Adaptor */ #define AccessByItk_n(mitkImage, itkImageTypeFunction, va_tuple) \ AccessFixedTypeByItk_n(mitkImage, itkImageTypeFunction, MITK_ACCESSBYITK_PIXEL_TYPES_SEQ, MITK_ACCESSBYITK_DIMENSIONS_SEQ, va_tuple) /** * \brief Access a mitk-image with known pixeltype (but unknown dimension) by an itk-image * with one or more parameters. * * For usage, see #AccessByItk_n. * * \param va_tuple A variable length tuple containing the arguments to be passed * to the access function itkImageTypeFunction, e.g. ("first", 2, THIRD). * \param pixelTypeSeq A sequence of pixel types, like (short)(char)(int). * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * If the image has a different pixel type, a mitk::AccessByItkException exception is * thrown. If you do not know the pixel type for sure, use #AccessByItk_n. * * \sa AccessByItk_n * \sa AccessFixedDimensionByItk_n * \sa AccessFixedTypeByItk_n * \sa AccessFixedPixelTypeByItk * * \ingroup Adaptor */ #define AccessFixedPixelTypeByItk_n(mitkImage, itkImageTypeFunction, pixelTypeSeq, va_tuple) \ AccessFixedTypeByItk_n(mitkImage, itkImageTypeFunction, pixelTypeSeq, MITK_ACCESSBYITK_DIMENSIONS_SEQ, va_tuple) /** * \brief Access an mitk::Image with an integral pixel type by an ITK image with * one or more parameters. * * See #AccessByItk_n for details. * * \param va_tuple A variable length tuple containing the arguments to be passed * to the access function itkImageTypeFunction, e.g. ("first", 2, THIRD). * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * \sa AccessFixedPixelTypeByItk_n * \sa AccessByItk_n * \sa AccessIntegralPixelTypeByItk */ #define AccessIntegralPixelTypeByItk_n(mitkImage, itkImageTypeFunction, va_tuple) \ AccessFixedTypeByItk_n(mitkImage, itkImageTypeFunction, MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES_SEQ, MITK_ACCESSBYITK_DIMENSIONS_SEQ, va_tuple) /** * \brief Access an mitk::Image with a floating point pixel type by an ITK image * with one or more parameters. * * See #AccessByItk_n for details. * * \param va_tuple A variable length tuple containing the arguments to be passed * to the access function itkImageTypeFunction, e.g. ("first", 2, THIRD). * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * \sa AccessFixedPixelTypeByItk_n * \sa AccessByItk_n * \sa AccessFloatingPixelTypeByItk */ #define AccessFloatingPixelTypeByItk_n(mitkImage, itkImageTypeFunction, va_tuple) \ AccessFixedTypeByItk_n(mitkImage, itkImageTypeFunction, MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES_SEQ, MITK_ACCESSBYITK_DIMENSIONS_SEQ, va_tuple) /** * \brief Access a mitk-image with known dimension by an itk-image with * one or more parameters. * * For usage, see #AccessByItk_n. * * \param dimension Dimension of the mitk-image. If the image has a different dimension, * a mitk::AccessByItkException exception is thrown. * \param va_tuple A variable length tuple containing the arguments to be passed * to the access function itkImageTypeFunction, e.g. ("first", 2, THIRD). * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * \note If you do not know the dimension for sure, use #AccessByItk_n. * * \sa AccessByItk_n * \sa AccessFixedDimensionByItk * \sa AccessFixedTypeByItk_n * \sa AccessFixedPixelTypeByItk_n * * \ingroup Adaptor */ #define AccessFixedDimensionByItk_n(mitkImage, itkImageTypeFunction, dimension, va_tuple) \ AccessFixedTypeByItk_n(mitkImage, itkImageTypeFunction, MITK_ACCESSBYITK_PIXEL_TYPES_SEQ, (dimension), va_tuple) /** * \brief Access a mitk-image with known type (pixel type and dimension) by an itk-image * with one or more parameters. * * For usage, see AccessFixedTypeByItk. * * \param pixelTypeSeq A sequence of pixel types, like (short)(char)(int). * \param dimension A sequence of dimensions, like (2)(3). * \param va_tuple A variable length tuple containing the arguments to be passed * to the access function itkImageTypeFunction, e.g. ("first", 2, THIRD). * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * If the image has a different dimension or pixel type, * a mitk::AccessByItkException exception is thrown. * * \note If you do not know the dimension for sure, use #AccessByItk_n. * * \sa AccessByItk_n * \sa AccessFixedDimensionByItk_n * \sa AccessFixedTypeByItk * \sa AccessFixedPixelTypeByItk_n * * \ingroup Adaptor */ #define AccessFixedTypeByItk_n(mitkImage, itkImageTypeFunction, pixelTypeSeq, dimSeq, va_tuple) \ { \ const mitk::PixelType& pixelType = mitkImage->GetPixelType(); \ const mitk::Image* constImage = mitkImage; \ const_cast(constImage)->Update(); \ _checkSpecificDimension(mitkImage, dimSeq); \ _accessFixedTypeByItk_n(itkImageTypeFunction, pixelTypeSeq, dimSeq, va_tuple) \ _accessByItkPixelTypeException(mitkImage->GetPixelType(), pixelTypeSeq) \ } //------------------------- For back-wards compatibility ------------------------------- #define AccessByItk_1(mitkImage, itkImageTypeFunction, arg1) AccessByItk_n(mitkImage, itkImageTypeFunction, (arg1)) #define AccessFixedPixelTypeByItk_1(mitkImage, itkImageTypeFunction, pixelTypeSeq, arg1) AccessFixedPixelTypeByItk_n(mitkImage, itkImageTypeFunction, pixelTypeSeq, (arg1)) #define AccessFixedDimensionByItk_1(mitkImage, itkImageTypeFunction, dimension, arg1) AccessFixedDimensionByItk_n(mitkImage, itkImageTypeFunction, dimension, (arg1)) #define AccessFixedTypeByItk_1(mitkImage, itkImageTypeFunction, pixelTypeSeq, dimSeq, arg1) AccessFixedTypeByItk_n(mitkImage, itkImageTypeFunction, pixelTypeSeq, dimSeq, (arg1)) #define AccessByItk_2(mitkImage, itkImageTypeFunction, arg1, arg2) AccessByItk_n(mitkImage, itkImageTypeFunction, (arg1,arg2)) #define AccessFixedPixelTypeByItk_2(mitkImage, itkImageTypeFunction, pixelTypeSeq, arg1, arg2) AccessFixedPixelTypeByItk_n(mitkImage, itkImageTypeFunction, pixelTypeSeq, (arg1,arg2)) #define AccessFixedDimensionByItk_2(mitkImage, itkImageTypeFunction, dimension, arg1, arg2) AccessFixedDimensionByItk_n(mitkImage, itkImageTypeFunction, dimension, (arg1,arg2)) #define AccessFixedTypeByItk_2(mitkImage, itkImageTypeFunction, pixelTypeSeq, dimSeq, arg1, arg2) AccessFixedTypeByItk_n(mitkImage, itkImageTypeFunction, pixelTypeSeq, dimSeq, (arg1,arg2)) #define AccessByItk_3(mitkImage, itkImageTypeFunction, arg1, arg2, arg3) AccessByItk_n(mitkImage, itkImageTypeFunction, (arg1,arg2,arg3)) #define AccessFixedPixelTypeByItk_3(mitkImage, itkImageTypeFunction, pixelTypeSeq, arg1, arg2, arg3) AccessFixedPixelTypeByItk_n(mitkImage, itkImageTypeFunction, pixelTypeSeq, (arg1,arg2,arg3)) #define AccessFixedDimensionByItk_3(mitkImage, itkImageTypeFunction, dimension, arg1, arg2, arg3) AccessFixedDimensionByItk_n(mitkImage, itkImageTypeFunction, dimension, (arg1,arg2,arg3)) #define AccessFixedTypeByItk_3(mitkImage, itkImageTypeFunction, pixelTypeSeq, dimSeq, arg1, arg2, arg3) AccessFixedTypeByItk_n(mitkImage, itkImageTypeFunction, pixelTypeSeq, dimSeq, (arg1,arg2,arg3)) //----------------------------- Access two MITK Images --------------------------------- #ifndef DOXYGEN_SKIP #define _accessTwoImagesByItk(itkImageTypeFunction, pixeltype1, dim1, pixeltype2, dim2) \ - if (pixelType1 == typeid(pixeltype1) && pixelType2 == typeid(pixeltype2) && \ + if (pixelType1 == mitk::MakePixelType< itk::Image >() && \ + pixelType2 == mitk::MakePixelType< itk::Image >() && \ constImage1->GetDimension() == dim1 && constImage2->GetDimension() == dim2) \ { \ typedef itk::Image ImageType1; \ typedef itk::Image ImageType2; \ typedef mitk::ImageToItk ImageToItkType1; \ typedef mitk::ImageToItk ImageToItkType2; \ itk::SmartPointer imagetoitk1 = ImageToItkType1::New(); \ imagetoitk1->SetInput(constImage1); \ imagetoitk1->Update(); \ itk::SmartPointer imagetoitk2 = ImageToItkType2::New(); \ imagetoitk2->SetInput(constImage2); \ imagetoitk2->Update(); \ itkImageTypeFunction(imagetoitk1->GetOutput(), imagetoitk2->GetOutput()); \ } else #define _accessTwoImagesByItkArgs2(itkImageTypeFunction, type1, type2) \ (itkImageTypeFunction, MITK_PP_TUPLE_REM(2) type1, MITK_PP_TUPLE_REM(2) type2) #define _accessTwoImagesByItkArgs(product) \ MITK_PP_EXPAND(_accessTwoImagesByItkArgs2 MITK_PP_EXPAND((MITK_PP_SEQ_HEAD(product), MITK_PP_TUPLE_REM(2) MITK_PP_SEQ_TO_TUPLE(MITK_PP_SEQ_TAIL(product))))) // product is of the form (itkImageTypeFunction)((short,2))((char,2)) #ifdef _MSC_VER #define _accessTwoImagesByItkIter(r, product) \ MITK_PP_EXPAND(_accessTwoImagesByItk _msvc_expand_bug(_accessTwoImagesByItkArgs2, (MITK_PP_SEQ_HEAD(product), _msvc_expand_bug(MITK_PP_TUPLE_REM(2), MITK_PP_EXPAND(MITK_PP_SEQ_TO_TUPLE (MITK_PP_SEQ_TAIL(product))))))) #else #define _accessTwoImagesByItkIter(r, product) \ MITK_PP_EXPAND(_accessTwoImagesByItk _accessTwoImagesByItkArgs(product)) #endif #define _accessTwoImagesByItkForEach(itkImageTypeFunction, tseq1, tseq2) \ MITK_PP_SEQ_FOR_EACH_PRODUCT(_accessTwoImagesByItkIter, ((itkImageTypeFunction))(tseq1)(tseq2)) #endif // DOXYGEN_SKIP /** * \brief Access two mitk-images with known dimension by itk-images * * Define a templated function or method (\a itkImageTypeFunction) * within which the mitk-images (\a mitkImage1 and \a mitkImage2) are accessed: * \code * template * void ExampleFunctionTwoImages(itk::Image* itkImage1, itk::Image* itkImage2); * \endcode * * The itk::Image passed to the function/method has the same * data-pointer as the mitk-image. So you have full read- and write- * access to the data vector of the mitk-image using the itk-image. * Call by: * \code * mitk::Image* inputMitkImage1 = ... * mitk::Image* inputMitkImage2 = ... * try * { * AccessTwoImagesFixedDimensionByItk(inputMitkImage1, inputMitkImage2, ExampleFunctionTwoImages, 3); * } * catch (const mitk::AccessByItkException& e) * { * // mitk::Image arguments are of wrong pixel type or dimension, * // insert error handling here * } * \endcode * * \note If your inputMitkImage1 or inputMitkImage2 is a mitk::Image::Pointer, use * inputMitkImage1.GetPointer(). * * \param mitkImage1 The first MITK input image. * \param mitkImage1 The second MITK input image. * \param itkImageTypeFunction The name of the template access-function to be called. * \param dimension Dimension of the two mitk-images. * * \throws mitk::AccessByItkException If mitkImage1 and mitkImage2 have different dimensions or * one of the images is of unsupported pixel type or dimension. * * \sa #AccessByItk * * \ingroup Adaptor */ #define AccessTwoImagesFixedDimensionByItk(mitkImage1, mitkImage2, itkImageTypeFunction, dimension) \ { \ const mitk::PixelType& pixelType1 = mitkImage1->GetPixelType(); \ const mitk::PixelType& pixelType2 = mitkImage2->GetPixelType(); \ const mitk::Image* constImage1 = mitkImage1; \ const mitk::Image* constImage2 = mitkImage2; \ const_cast(constImage1)->Update(); \ const_cast(constImage2)->Update(); \ _checkSpecificDimension(mitkImage1, (dimension)); \ _checkSpecificDimension(mitkImage2, (dimension)); \ _accessTwoImagesByItkForEach(itkImageTypeFunction, MITK_ACCESSBYITK_TYPES_DIMN_SEQ(dimension), MITK_ACCESSBYITK_TYPES_DIMN_SEQ(dimension)) \ { \ std::string msg("Pixel type "); \ msg.append(pixelType1.GetComponentTypeAsString() ); \ msg.append(" or pixel type "); \ msg.append(pixelType2.GetComponentTypeAsString() ); \ msg.append(" is not in " MITK_PP_STRINGIZE(MITK_ACCESSBYITK_TYPES_DIMN_SEQ(dimension))); \ throw mitk::AccessByItkException(msg); \ } \ } #endif // of MITKIMAGEACCESSBYITK_H_HEADER_INCLUDED diff --git a/Core/Code/DataManagement/mitkImageToItk.txx b/Core/Code/DataManagement/mitkImageToItk.txx index 03b0978bc7..dda6728e8d 100644 --- a/Core/Code/DataManagement/mitkImageToItk.txx +++ b/Core/Code/DataManagement/mitkImageToItk.txx @@ -1,257 +1,257 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 IMAGETOITK_TXX_INCLUDED_C1C2FCD2 #define IMAGETOITK_TXX_INCLUDED_C1C2FCD2 #include "mitkImageToItk.h" #include "mitkBaseProcess.h" #include "itkImportMitkImageContainer.h" template void mitk::ImageToItk::SetInput(const mitk::Image *input) { if(input == NULL) itkExceptionMacro( << "image is null" ); if(input->GetDimension()!=TOutputImage::GetImageDimension()) itkExceptionMacro( << "image has dimension " << input->GetDimension() << " instead of " << TOutputImage::GetImageDimension() ); - if(!(input->GetPixelType() == typeid(PixelType))) + if(!(input->GetPixelType() == mitk::MakePixelType())) itkExceptionMacro( << "image has wrong pixel type " ); // Process object is not const-correct so the const_cast is required here itk::ProcessObject::SetNthInput(0, const_cast< mitk::Image * >( input ) ); } template void mitk::ImageToItk::SetInput( unsigned int index, const mitk::Image * input ) { if( index+1 > this->GetNumberOfInputs() ) { this->SetNumberOfRequiredInputs( index + 1 ); } if(input == NULL) itkExceptionMacro( << "image is null" ); if(input->GetDimension()!=TOutputImage::GetImageDimension()) itkExceptionMacro( << "image has dimension " << input->GetDimension() << " instead of " << TOutputImage::GetImageDimension() ); - if(!(input->GetPixelType() == typeid(PixelType))) + if(!(input->GetPixelType() == mitk::MakePixelType() )) itkExceptionMacro( << "image has wrong pixel type " ); // Process object is not const-correct so the const_cast is required here itk::ProcessObject::SetNthInput(index, const_cast< mitk::Image *>( input ) ); } template const mitk::Image *mitk::ImageToItk::GetInput(void) { if (this->GetNumberOfInputs() < 1) { return 0; } return static_cast< const mitk::Image * > (itk::ProcessObject::GetInput(0) ); } template const mitk::Image *mitk::ImageToItk::GetInput(unsigned int idx) { return static_cast< mitk::Image * > (itk::ProcessObject::GetInput(idx)); } template void mitk::ImageToItk ::GenerateData() { // Allocate output mitk::Image::ConstPointer input = this->GetInput(); typename Superclass::OutputImageType::Pointer output = this->GetOutput(); unsigned long noBytes = input->GetDimension(0); for (unsigned int i=1; iGetDimension(i); } // hier wird momentan wohl nur der erste Channel verwendet??!! m_ImageDataItem = const_cast(input.GetPointer())->GetChannelData( m_Channel ); if(m_ImageDataItem.GetPointer() == NULL) { itkWarningMacro(<< "no image data to import in ITK image"); RegionType bufferedRegion; output->SetBufferedRegion(bufferedRegion); return; } if (m_CopyMemFlag) { itkDebugMacro("copyMem ..."); output->Allocate(); memcpy( (PixelType *) output->GetBufferPointer(), m_ImageDataItem->GetData(), sizeof(PixelType)*noBytes); } else { itkDebugMacro("do not copyMem ..."); typedef itk::ImportMitkImageContainer< unsigned long, PixelType > ImportContainerType; typename ImportContainerType::Pointer import; import = ImportContainerType::New(); import->Initialize(); itkDebugMacro( << "size of container = " << import->Size() ); import->SetImageDataItem(m_ImageDataItem); output->SetPixelContainer(import); itkDebugMacro( << "size of container = " << import->Size() ); } } template void mitk::ImageToItk ::UpdateOutputInformation() { mitk::Image::ConstPointer input = this->GetInput(); if(input.IsNotNull() && (input->GetSource().IsNotNull()) && input->GetSource()->Updating()) { typename Superclass::OutputImageType::Pointer output = this->GetOutput(); unsigned long t1 = input->GetUpdateMTime()+1; if (t1 > this->m_OutputInformationMTime.GetMTime()) { output->SetPipelineMTime(t1); this->GenerateOutputInformation(); this->m_OutputInformationMTime.Modified(); } return; } Superclass::UpdateOutputInformation(); } template void mitk::ImageToItk ::GenerateOutputInformation() { mitk::Image::ConstPointer input = this->GetInput(); typename Superclass::OutputImageType::Pointer output = this->GetOutput(); // allocate size, origin, spacing, direction in types of output image SizeType size; const unsigned int itkDimMin3 = (TOutputImage::ImageDimension > 3 ? TOutputImage::ImageDimension : 3); const unsigned int itkDimMax3 = (TOutputImage::ImageDimension < 3 ? TOutputImage::ImageDimension : 3); typename Superclass::OutputImageType::PointType::ValueType origin[ itkDimMin3 ]; typename Superclass::OutputImageType::SpacingType::ComponentType spacing[ itkDimMin3 ]; typename Superclass::OutputImageType::DirectionType direction; // copy as much information as possible into size and spacing unsigned int i; for ( i=0; i < itkDimMax3; ++i) { size[i] = input->GetDimension(i); spacing[i] = input->GetGeometry()->GetSpacing()[i]; } for ( ; i < TOutputImage::ImageDimension; ++i) { origin[i] = 0.0; size[i] = input->GetDimension(i); spacing[i] = 1.0; } // build region from size IndexType start; start.Fill( 0 ); RegionType region; region.SetIndex( start ); region.SetSize( size ); // copy as much information as possible into origin const mitk::Point3D& mitkorigin = input->GetGeometry()->GetOrigin(); itk2vtk(mitkorigin, origin); // copy as much information as possible into direction direction.SetIdentity(); unsigned int j; const AffineTransform3D::MatrixType& matrix = input->GetGeometry()->GetIndexToWorldTransform()->GetMatrix(); - /// \warning 2D MITK images could have a 3D rotation, since they have a 3x3 geometry matrix. - /// If it is only a rotation around the transversal plane normal, it can be express with a 2x2 matrix. + /// \warning 2D MITK images could have a 3D rotation, since they have a 3x3 geometry matrix. + /// If it is only a rotation around the axial plane normal, it can be express with a 2x2 matrix. /// In this case, the ITK image conservs this information and is identical to the MITK image! /// If the MITK image contains any other rotation, the ITK image will have no rotation at all. /// Spacing is of course conserved in both cases. // the following loop devides by spacing now to normalize columns. // counterpart of InitializeByItk in mitkImage.h line 372 of revision 15092. // Check if information is lost if ( TOutputImage::ImageDimension <= 2) { if (( TOutputImage::ImageDimension == 2) && ( ( matrix[0][2] != 0) || ( matrix[1][2] != 0) || ( matrix[2][0] != 0) || ( matrix[2][1] != 0) || (( matrix[2][2] != 1) && ( matrix[2][2] != -1) ))) { // The 2D MITK image contains 3D rotation information. // This cannot be expressed in a 2D ITK image, so the ITK image will have no rotation } else { // The 2D MITK image can be converted to an 2D ITK image without information loss! for ( i=0; i < itkDimMax3; ++i) for( j=0; j < itkDimMax3; ++j ) direction[i][j] = matrix[i][j]/spacing[j]; } } else { // Normal 3D image. Conversion possible without problem! for ( i=0; i < itkDimMax3; ++i) for( j=0; j < itkDimMax3; ++j ) direction[i][j] = matrix[i][j]/spacing[j]; } // set information into output image output->SetRegions( region ); output->SetOrigin( origin ); output->SetSpacing( spacing ); output->SetDirection( direction ); } template void mitk::ImageToItk ::PrintSelf(std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf(os,indent); } #endif //IMAGETOITK_TXX_INCLUDED_C1C2FCD2 diff --git a/Core/Code/DataManagement/mitkLevelWindow.cpp b/Core/Code/DataManagement/mitkLevelWindow.cpp index 47e1d553dd..216f44acc1 100644 --- a/Core/Code/DataManagement/mitkLevelWindow.cpp +++ b/Core/Code/DataManagement/mitkLevelWindow.cpp @@ -1,430 +1,432 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkImageSliceSelector.h" #include "mitkImageStatisticsHolder.h" #include void mitk::LevelWindow::EnsureConsistency() { // Check if total range is ok { if ( m_RangeMin > m_RangeMax ) std::swap(m_RangeMin,m_RangeMax); if (m_RangeMin == m_RangeMax ) m_RangeMin = m_RangeMax - 1; } // Check if current window is ok { if ( m_LowerWindowBound > m_UpperWindowBound ) std::swap(m_LowerWindowBound,m_UpperWindowBound); if ( m_LowerWindowBound < m_RangeMin ) m_LowerWindowBound = m_RangeMin; if ( m_UpperWindowBound < m_RangeMin ) m_UpperWindowBound = m_RangeMin; if ( m_LowerWindowBound > m_RangeMax ) m_LowerWindowBound = m_RangeMax; if ( m_UpperWindowBound > m_RangeMax ) m_UpperWindowBound = m_RangeMax; if (m_LowerWindowBound == m_UpperWindowBound ) { if(m_LowerWindowBound == m_RangeMin ) m_UpperWindowBound++; else m_LowerWindowBound--; } } } mitk::LevelWindow::LevelWindow(mitk::ScalarType level, mitk::ScalarType window) : m_LowerWindowBound( level - window / 2.0 ), m_UpperWindowBound( level + window / 2.0 ), m_RangeMin( -2048.0 ), m_RangeMax( 4096.0 ), m_DefaultLowerBound( -2048.0 ), m_DefaultUpperBound( 4096.0 ), m_Fixed( false ) { SetDefaultLevelWindow(level, window); } mitk::LevelWindow::LevelWindow(const mitk::LevelWindow& levWin) : m_LowerWindowBound( levWin.GetLowerWindowBound() ) , m_UpperWindowBound( levWin.GetUpperWindowBound() ) , m_RangeMin( levWin.GetRangeMin() ) , m_RangeMax( levWin.GetRangeMax() ) , m_DefaultLowerBound( levWin.GetDefaultLowerBound() ) , m_DefaultUpperBound( levWin.GetDefaultUpperBound() ) , m_Fixed( levWin.GetFixed() ) { } mitk::LevelWindow::~LevelWindow() { } mitk::ScalarType mitk::LevelWindow::GetLevel() const { return (m_UpperWindowBound-m_LowerWindowBound) / 2.0 + m_LowerWindowBound; } mitk::ScalarType mitk::LevelWindow::GetWindow() const { return (m_UpperWindowBound-m_LowerWindowBound); } mitk::ScalarType mitk::LevelWindow::GetDefaultLevel() const { return ((m_DefaultUpperBound+m_DefaultLowerBound)/2.0); } mitk::ScalarType mitk::LevelWindow::GetDefaultWindow() const { return ((m_DefaultUpperBound-m_DefaultLowerBound)); } void mitk::LevelWindow::ResetDefaultLevelWindow() { SetLevelWindow(GetDefaultLevel(), GetDefaultWindow()); } mitk::ScalarType mitk::LevelWindow::GetLowerWindowBound() const { return m_LowerWindowBound; } mitk::ScalarType mitk::LevelWindow::GetUpperWindowBound() const { return m_UpperWindowBound; } void mitk::LevelWindow::SetDefaultLevelWindow(mitk::ScalarType level, mitk::ScalarType window) { SetDefaultBoundaries((level-(window/2.0)), (level+(window/2.0))); } void mitk::LevelWindow::SetLevelWindow(mitk::ScalarType level, mitk::ScalarType window, bool expandRangesIfNecessary) { SetWindowBounds( (level-(window/2.0)), (level+(window/2.0)), expandRangesIfNecessary ); } void mitk::LevelWindow::SetWindowBounds(mitk::ScalarType lowerBound, mitk::ScalarType upperBound, bool expandRangesIfNecessary) { if ( IsFixed() ) return; m_LowerWindowBound = lowerBound; m_UpperWindowBound = upperBound; if (expandRangesIfNecessary) { /* if caller is sure he wants exactly that level/window, we make sure the limits match */ if ( m_LowerWindowBound < m_RangeMin ) { m_RangeMin = m_LowerWindowBound; } if ( m_UpperWindowBound > m_RangeMax ) { m_RangeMax = m_UpperWindowBound; } } EnsureConsistency(); } void mitk::LevelWindow::SetRangeMinMax(mitk::ScalarType min, mitk::ScalarType max) { if ( IsFixed() ) return; m_RangeMin = min; m_RangeMax = max; EnsureConsistency(); } void mitk::LevelWindow::SetDefaultBoundaries(mitk::ScalarType low, mitk::ScalarType up) { if ( IsFixed() ) return; m_DefaultLowerBound = low; m_DefaultUpperBound = up; // Check if default window is ok { if ( m_DefaultLowerBound > m_DefaultUpperBound ) std::swap(m_DefaultLowerBound,m_DefaultUpperBound); if (m_DefaultLowerBound == m_DefaultUpperBound ) m_DefaultLowerBound--; } EnsureConsistency(); } void mitk::LevelWindow::SetToMaxWindowSize() { SetWindowBounds( m_RangeMin , m_RangeMax ); } mitk::ScalarType mitk::LevelWindow::GetRangeMin() const { return m_RangeMin; } mitk::ScalarType mitk::LevelWindow::GetRangeMax() const { return m_RangeMax; } mitk::ScalarType mitk::LevelWindow::GetRange() const { return m_RangeMax - m_RangeMin; } mitk::ScalarType mitk::LevelWindow::GetDefaultUpperBound() const { return m_DefaultUpperBound; } mitk::ScalarType mitk::LevelWindow::GetDefaultLowerBound() const { return m_DefaultLowerBound; } void mitk::LevelWindow::ResetDefaultRangeMinMax() { SetRangeMinMax(m_DefaultLowerBound, m_DefaultUpperBound); } /*! This method initializes a mitk::LevelWindow from an mitk::Image. The algorithm is as follows: Default to taking the central image slice for quick analysis. Compute the smallest (minValue), second smallest (min2ndValue), second largest (max2ndValue), and largest (maxValue) data value by traversing the pixel values only once. In the same scan it also computes the count of minValue values and maxValue values. After that a basic histogram with specific information about the extrems is complete. If minValue == maxValue, the center slice is uniform and the above scan is repeated for the complete image, not just one slice Next, special cases of images with only 1, 2 or 3 distinct data values have hand assigned level window ranges. Next the level window is set relative to the inner range IR = lengthOf([min2ndValue, max2ndValue]) For count(minValue) > 20% the smallest values are frequent and should be distinct from the min2ndValue and larger values (minValue may be std:min, may signify something special) hence the lower end of the level window is set to min2ndValue - 0.5 * IR For count(minValue) <= 20% the smallest values are not so important and can blend with the next ones => min(level window) = min2ndValue And analog for max(level window): count(max2ndValue) > 20%: max(level window) = max2ndValue + 0.5 * IR count(max2ndValue) < 20%: max(level window) = max2ndValue In both 20%+ cases the level window bounds are clamped to the [minValue, maxValue] range In consequence the level window maximizes contrast with minimal amount of computation and does do useful things if the data contains std::min or std:max values or has only 1 or 2 or 3 data values. */ void mitk::LevelWindow::SetAuto(const mitk::Image* image, bool /*tryPicTags*/, bool guessByCentralSlice) { if ( IsFixed() ) return; if ( image == NULL || !image->IsInitialized() ) return; const mitk::Image* wholeImage = image; ScalarType minValue = 0.0; ScalarType maxValue = 0.0; ScalarType min2ndValue = 0.0; ScalarType max2ndValue = 0.0; mitk::ImageSliceSelector::Pointer sliceSelector = mitk::ImageSliceSelector::New(); if ( guessByCentralSlice ) { sliceSelector->SetInput(image); sliceSelector->SetSliceNr(image->GetDimension(2)/2); sliceSelector->SetTimeNr(image->GetDimension(3)/2); sliceSelector->SetChannelNr(image->GetDimension(4)/2); sliceSelector->Update(); image = sliceSelector->GetOutput(); if ( image == NULL || !image->IsInitialized() ) return; minValue = image->GetStatistics()->GetScalarValueMin(); maxValue = image->GetStatistics()->GetScalarValueMaxNoRecompute(); min2ndValue = image->GetStatistics()->GetScalarValue2ndMinNoRecompute(); max2ndValue = image->GetStatistics()->GetScalarValue2ndMaxNoRecompute(); if ( minValue == maxValue ) { // guessByCentralSlice seems to have failed, lets look at all data image = wholeImage; minValue = image->GetStatistics()->GetScalarValueMin(); maxValue = image->GetStatistics()->GetScalarValueMaxNoRecompute(); min2ndValue = image->GetStatistics()->GetScalarValue2ndMinNoRecompute(); max2ndValue = image->GetStatistics()->GetScalarValue2ndMaxNoRecompute(); } } else { const_cast(image)->Update(); minValue = image->GetStatistics()->GetScalarValueMin(0); maxValue = image->GetStatistics()->GetScalarValueMaxNoRecompute(0); min2ndValue = image->GetStatistics()->GetScalarValue2ndMinNoRecompute(0); max2ndValue = image->GetStatistics()->GetScalarValue2ndMaxNoRecompute(0); for (unsigned int i = 1; i < image->GetDimension(3); ++i) { ScalarType minValueTemp = image->GetStatistics()->GetScalarValueMin(i); if (minValue > minValueTemp) minValue = minValueTemp; ScalarType maxValueTemp = image->GetStatistics()->GetScalarValueMaxNoRecompute(i); if (maxValue < maxValueTemp) maxValue = maxValueTemp; ScalarType min2ndValueTemp = image->GetStatistics()->GetScalarValue2ndMinNoRecompute(i); if (min2ndValue > min2ndValueTemp) min2ndValue = min2ndValueTemp; ScalarType max2ndValueTemp = image->GetStatistics()->GetScalarValue2ndMaxNoRecompute(i); if (max2ndValue > max2ndValueTemp) max2ndValue = max2ndValueTemp; } } // Fix for bug# 344 Level Window wird bei Eris Cut bildern nicht richtig gesetzt - if (image->GetPixelType()== typeid(int) && image->GetPixelType().GetBpe() >= 8) + if ( image->GetPixelType().GetPixelTypeId()==itk::ImageIOBase::SCALAR + && image->GetPixelType().GetTypeId() == typeid(int) + && image->GetPixelType().GetBpe() >= 8) { // the windows compiler complains about ambiguos 'pow' call, therefore static casting to (double, int) if (minValue == -( pow( (double) 2.0, static_cast(image->GetPixelType().GetBpe()/2) ) ) ) { minValue = min2ndValue; } } // End fix //// uniform image if ( minValue == maxValue ) { minValue = maxValue-1; } SetRangeMinMax(minValue, maxValue); SetDefaultBoundaries(minValue, maxValue); /* if ( tryPicTags ) // level and window will be set by informations provided directly by the mitkIpPicDescriptor { if ( SetAutoByPicTags(const_cast(image)->GetPic()) ) { return; } } */ unsigned int numPixelsInDataset = image->GetDimensions()[0]; for ( unsigned int k=0; kGetDimension(); ++k ) numPixelsInDataset *= image->GetDimensions()[k]; unsigned int minCount = image->GetStatistics()->GetCountOfMinValuedVoxelsNoRecompute(); unsigned int maxCount = image->GetStatistics()->GetCountOfMaxValuedVoxelsNoRecompute(); float minCountFraction = minCount/float(numPixelsInDataset); float maxCountFraction = maxCount/float(numPixelsInDataset); //// binary image if ( min2ndValue == maxValue ) { // noop; full range is fine } //// triple value image, put middle value in center of gray level ramp else if ( min2ndValue == max2ndValue ) { ScalarType minDelta = std::min(min2ndValue-minValue, maxValue-min2ndValue); minValue = min2ndValue - minDelta; maxValue = min2ndValue + minDelta; } // now we can assume more than three distict scalar values else { ScalarType innerRange = max2ndValue - min2ndValue; if ( minCountFraction > 0.2 ) //// lots of min values -> make different from rest, but not miles away { ScalarType halfInnerRangeGapMinValue = min2ndValue - innerRange/2.0; minValue = std::max(minValue, halfInnerRangeGapMinValue); } else //// few min values -> focus on innerRange { minValue = min2ndValue; } if ( maxCountFraction > 0.2 ) //// lots of max values -> make different from rest { ScalarType halfInnerRangeGapMaxValue = max2ndValue + innerRange/2.0; maxValue = std::min(maxValue, halfInnerRangeGapMaxValue); } else //// few max values -> focus on innerRange { maxValue = max2ndValue; } } SetWindowBounds(minValue, maxValue); SetDefaultLevelWindow((maxValue - minValue) / 2 + minValue, maxValue - minValue); } void mitk::LevelWindow::SetFixed( bool fixed ) { m_Fixed = fixed; } bool mitk::LevelWindow::GetFixed() const { return m_Fixed; } bool mitk::LevelWindow::IsFixed() const { return m_Fixed; } bool mitk::LevelWindow::operator==(const mitk::LevelWindow& levWin) const { if ( m_RangeMin == levWin.GetRangeMin() && m_RangeMax == levWin.GetRangeMax() && m_LowerWindowBound == levWin.GetLowerWindowBound() && m_UpperWindowBound == levWin.GetUpperWindowBound() && m_DefaultLowerBound == levWin.GetDefaultLowerBound() && m_DefaultUpperBound == levWin.GetDefaultUpperBound() && m_Fixed == levWin.IsFixed() ) { return true; } else { return false; } } bool mitk::LevelWindow::operator!=(const mitk::LevelWindow& levWin) const { return ! ( (*this) == levWin); } mitk::LevelWindow& mitk::LevelWindow::operator=(const mitk::LevelWindow& levWin) { if (this == &levWin) { return *this; } else { m_RangeMin = levWin.GetRangeMin(); m_RangeMax = levWin.GetRangeMax(); m_LowerWindowBound= levWin.GetLowerWindowBound(); m_UpperWindowBound= levWin.GetUpperWindowBound(); m_DefaultLowerBound = levWin.GetDefaultLowerBound(); m_DefaultUpperBound = levWin.GetDefaultUpperBound(); m_Fixed = levWin.GetFixed(); return *this; } } diff --git a/Core/Code/DataManagement/mitkPlaneGeometry.cpp b/Core/Code/DataManagement/mitkPlaneGeometry.cpp index 8ae6971767..6ff9970b1e 100644 --- a/Core/Code/DataManagement/mitkPlaneGeometry.cpp +++ b/Core/Code/DataManagement/mitkPlaneGeometry.cpp @@ -1,777 +1,777 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkPlaneGeometry.h" #include "mitkPlaneOperation.h" #include "mitkInteractionConst.h" #include "mitkLine.h" #include #include namespace mitk { mitk::PlaneGeometry::PlaneGeometry() { Initialize(); } mitk::PlaneGeometry::~PlaneGeometry() { } void PlaneGeometry::Initialize() { Superclass::Initialize(); } void PlaneGeometry::EnsurePerpendicularNormal(mitk::AffineTransform3D *transform) { //ensure row(2) of transform to be perpendicular to plane, keep length. VnlVector normal = vnl_cross_3d( transform->GetMatrix().GetVnlMatrix().get_column(0), transform->GetMatrix().GetVnlMatrix().get_column(1) ); normal.normalize(); ScalarType len = transform->GetMatrix() .GetVnlMatrix().get_column(2).two_norm(); if (len==0) len = 1; normal*=len; Matrix3D matrix = transform->GetMatrix(); matrix.GetVnlMatrix().set_column(2, normal); transform->SetMatrix(matrix); } void PlaneGeometry::SetIndexToWorldTransform(mitk::AffineTransform3D *transform) { EnsurePerpendicularNormal(transform); Superclass::SetIndexToWorldTransform(transform); } void PlaneGeometry::SetBounds(const BoundingBox::BoundsArrayType &bounds) { //currently the unit rectangle must be starting at the origin [0,0] assert(bounds[0]==0); assert(bounds[2]==0); //the unit rectangle must be two-dimensional assert(bounds[1]>0); assert(bounds[3]>0); Superclass::SetBounds(bounds); } void PlaneGeometry::IndexToWorld( const Point2D &pt_units, Point2D &pt_mm ) const { pt_mm[0]=m_ScaleFactorMMPerUnitX*pt_units[0]; pt_mm[1]=m_ScaleFactorMMPerUnitY*pt_units[1]; } void PlaneGeometry::WorldToIndex( const Point2D &pt_mm, Point2D &pt_units ) const { pt_units[0]=pt_mm[0]*(1.0/m_ScaleFactorMMPerUnitX); pt_units[1]=pt_mm[1]*(1.0/m_ScaleFactorMMPerUnitY); } void PlaneGeometry::IndexToWorld( const Point2D & /*atPt2d_units*/, const Vector2D &vec_units, Vector2D &vec_mm) const { MITK_WARN<<"Warning! Call of the deprecated function PlaneGeometry::IndexToWorld(point, vec, vec). Use PlaneGeometry::IndexToWorld(vec, vec) instead!"; this->IndexToWorld(vec_units, vec_mm); } void PlaneGeometry::IndexToWorld(const Vector2D &vec_units, Vector2D &vec_mm) const { vec_mm[0] = m_ScaleFactorMMPerUnitX * vec_units[0]; vec_mm[1] = m_ScaleFactorMMPerUnitY * vec_units[1]; } void PlaneGeometry::WorldToIndex( const Point2D & /*atPt2d_mm*/, const Vector2D &vec_mm, Vector2D &vec_units) const { MITK_WARN<<"Warning! Call of the deprecated function PlaneGeometry::WorldToIndex(point, vec, vec). Use PlaneGeometry::WorldToIndex(vec, vec) instead!"; this->WorldToIndex(vec_mm, vec_units); } void PlaneGeometry::WorldToIndex( const Vector2D &vec_mm, Vector2D &vec_units) const { vec_units[0] = vec_mm[0] * ( 1.0 / m_ScaleFactorMMPerUnitX ); vec_units[1] = vec_mm[1] * ( 1.0 / m_ScaleFactorMMPerUnitY ); } void PlaneGeometry::InitializeStandardPlane( mitk::ScalarType width, ScalarType height, const Vector3D & spacing, PlaneGeometry::PlaneOrientation planeorientation, ScalarType zPosition, bool frontside, bool rotated ) { AffineTransform3D::Pointer transform; transform = AffineTransform3D::New(); AffineTransform3D::MatrixType matrix; AffineTransform3D::MatrixType::InternalMatrixType &vnlmatrix = matrix.GetVnlMatrix(); vnlmatrix.set_identity(); vnlmatrix(0,0) = spacing[0]; vnlmatrix(1,1) = spacing[1]; vnlmatrix(2,2) = spacing[2]; transform->SetIdentity(); transform->SetMatrix(matrix); InitializeStandardPlane(width, height, transform.GetPointer(), planeorientation, zPosition, frontside, rotated); } void PlaneGeometry::InitializeStandardPlane( mitk::ScalarType width, ScalarType height, const AffineTransform3D* transform, PlaneGeometry::PlaneOrientation planeorientation, ScalarType zPosition, bool frontside, bool rotated ) { Superclass::Initialize(); //construct standard view Point3D origin; VnlVector rightDV(3), bottomDV(3); origin.Fill(0); int normalDirection; switch(planeorientation) { - case Transversal: + case Axial: if(frontside) { if(rotated==false) { FillVector3D(origin, 0, 0, zPosition); FillVector3D(rightDV, 1, 0, 0); FillVector3D(bottomDV, 0, 1, 0); } else { FillVector3D(origin, width, height, zPosition); FillVector3D(rightDV, -1, 0, 0); FillVector3D(bottomDV, 0, -1, 0); } } else { if(rotated==false) { FillVector3D(origin, width, 0, zPosition); FillVector3D(rightDV, -1, 0, 0); FillVector3D(bottomDV, 0, 1, 0); } else { FillVector3D(origin, 0, height, zPosition); FillVector3D(rightDV, 1, 0, 0); FillVector3D(bottomDV, 0, -1, 0); } } normalDirection = 2; break; case Frontal: if(frontside) { if(rotated==false) { FillVector3D(origin, 0, zPosition, 0); FillVector3D(rightDV, 1, 0, 0); FillVector3D(bottomDV, 0, 0, 1); } else { FillVector3D(origin, width, zPosition, height); FillVector3D(rightDV, -1, 0, 0); FillVector3D(bottomDV, 0, 0, -1); } } else { if(rotated==false) { FillVector3D(origin, width, zPosition, 0); FillVector3D(rightDV, -1, 0, 0); FillVector3D(bottomDV, 0, 0, 1); } else { FillVector3D(origin, 0, zPosition, height); FillVector3D(rightDV, 1, 0, 0); FillVector3D(bottomDV, 0, 0, -1); } } normalDirection = 1; break; case Sagittal: if(frontside) { if(rotated==false) { FillVector3D(origin, zPosition, 0, 0); FillVector3D(rightDV, 0, 1, 0); FillVector3D(bottomDV, 0, 0, 1); } else { FillVector3D(origin, zPosition, width, height); FillVector3D(rightDV, 0, -1, 0); FillVector3D(bottomDV, 0, 0, -1); } } else { if(rotated==false) { FillVector3D(origin, zPosition, width, 0); FillVector3D(rightDV, 0, -1, 0); FillVector3D(bottomDV, 0, 0, 1); } else { FillVector3D(origin, zPosition, 0, height); FillVector3D(rightDV, 0, 1, 0); FillVector3D(bottomDV, 0, 0, -1); } } normalDirection = 0; break; default: itkExceptionMacro("unknown PlaneOrientation"); } if ( transform != NULL ) { origin = transform->TransformPoint( origin ); rightDV = transform->TransformVector( rightDV ); bottomDV = transform->TransformVector( bottomDV ); } ScalarType bounds[6]= { 0, width, 0, height, 0, 1 }; this->SetBounds( bounds ); if ( transform == NULL ) { this->SetMatrixByVectors( rightDV, bottomDV ); } else { this->SetMatrixByVectors( rightDV, bottomDV, transform->GetMatrix().GetVnlMatrix() .get_column(normalDirection).magnitude() ); } this->SetOrigin(origin); } void PlaneGeometry::InitializeStandardPlane( const Geometry3D *geometry3D, PlaneOrientation planeorientation, ScalarType zPosition, bool frontside, bool rotated ) { this->SetReferenceGeometry( const_cast< Geometry3D * >( geometry3D ) ); ScalarType width, height; const BoundingBox::BoundsArrayType& boundsarray = geometry3D->GetBoundingBox()->GetBounds(); Vector3D originVector; FillVector3D(originVector, boundsarray[0], boundsarray[2], boundsarray[4]); if(geometry3D->GetImageGeometry()) { FillVector3D( originVector, originVector[0] - 0.5, originVector[1] - 0.5, originVector[2] - 0.5 ); } switch(planeorientation) { - case Transversal: + case Axial: width = geometry3D->GetExtent(0); height = geometry3D->GetExtent(1); break; case Frontal: width = geometry3D->GetExtent(0); height = geometry3D->GetExtent(2); break; case Sagittal: width = geometry3D->GetExtent(1); height = geometry3D->GetExtent(2); break; default: itkExceptionMacro("unknown PlaneOrientation"); } InitializeStandardPlane( width, height, geometry3D->GetIndexToWorldTransform(), planeorientation, zPosition, frontside, rotated ); ScalarType bounds[6]= { 0, width, 0, height, 0, 1 }; this->SetBounds( bounds ); Point3D origin; originVector = geometry3D->GetIndexToWorldTransform() ->TransformVector( originVector ); origin = GetOrigin() + originVector; SetOrigin(origin); } void PlaneGeometry::InitializeStandardPlane( const Geometry3D *geometry3D, bool top, PlaneOrientation planeorientation, bool frontside, bool rotated ) { ScalarType zPosition; switch(planeorientation) { - case Transversal: + case Axial: zPosition = (top ? 0.5 : geometry3D->GetExtent(2)-1+0.5); break; case Frontal: zPosition = (top ? 0.5 : geometry3D->GetExtent(1)-1+0.5); break; case Sagittal: zPosition = (top ? 0.5 : geometry3D->GetExtent(0)-1+0.5); break; default: itkExceptionMacro("unknown PlaneOrientation"); } InitializeStandardPlane( geometry3D, planeorientation, zPosition, frontside, rotated ); } void PlaneGeometry::InitializeStandardPlane( const Vector3D &rightVector, const Vector3D &downVector, const Vector3D *spacing ) { InitializeStandardPlane( rightVector.Get_vnl_vector(), downVector.Get_vnl_vector(), spacing ); } void PlaneGeometry::InitializeStandardPlane( const VnlVector& rightVector, const VnlVector &downVector, const Vector3D *spacing ) { ScalarType width = rightVector.magnitude(); ScalarType height = downVector.magnitude(); InitializeStandardPlane( width, height, rightVector, downVector, spacing ); } void PlaneGeometry::InitializeStandardPlane( mitk::ScalarType width, ScalarType height, const Vector3D &rightVector, const Vector3D &downVector, const Vector3D *spacing ) { InitializeStandardPlane( width, height, rightVector.Get_vnl_vector(), downVector.Get_vnl_vector(), spacing ); } void PlaneGeometry::InitializeStandardPlane( mitk::ScalarType width, ScalarType height, const VnlVector &rightVector, const VnlVector &downVector, const Vector3D *spacing ) { assert(width > 0); assert(height > 0); VnlVector rightDV = rightVector; rightDV.normalize(); VnlVector downDV = downVector; downDV.normalize(); VnlVector normal = vnl_cross_3d(rightVector, downVector); normal.normalize(); if(spacing!=NULL) { rightDV *= (*spacing)[0]; downDV *= (*spacing)[1]; normal *= (*spacing)[2]; } AffineTransform3D::Pointer transform = AffineTransform3D::New(); Matrix3D matrix; matrix.GetVnlMatrix().set_column(0, rightDV); matrix.GetVnlMatrix().set_column(1, downDV); matrix.GetVnlMatrix().set_column(2, normal); transform->SetMatrix(matrix); transform->SetOffset(m_IndexToWorldTransform->GetOffset()); ScalarType bounds[6] = { 0, width, 0, height, 0, 1 }; this->SetBounds( bounds ); this->SetIndexToWorldTransform( transform ); } void PlaneGeometry::InitializePlane( const Point3D &origin, const Vector3D &normal ) { VnlVector rightVectorVnl(3), downVectorVnl; if( Equal( normal[1], 0.0f ) == false ) { FillVector3D( rightVectorVnl, 1.0f, -normal[0]/normal[1], 0.0f ); rightVectorVnl.normalize(); } else { FillVector3D( rightVectorVnl, 0.0f, 1.0f, 0.0f ); } downVectorVnl = vnl_cross_3d( normal.Get_vnl_vector(), rightVectorVnl ); downVectorVnl.normalize(); InitializeStandardPlane( rightVectorVnl, downVectorVnl ); SetOrigin(origin); } void PlaneGeometry::SetMatrixByVectors( const VnlVector &rightVector, const VnlVector &downVector, ScalarType thickness ) { VnlVector normal = vnl_cross_3d(rightVector, downVector); normal.normalize(); normal *= thickness; AffineTransform3D::Pointer transform = AffineTransform3D::New(); Matrix3D matrix; matrix.GetVnlMatrix().set_column(0, rightVector); matrix.GetVnlMatrix().set_column(1, downVector); matrix.GetVnlMatrix().set_column(2, normal); transform->SetMatrix(matrix); transform->SetOffset(m_IndexToWorldTransform->GetOffset()); SetIndexToWorldTransform(transform); } Vector3D PlaneGeometry::GetNormal() const { Vector3D frontToBack; frontToBack.Set_vnl_vector( m_IndexToWorldTransform ->GetMatrix().GetVnlMatrix().get_column(2) ); return frontToBack; } VnlVector PlaneGeometry::GetNormalVnl() const { return m_IndexToWorldTransform ->GetMatrix().GetVnlMatrix().get_column(2); } ScalarType PlaneGeometry::DistanceFromPlane( const Point3D &pt3d_mm ) const { return fabs(SignedDistance( pt3d_mm )); } ScalarType PlaneGeometry::SignedDistance( const Point3D &pt3d_mm ) const { return SignedDistanceFromPlane(pt3d_mm); } bool PlaneGeometry::IsAbove( const Point3D &pt3d_mm ) const { return SignedDistanceFromPlane(pt3d_mm) > 0; } bool PlaneGeometry::IntersectionLine( const PlaneGeometry* plane, Line3D& crossline ) const { Vector3D normal = this->GetNormal(); normal.Normalize(); Vector3D planeNormal = plane->GetNormal(); planeNormal.Normalize(); Vector3D direction = itk::CrossProduct( normal, planeNormal ); if ( direction.GetSquaredNorm() < eps ) return false; crossline.SetDirection( direction ); double N1dN2 = normal * planeNormal; double determinant = 1.0 - N1dN2 * N1dN2; Vector3D origin = this->GetOrigin().GetVectorFromOrigin(); Vector3D planeOrigin = plane->GetOrigin().GetVectorFromOrigin(); double d1 = normal * origin; double d2 = planeNormal * planeOrigin; double c1 = ( d1 - d2 * N1dN2 ) / determinant; double c2 = ( d2 - d1 * N1dN2 ) / determinant; Vector3D p = normal * c1 + planeNormal * c2; crossline.GetPoint().Get_vnl_vector() = p.Get_vnl_vector(); return true; } unsigned int PlaneGeometry::IntersectWithPlane2D( const PlaneGeometry* plane, Point2D& lineFrom, Point2D &lineTo ) const { Line3D crossline; if ( this->IntersectionLine( plane, crossline ) == false ) return 0; Point2D point2; Vector2D direction2; this->Map( crossline.GetPoint(), point2 ); this->Map( crossline.GetPoint(), crossline.GetDirection(), direction2 ); return Line3D::RectangleLineIntersection( 0, 0, GetExtentInMM(0), GetExtentInMM(1), point2, direction2, lineFrom, lineTo ); } double PlaneGeometry::Angle( const PlaneGeometry *plane ) const { return angle(plane->GetMatrixColumn(2), GetMatrixColumn(2)); } double PlaneGeometry::Angle( const Line3D &line ) const { return vnl_math::pi_over_2 - angle( line.GetDirection().Get_vnl_vector(), GetMatrixColumn(2) ); } bool PlaneGeometry::IntersectionPoint( const Line3D &line, Point3D &intersectionPoint ) const { Vector3D planeNormal = this->GetNormal(); planeNormal.Normalize(); Vector3D lineDirection = line.GetDirection(); lineDirection.Normalize(); double t = planeNormal * lineDirection; if ( fabs( t ) < eps ) { return false; } Vector3D diff; diff = this->GetOrigin() - line.GetPoint(); t = ( planeNormal * diff ) / t; intersectionPoint = line.GetPoint() + lineDirection * t; return true; } bool PlaneGeometry::IntersectionPointParam( const Line3D &line, double &t ) const { Vector3D planeNormal = this->GetNormal(); Vector3D lineDirection = line.GetDirection(); t = planeNormal * lineDirection; if ( fabs( t ) < eps ) { return false; } Vector3D diff; diff = this->GetOrigin() - line.GetPoint(); t = ( planeNormal * diff ) / t; return true; } bool PlaneGeometry::IsParallel( const PlaneGeometry *plane ) const { return ( (Angle(plane) < 10.0 * mitk::sqrteps ) || ( Angle(plane) > ( vnl_math::pi - 10.0 * sqrteps ) ) ) ; } bool PlaneGeometry::IsOnPlane( const Point3D &point ) const { return Distance(point) < eps; } bool PlaneGeometry::IsOnPlane( const Line3D &line ) const { return ( (Distance( line.GetPoint() ) < eps) && (Distance( line.GetPoint2() ) < eps) ); } bool PlaneGeometry::IsOnPlane( const PlaneGeometry *plane ) const { return ( IsParallel( plane ) && (Distance( plane->GetOrigin() ) < eps) ); } Point3D PlaneGeometry::ProjectPointOntoPlane( const Point3D& pt ) const { ScalarType len = this->GetNormalVnl().two_norm(); return pt - this->GetNormal() * this->SignedDistanceFromPlane( pt ) / len; } AffineGeometryFrame3D::Pointer PlaneGeometry::Clone() const { Self::Pointer newGeometry = new PlaneGeometry(*this); newGeometry->UnRegister(); return newGeometry.GetPointer(); } void PlaneGeometry::ExecuteOperation( Operation *operation ) { vtkTransform *transform = vtkTransform::New(); transform->SetMatrix( m_VtkMatrix ); switch ( operation->GetOperationType() ) { case OpORIENT: { mitk::PlaneOperation *planeOp = dynamic_cast< mitk::PlaneOperation * >( operation ); if ( planeOp == NULL ) { return; } Point3D center = planeOp->GetPoint(); Vector3D orientationVector = planeOp->GetNormal(); Vector3D defaultVector; FillVector3D( defaultVector, 0.0, 0.0, 1.0 ); Vector3D rotationAxis = itk::CrossProduct( orientationVector, defaultVector ); //vtkFloatingPointType rotationAngle = acos( orientationVector[2] / orientationVector.GetNorm() ); vtkFloatingPointType rotationAngle = atan2( (double) rotationAxis.GetNorm(), (double) (orientationVector * defaultVector) ); rotationAngle *= 180.0 / vnl_math::pi; transform->PostMultiply(); transform->Identity(); transform->Translate( center[0], center[1], center[2] ); transform->RotateWXYZ( rotationAngle, rotationAxis[0], rotationAxis[1], rotationAxis[2] ); transform->Translate( -center[0], -center[1], -center[2] ); break; } case OpRESTOREPLANEPOSITION: { RestorePlanePositionOperation *op = dynamic_cast< mitk::RestorePlanePositionOperation* >(operation); if(op == NULL) { return; } AffineTransform3D::Pointer transform2 = AffineTransform3D::New(); Matrix3D matrix; matrix.GetVnlMatrix().set_column(0, op->GetTransform()->GetMatrix().GetVnlMatrix().get_column(0)); matrix.GetVnlMatrix().set_column(1, op->GetTransform()->GetMatrix().GetVnlMatrix().get_column(1)); matrix.GetVnlMatrix().set_column(2, op->GetTransform()->GetMatrix().GetVnlMatrix().get_column(2)); transform2->SetMatrix(matrix); Vector3D offset = op->GetTransform()->GetOffset(); transform2->SetOffset(offset); this->SetIndexToWorldTransform(transform2); ScalarType bounds[6] = {0, op->GetWidth(), 0, op->GetHeight(), 0 ,1 }; this->SetBounds(bounds); TransferItkToVtkTransform(); this->Modified(); transform->Delete(); return; } default: Superclass::ExecuteOperation( operation ); transform->Delete(); return; } m_VtkMatrix->DeepCopy(transform->GetMatrix()); this->TransferVtkToItkTransform(); this->Modified(); transform->Delete(); } void PlaneGeometry::PrintSelf( std::ostream& os, itk::Indent indent ) const { Superclass::PrintSelf(os,indent); os << indent << " Normal: " << GetNormal() << std::endl; } } // namespace diff --git a/Core/Code/DataManagement/mitkPlaneGeometry.h b/Core/Code/DataManagement/mitkPlaneGeometry.h index 70625eb5fc..70a2951359 100644 --- a/Core/Code/DataManagement/mitkPlaneGeometry.h +++ b/Core/Code/DataManagement/mitkPlaneGeometry.h @@ -1,422 +1,434 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 PLANEGEOMETRY_H_HEADER_INCLUDED_C1C68A2C #define PLANEGEOMETRY_H_HEADER_INCLUDED_C1C68A2C #include #include "mitkGeometry2D.h" #include "mitkRestorePlanePositionOperation.h" #include namespace mitk { template < class TCoordRep, unsigned int NPointDimension > class Line; typedef Line Line3D; /** * \brief Describes a two-dimensional, rectangular plane * * \ingroup Geometry */ class MITK_CORE_EXPORT PlaneGeometry : public Geometry2D { public: mitkClassMacro(PlaneGeometry,Geometry2D); /** Method for creation through the object factory. */ itkNewMacro(Self); - enum PlaneOrientation { Transversal, Sagittal, Frontal }; + enum PlaneOrientation + { +#ifdef _MSC_VER + Transversal, // deprecated +#endif + Axial = 0, + Sagittal, + Frontal + }; + +#ifdef __GNUC__ + __attribute__ ((deprecated)) static const PlaneOrientation Transversal = PlaneOrientation(Axial); +#endif virtual void IndexToWorld(const Point2D &pt_units, Point2D &pt_mm) const; virtual void WorldToIndex(const Point2D &pt_mm, Point2D &pt_units) const; //##Documentation //## @brief Convert (continuous or discrete) index coordinates of a \em vector //## \a vec_units to world coordinates (in mm) //## @deprecated First parameter (Point2D) is not used. If possible, please use void IndexToWorld(const mitk::Vector2D& vec_units, mitk::Vector2D& vec_mm) const. //## For further information about coordinates types, please see the Geometry documentation virtual void IndexToWorld(const mitk::Point2D &atPt2d_untis, const mitk::Vector2D &vec_units, mitk::Vector2D &vec_mm) const; //##Documentation //## @brief Convert (continuous or discrete) index coordinates of a \em vector //## \a vec_units to world coordinates (in mm) //## For further information about coordinates types, please see the Geometry documentation virtual void IndexToWorld(const mitk::Vector2D &vec_units, mitk::Vector2D &vec_mm) const; //##Documentation //## @brief Convert world coordinates (in mm) of a \em vector //## \a vec_mm to (continuous!) index coordinates. //## @deprecated First parameter (Point2D) is not used. If possible, please use void WorldToIndex(const mitk::Vector2D& vec_mm, mitk::Vector2D& vec_units) const. //## For further information about coordinates types, please see the Geometry documentation virtual void WorldToIndex(const mitk::Point2D &atPt2d_mm, const mitk::Vector2D &vec_mm, mitk::Vector2D &vec_units) const; //##Documentation //## @brief Convert world coordinates (in mm) of a \em vector //## \a vec_mm to (continuous!) index coordinates. //## For further information about coordinates types, please see the Geometry documentation virtual void WorldToIndex(const mitk::Vector2D &vec_mm, mitk::Vector2D &vec_units) const; virtual void Initialize(); /** * \brief Initialize a plane with orientation \a planeorientation - * (default: transversal) with respect to \a geometry3D (default: identity). + * (default: axial) with respect to \a geometry3D (default: identity). * Spacing also taken from \a geometry3D. * * \warning A former version of this method created a geometry with unit * spacing. For unit spacing use * * \code * // for in-plane unit spacing: * thisgeometry->SetSizeInUnits(thisgeometry->GetExtentInMM(0), * thisgeometry->GetExtentInMM(1)); * // additionally, for unit spacing in normal direction (former version * // did not do this): * thisgeometry->SetExtentInMM(2, 1.0); * \endcode */ virtual void InitializeStandardPlane( const Geometry3D* geometry3D, - PlaneOrientation planeorientation = Transversal, ScalarType zPosition = 0, + PlaneOrientation planeorientation = Axial, ScalarType zPosition = 0, bool frontside=true, bool rotated=false ); /** * \brief Initialize a plane with orientation \a planeorientation - * (default: transversal) with respect to \a geometry3D (default: identity). + * (default: axial) with respect to \a geometry3D (default: identity). * Spacing also taken from \a geometry3D. * * \param top if \a true, create plane at top, otherwise at bottom - * (for PlaneOrientation Transversal, for other plane locations respectively) + * (for PlaneOrientation Axial, for other plane locations respectively) */ virtual void InitializeStandardPlane( const Geometry3D* geometry3D, bool top, - PlaneOrientation planeorientation = Transversal, + PlaneOrientation planeorientation = Axial, bool frontside=true, bool rotated=false ); /** * \brief Initialize a plane with orientation \a planeorientation - * (default: transversal) with respect to \a transform (default: identity) + * (default: axial) with respect to \a transform (default: identity) * given width and height in units. * */ virtual void InitializeStandardPlane( ScalarType width, ScalarType height, const AffineTransform3D* transform = NULL, - PlaneOrientation planeorientation = Transversal, + PlaneOrientation planeorientation = Axial, ScalarType zPosition = 0, bool frontside=true, bool rotated=false ); /** * \brief Initialize plane with orientation \a planeorientation - * (default: transversal) given width, height and spacing. + * (default: axial) given width, height and spacing. * */ virtual void InitializeStandardPlane( ScalarType width, ScalarType height, - const Vector3D & spacing, PlaneOrientation planeorientation = Transversal, + const Vector3D & spacing, PlaneOrientation planeorientation = Axial, ScalarType zPosition = 0, bool frontside = true, bool rotated = false ); /** * \brief Initialize plane by width and height in pixels, right-/down-vector * (itk) to describe orientation in world-space (vectors will be normalized) * and spacing (default: 1.0 mm in all directions). * * The vectors are normalized and multiplied by the respective spacing before * they are set in the matrix. */ virtual void InitializeStandardPlane( ScalarType width, ScalarType height, const Vector3D& rightVector, const Vector3D& downVector, const Vector3D *spacing = NULL ); /** * \brief Initialize plane by width and height in pixels, * right-/down-vector (vnl) to describe orientation in world-space (vectors * will be normalized) and spacing (default: 1.0 mm in all directions). * * The vectors are normalized and multiplied by the respective spacing * before they are set in the matrix. */ virtual void InitializeStandardPlane( ScalarType width, ScalarType height, const VnlVector& rightVector, const VnlVector& downVector, const Vector3D * spacing = NULL ); /** * \brief Initialize plane by right-/down-vector (itk) and spacing * (default: 1.0 mm in all directions). * * The length of the right-/-down-vector is used as width/height in units, * respectively. Then, the vectors are normalized and multiplied by the * respective spacing before they are set in the matrix. */ virtual void InitializeStandardPlane( const Vector3D& rightVector, const Vector3D& downVector, const Vector3D * spacing = NULL ); /** * \brief Initialize plane by right-/down-vector (vnl) and spacing * (default: 1.0 mm in all directions). * * The length of the right-/-down-vector is used as width/height in units, * respectively. Then, the vectors are normalized and multiplied by the * respective spacing before they are set in the matrix. */ virtual void InitializeStandardPlane( const VnlVector& rightVector, const VnlVector& downVector, const Vector3D * spacing = NULL ); /** * \brief Initialize plane by origin and normal (size is 1.0 mm in * all directions, direction of right-/down-vector valid but * undefined). * */ virtual void InitializePlane( const Point3D& origin, const Vector3D& normal); /** * \brief Initialize plane by right-/down-vector. * * \warning The vectors are set into the matrix as they are, * \em without normalization! */ void SetMatrixByVectors( const VnlVector& rightVector, const VnlVector& downVector, ScalarType thickness=1.0 ); /** * \brief Change \a transform so that the third column of the * transform-martix is perpendicular to the first two columns * */ static void EnsurePerpendicularNormal( AffineTransform3D* transform ); /** * \brief Normal of the plane * */ Vector3D GetNormal() const; /** * \brief Normal of the plane as VnlVector * */ VnlVector GetNormalVnl() const; virtual ScalarType SignedDistance( const Point3D& pt3d_mm ) const; virtual bool IsAbove( const Point3D& pt3d_mm ) const; /** * \brief Distance of the point from the plane * (bounding-box \em not considered) * */ ScalarType DistanceFromPlane( const Point3D& pt3d_mm ) const ; /** * \brief Signed distance of the point from the plane * (bounding-box \em not considered) * * > 0 : point is in the direction of the direction vector. */ inline ScalarType SignedDistanceFromPlane( const Point3D& pt3d_mm ) const { ScalarType len = GetNormalVnl().two_norm(); if( len == 0 ) return 0; return (pt3d_mm-GetOrigin())*GetNormal() / len; } /** * \brief Distance of the plane from another plane * (bounding-box \em not considered) * * Result is 0 if planes are not parallel. */ ScalarType DistanceFromPlane(const PlaneGeometry* plane) const { return fabs(SignedDistanceFromPlane(plane)); } /** * \brief Signed distance of the plane from another plane * (bounding-box \em not considered) * * Result is 0 if planes are not parallel. */ inline ScalarType SignedDistanceFromPlane( const PlaneGeometry *plane ) const { if(IsParallel(plane)) { return SignedDistance(plane->GetOrigin()); } return 0; } /** * \brief Calculate the intersecting line of two planes * * \return \a true planes are intersecting * \return \a false planes do not intersect */ bool IntersectionLine( const PlaneGeometry *plane, Line3D &crossline ) const; /** * \brief Calculate two points where another plane intersects the border of this plane * * \return number of intersection points (0..2). First interection point (if existing) * is returned in \a lineFrom, second in \a lineTo. */ unsigned int IntersectWithPlane2D(const PlaneGeometry *plane, Point2D &lineFrom, Point2D &lineTo ) const ; /** * \brief Calculate the angle between two planes * * \return angle in radiants */ double Angle( const PlaneGeometry *plane ) const; /** * \brief Calculate the angle between the plane and a line * * \return angle in radiants */ double Angle( const Line3D &line ) const; /** * \brief Calculate intersection point between the plane and a line * * \param intersectionPoint intersection point * \return \a true if \em unique intersection exists, i.e., if line * is \em not on or parallel to the plane */ bool IntersectionPoint( const Line3D &line, Point3D &intersectionPoint ) const; /** * \brief Calculate line parameter of intersection point between the * plane and a line * * \param t parameter of line: intersection point is * line.GetPoint()+t*line.GetDirection() * \return \a true if \em unique intersection exists, i.e., if line * is \em not on or parallel to the plane */ bool IntersectionPointParam( const Line3D &line, double &t ) const; /** * \brief Returns whether the plane is parallel to another plane * * @return true iff the normal vectors both point to the same or exactly oposit direction */ bool IsParallel( const PlaneGeometry *plane ) const; /** * \brief Returns whether the point is on the plane * (bounding-box \em not considered) */ bool IsOnPlane( const Point3D &point ) const; /** * \brief Returns whether the line is on the plane * (bounding-box \em not considered) */ bool IsOnPlane( const Line3D &line ) const; /** * \brief Returns whether the plane is on the plane * (bounding-box \em not considered) * * @return true iff the normal vector of the planes point to the same or the exactly oposit direction and * the distance of the planes is < eps * */ bool IsOnPlane( const PlaneGeometry *plane ) const; /** * \brief Returns the lot from the point to the plane */ Point3D ProjectPointOntoPlane( const Point3D &pt ) const; virtual void SetIndexToWorldTransform( AffineTransform3D *transform); virtual void SetBounds( const BoundingBox::BoundsArrayType &bounds ); AffineGeometryFrame3D::Pointer Clone() const; /** Implements operation to re-orient the plane */ virtual void ExecuteOperation( Operation *operation ); protected: PlaneGeometry(); virtual ~PlaneGeometry(); virtual void PrintSelf( std::ostream &os, itk::Indent indent ) const; private: /** * \brief Compares plane with another plane: \a true if IsOnPlane * (bounding-box \em not considered) */ virtual bool operator==( const PlaneGeometry * ) const { return false; }; /** * \brief Compares plane with another plane: \a false if IsOnPlane * (bounding-box \em not considered) */ virtual bool operator!=( const PlaneGeometry * ) const { return false; }; }; } // namespace mitk #endif /* PLANEGEOMETRY_H_HEADER_INCLUDED_C1C68A2C */ diff --git a/Core/Code/DataManagement/mitkSlicedGeometry3D.cpp b/Core/Code/DataManagement/mitkSlicedGeometry3D.cpp index 5540a3a454..67e3124355 100644 --- a/Core/Code/DataManagement/mitkSlicedGeometry3D.cpp +++ b/Core/Code/DataManagement/mitkSlicedGeometry3D.cpp @@ -1,952 +1,952 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkSlicedGeometry3D.h" #include "mitkPlaneGeometry.h" #include "mitkRotationOperation.h" #include "mitkPlaneOperation.h" #include "mitkRestorePlanePositionOperation.h" #include "mitkInteractionConst.h" #include "mitkSliceNavigationController.h" mitk::SlicedGeometry3D::SlicedGeometry3D() : m_EvenlySpaced( true ), m_Slices( 0 ), m_ReferenceGeometry( NULL ), m_SliceNavigationController( NULL ) { m_DirectionVector.Fill(0); this->InitializeSlicedGeometry( m_Slices ); } mitk::SlicedGeometry3D::SlicedGeometry3D(const SlicedGeometry3D& other) : Superclass(other), m_EvenlySpaced( other.m_EvenlySpaced ), m_Slices( other.m_Slices ), m_ReferenceGeometry( other.m_ReferenceGeometry ), m_SliceNavigationController( other.m_SliceNavigationController ) { m_DirectionVector.Fill(0); SetSpacing( other.GetSpacing() ); SetDirectionVector( other.GetDirectionVector() ); if ( m_EvenlySpaced ) { AffineGeometryFrame3D::Pointer geometry = other.m_Geometry2Ds[0]->Clone(); Geometry2D* geometry2D = dynamic_cast(geometry.GetPointer()); assert(geometry2D!=NULL); SetGeometry2D(geometry2D, 0); } else { unsigned int s; for ( s = 0; s < other.m_Slices; ++s ) { if ( other.m_Geometry2Ds[s].IsNull() ) { assert(other.m_EvenlySpaced); m_Geometry2Ds[s] = NULL; } else { AffineGeometryFrame3D::Pointer geometry = other.m_Geometry2Ds[s]->Clone(); Geometry2D* geometry2D = dynamic_cast(geometry.GetPointer()); assert(geometry2D!=NULL); SetGeometry2D(geometry2D, s); } } } } mitk::SlicedGeometry3D::~SlicedGeometry3D() { } mitk::Geometry2D * mitk::SlicedGeometry3D::GetGeometry2D( int s ) const { mitk::Geometry2D::Pointer geometry2D = NULL; if ( this->IsValidSlice(s) ) { geometry2D = m_Geometry2Ds[s]; // If (a) m_EvenlySpaced==true, (b) we don't have a Geometry2D stored // for the requested slice, and (c) the first slice (s=0) // is a PlaneGeometry instance, then we calculate the geometry of the // requested as the plane of the first slice shifted by m_Spacing[2]*s // in the direction of m_DirectionVector. if ( (m_EvenlySpaced) && (geometry2D.IsNull()) ) { PlaneGeometry *firstSlice = dynamic_cast< PlaneGeometry * > ( m_Geometry2Ds[0].GetPointer() ); if ( firstSlice != NULL ) { if ( (m_DirectionVector[0] == 0.0) && (m_DirectionVector[1] == 0.0) && (m_DirectionVector[2] == 0.0) ) { m_DirectionVector = firstSlice->GetNormal(); m_DirectionVector.Normalize(); } Vector3D direction; direction = m_DirectionVector * m_Spacing[2]; mitk::PlaneGeometry::Pointer requestedslice; requestedslice = static_cast< mitk::PlaneGeometry * >( firstSlice->Clone().GetPointer() ); requestedslice->SetOrigin( requestedslice->GetOrigin() + direction * s ); geometry2D = requestedslice; m_Geometry2Ds[s] = geometry2D; } } return geometry2D; } else { return NULL; } } const mitk::BoundingBox * mitk::SlicedGeometry3D::GetBoundingBox() const { assert(m_BoundingBox.IsNotNull()); return m_BoundingBox.GetPointer(); } bool mitk::SlicedGeometry3D::SetGeometry2D( mitk::Geometry2D *geometry2D, int s ) { if ( this->IsValidSlice(s) ) { m_Geometry2Ds[s] = geometry2D; m_Geometry2Ds[s]->SetReferenceGeometry( m_ReferenceGeometry ); return true; } return false; } void mitk::SlicedGeometry3D::InitializeSlicedGeometry( unsigned int slices ) { Superclass::Initialize(); m_Slices = slices; Geometry2D::Pointer gnull = NULL; m_Geometry2Ds.assign( m_Slices, gnull ); Vector3D spacing; spacing.Fill( 1.0 ); this->SetSpacing( spacing ); m_DirectionVector.Fill( 0 ); } void mitk::SlicedGeometry3D::InitializeEvenlySpaced( mitk::Geometry2D* geometry2D, unsigned int slices, bool flipped ) { assert( geometry2D != NULL ); this->InitializeEvenlySpaced( geometry2D, geometry2D->GetExtentInMM(2)/geometry2D->GetExtent(2), slices, flipped ); } void mitk::SlicedGeometry3D::InitializeEvenlySpaced( mitk::Geometry2D* geometry2D, mitk::ScalarType zSpacing, unsigned int slices, bool flipped ) { assert( geometry2D != NULL ); assert( geometry2D->GetExtent(0) > 0 ); assert( geometry2D->GetExtent(1) > 0 ); geometry2D->Register(); Superclass::Initialize(); m_Slices = slices; BoundingBox::BoundsArrayType bounds = geometry2D->GetBounds(); bounds[4] = 0; bounds[5] = slices; // clear and reserve Geometry2D::Pointer gnull = NULL; m_Geometry2Ds.assign( m_Slices, gnull ); Vector3D directionVector = geometry2D->GetAxisVector(2); directionVector.Normalize(); directionVector *= zSpacing; if ( flipped == false ) { // Normally we should use the following four lines to create a copy of // the transform contrained in geometry2D, because it may not be changed // by us. But we know that SetSpacing creates a new transform without // changing the old (coming from geometry2D), so we can use the fifth // line instead. We check this at (**). // // AffineTransform3D::Pointer transform = AffineTransform3D::New(); // transform->SetMatrix(geometry2D->GetIndexToWorldTransform()->GetMatrix()); // transform->SetOffset(geometry2D->GetIndexToWorldTransform()->GetOffset()); // SetIndexToWorldTransform(transform); m_IndexToWorldTransform = const_cast< AffineTransform3D * >( geometry2D->GetIndexToWorldTransform() ); } else { directionVector *= -1.0; m_IndexToWorldTransform = AffineTransform3D::New(); m_IndexToWorldTransform->SetMatrix( geometry2D->GetIndexToWorldTransform()->GetMatrix() ); AffineTransform3D::OutputVectorType scaleVector; FillVector3D(scaleVector, 1.0, 1.0, -1.0); m_IndexToWorldTransform->Scale(scaleVector, true); m_IndexToWorldTransform->SetOffset( geometry2D->GetIndexToWorldTransform()->GetOffset() ); } mitk::Vector3D spacing; FillVector3D( spacing, geometry2D->GetExtentInMM(0) / bounds[1], geometry2D->GetExtentInMM(1) / bounds[3], zSpacing ); // Ensure that spacing differs from m_Spacing to make SetSpacing change the // matrix. m_Spacing[2] = zSpacing - 1; this->SetDirectionVector( directionVector ); this->SetBounds( bounds ); this->SetGeometry2D( geometry2D, 0 ); this->SetSpacing( spacing ); this->SetEvenlySpaced(); this->SetTimeBounds( geometry2D->GetTimeBounds() ); assert(m_IndexToWorldTransform.GetPointer() != geometry2D->GetIndexToWorldTransform()); // (**) see above. this->SetFrameOfReferenceID( geometry2D->GetFrameOfReferenceID() ); this->SetImageGeometry( geometry2D->GetImageGeometry() ); geometry2D->UnRegister(); } void mitk::SlicedGeometry3D::InitializePlanes( const mitk::Geometry3D *geometry3D, mitk::PlaneGeometry::PlaneOrientation planeorientation, bool top, bool frontside, bool rotated ) { m_ReferenceGeometry = const_cast< Geometry3D * >( geometry3D ); PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New(); planeGeometry->InitializeStandardPlane( geometry3D, top, planeorientation, frontside, rotated ); ScalarType viewSpacing = 1; unsigned int slices = 1; switch ( planeorientation ) { - case PlaneGeometry::Transversal: + case PlaneGeometry::Axial: viewSpacing = geometry3D->GetSpacing()[2]; slices = (unsigned int) geometry3D->GetExtent( 2 ); break; case PlaneGeometry::Frontal: viewSpacing = geometry3D->GetSpacing()[1]; slices = (unsigned int) geometry3D->GetExtent( 1 ); break; case PlaneGeometry::Sagittal: viewSpacing = geometry3D->GetSpacing()[0]; slices = (unsigned int) geometry3D->GetExtent( 0 ); break; default: itkExceptionMacro("unknown PlaneOrientation"); } mitk::Vector3D normal = this->AdjustNormal( planeGeometry->GetNormal() ); ScalarType directedExtent = fabs( m_ReferenceGeometry->GetExtentInMM( 0 ) * normal[0] ) + fabs( m_ReferenceGeometry->GetExtentInMM( 1 ) * normal[1] ) + fabs( m_ReferenceGeometry->GetExtentInMM( 2 ) * normal[2] ); if ( directedExtent >= viewSpacing ) { slices = static_cast< int >(directedExtent / viewSpacing + 0.5); } else { slices = 1; } bool flipped = (top == false); if ( frontside == false ) { flipped = !flipped; } if ( planeorientation == PlaneGeometry::Frontal ) { flipped = !flipped; } this->InitializeEvenlySpaced( planeGeometry, viewSpacing, slices, flipped ); } void mitk::SlicedGeometry3D ::ReinitializePlanes( const Point3D ¢er, const Point3D &referencePoint ) { // Need a reference frame to align the rotated planes if ( !m_ReferenceGeometry ) { return; } // Get first plane of plane stack PlaneGeometry *firstPlane = dynamic_cast< PlaneGeometry * >( m_Geometry2Ds[0].GetPointer() ); // If plane stack is empty, exit if ( firstPlane == NULL ) { return; } // Calculate the "directed" spacing when taking the plane (defined by its axes // vectors and normal) as the reference coordinate frame. // // This is done by calculating the radius of the ellipsoid defined by the // original volume spacing axes, in the direction of the respective axis of the // reference frame. mitk::Vector3D axis0 = firstPlane->GetAxisVector(0); mitk::Vector3D axis1 = firstPlane->GetAxisVector(1); mitk::Vector3D normal = firstPlane->GetNormal(); normal.Normalize(); Vector3D spacing; spacing[0] = this->CalculateSpacing( axis0 ); spacing[1] = this->CalculateSpacing( axis1 ); spacing[2] = this->CalculateSpacing( normal ); Superclass::SetSpacing( spacing ); // Now we need to calculate the number of slices in the plane's normal // direction, so that the entire volume is covered. This is done by first // calculating the dot product between the volume diagonal (the maximum // distance inside the volume) and the normal, and dividing this value by // the directed spacing calculated above. ScalarType directedExtent = fabs( m_ReferenceGeometry->GetExtentInMM( 0 ) * normal[0] ) + fabs( m_ReferenceGeometry->GetExtentInMM( 1 ) * normal[1] ) + fabs( m_ReferenceGeometry->GetExtentInMM( 2 ) * normal[2] ); if ( directedExtent >= spacing[2] ) { m_Slices = static_cast< unsigned int >(directedExtent / spacing[2] + 0.5); } else { m_Slices = 1; } // The origin of our "first plane" needs to be adapted to this new extent. // To achieve this, we first calculate the current distance to the volume's // center, and then shift the origin in the direction of the normal by the // difference between this distance and half of the new extent. double centerOfRotationDistance = firstPlane->SignedDistanceFromPlane( center ); if ( centerOfRotationDistance > 0 ) { firstPlane->SetOrigin( firstPlane->GetOrigin() + normal * (centerOfRotationDistance - directedExtent / 2.0) ); m_DirectionVector = normal; } else { firstPlane->SetOrigin( firstPlane->GetOrigin() + normal * (directedExtent / 2.0 + centerOfRotationDistance) ); m_DirectionVector = -normal; } // Now we adjust this distance according with respect to the given reference // point: we need to make sure that the point is touched by one slice of the // new slice stack. double referencePointDistance = firstPlane->SignedDistanceFromPlane( referencePoint ); int referencePointSlice = static_cast< int >( referencePointDistance / spacing[2]); double alignmentValue = referencePointDistance / spacing[2] - referencePointSlice; firstPlane->SetOrigin( firstPlane->GetOrigin() + normal * alignmentValue * spacing[2] ); // Finally, we can clear the previous geometry stack and initialize it with // our re-initialized "first plane". m_Geometry2Ds.assign( m_Slices, Geometry2D::Pointer( NULL ) ); if ( m_Slices > 0 ) { m_Geometry2Ds[0] = firstPlane; } // Reinitialize SNC with new number of slices m_SliceNavigationController->GetSlice()->SetSteps( m_Slices ); this->Modified(); } double mitk::SlicedGeometry3D::CalculateSpacing( const mitk::Vector3D &d ) const { // Need the spacing of the underlying dataset / geometry if ( !m_ReferenceGeometry ) { return 1.0; } const mitk::Vector3D &spacing = m_ReferenceGeometry->GetSpacing(); return SlicedGeometry3D::CalculateSpacing( spacing, d ); } double mitk::SlicedGeometry3D::CalculateSpacing( const mitk::Vector3D spacing, const mitk::Vector3D &d ) { // The following can be derived from the ellipsoid equation // // 1 = x^2/a^2 + y^2/b^2 + z^2/c^2 // // where (a,b,c) = spacing of original volume (ellipsoid radii) // and (x,y,z) = scaled coordinates of vector d (according to ellipsoid) // double scaling = d[0]*d[0] / (spacing[0] * spacing[0]) + d[1]*d[1] / (spacing[1] * spacing[1]) + d[2]*d[2] / (spacing[2] * spacing[2]); scaling = sqrt( scaling ); return ( sqrt( d[0]*d[0] + d[1]*d[1] + d[2]*d[2] ) / scaling ); } mitk::Vector3D mitk::SlicedGeometry3D::AdjustNormal( const mitk::Vector3D &normal ) const { Geometry3D::TransformType::Pointer inverse = Geometry3D::TransformType::New(); m_ReferenceGeometry->GetIndexToWorldTransform()->GetInverse( inverse ); Vector3D transformedNormal = inverse->TransformVector( normal ); transformedNormal.Normalize(); return transformedNormal; } void mitk::SlicedGeometry3D::SetImageGeometry( const bool isAnImageGeometry ) { Superclass::SetImageGeometry( isAnImageGeometry ); mitk::Geometry3D* geometry; unsigned int s; for ( s = 0; s < m_Slices; ++s ) { geometry = m_Geometry2Ds[s]; if ( geometry!=NULL ) { geometry->SetImageGeometry( isAnImageGeometry ); } } } void mitk::SlicedGeometry3D::ChangeImageGeometryConsideringOriginOffset( const bool isAnImageGeometry ) { mitk::Geometry3D* geometry; unsigned int s; for ( s = 0; s < m_Slices; ++s ) { geometry = m_Geometry2Ds[s]; if ( geometry!=NULL ) { geometry->ChangeImageGeometryConsideringOriginOffset( isAnImageGeometry ); } } Superclass::ChangeImageGeometryConsideringOriginOffset( isAnImageGeometry ); } bool mitk::SlicedGeometry3D::IsValidSlice( int s ) const { return ((s >= 0) && (s < (int)m_Slices)); } void mitk::SlicedGeometry3D::SetReferenceGeometry( Geometry3D *referenceGeometry ) { m_ReferenceGeometry = referenceGeometry; std::vector::iterator it; for ( it = m_Geometry2Ds.begin(); it != m_Geometry2Ds.end(); ++it ) { (*it)->SetReferenceGeometry( referenceGeometry ); } } void mitk::SlicedGeometry3D::SetSpacing( const mitk::Vector3D &aSpacing ) { bool hasEvenlySpacedPlaneGeometry = false; mitk::Point3D origin; mitk::Vector3D rightDV, bottomDV; BoundingBox::BoundsArrayType bounds; assert(aSpacing[0]>0 && aSpacing[1]>0 && aSpacing[2]>0); // In case of evenly-spaced data: re-initialize instances of Geometry2D, // since the spacing influences them if ((m_EvenlySpaced) && (m_Geometry2Ds.size() > 0)) { mitk::Geometry2D::ConstPointer firstGeometry = m_Geometry2Ds[0].GetPointer(); const PlaneGeometry *planeGeometry = dynamic_cast< const PlaneGeometry * >( firstGeometry.GetPointer() ); if (planeGeometry != NULL ) { this->WorldToIndex( planeGeometry->GetOrigin(), origin ); this->WorldToIndex( planeGeometry->GetAxisVector(0), rightDV ); this->WorldToIndex( planeGeometry->GetAxisVector(1), bottomDV ); bounds = planeGeometry->GetBounds(); hasEvenlySpacedPlaneGeometry = true; } } Superclass::SetSpacing(aSpacing); mitk::Geometry2D::Pointer firstGeometry; // In case of evenly-spaced data: re-initialize instances of Geometry2D, // since the spacing influences them if ( hasEvenlySpacedPlaneGeometry ) { //create planeGeometry according to new spacing this->IndexToWorld( origin, origin ); this->IndexToWorld( rightDV, rightDV ); this->IndexToWorld( bottomDV, bottomDV ); mitk::PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New(); planeGeometry->SetImageGeometry( this->GetImageGeometry() ); planeGeometry->SetReferenceGeometry( m_ReferenceGeometry ); planeGeometry->InitializeStandardPlane( rightDV.Get_vnl_vector(), bottomDV.Get_vnl_vector(), &m_Spacing ); planeGeometry->SetOrigin(origin); planeGeometry->SetBounds(bounds); firstGeometry = planeGeometry; } else if ( (m_EvenlySpaced) && (m_Geometry2Ds.size() > 0) ) { firstGeometry = m_Geometry2Ds[0].GetPointer(); } //clear and reserve Geometry2D::Pointer gnull=NULL; m_Geometry2Ds.assign(m_Slices, gnull); if ( m_Slices > 0 ) { m_Geometry2Ds[0] = firstGeometry; } this->Modified(); } void mitk::SlicedGeometry3D ::SetSliceNavigationController( SliceNavigationController *snc ) { m_SliceNavigationController = snc; } mitk::SliceNavigationController * mitk::SlicedGeometry3D::GetSliceNavigationController() { return m_SliceNavigationController; } void mitk::SlicedGeometry3D::SetEvenlySpaced(bool on) { if(m_EvenlySpaced!=on) { m_EvenlySpaced=on; this->Modified(); } } void mitk::SlicedGeometry3D ::SetDirectionVector( const mitk::Vector3D& directionVector ) { Vector3D newDir = directionVector; newDir.Normalize(); if ( newDir != m_DirectionVector ) { m_DirectionVector = newDir; this->Modified(); } } void mitk::SlicedGeometry3D::SetTimeBounds( const mitk::TimeBounds& timebounds ) { Superclass::SetTimeBounds( timebounds ); unsigned int s; for ( s = 0; s < m_Slices; ++s ) { if(m_Geometry2Ds[s].IsNotNull()) { m_Geometry2Ds[s]->SetTimeBounds( timebounds ); } } m_TimeBounds = timebounds; } mitk::AffineGeometryFrame3D::Pointer mitk::SlicedGeometry3D::Clone() const { Self::Pointer newGeometry = new SlicedGeometry3D(*this); newGeometry->UnRegister(); return newGeometry.GetPointer(); } void mitk::SlicedGeometry3D::PrintSelf( std::ostream& os, itk::Indent indent ) const { Superclass::PrintSelf(os,indent); os << indent << " EvenlySpaced: " << m_EvenlySpaced << std::endl; if ( m_EvenlySpaced ) { os << indent << " DirectionVector: " << m_DirectionVector << std::endl; } os << indent << " Slices: " << m_Slices << std::endl; os << std::endl; os << indent << " GetGeometry2D(0): "; if ( this->GetGeometry2D(0) == NULL ) { os << "NULL" << std::endl; } else { this->GetGeometry2D(0)->Print(os, indent); } } void mitk::SlicedGeometry3D::ExecuteOperation(Operation* operation) { switch ( operation->GetOperationType() ) { case OpNOTHING: break; case OpROTATE: if ( m_EvenlySpaced ) { // Need a reference frame to align the rotation if ( m_ReferenceGeometry ) { // Clear all generated geometries and then rotate only the first slice. // The other slices will be re-generated on demand // Save first slice Geometry2D::Pointer geometry2D = m_Geometry2Ds[0]; RotationOperation *rotOp = dynamic_cast< RotationOperation * >( operation ); // Generate a RotationOperation using the dataset center instead of // the supplied rotation center. This is necessary so that the rotated // zero-plane does not shift away. The supplied center is instead used // to adjust the slice stack afterwards. Point3D center = m_ReferenceGeometry->GetCenter(); RotationOperation centeredRotation( rotOp->GetOperationType(), center, rotOp->GetVectorOfRotation(), rotOp->GetAngleOfRotation() ); // Rotate first slice geometry2D->ExecuteOperation( ¢eredRotation ); // Clear the slice stack and adjust it according to the center of // the dataset and the supplied rotation center (see documentation of // ReinitializePlanes) this->ReinitializePlanes( center, rotOp->GetCenterOfRotation() ); geometry2D->SetSpacing(this->GetSpacing()); if ( m_SliceNavigationController ) { m_SliceNavigationController->SelectSliceByPoint( rotOp->GetCenterOfRotation() ); m_SliceNavigationController->AdjustSliceStepperRange(); } Geometry3D::ExecuteOperation( ¢eredRotation ); } else { // we also have to consider the case, that there is no reference geometry available. if ( m_Geometry2Ds.size() > 0 ) { // Reach through to all slices in my container for (std::vector::iterator iter = m_Geometry2Ds.begin(); iter != m_Geometry2Ds.end(); ++iter) { (*iter)->ExecuteOperation(operation); } // rotate overall geometry RotationOperation *rotOp = dynamic_cast< RotationOperation * >( operation ); Geometry3D::ExecuteOperation( rotOp); } } } else { // Reach through to all slices for (std::vector::iterator iter = m_Geometry2Ds.begin(); iter != m_Geometry2Ds.end(); ++iter) { (*iter)->ExecuteOperation(operation); } } break; case OpORIENT: if ( m_EvenlySpaced ) { // Save first slice Geometry2D::Pointer geometry2D = m_Geometry2Ds[0]; PlaneGeometry *planeGeometry = dynamic_cast< PlaneGeometry * >( geometry2D.GetPointer() ); PlaneOperation *planeOp = dynamic_cast< PlaneOperation * >( operation ); // Need a PlaneGeometry, a PlaneOperation and a reference frame to // carry out the re-orientation if ( m_ReferenceGeometry && planeGeometry && planeOp ) { // Clear all generated geometries and then rotate only the first slice. // The other slices will be re-generated on demand // Generate a RotationOperation by calculating the angle between // the current and the requested slice orientation Point3D center = m_ReferenceGeometry->GetCenter(); const mitk::Vector3D ¤tNormal = planeGeometry->GetNormal(); const mitk::Vector3D &newNormal = planeOp->GetNormal(); Vector3D rotationAxis = itk::CrossProduct( newNormal, currentNormal ); vtkFloatingPointType rotationAngle = - atan2( (double) rotationAxis.GetNorm(), (double) (newNormal * currentNormal) ); rotationAngle *= 180.0 / vnl_math::pi; RotationOperation centeredRotation( mitk::OpROTATE, center, rotationAxis, rotationAngle ); // Rotate first slice geometry2D->ExecuteOperation( ¢eredRotation ); // Clear the slice stack and adjust it according to the center of // rotation and plane position (see documentation of ReinitializePlanes) this->ReinitializePlanes( center, planeOp->GetPoint() ); if ( m_SliceNavigationController ) { m_SliceNavigationController->SelectSliceByPoint( planeOp->GetPoint() ); m_SliceNavigationController->AdjustSliceStepperRange(); } Geometry3D::ExecuteOperation( ¢eredRotation ); } } else { // Reach through to all slices for (std::vector::iterator iter = m_Geometry2Ds.begin(); iter != m_Geometry2Ds.end(); ++iter) { (*iter)->ExecuteOperation(operation); } } break; case OpRESTOREPLANEPOSITION: if ( m_EvenlySpaced ) { // Save first slice Geometry2D::Pointer geometry2D = m_Geometry2Ds[0]; PlaneGeometry* planeGeometry = dynamic_cast< PlaneGeometry * >( geometry2D.GetPointer() ); RestorePlanePositionOperation *restorePlaneOp = dynamic_cast< RestorePlanePositionOperation* >( operation ); // Need a PlaneGeometry, a PlaneOperation and a reference frame to // carry out the re-orientation if ( m_ReferenceGeometry && planeGeometry && restorePlaneOp ) { // Clear all generated geometries and then rotate only the first slice. // The other slices will be re-generated on demand // Rotate first slice geometry2D->ExecuteOperation( restorePlaneOp ); m_DirectionVector = restorePlaneOp->GetDirectionVector(); double centerOfRotationDistance = planeGeometry->SignedDistanceFromPlane( m_ReferenceGeometry->GetCenter() ); if ( centerOfRotationDistance > 0 ) { m_DirectionVector = m_DirectionVector; } else { m_DirectionVector = -m_DirectionVector; } Vector3D spacing = restorePlaneOp->GetSpacing(); Superclass::SetSpacing( spacing ); // /*Now we need to calculate the number of slices in the plane's normal // direction, so that the entire volume is covered. This is done by first // calculating the dot product between the volume diagonal (the maximum // distance inside the volume) and the normal, and dividing this value by // the directed spacing calculated above.*/ ScalarType directedExtent = fabs( m_ReferenceGeometry->GetExtentInMM( 0 ) * m_DirectionVector[0] ) + fabs( m_ReferenceGeometry->GetExtentInMM( 1 ) * m_DirectionVector[1] ) + fabs( m_ReferenceGeometry->GetExtentInMM( 2 ) * m_DirectionVector[2] ); if ( directedExtent >= spacing[2] ) { m_Slices = static_cast< unsigned int >(directedExtent / spacing[2] + 0.5); } else { m_Slices = 1; } m_Geometry2Ds.assign( m_Slices, Geometry2D::Pointer( NULL ) ); if ( m_Slices > 0 ) { m_Geometry2Ds[0] = geometry2D; } m_SliceNavigationController->GetSlice()->SetSteps( m_Slices ); this->Modified(); //End Reinitialization if ( m_SliceNavigationController ) { m_SliceNavigationController->GetSlice()->SetPos( restorePlaneOp->GetPos() ); m_SliceNavigationController->AdjustSliceStepperRange(); } Geometry3D::ExecuteOperation(restorePlaneOp); } } else { // Reach through to all slices for (std::vector::iterator iter = m_Geometry2Ds.begin(); iter != m_Geometry2Ds.end(); ++iter) { (*iter)->ExecuteOperation(operation); } } break; } this->Modified(); } diff --git a/Core/Code/DataManagement/mitkSlicedGeometry3D.h b/Core/Code/DataManagement/mitkSlicedGeometry3D.h index b4391c4383..f7637c8b1a 100644 --- a/Core/Code/DataManagement/mitkSlicedGeometry3D.h +++ b/Core/Code/DataManagement/mitkSlicedGeometry3D.h @@ -1,324 +1,324 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 MITKSLICEDGEOMETRY3D_H_HEADER_INCLUDED_C1EBD0AD #define MITKSLICEDGEOMETRY3D_H_HEADER_INCLUDED_C1EBD0AD #include "mitkGeometry3D.h" #include "mitkPlaneGeometry.h" namespace mitk { class SliceNavigationController; class NavigationController; /** \brief Describes the geometry of a data object consisting of slices. * * A Geometry2D can be requested for each slice. In the case of * \em evenly-spaced, \em plane geometries (m_EvenlySpaced==true), * only the 2D-geometry of the first slice has to be set (to an instance of * PlaneGeometry). The 2D geometries of the other slices are calculated * by shifting the first slice in the direction m_DirectionVector by * m_Spacing.z * sliceNumber. The m_Spacing member (which is only * relevant in the case m_EvenlySpaced==true) descibes the size of a voxel * (in mm), i.e., m_Spacing.x is the voxel width in the x-direction of the * plane. It is derived from the reference geometry of this SlicedGeometry3D, * which usually would be the global geometry describing how datasets are to * be resliced. * * By default, slices are oriented in the direction of one of the main axes * (x, y, z). However, by means of rotation, it is possible to realign the * slices in any possible direction. In case of an inclined plane, the spacing * is derived as a product of the (regular) geometry spacing and the direction * vector of the plane. * * SlicedGeometry3D and the associated Geometry2Ds 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 * * \sa itk::ProcessObject::GenerateOutputInformation(), * \sa itk::DataObject::CopyInformation() and * \a itk::DataObject::UpdateOutputInformation(). * * Rule: everything is in mm (or ms for temporal information) if not * stated otherwise. * * \warning The hull (i.e., transform, bounding-box and * time-bounds) is only guaranteed to be up-to-date after calling * UpdateInformation(). * * \ingroup Geometry */ class MITK_CORE_EXPORT SlicedGeometry3D : public mitk::Geometry3D { public: mitkClassMacro(SlicedGeometry3D, Geometry3D); /** Method for creation through the object factory. */ itkNewMacro(Self); /** * \brief Returns the Geometry2D of the slice (\a s). * * If (a) m_EvenlySpaced==true, (b) we don't have a Geometry2D stored * for the requested slice, and (c) the first slice (s=0) * is a PlaneGeometry instance, then we calculate the geometry of the * requested as the plane of the first slice shifted by m_Spacing[3]*s * in the direction of m_DirectionVector. * * \warning The Geometry2Ds are not necessarily up-to-date and not even * initialized. * * The Geometry2Ds 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 * * \sa itk::ProcessObject::GenerateOutputInformation(), * \sa itk::DataObject::CopyInformation() and * \sa itk::DataObject::UpdateOutputInformation(). */ virtual mitk::Geometry2D* GetGeometry2D( int s ) const; /** * \brief Set Geometry2D of slice \a s. */ virtual bool SetGeometry2D( mitk::Geometry2D *geometry2D, int s ); //##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 ); virtual void SetTimeBounds( const mitk::TimeBounds& timebounds ); virtual const mitk::BoundingBox* GetBoundingBox() const; /** * \brief Get the number of slices */ itkGetConstMacro( Slices, unsigned int ); /** * \brief Check whether a slice exists */ virtual bool IsValidSlice( int s = 0 ) const; virtual void SetReferenceGeometry( Geometry3D *referenceGeometry ); /** * \brief Set the spacing (m_Spacing), in direction of the plane normal. * * INTERNAL METHOD. */ virtual void SetSpacing( const mitk::Vector3D &aSpacing ); /** * \brief Set the SliceNavigationController corresponding to this sliced * geometry. * * The SNC needs to be informed when the number of slices in the geometry * changes, which can occur whenthe slices are re-oriented by rotation. */ virtual void SetSliceNavigationController( mitk::SliceNavigationController *snc ); mitk::SliceNavigationController *GetSliceNavigationController(); /** * \brief Set/Get whether the SlicedGeometry3D is evenly-spaced * (m_EvenlySpaced) * * If (a) m_EvenlySpaced==true, (b) we don't have a Geometry2D stored for * the requested slice, and (c) the first slice (s=0) is a PlaneGeometry * instance, then we calculate the geometry of the requested as the plane * of the first slice shifted by m_Spacing.z * s in the direction of * m_DirectionVector. * * \sa GetGeometry2D */ itkGetConstMacro(EvenlySpaced, bool); virtual void SetEvenlySpaced(bool on = true); /** * \brief Set/Get the vector between slices for the evenly-spaced case * (m_EvenlySpaced==true). * * If the direction-vector is (0,0,0) (the default) and the first * 2D geometry is a PlaneGeometry, then the direction-vector will be * calculated from the plane normal. * * \sa m_DirectionVector */ virtual void SetDirectionVector(const mitk::Vector3D& directionVector); itkGetConstMacro(DirectionVector, const mitk::Vector3D&); virtual AffineGeometryFrame3D::Pointer Clone() const; static const std::string SLICES; const static std::string DIRECTION_VECTOR; const static std::string EVENLY_SPACED; /** * \brief Tell this instance how many Geometry2Ds it shall manage. Bounding * box and the Geometry2Ds must be set additionally by calling the respective * methods! * * \warning Bounding box and the 2D-geometries must be set additionally: use * SetBounds(), SetGeometry(). */ virtual void InitializeSlicedGeometry( unsigned int slices ); /** * \brief Completely initialize this instance as evenly-spaced with slices * parallel to the provided Geometry2D that is used as the first slice and * for spacing calculation. * * Initializes the bounding box according to the width/height of the * Geometry2D and \a slices. The spacing is calculated from the Geometry2D. */ virtual void InitializeEvenlySpaced( mitk::Geometry2D *geometry2D, unsigned int slices, bool flipped=false ); /** * \brief Completely initialize this instance as evenly-spaced with slices * parallel to the provided Geometry2D that is used as the first slice and * for spacing calculation (except z-spacing). * * Initializes the bounding box according to the width/height of the * Geometry2D and \a slices. The x-/y-spacing is calculated from the * Geometry2D. */ virtual void InitializeEvenlySpaced( mitk::Geometry2D *geometry2D, mitk::ScalarType zSpacing, unsigned int slices, bool flipped=false ); /** * \brief Completely initialize this instance as evenly-spaced plane slices * parallel to a side of the provided Geometry3D and using its spacing * information. * * Initializes the bounding box according to the width/height of the * Geometry3D and the number of slices according to * Geometry3D::GetExtent(2). * * \param planeorientation side parallel to which the slices will be oriented * \param top if \a true, create plane at top, otherwise at bottom - * (for PlaneOrientation Transversal, for other plane locations respectively) + * (for PlaneOrientation Axial, for other plane locations respectively) * \param frontside defines the side of the plane (the definition of * front/back is somewhat arbitrary) * * \param rotate rotates the plane by 180 degree around its normal (the * definition of rotated vs not rotated is somewhat arbitrary) */ virtual void InitializePlanes( const mitk::Geometry3D *geometry3D, mitk::PlaneGeometry::PlaneOrientation planeorientation, bool top=true, bool frontside=true, bool rotated=false ); virtual void SetImageGeometry(const bool isAnImageGeometry); virtual void ExecuteOperation(Operation* operation); static double CalculateSpacing( const mitk::Vector3D spacing, const mitk::Vector3D &d ); protected: SlicedGeometry3D(); SlicedGeometry3D(const SlicedGeometry3D& other); virtual ~SlicedGeometry3D(); /** * Reinitialize plane stack after rotation. More precisely, the first plane * of the stack needs to spatially aligned, in two respects: * * 1. Re-alignment with respect to the dataset center; this is necessary * since the distance from the first plane to the center could otherwise * continuously decrease or increase. * 2. Re-alignment with respect to a given reference point; the reference * point is a location which the user wants to be exactly touched by one * plane of the plane stack. The first plane is minimally shifted to * ensure this touching. Usually, the reference point would be the * point around which the geometry is rotated. */ virtual void ReinitializePlanes( const Point3D ¢er, const Point3D &referencePoint ); ScalarType GetLargestExtent( const Geometry3D *geometry ); void PrintSelf(std::ostream& os, itk::Indent indent) const; /** Calculate "directed spacing", i.e. the spacing in directions * non-orthogonal to the coordinate axes. This is done via the * ellipsoid equation. */ double CalculateSpacing( const mitk::Vector3D &direction ) const; /** The extent of the slice stack, i.e. the number of slices, depends on the * plane normal. For rotated geometries, the geometry's transform needs to * be accounted in this calculation. */ mitk::Vector3D AdjustNormal( const mitk::Vector3D &normal ) const; /** * Container for the 2D-geometries contained within this SliceGeometry3D. */ mutable std::vector m_Geometry2Ds; /** * If (a) m_EvenlySpaced==true, (b) we don't have a Geometry2D stored * for the requested slice, and (c) the first slice (s=0) * is a PlaneGeometry instance, then we calculate the geometry of the * requested as the plane of the first slice shifted by m_Spacing.z*s * in the direction of m_DirectionVector. * * \sa GetGeometry2D */ bool m_EvenlySpaced; /** * Vector between slices for the evenly-spaced case (m_EvenlySpaced==true). * If the direction-vector is (0,0,0) (the default) and the first * 2D geometry is a PlaneGeometry, then the direction-vector will be * calculated from the plane normal. */ mutable mitk::Vector3D m_DirectionVector; /** Number of slices this SliceGeometry3D is descibing. */ unsigned int m_Slices; /** Underlying Geometry3D for this SlicedGeometry */ mitk::Geometry3D *m_ReferenceGeometry; /** SNC correcsponding to this geometry; used to reflect changes in the * number of slices due to rotation. */ //mitk::NavigationController *m_NavigationController; mitk::SliceNavigationController *m_SliceNavigationController; }; } // namespace mitk #endif /* MITKSLICEDGEOMETRY3D_H_HEADER_INCLUDED_C1EBD0AD */ diff --git a/Core/Code/IO/mitkDicomSeriesReader.cpp b/Core/Code/IO/mitkDicomSeriesReader.cpp index 921a331726..5b9865b7d7 100644 --- a/Core/Code/IO/mitkDicomSeriesReader.cpp +++ b/Core/Code/IO/mitkDicomSeriesReader.cpp @@ -1,1363 +1,1463 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // uncomment for learning more about the internal sorting mechanisms //#define MBILOG_ENABLE_DEBUG #include #include #include #include #include #include #include #include "mitkProperties.h" namespace mitk { typedef itk::GDCMSeriesFileNames DcmFileNamesGeneratorType; DicomSeriesReader::SliceGroupingAnalysisResult::SliceGroupingAnalysisResult() :m_GantryTilt(false) { } DicomSeriesReader::StringContainer DicomSeriesReader::SliceGroupingAnalysisResult::GetBlockFilenames() { return m_GroupedFiles; } DicomSeriesReader::StringContainer DicomSeriesReader::SliceGroupingAnalysisResult::GetUnsortedFilenames() { return m_UnsortedFiles; } bool DicomSeriesReader::SliceGroupingAnalysisResult::ContainsGantryTilt() { return m_GantryTilt; } void DicomSeriesReader::SliceGroupingAnalysisResult::AddFileToSortedBlock(const std::string& filename) { m_GroupedFiles.push_back( filename ); } void DicomSeriesReader::SliceGroupingAnalysisResult::AddFileToUnsortedBlock(const std::string& filename) { m_UnsortedFiles.push_back( filename ); } void DicomSeriesReader::SliceGroupingAnalysisResult::FlagGantryTilt() { m_GantryTilt = true; } void DicomSeriesReader::SliceGroupingAnalysisResult::UndoPrematureGrouping() { assert( !m_GroupedFiles.empty() ); m_UnsortedFiles.insert( m_UnsortedFiles.begin(), m_GroupedFiles.back() ); m_GroupedFiles.pop_back(); } const DicomSeriesReader::TagToPropertyMapType& DicomSeriesReader::GetDICOMTagsToMITKPropertyMap() { static bool initialized = false; static TagToPropertyMapType dictionary; if (!initialized) { /* Selection criteria: - no sequences because we cannot represent that - nothing animal related (specied, breed registration number), MITK focusses on human medical image processing. - only general attributes so far When extending this, we should make use of a real dictionary (GDCM/DCMTK and lookup the tag names there) */ // Patient module dictionary["0010|0010"] = "dicom.patient.PatientsName"; dictionary["0010|0020"] = "dicom.patient.PatientID"; dictionary["0010|0030"] = "dicom.patient.PatientsBirthDate"; dictionary["0010|0040"] = "dicom.patient.PatientsSex"; dictionary["0010|0032"] = "dicom.patient.PatientsBirthTime"; dictionary["0010|1000"] = "dicom.patient.OtherPatientIDs"; dictionary["0010|1001"] = "dicom.patient.OtherPatientNames"; dictionary["0010|2160"] = "dicom.patient.EthnicGroup"; dictionary["0010|4000"] = "dicom.patient.PatientComments"; dictionary["0012|0062"] = "dicom.patient.PatientIdentityRemoved"; dictionary["0012|0063"] = "dicom.patient.DeIdentificationMethod"; // General Study module dictionary["0020|000d"] = "dicom.study.StudyInstanceUID"; dictionary["0008|0020"] = "dicom.study.StudyDate"; dictionary["0008|0030"] = "dicom.study.StudyTime"; dictionary["0008|0090"] = "dicom.study.ReferringPhysiciansName"; dictionary["0020|0010"] = "dicom.study.StudyID"; dictionary["0008|0050"] = "dicom.study.AccessionNumber"; dictionary["0008|1030"] = "dicom.study.StudyDescription"; dictionary["0008|1048"] = "dicom.study.PhysiciansOfRecord"; dictionary["0008|1060"] = "dicom.study.NameOfPhysicianReadingStudy"; // General Series module dictionary["0008|0060"] = "dicom.series.Modality"; dictionary["0020|000e"] = "dicom.series.SeriesInstanceUID"; dictionary["0020|0011"] = "dicom.series.SeriesNumber"; dictionary["0020|0060"] = "dicom.series.Laterality"; dictionary["0008|0021"] = "dicom.series.SeriesDate"; dictionary["0008|0031"] = "dicom.series.SeriesTime"; dictionary["0008|1050"] = "dicom.series.PerformingPhysiciansName"; dictionary["0018|1030"] = "dicom.series.ProtocolName"; dictionary["0008|103e"] = "dicom.series.SeriesDescription"; dictionary["0008|1070"] = "dicom.series.OperatorsName"; dictionary["0018|0015"] = "dicom.series.BodyPartExamined"; dictionary["0018|5100"] = "dicom.series.PatientPosition"; dictionary["0028|0108"] = "dicom.series.SmallestPixelValueInSeries"; dictionary["0028|0109"] = "dicom.series.LargestPixelValueInSeries"; // VOI LUT module dictionary["0028|1050"] = "dicom.voilut.WindowCenter"; dictionary["0028|1051"] = "dicom.voilut.WindowWidth"; dictionary["0028|1055"] = "dicom.voilut.WindowCenterAndWidthExplanation"; initialized = true; } return dictionary; } DataNode::Pointer DicomSeriesReader::LoadDicomSeries(const StringContainer &filenames, bool sort, bool check_4d, bool correctTilt, UpdateCallBackMethod callback) { DataNode::Pointer node = DataNode::New(); if (DicomSeriesReader::LoadDicomSeries(filenames, *node, sort, check_4d, correctTilt, callback)) { if( filenames.empty() ) { return NULL; } return node; } else { return NULL; } } bool DicomSeriesReader::LoadDicomSeries(const StringContainer &filenames, DataNode &node, bool sort, bool check_4d, bool correctTilt, UpdateCallBackMethod callback) { if( filenames.empty() ) { MITK_WARN << "Calling LoadDicomSeries with empty filename string container. Probably invalid application logic."; node.SetData(NULL); return true; // this is not actually an error but the result is very simple } DcmIoType::Pointer io = DcmIoType::New(); try { if (io->CanReadFile(filenames.front().c_str())) { io->SetFileName(filenames.front().c_str()); io->ReadImageInformation(); switch (io->GetComponentType()) { case DcmIoType::UCHAR: DicomSeriesReader::LoadDicom(filenames, node, sort, check_4d, correctTilt, callback); break; case DcmIoType::CHAR: DicomSeriesReader::LoadDicom(filenames, node, sort, check_4d, correctTilt, callback); break; case DcmIoType::USHORT: DicomSeriesReader::LoadDicom(filenames, node, sort, check_4d, correctTilt, callback); break; case DcmIoType::SHORT: DicomSeriesReader::LoadDicom(filenames, node, sort, check_4d, correctTilt, callback); break; case DcmIoType::UINT: DicomSeriesReader::LoadDicom(filenames, node, sort, check_4d, correctTilt, callback); break; case DcmIoType::INT: DicomSeriesReader::LoadDicom(filenames, node, sort, check_4d, correctTilt, callback); break; case DcmIoType::ULONG: DicomSeriesReader::LoadDicom(filenames, node, sort, check_4d, correctTilt, callback); break; case DcmIoType::LONG: DicomSeriesReader::LoadDicom(filenames, node, sort, check_4d, correctTilt, callback); break; case DcmIoType::FLOAT: DicomSeriesReader::LoadDicom(filenames, node, sort, check_4d, correctTilt, callback); break; case DcmIoType::DOUBLE: DicomSeriesReader::LoadDicom(filenames, node, sort, check_4d, correctTilt, callback); break; default: MITK_ERROR << "Found unsupported DICOM pixel type: (enum value) " << io->GetComponentType(); } if (node.GetData()) { return true; } } } catch(itk::MemoryAllocationError& e) { MITK_ERROR << "Out of memory. Cannot load DICOM series: " << e.what(); } catch(std::exception& e) { MITK_ERROR << "Error encountered when loading DICOM series:" << e.what(); } catch(...) { MITK_ERROR << "Unspecified error encountered when loading DICOM series."; } return false; } bool DicomSeriesReader::IsDicom(const std::string &filename) { DcmIoType::Pointer io = DcmIoType::New(); return io->CanReadFile(filename.c_str()); } bool DicomSeriesReader::IsPhilips3DDicom(const std::string &filename) { DcmIoType::Pointer io = DcmIoType::New(); if (io->CanReadFile(filename.c_str())) { //Look at header Tag 3001,0010 if it is "Philips3D" gdcm::Reader reader; reader.SetFileName(filename.c_str()); reader.Read(); gdcm::DataSet &data_set = reader.GetFile().GetDataSet(); gdcm::StringFilter sf; sf.SetFile(reader.GetFile()); if (data_set.FindDataElement(gdcm::Tag(0x3001, 0x0010)) && (sf.ToString(gdcm::Tag(0x3001, 0x0010)) == "Philips3D ")) { return true; } } return false; } bool DicomSeriesReader::ReadPhilips3DDicom(const std::string &filename, mitk::Image::Pointer output_image) { // Now get PhilipsSpecific Tags gdcm::PixmapReader reader; reader.SetFileName(filename.c_str()); reader.Read(); gdcm::DataSet &data_set = reader.GetFile().GetDataSet(); gdcm::StringFilter sf; sf.SetFile(reader.GetFile()); gdcm::Attribute<0x0028,0x0011> dimTagX; // coloumns || sagittal - gdcm::Attribute<0x3001,0x1001, gdcm::VR::UL, gdcm::VM::VM1> dimTagZ; //I have no idea what is VM1. // (Philips specific) // transversal + gdcm::Attribute<0x3001,0x1001, gdcm::VR::UL, gdcm::VM::VM1> dimTagZ; //I have no idea what is VM1. // (Philips specific) // axial gdcm::Attribute<0x0028,0x0010> dimTagY; // rows || coronal gdcm::Attribute<0x0028,0x0008> dimTagT; // how many frames gdcm::Attribute<0x0018,0x602c> spaceTagX; // Spacing in X , unit is "physicalTagx" (usually centimeter) gdcm::Attribute<0x0018,0x602e> spaceTagY; gdcm::Attribute<0x3001,0x1003, gdcm::VR::FD, gdcm::VM::VM1> spaceTagZ; // (Philips specific) gdcm::Attribute<0x0018,0x6024> physicalTagX; // if 3, then spacing params are centimeter gdcm::Attribute<0x0018,0x6026> physicalTagY; gdcm::Attribute<0x3001,0x1002, gdcm::VR::US, gdcm::VM::VM1> physicalTagZ; // (Philips specific) dimTagX.Set(data_set); dimTagY.Set(data_set); dimTagZ.Set(data_set); dimTagT.Set(data_set); spaceTagX.Set(data_set); spaceTagY.Set(data_set); spaceTagZ.Set(data_set); physicalTagX.Set(data_set); physicalTagY.Set(data_set); physicalTagZ.Set(data_set); unsigned int dimX = dimTagX.GetValue(), dimY = dimTagY.GetValue(), dimZ = dimTagZ.GetValue(), dimT = dimTagT.GetValue(), physicalX = physicalTagX.GetValue(), physicalY = physicalTagY.GetValue(), physicalZ = physicalTagZ.GetValue(); float spaceX = spaceTagX.GetValue(), spaceY = spaceTagY.GetValue(), spaceZ = spaceTagZ.GetValue(); if (physicalX == 3) // spacing parameter in cm, have to convert it to mm. spaceX = spaceX * 10; if (physicalY == 3) // spacing parameter in cm, have to convert it to mm. spaceY = spaceY * 10; if (physicalZ == 3) // spacing parameter in cm, have to convert it to mm. spaceZ = spaceZ * 10; // Ok, got all necessary Tags! // Now read Pixeldata (7fe0,0010) X x Y x Z x T Elements const gdcm::Pixmap &pixels = reader.GetPixmap(); gdcm::RAWCodec codec; codec.SetPhotometricInterpretation(gdcm::PhotometricInterpretation::MONOCHROME2); codec.SetPixelFormat(pixels.GetPixelFormat()); codec.SetPlanarConfiguration(0); gdcm::DataElement out; codec.Decode(data_set.GetDataElement(gdcm::Tag(0x7fe0, 0x0010)), out); const gdcm::ByteValue *bv = out.GetByteValue(); const char *new_pixels = bv->GetPointer(); // Create MITK Image + Geometry typedef itk::Image ImageType; //Pixeltype might be different sometimes? Maybe read it out from header ImageType::RegionType myRegion; ImageType::SizeType mySize; ImageType::IndexType myIndex; ImageType::SpacingType mySpacing; ImageType::Pointer imageItk = ImageType::New(); mySpacing[0] = spaceX; mySpacing[1] = spaceY; mySpacing[2] = spaceZ; mySpacing[3] = 1; myIndex[0] = 0; myIndex[1] = 0; myIndex[2] = 0; myIndex[3] = 0; mySize[0] = dimX; mySize[1] = dimY; mySize[2] = dimZ; mySize[3] = dimT; myRegion.SetSize( mySize); myRegion.SetIndex( myIndex ); imageItk->SetSpacing(mySpacing); imageItk->SetRegions( myRegion); imageItk->Allocate(); imageItk->FillBuffer(0); itk::ImageRegionIterator iterator(imageItk, imageItk->GetLargestPossibleRegion()); iterator.GoToBegin(); unsigned long pixCount = 0; unsigned long planeSize = dimX*dimY; unsigned long planeCount = 0; unsigned long timeCount = 0; unsigned long numberOfSlices = dimZ; while (!iterator.IsAtEnd()) { unsigned long adressedPixel = pixCount + (numberOfSlices-1-planeCount)*planeSize // add offset to adress the first pixel of current plane + timeCount*numberOfSlices*planeSize; // add time offset iterator.Set( new_pixels[ adressedPixel ] ); pixCount++; ++iterator; if (pixCount == planeSize) { pixCount = 0; planeCount++; } if (planeCount == numberOfSlices) { planeCount = 0; timeCount++; } if (timeCount == dimT) { break; } } mitk::CastToMitkImage(imageItk, output_image); return true; // actually never returns false yet.. but exception possible } DicomSeriesReader::GantryTiltInformation::GantryTiltInformation() : m_ShiftUp(0.0) , m_ShiftRight(0.0) , m_ShiftNormal(0.0) +, m_ITKAssumedSliceSpacing(0.0) , m_NumberOfSlicesApart(1) { } + +#define doublepoint(x) \ + Point3Dd x; \ + x[0] = x ## f[0]; \ + x[1] = x ## f[1]; \ + x[2] = x ## f[2]; + + +#define doublevector(x) \ + Vector3Dd x; \ + x[0] = x ## f[0]; \ + x[1] = x ## f[1]; \ + x[2] = x ## f[2]; + DicomSeriesReader::GantryTiltInformation::GantryTiltInformation( - const Point3D& origin1, const Point3D& origin2, - const Vector3D& right, const Vector3D& up, + const Point3D& origin1f, const Point3D& origin2f, + const Vector3D& rightf, const Vector3D& upf, unsigned int numberOfSlicesApart) : m_ShiftUp(0.0) , m_ShiftRight(0.0) , m_ShiftNormal(0.0) , m_NumberOfSlicesApart(numberOfSlicesApart) { assert(numberOfSlicesApart); + + doublepoint(origin1); + doublepoint(origin2); + doublevector(right); + doublevector(up); + // determine if slice 1 (imagePosition1 and imageOrientation1) and slice 2 can be in one orthogonal slice stack: // calculate a line from origin 1, directed along the normal of slice (calculated as the cross product of orientation 1) // check if this line passes through origin 2 /* Determine if line (imagePosition2 + l * normal) contains imagePosition1. Done by calculating the distance of imagePosition1 from line (imagePosition2 + l *normal) E.g. http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html squared distance = | (pointAlongNormal - origin2) x (origin2 - origin1) | ^ 2 / |pointAlongNormal - origin2| ^ 2 ( x meaning the cross product ) */ - Vector3D normal = itk::CrossProduct(right, up); - Point3D pointAlongNormal = origin2 + normal; + Vector3Dd normal = itk::CrossProduct(right, up); + Point3Dd pointAlongNormal = origin2 + normal; double numerator = itk::CrossProduct( pointAlongNormal - origin2 , origin2 - origin1 ).GetSquaredNorm(); double denominator = (pointAlongNormal - origin2).GetSquaredNorm(); double distance = sqrt(numerator / denominator); if ( distance > 0.001 ) // mitk::eps is too small; 1/1000 of a mm should be enough to detect tilt { MITK_DEBUG << " Series seems to contain a tilted (or sheared) geometry"; MITK_DEBUG << " Distance of expected slice origin from actual slice origin: " << distance; MITK_DEBUG << " ==> storing this shift for later analysis:"; MITK_DEBUG << " v right: " << right; MITK_DEBUG << " v up: " << up; MITK_DEBUG << " v normal: " << normal; - Point3D projectionRight = projectPointOnLine( origin1, origin2, right ); - Point3D projectionUp = projectPointOnLine( origin1, origin2, up ); - Point3D projectionNormal = projectPointOnLine( origin1, origin2, normal ); + Point3Dd projectionRight = projectPointOnLine( origin1, origin2, right ); + Point3Dd projectionNormal = projectPointOnLine( origin1, origin2, normal ); m_ShiftRight = (projectionRight - origin2).GetNorm(); - m_ShiftUp = (projectionUp - origin2).GetNorm(); m_ShiftNormal = (projectionNormal - origin2).GetNorm(); + /* + now also check to which side the image is shifted. + + Calculation e.g. from + http://mathworld.wolfram.com/Point-PlaneDistance.html + */ + + Point3Dd testPoint = origin1; + Vector3Dd planeNormal = up; + + double signedDistance = ( + planeNormal[0] * testPoint[0] + + planeNormal[1] * testPoint[1] + + planeNormal[2] * testPoint[2] + - ( + planeNormal[0] * origin2[0] + + planeNormal[1] * origin2[1] + + planeNormal[2] * origin2[2] + ) + ) + / + sqrt( planeNormal[0] * planeNormal[0] + + planeNormal[1] * planeNormal[1] + + planeNormal[2] * planeNormal[2] + ); + + m_ShiftUp = signedDistance; + + m_ITKAssumedSliceSpacing = (origin2 - origin1).GetNorm(); + //double itkAssumedSliceSpacing = sqrt( m_ShiftUp * m_ShiftUp + m_ShiftNormal * m_ShiftNormal ); + MITK_DEBUG << " shift normal: " << m_ShiftNormal; + MITK_DEBUG << " shift normal assumed by ITK: " << m_ITKAssumedSliceSpacing; MITK_DEBUG << " shift up: " << m_ShiftUp; MITK_DEBUG << " shift right: " << m_ShiftRight; - MITK_DEBUG << " tilt angle (rad): " << tanh( m_ShiftUp / m_ShiftNormal ); - MITK_DEBUG << " tilt angle (deg): " << tanh( m_ShiftUp / m_ShiftNormal ) * 180.0 / 3.1415926535; + MITK_DEBUG << " tilt angle (deg): " << atan( m_ShiftUp / m_ShiftNormal ) * 180.0 / 3.1415926535; } } Point3D -DicomSeriesReader::GantryTiltInformation::projectPointOnLine( Point3D p, Point3D lineOrigin, Vector3D lineDirection ) +DicomSeriesReader::GantryTiltInformation::projectPointOnLine( Point3Dd p, Point3Dd lineOrigin, Vector3Dd lineDirection ) { /** See illustration at http://mo.mathematik.uni-stuttgart.de/inhalt/aussage/aussage472/ vector(lineOrigin,p) = normal * ( innerproduct((p - lineOrigin),normal) / squared-length(normal) ) */ - Vector3D lineOriginToP = p - lineOrigin; - ScalarType innerProduct = lineOriginToP * lineDirection; + Vector3Dd lineOriginToP = p - lineOrigin; + double innerProduct = lineOriginToP * lineDirection; - ScalarType factor = innerProduct / lineDirection.GetSquaredNorm(); - Point3D projection = lineOrigin + factor * lineDirection; + double factor = innerProduct / lineDirection.GetSquaredNorm(); + Point3Dd projection = lineOrigin + factor * lineDirection; return projection; } -ScalarType +double DicomSeriesReader::GantryTiltInformation::GetTiltCorrectedAdditionalSize() const { - // this seems to be a bit too much sometimes, but better too much than cutting off parts of the image - return int(m_ShiftUp + 1.0); // to next bigger int: plus 1, then cut off after point + return fabs(m_ShiftUp); +} + +double +DicomSeriesReader::GantryTiltInformation::GetTiltAngleInDegrees() const +{ + return atan( fabs(m_ShiftUp) / m_ShiftNormal ) * 180.0 / 3.1415926535; } -ScalarType +double DicomSeriesReader::GantryTiltInformation::GetMatrixCoefficientForCorrectionInWorldCoordinates() const { - // so many mm shifted per slice! - return m_ShiftUp / static_cast(m_NumberOfSlicesApart); + // so many mm need to be shifted per slice! + return m_ShiftUp / static_cast(m_NumberOfSlicesApart); } -ScalarType +double DicomSeriesReader::GantryTiltInformation::GetRealZSpacing() const { - return m_ShiftNormal / static_cast(m_NumberOfSlicesApart); + return m_ShiftNormal / static_cast(m_NumberOfSlicesApart); } bool DicomSeriesReader::GantryTiltInformation::IsSheared() const { - return ( m_ShiftRight > 0.001 - || m_ShiftUp > 0.001); + return ( fabs(m_ShiftRight) > 0.001 + || fabs(m_ShiftUp) > 0.001); } bool DicomSeriesReader::GantryTiltInformation::IsRegularGantryTilt() const { - return ( m_ShiftRight < 0.001 - && m_ShiftUp > 0.001); + return ( fabs(m_ShiftRight) < 0.001 + && fabs(m_ShiftUp) > 0.001); } std::string DicomSeriesReader::ConstCharStarToString(const char* s) { return s ? std::string(s) : std::string(); } Point3D DicomSeriesReader::DICOMStringToPoint3D(const std::string& s, bool& successful) { Point3D p; successful = true; std::istringstream originReader(s); std::string coordinate; unsigned int dim(0); while( std::getline( originReader, coordinate, '\\' ) && dim < 3) { p[dim++]= atof(coordinate.c_str()); } if (dim != 3) { successful = false; MITK_ERROR << "Reader implementation made wrong assumption on tag (0020,0032). Found " << dim << " instead of 3 values."; } return p; } void DicomSeriesReader::DICOMStringToOrientationVectors(const std::string& s, Vector3D& right, Vector3D& up, bool& successful) { successful = true; std::istringstream orientationReader(s); std::string coordinate; unsigned int dim(0); while( std::getline( orientationReader, coordinate, '\\' ) && dim < 6 ) { if (dim<3) { right[dim++] = atof(coordinate.c_str()); } else { up[dim++ - 3] = atof(coordinate.c_str()); } } if (dim != 6) { successful = false; MITK_ERROR << "Reader implementation made wrong assumption on tag (0020,0037). Found " << dim << " instead of 6 values."; } } DicomSeriesReader::SliceGroupingAnalysisResult DicomSeriesReader::AnalyzeFileForITKImageSeriesReaderSpacingAssumption( const StringContainer& files, bool groupImagesWithGantryTilt, const gdcm::Scanner::MappingType& tagValueMappings_) { // result.first = files that fit ITK's assumption // result.second = files that do not fit, should be run through AnalyzeFileForITKImageSeriesReaderSpacingAssumption() again SliceGroupingAnalysisResult result; // we const_cast here, because I could not use a map.at(), which would make the code much more readable gdcm::Scanner::MappingType& tagValueMappings = const_cast(tagValueMappings_); const gdcm::Tag tagImagePositionPatient(0x0020,0x0032); // Image Position (Patient) const gdcm::Tag tagImageOrientation(0x0020, 0x0037); // Image Orientation + const gdcm::Tag tagGantryTilt(0x0018, 0x1120); // gantry tilt Vector3D fromFirstToSecondOrigin; fromFirstToSecondOrigin.Fill(0.0); bool fromFirstToSecondOriginInitialized(false); Point3D thisOrigin; thisOrigin.Fill(0.0f); Point3D lastOrigin; lastOrigin.Fill(0.0f); Point3D lastDifferentOrigin; lastDifferentOrigin.Fill(0.0f); bool lastOriginInitialized(false); MITK_DEBUG << "--------------------------------------------------------------------------------"; MITK_DEBUG << "Analyzing files for z-spacing assumption of ITK's ImageSeriesReader (group tilted: " << groupImagesWithGantryTilt << ")"; unsigned int fileIndex(0); for (StringContainer::const_iterator fileIter = files.begin(); fileIter != files.end(); ++fileIter, ++fileIndex) { bool fileFitsIntoPattern(false); std::string thisOriginString; // Read tag value into point3D. PLEASE replace this by appropriate GDCM code if you figure out how to do that thisOriginString = ConstCharStarToString( tagValueMappings[fileIter->c_str()][tagImagePositionPatient] ); bool ignoredConversionError(-42); // hard to get here, no graceful way to react thisOrigin = DICOMStringToPoint3D( thisOriginString, ignoredConversionError ); MITK_DEBUG << " " << fileIndex << " " << *fileIter << " at " - << thisOriginString << "(" << thisOrigin[0] << "," << thisOrigin[1] << "," << thisOrigin[2] << ")"; + /* << thisOriginString */ << "(" << thisOrigin[0] << "," << thisOrigin[1] << "," << thisOrigin[2] << ")"; if ( lastOriginInitialized && (thisOrigin == lastOrigin) ) { MITK_DEBUG << " ==> Sort away " << *fileIter << " for separate time step"; // we already have one occupying this position result.AddFileToUnsortedBlock( *fileIter ); fileFitsIntoPattern = false; } else { if (!fromFirstToSecondOriginInitialized && lastOriginInitialized) // calculate vector as soon as possible when we get a new position { fromFirstToSecondOrigin = thisOrigin - lastDifferentOrigin; fromFirstToSecondOriginInitialized = true; // Here we calculate if this slice and the previous one are well aligned, // i.e. we test if the previous origin is on a line through the current // origin, directed into the normal direction of the current slice. // If this is NOT the case, then we have a data set with a TILTED GANTRY geometry, // which cannot be simply loaded into a single mitk::Image at the moment. // For this case, we flag this finding in the result and DicomSeriesReader // can correct for that later. Vector3D right; right.Fill(0.0); Vector3D up; right.Fill(0.0); // might be down as well, but it is just a name at this point DICOMStringToOrientationVectors( tagValueMappings[fileIter->c_str()][tagImageOrientation], right, up, ignoredConversionError ); GantryTiltInformation tiltInfo( lastDifferentOrigin, thisOrigin, right, up, 1 ); if ( tiltInfo.IsSheared() ) // mitk::eps is too small; 1/1000 of a mm should be enough to detect tilt { /* optimistic approach, accepting gantry tilt: save file for later, check all further files */ // at this point we have TWO slices analyzed! if they are the only two files, we still split, because there is no third to verify our tilting assumption. // later with a third being available, we must check if the initial tilting vector is still valid. if yes, continue. // if NO, we need to split the already sorted part (result.first) and the currently analyzed file (*fileIter) // tell apart gantry tilt from overall skewedness // sort out irregularly sheared slices, that IS NOT tilting if ( groupImagesWithGantryTilt && tiltInfo.IsRegularGantryTilt() ) { - result.FlagGantryTilt(); - result.AddFileToSortedBlock(*fileIter); // this file is good for current block - fileFitsIntoPattern = true; + // check if this is at least roughly the same angle as recorded in DICOM tags + if ( tagValueMappings[fileIter->c_str()].find(tagGantryTilt) != tagValueMappings[fileIter->c_str()].end() ) + { + // read value, compare to calculated angle + std::string tiltStr = ConstCharStarToString( tagValueMappings[fileIter->c_str()][tagGantryTilt] ); + double angle = atof(tiltStr.c_str()); + + MITK_DEBUG << "Comparing recorded tilt angle " << angle << " against calculated value " << tiltInfo.GetTiltAngleInDegrees(); + // TODO we probably want the signs correct, too + if ( fabs(angle) - tiltInfo.GetTiltAngleInDegrees() > 0.25) + { + result.AddFileToUnsortedBlock( *fileIter ); // sort away for further analysis + fileFitsIntoPattern = false; + } + else // tilt angle from header is less than 0.25 degrees different from what we calculated, assume this is fine + { + result.FlagGantryTilt(); + result.AddFileToSortedBlock(*fileIter); // this file is good for current block + fileFitsIntoPattern = true; + } + } + else // we cannot check the calculated tilt angle against the one from the dicom header (so we assume we are right) + { + result.FlagGantryTilt(); + result.AddFileToSortedBlock(*fileIter); // this file is good for current block + fileFitsIntoPattern = true; + } } - else + else // caller does not want tilt compensation OR shearing is more complicated than tilt { result.AddFileToUnsortedBlock( *fileIter ); // sort away for further analysis fileFitsIntoPattern = false; } } - else + else // not sheared { result.AddFileToSortedBlock(*fileIter); // this file is good for current block fileFitsIntoPattern = true; } } else if (fromFirstToSecondOriginInitialized) // we already know the offset between slices { Point3D assumedOrigin = lastDifferentOrigin + fromFirstToSecondOrigin; Vector3D originError = assumedOrigin - thisOrigin; double norm = originError.GetNorm(); double toleratedError(0.005); // max. 1/10mm error when measurement crosses 20 slices in z direction if (norm > toleratedError) { MITK_DEBUG << " File does not fit into the inter-slice distance pattern (diff = " << norm << ", allowed " << toleratedError << ")."; MITK_DEBUG << " Expected position (" << assumedOrigin[0] << "," << assumedOrigin[1] << "," << assumedOrigin[2] << "), got position (" << thisOrigin[0] << "," << thisOrigin[1] << "," << thisOrigin[2] << ")"; MITK_DEBUG << " ==> Sort away " << *fileIter << " for later analysis"; // At this point we know we deviated from the expectation of ITK's ImageSeriesReader // We split the input file list at this point, i.e. all files up to this one (excluding it) // are returned as group 1, the remaining files (including the faulty one) are group 2 /* Optimistic approach: check if any of the remaining slices fits in */ result.AddFileToUnsortedBlock( *fileIter ); // sort away for further analysis fileFitsIntoPattern = false; } else { result.AddFileToSortedBlock(*fileIter); // this file is good for current block fileFitsIntoPattern = true; } } else // this should be the very first slice { result.AddFileToSortedBlock(*fileIter); // this file is good for current block fileFitsIntoPattern = true; } } // record current origin for reference in later iterations if ( !lastOriginInitialized || ( fileFitsIntoPattern && (thisOrigin != lastOrigin) ) ) { lastDifferentOrigin = thisOrigin; } lastOrigin = thisOrigin; lastOriginInitialized = true; } if ( result.ContainsGantryTilt() ) { // check here how many files were grouped. // IF it was only two files AND we assume tiltedness (e.g. save "distance") // THEN we would want to also split the two previous files (simple) because // we don't have any reason to assume they belong together if ( result.GetBlockFilenames().size() == 2 ) { result.UndoPrematureGrouping(); } } return result; } DicomSeriesReader::UidFileNamesMap DicomSeriesReader::GetSeries(const StringContainer& files, bool groupImagesWithGantryTilt, const StringContainer &restrictions) { return GetSeries(files, true, groupImagesWithGantryTilt, restrictions); } DicomSeriesReader::UidFileNamesMap DicomSeriesReader::GetSeries(const StringContainer& files, bool sortTo3DPlust, bool groupImagesWithGantryTilt, const StringContainer& /*restrictions*/) { /** assumption about this method: returns a map of uid-like-key --> list(filename) each entry should contain filenames that have images of same - series instance uid (automatically done by GDCMSeriesFileNames - 0020,0037 image orientation (patient) - 0028,0030 pixel spacing (x,y) - 0018,0050 slice thickness */ UidFileNamesMap groupsOfSimilarImages; // preliminary result, refined into the final result mapOf3DPlusTBlocks // use GDCM directly, itk::GDCMSeriesFileNames does not work with GDCM 2 // PART I: scan files for sorting relevant DICOM tags, // separate images that differ in any of those // attributes (they cannot possibly form a 3D block) // scan for relevant tags in dicom files gdcm::Scanner scanner; const gdcm::Tag tagSeriesInstanceUID(0x0020,0x000e); // Series Instance UID scanner.AddTag( tagSeriesInstanceUID ); const gdcm::Tag tagImageOrientation(0x0020, 0x0037); // image orientation scanner.AddTag( tagImageOrientation ); const gdcm::Tag tagPixelSpacing(0x0028, 0x0030); // pixel spacing scanner.AddTag( tagPixelSpacing ); const gdcm::Tag tagSliceThickness(0x0018, 0x0050); // slice thickness scanner.AddTag( tagSliceThickness ); const gdcm::Tag tagNumberOfRows(0x0028, 0x0010); // number rows scanner.AddTag( tagNumberOfRows ); const gdcm::Tag tagNumberOfColumns(0x0028, 0x0011); // number cols scanner.AddTag( tagNumberOfColumns ); + const gdcm::Tag tagGantryTilt(0x0018, 0x1120); // gantry tilt + scanner.AddTag( tagGantryTilt ); + // additional tags read in this scan to allow later analysis // THESE tag are not used for initial separating of files const gdcm::Tag tagImagePositionPatient(0x0020,0x0032); // Image Position (Patient) scanner.AddTag( tagImagePositionPatient ); // TODO add further restrictions from arguments // let GDCM scan files if ( !scanner.Scan( files ) ) { MITK_ERROR << "gdcm::Scanner failed when scanning " << files.size() << " input files."; return groupsOfSimilarImages; } // assign files IDs that will separate them for loading into image blocks for (gdcm::Scanner::ConstIterator fileIter = scanner.Begin(); fileIter != scanner.End(); ++fileIter) { //MITK_DEBUG << "Scan file " << fileIter->first << std::endl; if ( std::string(fileIter->first).empty() ) continue; // TODO understand why Scanner has empty string entries if ( std::string(fileIter->first) == std::string("DICOMDIR") ) continue; // we const_cast here, because I could not use a map.at() function in CreateMoreUniqueSeriesIdentifier. // doing the same thing with find would make the code less readable. Since we forget the Scanner results // anyway after this function, we can simply tolerate empty map entries introduced by bad operator[] access std::string moreUniqueSeriesId = CreateMoreUniqueSeriesIdentifier( const_cast(fileIter->second) ); groupsOfSimilarImages [ moreUniqueSeriesId ].push_back( fileIter->first ); } // PART II: sort slices spatially for ( UidFileNamesMap::const_iterator groupIter = groupsOfSimilarImages.begin(); groupIter != groupsOfSimilarImages.end(); ++groupIter ) { try { groupsOfSimilarImages[ groupIter->first ] = SortSeriesSlices( groupIter->second ); // sort each slice group spatially } catch(...) { MITK_ERROR << "Catched something."; } } // PART III: analyze pre-sorted images for valid blocks (i.e. blocks of equal z-spacing), // separate into multiple blocks if necessary. // // Analysis performs the following steps: // * imitate itk::ImageSeriesReader: use the distance between the first two images as z-spacing // * check what images actually fulfill ITK's z-spacing assumption // * separate all images that fail the test into new blocks, re-iterate analysis for these blocks UidFileNamesMap mapOf3DPlusTBlocks; // final result of this function for ( UidFileNamesMap::const_iterator groupIter = groupsOfSimilarImages.begin(); groupIter != groupsOfSimilarImages.end(); ++groupIter ) { UidFileNamesMap mapOf3DBlocks; // intermediate result for only this group(!) std::map mapOf3DBlockAnalysisResults; StringContainer filesStillToAnalyze = groupIter->second; std::string groupUID = groupIter->first; unsigned int subgroup(0); MITK_DEBUG << "Analyze group " << groupUID; while (!filesStillToAnalyze.empty()) // repeat until all files are grouped somehow { SliceGroupingAnalysisResult analysisResult = AnalyzeFileForITKImageSeriesReaderSpacingAssumption( filesStillToAnalyze, groupImagesWithGantryTilt, scanner.GetMappings() ); // enhance the UID for additional groups std::stringstream newGroupUID; newGroupUID << groupUID << '.' << subgroup; mapOf3DBlocks[ newGroupUID.str() ] = analysisResult.GetBlockFilenames(); MITK_DEBUG << "Result: sorted 3D group " << newGroupUID.str() << " with " << mapOf3DBlocks[ newGroupUID.str() ].size() << " files"; ++subgroup; filesStillToAnalyze = analysisResult.GetUnsortedFilenames(); // remember what needs further analysis } // end of grouping, now post-process groups // PART IV: attempt to group blocks to 3D+t blocks if requested // inspect entries of mapOf3DBlocks // - if number of files is identical to previous entry, collect for 3D+t block // - as soon as number of files changes from previous entry, record collected blocks as 3D+t block, start a new one, continue // decide whether or not to group 3D blocks into 3D+t blocks where possible if ( !sortTo3DPlust ) { // copy 3D blocks to output // TODO avoid collisions (or prove impossibility) mapOf3DPlusTBlocks.insert( mapOf3DBlocks.begin(), mapOf3DBlocks.end() ); } else { // sort 3D+t (as described in "PART IV") MITK_DEBUG << "================================================================================"; MITK_DEBUG << "3D+t analysis:"; unsigned int numberOfFilesInPreviousBlock(0); std::string previousBlockKey; for ( UidFileNamesMap::const_iterator block3DIter = mapOf3DBlocks.begin(); block3DIter != mapOf3DBlocks.end(); ++block3DIter ) { unsigned int numberOfFilesInThisBlock = block3DIter->second.size(); std::string thisBlockKey = block3DIter->first; if (numberOfFilesInPreviousBlock == 0) { numberOfFilesInPreviousBlock = numberOfFilesInThisBlock; mapOf3DPlusTBlocks[thisBlockKey].insert( mapOf3DPlusTBlocks[thisBlockKey].end(), block3DIter->second.begin(), block3DIter->second.end() ); - MITK_DEBUG << " 3D+t group " << thisBlockKey << " started"; + MITK_DEBUG << " 3D+t group " << thisBlockKey; previousBlockKey = thisBlockKey; } else { bool identicalOrigins; try { // check whether this and the previous block share a comon origin // TODO should be safe, but a little try/catch or other error handling wouldn't hurt const char *origin_value = scanner.GetValue( mapOf3DBlocks[thisBlockKey].front().c_str(), tagImagePositionPatient ), *previous_origin_value = scanner.GetValue( mapOf3DBlocks[previousBlockKey].front().c_str(), tagImagePositionPatient ), *destination_value = scanner.GetValue( mapOf3DBlocks[thisBlockKey].back().c_str(), tagImagePositionPatient ), *previous_destination_value = scanner.GetValue( mapOf3DBlocks[previousBlockKey].back().c_str(), tagImagePositionPatient ); if (!origin_value || !previous_origin_value || !destination_value || !previous_destination_value) { identicalOrigins = false; } else { std::string thisOriginString = ConstCharStarToString( origin_value ); std::string previousOriginString = ConstCharStarToString( previous_origin_value ); // also compare last origin, because this might differ if z-spacing is different std::string thisDestinationString = ConstCharStarToString( destination_value ); std::string previousDestinationString = ConstCharStarToString( previous_destination_value ); identicalOrigins = ( (thisOriginString == previousOriginString) && (thisDestinationString == previousDestinationString) ); } } catch(...) { identicalOrigins = false; } if (identicalOrigins && (numberOfFilesInPreviousBlock == numberOfFilesInThisBlock)) { // group with previous block mapOf3DPlusTBlocks[previousBlockKey].insert( mapOf3DPlusTBlocks[previousBlockKey].end(), block3DIter->second.begin(), block3DIter->second.end() ); MITK_DEBUG << " --> group enhanced with another timestep"; } else { // start a new block mapOf3DPlusTBlocks[thisBlockKey].insert( mapOf3DPlusTBlocks[thisBlockKey].end(), block3DIter->second.begin(), block3DIter->second.end() ); MITK_DEBUG << " ==> group closed with " << mapOf3DPlusTBlocks[previousBlockKey].size() / numberOfFilesInPreviousBlock << " time steps"; previousBlockKey = thisBlockKey; MITK_DEBUG << " 3D+t group " << thisBlockKey << " started"; } } numberOfFilesInPreviousBlock = numberOfFilesInThisBlock; } } } MITK_DEBUG << "================================================================================"; MITK_DEBUG << "Summary: "; for ( UidFileNamesMap::const_iterator groupIter = mapOf3DPlusTBlocks.begin(); groupIter != mapOf3DPlusTBlocks.end(); ++groupIter ) { - MITK_DEBUG << " Image volume " << groupIter->first << " with " << groupIter->second.size() << " files"; + MITK_DEBUG << " " << groupIter->second.size() << " images in volume " << groupIter->first; } - MITK_DEBUG << "Done. "; MITK_DEBUG << "================================================================================"; return mapOf3DPlusTBlocks; } DicomSeriesReader::UidFileNamesMap DicomSeriesReader::GetSeries(const std::string &dir, bool groupImagesWithGantryTilt, const StringContainer &restrictions) { gdcm::Directory directoryLister; directoryLister.Load( dir.c_str(), false ); // non-recursive return GetSeries(directoryLister.GetFilenames(), groupImagesWithGantryTilt, restrictions); } std::string DicomSeriesReader::CreateSeriesIdentifierPart( gdcm::Scanner::TagToValue& tagValueMap, const gdcm::Tag& tag ) { std::string result; try { result = IDifyTagValue( tagValueMap[ tag ] ? tagValueMap[ tag ] : std::string("") ); } catch (std::exception& e) { MITK_WARN << "Could not access tag " << tag << ": " << e.what(); } return result; } std::string DicomSeriesReader::CreateMoreUniqueSeriesIdentifier( gdcm::Scanner::TagToValue& tagValueMap ) { const gdcm::Tag tagSeriesInstanceUID(0x0020,0x000e); // Series Instance UID const gdcm::Tag tagImageOrientation(0x0020, 0x0037); // image orientation const gdcm::Tag tagPixelSpacing(0x0028, 0x0030); // pixel spacing const gdcm::Tag tagSliceThickness(0x0018, 0x0050); // slice thickness const gdcm::Tag tagNumberOfRows(0x0028, 0x0010); // number rows const gdcm::Tag tagNumberOfColumns(0x0028, 0x0011); // number cols const char* tagSeriesInstanceUid = tagValueMap[tagSeriesInstanceUID]; if (!tagSeriesInstanceUid) { mitkThrow() << "CreateMoreUniqueSeriesIdentifier() could not access series instance UID. Something is seriously wrong with this image, so stopping here."; } std::string constructedID = tagSeriesInstanceUid; constructedID += CreateSeriesIdentifierPart( tagValueMap, tagNumberOfRows ); constructedID += CreateSeriesIdentifierPart( tagValueMap, tagNumberOfColumns ); constructedID += CreateSeriesIdentifierPart( tagValueMap, tagPixelSpacing ); constructedID += CreateSeriesIdentifierPart( tagValueMap, tagSliceThickness ); // be a bit tolerant for orienatation, let only the first few digits matter (http://bugs.mitk.org/show_bug.cgi?id=12263) // NOT constructedID += CreateSeriesIdentifierPart( tagValueMap, tagImageOrientation ); if (tagValueMap.find(tagImageOrientation) != tagValueMap.end()) { bool conversionError(false); Vector3D right; right.Fill(0.0); Vector3D up; right.Fill(0.0); DICOMStringToOrientationVectors( tagValueMap[tagImageOrientation], right, up, conversionError ); //string newstring sprintf(simplifiedOrientationString, "%.3f\\%.3f\\%.3f\\%.3f\\%.3f\\%.3f", right[0], right[1], right[2], up[0], up[1], up[2]); std::ostringstream ss; ss.setf(std::ios::fixed, std::ios::floatfield); ss.precision(5); ss << right[0] << "\\" << right[1] << "\\" << right[2] << "\\" << up[0] << "\\" << up[1] << "\\" << up[2]; std::string simplifiedOrientationString(ss.str()); constructedID += IDifyTagValue( simplifiedOrientationString ); } constructedID.resize( constructedID.length() - 1 ); // cut of trailing '.' return constructedID; } std::string DicomSeriesReader::IDifyTagValue(const std::string& value) { std::string IDifiedValue( value ); if (value.empty()) throw std::logic_error("IDifyTagValue() illegaly called with empty tag value"); // Eliminate non-alnum characters, including whitespace... // that may have been introduced by concats. for(std::size_t i=0; i= 'a' && IDifiedValue[i] <= 'z') || (IDifiedValue[i] >= '0' && IDifiedValue[i] <= '9') || (IDifiedValue[i] >= 'A' && IDifiedValue[i] <= 'Z'))) { IDifiedValue.erase(i, 1); } } IDifiedValue += "."; return IDifiedValue; } DicomSeriesReader::StringContainer DicomSeriesReader::GetSeries(const std::string &dir, const std::string &series_uid, bool groupImagesWithGantryTilt, const StringContainer &restrictions) { UidFileNamesMap allSeries = GetSeries(dir, groupImagesWithGantryTilt, restrictions); StringContainer resultingFileList; for ( UidFileNamesMap::const_iterator idIter = allSeries.begin(); idIter != allSeries.end(); ++idIter ) { if ( idIter->first.find( series_uid ) == 0 ) // this ID starts with given series_uid { resultingFileList.insert( resultingFileList.end(), idIter->second.begin(), idIter->second.end() ); // append } } return resultingFileList; } DicomSeriesReader::StringContainer DicomSeriesReader::SortSeriesSlices(const StringContainer &unsortedFilenames) { gdcm::Sorter sorter; sorter.SetSortFunction(DicomSeriesReader::GdcmSortFunction); try { sorter.Sort(unsortedFilenames); return sorter.GetFilenames(); } catch(std::logic_error&) { MITK_WARN << "Sorting error. Leaving series unsorted."; return unsortedFilenames; } } bool DicomSeriesReader::GdcmSortFunction(const gdcm::DataSet &ds1, const gdcm::DataSet &ds2) { // make sure we have Image Position and Orientation if ( ! ( ds1.FindDataElement(gdcm::Tag(0x0020,0x0032)) && ds1.FindDataElement(gdcm::Tag(0x0020,0x0037)) && ds2.FindDataElement(gdcm::Tag(0x0020,0x0032)) && ds2.FindDataElement(gdcm::Tag(0x0020,0x0037)) ) ) { MITK_WARN << "Dicom images are missing attributes for a meaningful sorting."; throw std::logic_error("Dicom images are missing attributes for a meaningful sorting."); } gdcm::Attribute<0x0020,0x0032> image_pos1; // Image Position (Patient) gdcm::Attribute<0x0020,0x0037> image_orientation1; // Image Orientation (Patient) image_pos1.Set(ds1); image_orientation1.Set(ds1); gdcm::Attribute<0x0020,0x0032> image_pos2; gdcm::Attribute<0x0020,0x0037> image_orientation2; image_pos2.Set(ds2); image_orientation2.Set(ds2); /* we tolerate very small differences in image orientation, since we got to know about acquisitions where these values change across a single series (7th decimal digit) (http://bugs.mitk.org/show_bug.cgi?id=12263) still, we want to check if our assumption of 'almost equal' orientations is valid */ for (unsigned int dim = 0; dim < 6; ++dim) { if ( fabs(image_orientation2[dim] - image_orientation1[dim]) > 0.0001 ) { MITK_ERROR << "Dicom images have different orientations."; throw std::logic_error("Dicom images have different orientations. Call GetSeries() first to separate images."); } } double normal[3]; normal[0] = image_orientation1[1] * image_orientation1[5] - image_orientation1[2] * image_orientation1[4]; normal[1] = image_orientation1[2] * image_orientation1[3] - image_orientation1[0] * image_orientation1[5]; normal[2] = image_orientation1[0] * image_orientation1[4] - image_orientation1[1] * image_orientation1[3]; double dist1 = 0.0, dist2 = 0.0; for (unsigned char i = 0u; i < 3u; ++i) { dist1 += normal[i] * image_pos1[i]; dist2 += normal[i] * image_pos2[i]; } if ( fabs(dist1 - dist2) < mitk::eps) { - gdcm::Attribute<0x0008,0x0032> acq_time1; // Acquisition time (may be missing, so we check existence first) - gdcm::Attribute<0x0008,0x0032> acq_time2; - gdcm::Attribute<0x0020,0x0012> acq_number1; // Acquisition number (may also be missing, so we check existence first) gdcm::Attribute<0x0020,0x0012> acq_number2; - if (ds1.FindDataElement(gdcm::Tag(0x0008,0x0032)) && ds2.FindDataElement(gdcm::Tag(0x0008,0x0032))) - { - acq_time1.Set(ds1); - acq_time2.Set(ds2); + gdcm::Attribute<0x0008,0x0032> acq_time1; // Acquisition time (may be missing, so we check existence first) + gdcm::Attribute<0x0008,0x0032> acq_time2; - return acq_time1 < acq_time2; - } - else if (ds1.FindDataElement(gdcm::Tag(0x0020,0x0012)) && ds2.FindDataElement(gdcm::Tag(0x0020,0x0012))) + gdcm::Attribute<0x0018,0x1060> trg_time1; // Trigger time (may be missing, so we check existence first) + gdcm::Attribute<0x0018,0x1060> trg_time2; + + if (ds1.FindDataElement(gdcm::Tag(0x0020,0x0012)) && ds2.FindDataElement(gdcm::Tag(0x0020,0x0012))) { acq_number1.Set(ds1); acq_number2.Set(ds2); + if (acq_number1 == acq_number2) + { + if (ds1.FindDataElement(gdcm::Tag(0x0008,0x0032)) && ds2.FindDataElement(gdcm::Tag(0x0008,0x0032))) + { + acq_time1.Set(ds1); + acq_time2.Set(ds2); + + if (acq_time1 == acq_time2) + { + if (ds1.FindDataElement(gdcm::Tag(0x0018,0x1060)) && ds2.FindDataElement(gdcm::Tag(0x0018,0x1060))) + { + trg_time1.Set(ds1); + trg_time2.Set(ds2); + + return trg_time1 < trg_time2; + } + } + + return acq_time1 < acq_time2; + } + } + return acq_number1 < acq_number2; } else { // we need some reproducible sort criteria here gdcm::Attribute<0x0008,0x0018> sop_uid1; // SOP instance UID, mandatory gdcm::Attribute<0x0008,0x0018> sop_uid2; sop_uid1.Set(ds1); sop_uid2.Set(ds2); return sop_uid1 < sop_uid2; } } else { // default: compare position return dist1 < dist2; } } std::string DicomSeriesReader::GetConfigurationString() { std::stringstream configuration; configuration << "MITK_USE_GDCMIO: "; configuration << "true"; configuration << "\n"; configuration << "GDCM_VERSION: "; #ifdef GDCM_MAJOR_VERSION configuration << GDCM_VERSION; #endif //configuration << "\n"; return configuration.str(); } void DicomSeriesReader::CopyMetaDataToImageProperties(StringContainer filenames, const gdcm::Scanner::MappingType &tagValueMappings_, DcmIoType *io, Image *image) { std::list imageBlock; imageBlock.push_back(filenames); CopyMetaDataToImageProperties(imageBlock, tagValueMappings_, io, image); } void DicomSeriesReader::CopyMetaDataToImageProperties( std::list imageBlock, const gdcm::Scanner::MappingType& tagValueMappings_, DcmIoType* io, Image* image) { if (!io || !image) return; StringLookupTable filesForSlices; StringLookupTable sliceLocationForSlices; StringLookupTable instanceNumberForSlices; StringLookupTable SOPInstanceNumberForSlices; gdcm::Scanner::MappingType& tagValueMappings = const_cast(tagValueMappings_); //DICOM tags which should be added to the image properties const gdcm::Tag tagSliceLocation(0x0020, 0x1041); // slice location const gdcm::Tag tagInstanceNumber(0x0020, 0x0013); // (image) instance number const gdcm::Tag tagSOPInstanceNumber(0x0008, 0x0018); // SOP instance number unsigned int timeStep(0); std::string propertyKeySliceLocation = "dicom.image.0020.1041"; std::string propertyKeyInstanceNumber = "dicom.image.0020.0013"; std::string propertyKeySOPInstanceNumber = "dicom.image.0008.0018"; // tags for each image for ( std::list::iterator i = imageBlock.begin(); i != imageBlock.end(); i++, timeStep++ ) { const StringContainer& files = (*i); unsigned int slice(0); for ( StringContainer::const_iterator fIter = files.begin(); fIter != files.end(); ++fIter, ++slice ) { filesForSlices.SetTableValue( slice, *fIter ); gdcm::Scanner::TagToValue tagValueMapForFile = tagValueMappings[fIter->c_str()]; if(tagValueMapForFile.find(tagSliceLocation) != tagValueMapForFile.end()) sliceLocationForSlices.SetTableValue(slice, tagValueMapForFile[tagSliceLocation]); if(tagValueMapForFile.find(tagInstanceNumber) != tagValueMapForFile.end()) instanceNumberForSlices.SetTableValue(slice, tagValueMapForFile[tagInstanceNumber]); if(tagValueMapForFile.find(tagSOPInstanceNumber) != tagValueMapForFile.end()) SOPInstanceNumberForSlices.SetTableValue(slice, tagValueMapForFile[tagSOPInstanceNumber]); } image->SetProperty( "files", StringLookupTableProperty::New( filesForSlices ) ); //If more than one time step add postfix ".t" + timestep if(timeStep != 0) { propertyKeySliceLocation.append(".t" + timeStep); propertyKeyInstanceNumber.append(".t" + timeStep); propertyKeySOPInstanceNumber.append(".t" + timeStep); } image->SetProperty( propertyKeySliceLocation.c_str(), StringLookupTableProperty::New( sliceLocationForSlices ) ); image->SetProperty( propertyKeyInstanceNumber.c_str(), StringLookupTableProperty::New( instanceNumberForSlices ) ); image->SetProperty( propertyKeySOPInstanceNumber.c_str(), StringLookupTableProperty::New( SOPInstanceNumberForSlices ) ); } // Copy tags for series, study, patient level (leave interpretation to application). // These properties will be copied to the DataNode by DicomSeriesReader. // tags for the series (we just use the one that ITK copied to its dictionary (proably that of the last slice) const itk::MetaDataDictionary& dict = io->GetMetaDataDictionary(); const TagToPropertyMapType& propertyLookup = DicomSeriesReader::GetDICOMTagsToMITKPropertyMap(); itk::MetaDataDictionary::ConstIterator dictIter = dict.Begin(); while ( dictIter != dict.End() ) { //MITK_DEBUG << "Key " << dictIter->first; std::string value; if ( itk::ExposeMetaData( dict, dictIter->first, value ) ) { //MITK_DEBUG << "Value " << value; TagToPropertyMapType::const_iterator valuePosition = propertyLookup.find( dictIter->first ); if ( valuePosition != propertyLookup.end() ) { std::string propertyKey = valuePosition->second; //MITK_DEBUG << "--> " << propertyKey; image->SetProperty( propertyKey.c_str(), StringProperty::New(value) ); } } else { MITK_WARN << "Tag " << dictIter->first << " not read as string as expected. Ignoring..." ; } ++dictIter; } } } // end namespace mitk #include diff --git a/Core/Code/IO/mitkDicomSeriesReader.h b/Core/Code/IO/mitkDicomSeriesReader.h index d7484fb62d..8acc5023d2 100644 --- a/Core/Code/IO/mitkDicomSeriesReader.h +++ b/Core/Code/IO/mitkDicomSeriesReader.h @@ -1,687 +1,744 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 mitkDicomSeriesReader_h #define mitkDicomSeriesReader_h #include "mitkDataNode.h" #include "mitkConfig.h" #include #include #include #ifdef NOMINMAX # define DEF_NOMINMAX # undef NOMINMAX #endif #include #ifdef DEF_NOMINMAX # ifndef NOMINMAX # define NOMINMAX # endif # undef DEF_NOMINMAX #endif #include #include #include #include #include #include namespace mitk { /** \brief Loading DICOM images as MITK images. - \ref DicomSeriesReader_purpose - \ref DicomSeriesReader_limitations - \ref DicomSeriesReader_usage - \ref DicomSeriesReader_sorting - \ref DicomSeriesReader_sorting1 - \ref DicomSeriesReader_sorting2 - \ref DicomSeriesReader_sorting3 - \ref DicomSeriesReader_sorting4 - \ref DicomSeriesReader_tests \section DicomSeriesReader_purpose Purpose DicomSeriesReader serves as a central class for loading DICOM images as mitk::Image. As the term "DICOM image" covers a huge variety of possible modalities and implementations, and since MITK assumes that 3D images are made up of continuous blocks of slices without any gaps or changes in orientation, the loading mechanism must implement a number of decisions and compromises. The main intention of this implementation is not efficiency but correcness of generated slice positions! \section DicomSeriesReader_limitations Assumptions and limitations The class is working only with GDCM 2.0.14 (or possibly newer). This version is the default of an MITK super-build. Support for other versions or ITK's DicomIO was dropped because of the associated complexity of DicomSeriesReader. \b Assumptions - expected to work for SOP Classes CT Image Storage and MR Image Storage (NOT for the "Enhanced" variants containing multi-frame images) - special treatment for a certain type of Philips 3D ultrasound (recogized by tag 3001,0010 set to "Philips3D") - loader will always attempt to read multiple single slices as a single 3D image volume (i.e. mitk::Image) - slices will be grouped by basic properties such as orientation, rows, columns, spacing and grouped into as large blocks as possible \b Options - images that cover the same piece of space (i.e. position, orientation, and dimensions are equal) can be interpreted as time-steps of the same image, i.e. a series will be loaded as 3D+t \b Limitations - the 3D+t assumption only works if all time-steps have an equal number of slices and if all have the Acquisition Time attribute set to meaningful values - Images from tilted CT gantries CAN ONLY be loaded as a series of single-slice images, since mitk::Image or the accompanying mapper are not (yet?) capable of representing such geometries - Secondary Capture images are expected to have the (0018,2010) tag describing the pixel spacing. If only the (0028,0030) tag is set, the spacing will be misinterpreted as (1,1) \section DicomSeriesReader_usage Usage The starting point for an application is a set of DICOM files that should be loaded. For convenience, DicomSeriesReader can also parse a whole directory for DICOM files, but an application should better know exactly what to load. Loading is then done in two steps: 1. Group the files into spatial blocks by calling GetSeries(). This method will sort all passed files into meaningful blocks that could fit into an mitk::Image. Sorting for 3D+t loading is optional but default. The \b return value of this function is a list of identifiers similar to DICOM UIDs, each associated to a sorted list of file names. 2. Load a sorted set of files by calling LoadDicomSeries(). This method expects go receive the sorting output of GetSeries(). The method will then invoke ITK methods to actually load the files into memory and put them into mitk::Images. Again, loading as 3D+t is optional. Example: \code // only a directory is known at this point: /home/who/dicom DicomSeriesReader::UidFileNamesMap allImageBlocks = DicomSeriesReader::GetSeries("/home/who/dicom/"); // file now divided into groups of identical image size, orientation, spacing, etc. // each of these lists should be loadable as an mitk::Image. DicomSeriesReader::StringContainer seriesToLoad = allImageBlocks[...]; // decide what to load // final step: load into DataNode (can result in 3D+t image) DataNode::Pointer node = DicomSeriesReader::LoadDicomSeries( oneBlockSorted ); Image::Pointer image = dynamic_cast( node->GetData() ); \endcode \section DicomSeriesReader_sorting Logic for sorting 2D slices from DICOM images into 3D+t blocks for mitk::Image The general sorting mechanism (implemented in GetSeries) groups and sorts a set of DICOM files, each assumed to contain a single CT/MR slice. In the following we refer to those file groups as "blocks", since this is what they are meant to become when loaded into an mitk::Image. \subsection DicomSeriesReader_sorting1 Step 1: Avoiding pure non-sense A first pass separates slices that cannot possibly be loaded together because of restrictions of mitk::Image. After this steps, each block contains only slices that match in all of the following DICOM tags: - (0020,0037) Image Orientation - (0028,0030) Pixel Spacing - (0018,0050) Slice Thickness - (0028,0010) Number Of Rows - (0028,0011) Number Of Columns - (0020,000e) Series Instance UID : could be argued about, might be dropped in the future (optionally) \subsection DicomSeriesReader_sorting2 Step 2: Sort slices spatially Before slices are further analyzed, they are sorted spatially. As implemented by GdcmSortFunction(), slices are sorted by 1. distance from origin (calculated using (0020,0032) Image Position Patient and (0020,0037) Image Orientation) - 2. when distance is equal, (0008,0032) Acquisition Time is used as a backup criterion (necessary for meaningful 3D+t sorting) + 2. when distance is equal, (0020,0012) Aquisition Number, (0008,0032) Acquisition Time and (0018,1060) Trigger Time are + used as a backup criterions (necessary for meaningful 3D+t sorting) \subsection DicomSeriesReader_sorting3 Step 3: Ensure equal z spacing Since inter-slice distance is not recorded in DICOM tags, we must ensure that blocks are made up of slices that have equal distances between neighboring slices. This is especially necessary because itk::ImageSeriesReader is later used for the actual loading, and this class expects (and does nocht verify) equal inter-slice distance. To achieve such grouping, the inter-slice distance is calculated from the first two different slice positions of a block. Following slices are added to a block as long as they can be added by adding the calculated inter-slice distance to the last slice of the block. Slices that do not fit into the expected distance pattern, are set aside for further analysis. This grouping is done until each file has been assigned to a group. Slices that share a position in space are also sorted into separate blocks during this step. So the result of this step is a set of blocks that contain only slices with equal z spacing and uniqe slices at each position. \subsection DicomSeriesReader_sorting4 Step 4 (optional): group 3D blocks as 3D+t when possible This last step depends on an option of GetSeries(). When requested, image blocks from the previous step are merged again whenever two blocks occupy the same portion of space (i.e. same origin, number of slices and z-spacing). \section DicomSeriesReader_gantrytilt Handling of gantry tilt When CT gantry tilt is used, the gantry plane (= X-Ray source and detector ring) and the vertical plane do not align anymore. This scanner feature is used for example to reduce metal artifacs (e.g. Lee C , Evaluation of Using CT Gantry Tilt Scan on Head and Neck Cancer Patients with Dental Structure: Scans Show Less Metal Artifacts. Presented at: Radiological Society of North America 2011 Scientific Assembly and Annual Meeting; November 27- December 2, 2011 Chicago IL.). The acquired planes of such CT series do not match the expectations of a orthogonal geometry in mitk::Image: if you stack the slices, they show a small shift along the Y axis: \verbatim without tilt with tilt |||||| ////// |||||| ////// -- |||||| --------- ////// -------- table orientation |||||| ////// |||||| ////// Stacked slices: without tilt with tilt -------------- -------------- -------------- -------------- -------------- -------------- -------------- -------------- -------------- -------------- \endverbatim As such gemetries do not in conjunction with mitk::Image, DicomSeriesReader performs a correction for such series if the groupImagesWithGantryTilt or correctGantryTilt flag in GetSeries and LoadDicomSeries is set (default = on). The correction algorithms undoes two errors introduced by ITK's ImageSeriesReader: - the plane shift that is ignored by ITK's reader is recreated by applying a shearing transformation using itk::ResampleFilter. - the spacing is corrected (it is calculated by ITK's reader from the distance between two origins, which is NOT the slice distance in this special case) Both errors are introduced in itkImageSeriesReader.txx (ImageSeriesReader::GenerateOutputInformation(void)), lines 176 to 245 (as of ITK 3.20) - For the correction, we examine two slices of a series, both described as a pair (origin/orientation): - - we calculate if the second origin is on a line along the normal of the first slice + For the correction, we examine two consecutive slices of a series, both described as a pair (origin/orientation): + - we calculate if the first origin is on a line along the normal of the second slice - if this is not the case, the geometry will not fit a normal mitk::Image/mitk::Geometry3D - we then project the second origin into the first slice's coordinate system to quantify the shift - both is done in class GantryTiltInformation with quite some comments. + + The geometry of image stacks with tilted geometries is illustrated below: + - green: the DICOM images as described by their tags: origin as a point with the line indicating the orientation + - red: the output of ITK ImageSeriesReader: wrong, larger spacing, no tilt + - blue: how much a shear must correct + + \image tilt-correction.jpg \section DicomSeriesReader_whynotinitk Why is this not in ITK? Some of this code would probably be better located in ITK. It is just a matter of resources that this is not the case yet. Any attempts into this direction are welcome and can be supported. At least the gantry tilt correction should be a simple addition to itk::ImageSeriesReader. \section DicomSeriesReader_tests Tests regarding DICOM loading A number of tests have been implemented to check our assumptions regarding DICOM loading. Please see \ref DICOMTesting \todo refactor all the protected helper objects/methods into a separate header so we compile faster */ class MITK_CORE_EXPORT DicomSeriesReader { public: /** \brief Lists of filenames. */ typedef std::vector StringContainer; /** \brief For grouped lists of filenames, assigned an ID each. */ typedef std::map UidFileNamesMap; /** \brief Interface for the progress callback. */ typedef void (*UpdateCallBackMethod)(float); /** \brief Provide combination of preprocessor defines that was active during compilation. Since this class is a combination of several possible implementations, separated only by ifdef's, calling instances might want to know which flags were active at compile time. */ static std::string GetConfigurationString(); /** \brief Checks if a specific file contains DICOM data. */ static bool IsDicom(const std::string &filename); /** \brief see other GetSeries(). Find all series (and sub-series -- see details) in a particular directory. */ static UidFileNamesMap GetSeries(const std::string &dir, bool groupImagesWithGantryTilt, const StringContainer &restrictions = StringContainer()); /** \brief see other GetSeries(). \warning Untested, could or could not work. This differs only by having an additional restriction to a single known DICOM series. Internally, it uses the other GetSeries() method. */ static StringContainer GetSeries(const std::string &dir, const std::string &series_uid, bool groupImagesWithGantryTilt, const StringContainer &restrictions = StringContainer()); /** \brief PREFERRED version of this method - scan and sort DICOM files. Parse a list of files for images of DICOM series. For each series, an enumeration of the files contained in it is created. \return The resulting maps UID-like keys (based on Series Instance UID and slice properties) to sorted lists of file names. SeriesInstanceUID will be enhanced to be unique for each set of file names that is later loadable as a single mitk::Image. This implies that Image orientation, slice thickness, pixel spacing, rows, and columns must be the same for each file (i.e. the image slice contained in the file). If this separation logic requires that a SeriesInstanceUID must be made more specialized, it will follow the same logic as itk::GDCMSeriesFileNames to enhance the UID with more digits and dots. Optionally, more tags can be used to separate files into different logical series by setting the restrictions parameter. \warning Adding restrictions is not yet implemented! */ static UidFileNamesMap GetSeries(const StringContainer& files, bool sortTo3DPlust, bool groupImagesWithGantryTilt, const StringContainer &restrictions = StringContainer()); /** \brief See other GetSeries(). Use GetSeries(const StringContainer& files, bool sortTo3DPlust, const StringContainer &restrictions) instead. */ static UidFileNamesMap GetSeries(const StringContainer& files, bool groupImagesWithGantryTilt, const StringContainer &restrictions = StringContainer()); /** Loads a DICOM series composed by the file names enumerated in the file names container. If a callback method is supplied, it will be called after every progress update with a progress value in [0,1]. \param filenames The filenames to load. \param sort Whether files should be sorted spatially (true) or not (false - maybe useful if presorted) \param load4D Whether to load the files as 3D+t (if possible) */ static DataNode::Pointer LoadDicomSeries(const StringContainer &filenames, bool sort = true, bool load4D = true, bool correctGantryTilt = true, UpdateCallBackMethod callback = 0); /** \brief See LoadDicomSeries! Just a slightly different interface. */ static bool LoadDicomSeries(const StringContainer &filenames, DataNode &node, bool sort = true, bool load4D = true, bool correctGantryTilt = true, UpdateCallBackMethod callback = 0); protected: /** \brief Return type of DicomSeriesReader::AnalyzeFileForITKImageSeriesReaderSpacingAssumption. Class contains the grouping result of method DicomSeriesReader::AnalyzeFileForITKImageSeriesReaderSpacingAssumption, which takes as input a number of images, which are all equally oriented and spatially sorted along their normal direction. The result contains of two blocks: a first one is the grouping result, all of those images can be loaded into one image block because they have an equal origin-to-origin distance without any gaps in-between. */ class SliceGroupingAnalysisResult { public: SliceGroupingAnalysisResult(); /** \brief Grouping result, all same origin-to-origin distance w/o gaps. */ StringContainer GetBlockFilenames(); /** \brief Remaining files, which could not be grouped. */ StringContainer GetUnsortedFilenames(); /** \brief Wheter or not the grouped result contain a gantry tilt. */ bool ContainsGantryTilt(); /** \brief Meant for internal use by AnalyzeFileForITKImageSeriesReaderSpacingAssumption only. */ void AddFileToSortedBlock(const std::string& filename); /** \brief Meant for internal use by AnalyzeFileForITKImageSeriesReaderSpacingAssumption only. */ void AddFileToUnsortedBlock(const std::string& filename); /** \brief Meant for internal use by AnalyzeFileForITKImageSeriesReaderSpacingAssumption only. \todo Could make sense to enhance this with an instance of GantryTiltInformation to store the whole result! */ void FlagGantryTilt(); /** \brief Only meaningful for use by AnalyzeFileForITKImageSeriesReaderSpacingAssumption. */ void UndoPrematureGrouping(); protected: StringContainer m_GroupedFiles; StringContainer m_UnsortedFiles; bool m_GantryTilt; }; /** \brief Gantry tilt analysis result. Takes geometry information for two slices of a DICOM series and calculates whether these fit into an orthogonal block or not. If NOT, they can either be the result of an acquisition with gantry tilt OR completly broken by some shearing transformation. - All calculations are done in the constructor, results can then + Most calculations are done in the constructor, results can then be read via the remaining methods. */ class GantryTiltInformation { public: + // two types to avoid any rounding errors + typedef itk::Point Point3Dd; + typedef itk::Vector Vector3Dd; + /** \brief Just so we can create empty instances for assigning results later. */ GantryTiltInformation(); /** \brief THE constructor, which does all the calculations. - See code comments for explanation. + Determining the amount of tilt is done by checking the distances + of origin1 from planes through origin2. Two planes are considered: + - normal vector along normal of slices (right x up): gives the slice distance + - normal vector along orientation vector "up": gives the shift parallel to the plane orientation + + The tilt angle can then be calculated from these distances + + \param origin1 origin of the first slice + \param origin2 origin of the second slice + \param right right/up describe the orientatation of borth slices + \param up right/up describe the orientatation of borth slices + \param numberOfSlicesApart how many slices are the given origins apart (1 for neighboring slices) */ GantryTiltInformation( const Point3D& origin1, const Point3D& origin2, const Vector3D& right, const Vector3D& up, unsigned int numberOfSlicesApart); /** \brief Whether the slices were sheared. + + True if any of the shifts along right or up vector are non-zero. */ bool IsSheared() const; /** \brief Whether the shearing is a gantry tilt or more complicated. + + Gantry tilt will only produce shifts in ONE orientation, not in both. + + Since the correction code currently only coveres one tilt direction + AND we don't know of medical images with two tilt directions, the + loading code wants to check if our assumptions are true. */ bool IsRegularGantryTilt() const; /** - \brief The offset distance in Y direction for each slice (describes the tilt result). + \brief The offset distance in Y direction for each slice in mm (describes the tilt result). */ - ScalarType GetMatrixCoefficientForCorrectionInWorldCoordinates() const; + double GetMatrixCoefficientForCorrectionInWorldCoordinates() const; /** \brief The z / inter-slice spacing. Needed to correct ImageSeriesReader's result. */ - ScalarType GetRealZSpacing() const; + double GetRealZSpacing() const; /** \brief The shift between first and last slice in mm. Needed to resize an orthogonal image volume. */ - ScalarType GetTiltCorrectedAdditionalSize() const; + double GetTiltCorrectedAdditionalSize() const; + + /** + \brief Calculated tilt angle in degrees. + */ + double GetTiltAngleInDegrees() const; protected: /** \brief Projection of point p onto line through lineOrigin in direction of lineDirection. */ - Point3D projectPointOnLine( Point3D p, Point3D lineOrigin, Vector3D lineDirection ); + Point3D projectPointOnLine( Point3Dd p, Point3Dd lineOrigin, Vector3Dd lineDirection ); - ScalarType m_ShiftUp; - ScalarType m_ShiftRight; - ScalarType m_ShiftNormal; + double m_ShiftUp; + double m_ShiftRight; + double m_ShiftNormal; + double m_ITKAssumedSliceSpacing; unsigned int m_NumberOfSlicesApart; }; /** \brief for internal sorting. */ typedef std::pair TwoStringContainers; /** \brief Maps DICOM tags to MITK properties. */ typedef std::map TagToPropertyMapType; /** \brief Ensure an equal z-spacing for a group of files. Takes as input a number of images, which are all equally oriented and spatially sorted along their normal direction. Internally used by GetSeries. Returns two lists: the first one contins slices of equal inter-slice spacing. The second list contains remaining files, which need to be run through AnalyzeFileForITKImageSeriesReaderSpacingAssumption again. Relevant code that is matched here is in itkImageSeriesReader.txx (ImageSeriesReader::GenerateOutputInformation(void)), lines 176 to 245 (as of ITK 3.20) */ static SliceGroupingAnalysisResult AnalyzeFileForITKImageSeriesReaderSpacingAssumption(const StringContainer& files, bool groupsOfSimilarImages, const gdcm::Scanner::MappingType& tagValueMappings_); - + + /** + \brief Safely convert const char* to std::string. + */ static std::string ConstCharStarToString(const char* s); + /** + \brief Convert DICOM string describing a point to Point3D. + + DICOM tags like ImagePositionPatient contain a position as float numbers separated by backslashes: + \verbatim + 42.7131\13.77\0.7 + \endverbatim + */ static Point3D DICOMStringToPoint3D(const std::string& s, bool& successful); + /** + \brief Convert DICOM string describing a point two Vector3D. + + DICOM tags like ImageOrientationPatient contain two vectors as float numbers separated by backslashes: + \verbatim + 42.7131\13.77\0.7\137.76\0.3 + \endverbatim + */ static void DICOMStringToOrientationVectors(const std::string& s, Vector3D& right, Vector3D& up, bool& successful); template static typename ImageType::Pointer + // TODO this is NOT inplace! InPlaceFixUpTiltedGeometry( ImageType* input, const GantryTiltInformation& tiltInfo ); /** \brief Sort a set of file names in an order that is meaningful for loading them into an mitk::Image. \warning This method assumes that input files are similar in basic properties such as slice thicknes, image orientation, pixel spacing, rows, columns. It should always be ok to put the result of a call to GetSeries(..) into this method. Sorting order is determined by 1. image position along its normal (distance from world origin) 2. acquisition time If P denotes a position and T denotes a time step, this method will order slices from three timesteps like this: \verbatim P1T1 P1T2 P1T3 P2T1 P2T2 P2T3 P3T1 P3T2 P3T3 \endverbatim */ static StringContainer SortSeriesSlices(const StringContainer &unsortedFilenames); public: /** \brief Checks if a specific file is a Philips3D ultrasound DICOM file. */ static bool IsPhilips3DDicom(const std::string &filename); protected: /** \brief Read a Philips3D ultrasound DICOM file and put into an mitk::Image. */ static bool ReadPhilips3DDicom(const std::string &filename, mitk::Image::Pointer output_image); /** \brief Construct a UID that takes into account sorting criteria from GetSeries(). */ static std::string CreateMoreUniqueSeriesIdentifier( gdcm::Scanner::TagToValue& tagValueMap ); /** \brief Helper for CreateMoreUniqueSeriesIdentifier */ static std::string CreateSeriesIdentifierPart( gdcm::Scanner::TagToValue& tagValueMap, const gdcm::Tag& tag ); /** \brief Helper for CreateMoreUniqueSeriesIdentifier */ static std::string IDifyTagValue(const std::string& value); typedef itk::GDCMImageIO DcmIoType; /** \brief Progress callback for DicomSeriesReader. */ class CallbackCommand : public itk::Command { public: CallbackCommand(UpdateCallBackMethod callback) : m_Callback(callback) { } void Execute(const itk::Object *caller, const itk::EventObject&) { (*this->m_Callback)(static_cast(caller)->GetProgress()); } void Execute(itk::Object *caller, const itk::EventObject&) { (*this->m_Callback)(static_cast(caller)->GetProgress()); } protected: UpdateCallBackMethod m_Callback; }; /** \brief Scan for slice image information */ static void ScanForSliceInformation( const StringContainer &filenames, gdcm::Scanner& scanner ); /** \brief Performs actual loading of a series and creates an image having the specified pixel type. */ template static void LoadDicom(const StringContainer &filenames, DataNode &node, bool sort, bool check_4d, bool correctTilt, UpdateCallBackMethod callback); /** \brief Feed files into itk::ImageSeriesReader and retrieve a 3D MITK image. \param command can be used for progress reporting */ template static Image::Pointer LoadDICOMByITK( const StringContainer&, bool correctTilt, const GantryTiltInformation& tiltInfo, CallbackCommand* command = NULL); /** \brief Sort files into time step blocks of a 3D+t image. Called by LoadDicom. Expects to be fed a single list of filenames that have been sorted by GetSeries previously (one map entry). This method will check how many timestep can be filled with given files. Assumption is that the number of time steps is determined by how often the first position in space repeats. I.e. if the first three files in the input parameter all describe the same location in space, we'll construct three lists of files. and sort the remaining files into them. \todo We can probably remove this method if we somehow transfer 3D+t information from GetSeries to LoadDicomSeries. */ static std::list SortIntoBlocksFor3DplusT( const StringContainer& presortedFilenames, const gdcm::Scanner::MappingType& tagValueMappings_, bool sort, bool& canLoadAs4D); /** \brief Defines spatial sorting for sorting by GDCM 2. Sorts by image position along image normal (distance from world origin). In cases of conflict, acquisition time is used as a secondary sort criterium. */ static bool GdcmSortFunction(const gdcm::DataSet &ds1, const gdcm::DataSet &ds2); /** \brief Copy information about files and DICOM tags from ITK's MetaDataDictionary and from the list of input files to the PropertyList of mitk::Image. \todo Tag copy must follow; image level will cause some additional files parsing, probably. */ static void CopyMetaDataToImageProperties( StringContainer filenames, const gdcm::Scanner::MappingType& tagValueMappings_, DcmIoType* io, Image* image); static void CopyMetaDataToImageProperties( std::list imageBlock, const gdcm::Scanner::MappingType& tagValueMappings_, DcmIoType* io, Image* image); /** \brief Map between DICOM tags and MITK properties. Uses as a positive list for copying specified DICOM tags (from ITK's ImageIO) to MITK properties. ITK provides MetaDataDictionary entries of form "gggg|eeee" (g = group, e = element), e.g. "0028,0109" (Largest Pixel in Series), which we want to sort as dicom.series.largest_pixel_in_series". */ static const TagToPropertyMapType& GetDICOMTagsToMITKPropertyMap(); }; } -#endif /* MITKDICOMSERIESREADER_H_ */ +#endif /* mitkDicomSeriesReader_h */ diff --git a/Core/Code/IO/mitkDicomSeriesReader.txx b/Core/Code/IO/mitkDicomSeriesReader.txx index 551bfca331..e6a98edf34 100644 --- a/Core/Code/IO/mitkDicomSeriesReader.txx +++ b/Core/Code/IO/mitkDicomSeriesReader.txx @@ -1,489 +1,509 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 MITKDICOMSERIESREADER_TXX_ #define MITKDICOMSERIESREADER_TXX_ #include #include #include #include #include #include #include namespace mitk { template void DicomSeriesReader::LoadDicom(const StringContainer &filenames, DataNode &node, bool sort, bool load4D, bool correctTilt, UpdateCallBackMethod callback) { const char* previousCLocale = setlocale(LC_NUMERIC, NULL); setlocale(LC_NUMERIC, "C"); std::locale previousCppLocale( std::cin.getloc() ); std::locale l( "C" ); std::cin.imbue(l); const gdcm::Tag tagImagePositionPatient(0x0020,0x0032); // Image Position (Patient) const gdcm::Tag tagImageOrientation(0x0020, 0x0037); // Image Orientation try { mitk::Image::Pointer image = mitk::Image::New(); CallbackCommand *command = callback ? new CallbackCommand(callback) : 0; bool initialize_node = false; /* special case for Philips 3D+t ultrasound images */ if ( DicomSeriesReader::IsPhilips3DDicom(filenames.front().c_str()) ) { ReadPhilips3DDicom(filenames.front().c_str(), image); initialize_node = true; } else { /* default case: assume "normal" image blocks, possibly 3D+t */ bool canLoadAs4D(true); gdcm::Scanner scanner; ScanForSliceInformation(filenames, scanner); // need non-const access for map gdcm::Scanner::MappingType& tagValueMappings = const_cast(scanner.GetMappings()); std::list imageBlocks = SortIntoBlocksFor3DplusT( filenames, tagValueMappings, sort, canLoadAs4D ); unsigned int volume_count = imageBlocks.size(); GantryTiltInformation tiltInfo; // check possibility of a single slice with many timesteps. In this case, don't check for tilt, no second slice possible if ( !imageBlocks.empty() && imageBlocks.front().size() > 1 && correctTilt) { // check tiltedness here, potentially fixup ITK's loading result by shifting slice contents // check first and last position slice from tags, make some calculations to detect tilt std::string firstFilename(imageBlocks.front().front()); // calculate from first and last slice to minimize rounding errors std::string secondFilename(imageBlocks.front().back()); std::string imagePosition1( ConstCharStarToString( tagValueMappings[ firstFilename.c_str() ][ tagImagePositionPatient ] ) ); std::string imageOrientation( ConstCharStarToString( tagValueMappings[ firstFilename.c_str() ][ tagImageOrientation ] ) ); std::string imagePosition2( ConstCharStarToString( tagValueMappings[secondFilename.c_str() ][ tagImagePositionPatient ] ) ); bool ignoredConversionError(-42); // hard to get here, no graceful way to react Point3D origin1( DICOMStringToPoint3D( imagePosition1, ignoredConversionError ) ); Point3D origin2( DICOMStringToPoint3D( imagePosition2, ignoredConversionError ) ); Vector3D right; right.Fill(0.0); Vector3D up; right.Fill(0.0); // might be down as well, but it is just a name at this point DICOMStringToOrientationVectors( imageOrientation, right, up, ignoredConversionError ); tiltInfo = GantryTiltInformation ( origin1, origin2, right, up, filenames.size()-1 ); correctTilt = tiltInfo.IsSheared() && tiltInfo.IsRegularGantryTilt(); - - MITK_DEBUG << "** Loading now: shear? " << tiltInfo.IsSheared(); - MITK_DEBUG << "** Loading now: normal tilt? " << tiltInfo.IsRegularGantryTilt(); - MITK_DEBUG << "** Loading now: perform tilt correction? " << correctTilt; } else { correctTilt = false; // we CANNOT do that } if (volume_count == 1 || !canLoadAs4D || !load4D) { image = LoadDICOMByITK( imageBlocks.front(), correctTilt, tiltInfo, command ); // load first 3D block initialize_node = true; } else if (volume_count > 1) { // It is 3D+t! Read it and store into mitk image typedef itk::Image ImageType; typedef itk::ImageSeriesReader ReaderType; DcmIoType::Pointer io = DcmIoType::New(); typename ReaderType::Pointer reader = ReaderType::New(); reader->SetImageIO(io); reader->ReverseOrderOff(); if (command) { reader->AddObserver(itk::ProgressEvent(), command); } unsigned int act_volume = 1u; reader->SetFileNames(imageBlocks.front()); reader->Update(); typename ImageType::Pointer readVolume = reader->GetOutput(); // if we detected that the images are from a tilted gantry acquisition, we need to push some pixels into the right position if (correctTilt) { readVolume = InPlaceFixUpTiltedGeometry( reader->GetOutput(), tiltInfo ); } image->InitializeByItk( readVolume.GetPointer(), 1, volume_count); image->SetImportVolume( readVolume->GetBufferPointer(), 0u); gdcm::Scanner scanner; ScanForSliceInformation(filenames, scanner); DicomSeriesReader::CopyMetaDataToImageProperties( imageBlocks, scanner.GetMappings(), io, image); MITK_DEBUG << "Volume dimension: [" << image->GetDimension(0) << ", " << image->GetDimension(1) << ", " << image->GetDimension(2) << ", " << image->GetDimension(3) << "]"; #if (GDCM_MAJOR_VERSION == 2) && (GDCM_MINOR_VERSION < 1) && (GDCM_BUILD_VERSION < 15) // workaround for a GDCM 2 bug until version 2.0.15: // GDCM read spacing vector wrongly. Instead of "row spacing, column spacing", it misinterprets the DICOM tag as "column spacing, row spacing". // this is undone here, until we use a GDCM that has this issue fixed. // From the commit comments, GDCM 2.0.15 fixed the spacing interpretation with bug 2901181 // http://sourceforge.net/tracker/index.php?func=detail&aid=2901181&group_id=137895&atid=739587 Vector3D correctedImageSpacing = image->GetGeometry()->GetSpacing(); std::swap( correctedImageSpacing[0], correctedImageSpacing[1] ); image->GetGeometry()->SetSpacing( correctedImageSpacing ); #endif MITK_DEBUG << "Volume spacing: [" << image->GetGeometry()->GetSpacing()[0] << ", " << image->GetGeometry()->GetSpacing()[1] << ", " << image->GetGeometry()->GetSpacing()[2] << "]"; for (std::list::iterator df_it = ++imageBlocks.begin(); df_it != imageBlocks.end(); ++df_it) { reader->SetFileNames(*df_it); reader->Update(); readVolume = reader->GetOutput(); if (correctTilt) { readVolume = InPlaceFixUpTiltedGeometry( reader->GetOutput(), tiltInfo ); } image->SetImportVolume(readVolume->GetBufferPointer(), act_volume++); } initialize_node = true; } } if (initialize_node) { // forward some image properties to node node.GetPropertyList()->ConcatenatePropertyList( image->GetPropertyList(), true ); node.SetData( image ); setlocale(LC_NUMERIC, previousCLocale); std::cin.imbue(previousCppLocale); } } catch (std::exception& e) { // reset locale then throw up setlocale(LC_NUMERIC, previousCLocale); std::cin.imbue(previousCppLocale); throw e; } } template Image::Pointer DicomSeriesReader::LoadDICOMByITK( const StringContainer& filenames, bool correctTilt, const GantryTiltInformation& tiltInfo, CallbackCommand* command ) { /******** Normal Case, 3D (also for GDCM < 2 usable) ***************/ mitk::Image::Pointer image = mitk::Image::New(); typedef itk::Image ImageType; typedef itk::ImageSeriesReader ReaderType; DcmIoType::Pointer io = DcmIoType::New(); typename ReaderType::Pointer reader = ReaderType::New(); reader->SetImageIO(io); reader->ReverseOrderOff(); if (command) { reader->AddObserver(itk::ProgressEvent(), command); } reader->SetFileNames(filenames); reader->Update(); typename ImageType::Pointer readVolume = reader->GetOutput(); // if we detected that the images are from a tilted gantry acquisition, we need to push some pixels into the right position if (correctTilt) { readVolume = InPlaceFixUpTiltedGeometry( reader->GetOutput(), tiltInfo ); } image->InitializeByItk(readVolume.GetPointer()); image->SetImportVolume(readVolume->GetBufferPointer()); gdcm::Scanner scanner; ScanForSliceInformation(filenames, scanner); DicomSeriesReader::CopyMetaDataToImageProperties( filenames, scanner.GetMappings(), io, image); MITK_DEBUG << "Volume dimension: [" << image->GetDimension(0) << ", " << image->GetDimension(1) << ", " << image->GetDimension(2) << "]"; #if (GDCM_MAJOR_VERSION == 2) && (GDCM_MINOR_VERSION < 1) && (GDCM_BUILD_VERSION < 15) // workaround for a GDCM 2 bug until version 2.0.15: // GDCM read spacing vector wrongly. Instead of "row spacing, column spacing", it misinterprets the DICOM tag as "column spacing, row spacing". // this is undone here, until we use a GDCM that has this issue fixed. // From the commit comments, GDCM 2.0.15 fixed the spacing interpretation with bug 2901181 // http://sourceforge.net/tracker/index.php?func=detail&aid=2901181&group_id=137895&atid=739587 Vector3D correctedImageSpacing = image->GetGeometry()->GetSpacing(); std::swap( correctedImageSpacing[0], correctedImageSpacing[1] ); image->GetGeometry()->SetSpacing( correctedImageSpacing ); #endif MITK_DEBUG << "Volume spacing: [" << image->GetGeometry()->GetSpacing()[0] << ", " << image->GetGeometry()->GetSpacing()[1] << ", " << image->GetGeometry()->GetSpacing()[2] << "]"; return image; } void DicomSeriesReader::ScanForSliceInformation(const StringContainer &filenames, gdcm::Scanner& scanner) { const gdcm::Tag ippTag(0x0020,0x0032); //Image position (Patient) scanner.AddTag(ippTag); const gdcm::Tag tagImageOrientation(0x0020,0x0037); //Image orientation scanner.AddTag(tagImageOrientation); // TODO what if tags don't exist? const gdcm::Tag tagSliceLocation(0x0020, 0x1041); // slice location scanner.AddTag( tagSliceLocation ); const gdcm::Tag tagInstanceNumber(0x0020, 0x0013); // (image) instance number scanner.AddTag( tagInstanceNumber ); const gdcm::Tag tagSOPInstanceNumber(0x0008, 0x0018); // SOP instance number scanner.AddTag( tagSOPInstanceNumber ); scanner.Scan(filenames); // make available image position for each file } std::list DicomSeriesReader::SortIntoBlocksFor3DplusT( const StringContainer& presortedFilenames, const gdcm::Scanner::MappingType& tagValueMappings, bool /*sort*/, bool& canLoadAs4D ) { std::list imageBlocks; // ignore sort request, because most likely re-sorting is now needed due to changes in GetSeries(bug #8022) StringContainer sorted_filenames = DicomSeriesReader::SortSeriesSlices(presortedFilenames); std::string firstPosition; unsigned int numberOfBlocks(0); // number of 3D image blocks const gdcm::Tag ippTag(0x0020,0x0032); //Image position (Patient) // loop files to determine number of image blocks for (StringContainer::const_iterator fileIter = sorted_filenames.begin(); fileIter != sorted_filenames.end(); ++fileIter) { gdcm::Scanner::TagToValue tagToValueMap = tagValueMappings.find( fileIter->c_str() )->second; if(tagToValueMap.find(ippTag) == tagToValueMap.end()) { continue; } std::string position = tagToValueMap.find(ippTag)->second; MITK_DEBUG << " " << *fileIter << " at " << position; if (firstPosition.empty()) { firstPosition = position; } if ( position == firstPosition ) { ++numberOfBlocks; } else { break; // enough information to know the number of image blocks } } MITK_DEBUG << " ==> Assuming " << numberOfBlocks << " time steps"; if (numberOfBlocks == 0) return imageBlocks; // only possible if called with no files // loop files to sort them into image blocks unsigned int numberOfExpectedSlices(0); for (unsigned int block = 0; block < numberOfBlocks; ++block) { StringContainer filesOfCurrentBlock; for ( StringContainer::const_iterator fileIter = sorted_filenames.begin() + block; fileIter != sorted_filenames.end(); //fileIter += numberOfBlocks) // TODO shouldn't this work? give invalid iterators on first attempts ) { filesOfCurrentBlock.push_back( *fileIter ); for (unsigned int b = 0; b < numberOfBlocks; ++b) { if (fileIter != sorted_filenames.end()) ++fileIter; } } imageBlocks.push_back(filesOfCurrentBlock); if (block == 0) { numberOfExpectedSlices = filesOfCurrentBlock.size(); } else { if (filesOfCurrentBlock.size() != numberOfExpectedSlices) { MITK_WARN << "DicomSeriesReader expected " << numberOfBlocks << " image blocks of " << numberOfExpectedSlices << " images each. Block " << block << " got " << filesOfCurrentBlock.size() << " instead. Cannot load this as 3D+t"; // TODO implement recovery (load as many slices 3D+t as much as possible) canLoadAs4D = false; } } } return imageBlocks; } template typename ImageType::Pointer DicomSeriesReader::InPlaceFixUpTiltedGeometry( ImageType* input, const GantryTiltInformation& tiltInfo ) { typedef itk::ResampleImageFilter ResampleFilterType; typename ResampleFilterType::Pointer resampler = ResampleFilterType::New(); resampler->SetInput( input ); /* Transform for a point is - transform from actual position to index coordinates - apply a shear that undoes the gantry tilt - transform back into world coordinates Anybody who does this in a simpler way: don't forget to write up how and why your solution works */ - typedef itk::AffineTransform< double, ImageType::ImageDimension > TransformType; + typedef itk::ScalableAffineTransform< double, ImageType::ImageDimension > TransformType; typename TransformType::Pointer transformShear = TransformType::New(); /** - What I think should be done here: - - apply a shear and spacing correction to the image block that corrects the ITK reader's error - ITK ignores the shear and loads slices into an orthogonal volume - ITK calculates the spacing from the origin distance, which is more than the actual spacing with gantry tilt images - to undo the effect - we have calculated some information in tiltInfo: - the shift in Y direction that is added with each additional slice is the most important information - the Y-shift is calculated in mm world coordinates - we apply a shearing transformation to the ITK-read image volume - to do this locally, - we transform the image volume back to origin and "normal" orientation by applying the inverse of its transform - - this should bring us into the image's "index coordinate" system + (this brings us into the image's "index coordinate" system) - we apply a shear with the Y-shift factor put into a unit transform at row 1, col 2 - - we probably would need the shift factor in index coordinates but we use mm, which appears strange, see below - - we transform the image volume back to its actual position - - presumably back from index to world coordinates + - we transform the image volume back to its actual position (from index to world coordinates) - we lastly apply modify the image spacing in z direction by replacing this number with the correctly calulcated inter-slice distance - - Here comes the unsolved PROBLEM: - - WHY is it correct to apply the shift factor in millimeters, when we assume we are in a index coordinate system? - - or why is it not millimeters but index coordinates? - - or what else is the wrong assumption here? - - This is a serious question to anybody very firm in transforms, ITK, etc. - - this is also a chocolate reward question. Provide a good explanation with corrected code as a git commit and get it. */ - // ScalarType factor = tiltInfo.GetMatrixCoefficientForCorrectionInWorldCoordinates() / input->GetSpacing()[1]; - ScalarType factor = tiltInfo.GetMatrixCoefficientForCorrectionInWorldCoordinates(); + ScalarType factor = tiltInfo.GetMatrixCoefficientForCorrectionInWorldCoordinates() / input->GetSpacing()[1]; // row 1, column 2 corrects shear in parallel to Y axis, proportional to distance in Z direction transformShear->Shear( 1, 2, factor ); typename TransformType::Pointer imageIndexToWorld = TransformType::New(); imageIndexToWorld->SetOffset( input->GetOrigin().GetVectorFromOrigin() ); - imageIndexToWorld->SetMatrix( input->GetDirection() ); + + typename TransformType::MatrixType indexToWorldMatrix; + indexToWorldMatrix = input->GetDirection(); + + typename ImageType::DirectionType scale; + for ( unsigned int i = 0; i < ImageType::ImageDimension; i++ ) + { + scale[i][i] = input->GetSpacing()[i]; + } + indexToWorldMatrix *= scale; + + imageIndexToWorld->SetMatrix( indexToWorldMatrix ); typename TransformType::Pointer imageWorldToIndex = TransformType::New(); imageIndexToWorld->GetInverse( imageWorldToIndex ); typename TransformType::Pointer gantryTiltCorrection = TransformType::New(); gantryTiltCorrection->Compose( imageWorldToIndex ); gantryTiltCorrection->Compose( transformShear ); gantryTiltCorrection->Compose( imageIndexToWorld ); resampler->SetTransform( gantryTiltCorrection ); typedef itk::LinearInterpolateImageFunction< ImageType, double > InterpolatorType; typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); resampler->SetInterpolator( interpolator ); /* This would be the right place to invent a meaningful value for positions outside of the image. For CT, HU -1000 might be meaningful, but a general solution seems not possible. Even for CT, -1000 would only look natural for many not all images. */ resampler->SetDefaultPixelValue( std::numeric_limits::min() ); // adjust size in Y direction! (maybe just transform the outer last pixel to see how much space we would need resampler->SetOutputParametersFromImage( input ); // we basically need the same image again, just sheared + + // if tilt positive, then we need additional pixels BELOW origin, otherwise we need pixels behind the end of the block + + // in any case we need more size to accomodate shifted slices typename ImageType::SizeType largerSize = resampler->GetSize(); // now the resampler already holds the input image's size. - largerSize[1] += static_cast(tiltInfo.GetTiltCorrectedAdditionalSize()); + largerSize[1] += static_cast(tiltInfo.GetTiltCorrectedAdditionalSize() / input->GetSpacing()[1]+ 2.0); resampler->SetSize( largerSize ); + // in SOME cases this additional size is below/behind origin + if ( tiltInfo.GetMatrixCoefficientForCorrectionInWorldCoordinates() > 0.0 ) + { + typename ImageType::DirectionType imageDirection = input->GetDirection(); + Vector3D yDirection; + yDirection[0] = imageDirection[0][1]; + yDirection[1] = imageDirection[1][1]; + yDirection[2] = imageDirection[2][1]; + yDirection.Normalize(); + + typename ImageType::PointType shiftedOrigin; + shiftedOrigin = input->GetOrigin(); + + // add some pixels to make everything fit + shiftedOrigin[0] -= yDirection[0] * (tiltInfo.GetTiltCorrectedAdditionalSize() + 1.0 * input->GetSpacing()[1]); + shiftedOrigin[1] -= yDirection[1] * (tiltInfo.GetTiltCorrectedAdditionalSize() + 1.0 * input->GetSpacing()[1]); + shiftedOrigin[2] -= yDirection[2] * (tiltInfo.GetTiltCorrectedAdditionalSize() + 1.0 * input->GetSpacing()[1]); + + resampler->SetOutputOrigin( shiftedOrigin ); + } + resampler->Update(); typename ImageType::Pointer result = resampler->GetOutput(); // ImageSeriesReader calculates z spacing as the distance between the first two origins. // This is not correct in case of gantry tilt, so we set our calculated spacing. typename ImageType::SpacingType correctedSpacing = result->GetSpacing(); correctedSpacing[2] = tiltInfo.GetRealZSpacing(); result->SetSpacing( correctedSpacing ); return result; } } #endif diff --git a/Core/Code/IO/mitkImageGenerator.h b/Core/Code/IO/mitkImageGenerator.h index 16b4e0e0b4..60b4fb77ee 100644 --- a/Core/Code/IO/mitkImageGenerator.h +++ b/Core/Code/IO/mitkImageGenerator.h @@ -1,115 +1,117 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 ImageGenerator_H_HEADER_INCLUDED #define ImageGenerator_H_HEADER_INCLUDED #include #include #include namespace mitk { //##Documentation //## @brief generator for random MITK images //## This is a helper class to generate MITK images filled with random values. //## The parameters dimX, dimY, dimZ, and dimT are used to set the dimensions of the MITK image. //## Default parameters are dimT = 1 and dimZ = 1 which is a 2D image (or a 4D image with just 1 slice and 1 time step). //## The parameters randomMax and randomMin are boundary values for the random generator. //## In other words: the generator will generate values between randomMin and randomMax. //## @ingroup IO class MITK_CORE_EXPORT ImageGenerator { public: template static mitk::Image::Pointer GenerateRandomImage(unsigned int dimX, unsigned int dimY, unsigned int dimZ = 1, unsigned int dimT = 1, const double randomMax = 1000.0f, const double randMin = 0.0f) { //set the data type according to the template mitk::PixelType type = MakeScalarPixelType(); //type.Initialize(typeid(TPixelType)); //initialize the MITK image with given dimenion and data type mitk::Image::Pointer output = mitk::Image::New(); unsigned int* dimensions = new unsigned int[4]; unsigned int numberOfDimensions = 0; unsigned int bufferSize = 0; //check which dimension is needed if(dimT <= 1) { if(dimZ <= 1) { //2D numberOfDimensions = 2; dimensions[0] = dimX; dimensions[1] = dimY; bufferSize = dimX*dimY; } else { //3D numberOfDimensions = 3; dimensions[0] = dimX; dimensions[1] = dimY; dimensions[2] = dimZ; bufferSize = dimX*dimY*dimZ; } } else { //4D numberOfDimensions = 4; dimensions[0] = dimX; dimensions[1] = dimY; dimensions[2] = dimZ; dimensions[3] = dimT; bufferSize = dimX*dimY*dimZ*dimT; } output->Initialize(type, numberOfDimensions, dimensions); //get a pointer to the image buffer to write into TPixelType* imageBuffer = (TPixelType*)output->GetData(); //initialize the random generator itk::Statistics::MersenneTwisterRandomVariateGenerator::Pointer randomGenerator = itk::Statistics::MersenneTwisterRandomVariateGenerator::New(); randomGenerator->Initialize(); //fill the buffer for each pixel/voxel for(unsigned int i = 0; i < bufferSize; i++) { - if(type == typeid(int)) //call integer function + // the comparison of the component type is sufficient enough since the mitk::PixelType type object is + // created as SCALAR and hence does not need the comparison against type.GetPixelTypeId() == itk::ImageIOBase::SCALAR + if(type.GetTypeId() == typeid(int)) //call integer function { imageBuffer[i] = (TPixelType)randomGenerator->GetIntegerVariate((int)randomMax); //TODO random generator does not support integer values in a given range (e.g. from 5-10) //range is always [0, (int)randomMax] - }else if((type == typeid(double)) || (type == typeid(float))) //call integer function + }else if((type.GetTypeId() == typeid(double)) || (type.GetTypeId() == typeid(float))) //call integer function { imageBuffer[i] = (TPixelType)randomGenerator->GetUniformVariate(randMin,randomMax); - }else if(type == typeid(unsigned char)) + }else if(type.GetTypeId() == typeid(unsigned char)) { //use the integer randomGenerator with mod 256 to generate unsigned char values imageBuffer[i] = (unsigned char) ((int)randomGenerator->GetIntegerVariate((int)randomMax)) % 256; }else{ MITK_ERROR << "Datatype not supported yet."; //TODO call different methods for other datatypes } } return output; } }; } // namespace mitk #endif /* ImageGenerator_H_HEADER_INCLUDED */ diff --git a/Core/Code/IO/mitkImageWriter.cpp b/Core/Code/IO/mitkImageWriter.cpp index 1947b83483..566b181a1d 100644 --- a/Core/Code/IO/mitkImageWriter.cpp +++ b/Core/Code/IO/mitkImageWriter.cpp @@ -1,378 +1,381 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkImageWriter.h" #include "mitkItkPictureWrite.h" #include "mitkImage.h" #include "mitkImageTimeSelector.h" #include "mitkImageAccessByItk.h" #include #include mitk::ImageWriter::ImageWriter() { this->SetNumberOfRequiredInputs( 1 ); m_MimeType = ""; SetDefaultExtension(); } mitk::ImageWriter::~ImageWriter() { } void mitk::ImageWriter::SetDefaultExtension() { m_Extension = ".mhd"; } #include #include #include static void writeVti(const char * filename, mitk::Image* image, int t=0) { vtkXMLImageDataWriter * vtkwriter = vtkXMLImageDataWriter::New(); vtkwriter->SetFileName( filename ); vtkwriter->SetInput(image->GetVtkImageData(t)); vtkwriter->Write(); vtkwriter->Delete(); } #include void mitk::ImageWriter::WriteByITK(mitk::Image* image, const std::string& fileName) { // Pictures and picture series like .png are written via a different mechanism then volume images. // So, they are still multiplexed and thus not support vector images. if (fileName.find(".png") != std::string::npos || fileName.find(".tif") != std::string::npos || fileName.find(".jpg") != std::string::npos) { try { // switch processing of single/multi-component images if( image->GetPixelType(0).GetNumberOfComponents() == 1) { AccessByItk_1( image, _mitkItkPictureWrite, fileName ); } else { AccessFixedPixelTypeByItk_1( image, _mitkItkPictureWriteComposite, MITK_ACCESSBYITK_PIXEL_TYPES_SEQ MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES_SEQ , fileName); } } catch(itk::ExceptionObject &e) { std::cerr << "Caught " << e.what() << std::endl; } catch(std::exception &e) { std::cerr << "Caught std::exception " << e.what() << std::endl; } return; } // Implementation of writer using itkImageIO directly. This skips the use // of templated itkImageFileWriter, which saves the multiplexing on MITK side. unsigned int dimension = image->GetDimension(); unsigned int* dimensions = image->GetDimensions(); mitk::PixelType pixelType = image->GetPixelType(); mitk::Vector3D spacing = image->GetGeometry()->GetSpacing(); mitk::Point3D origin = image->GetGeometry()->GetOrigin(); itk::ImageIOBase::Pointer imageIO = itk::ImageIOFactory::CreateImageIO( fileName.c_str(), itk::ImageIOFactory::WriteMode ); if(imageIO.IsNull()) { itkExceptionMacro(<< "Error: Could not create itkImageIO via factory for file " << fileName); } // Set the necessary information for imageIO imageIO->SetNumberOfDimensions(dimension); imageIO->SetPixelTypeInfo( pixelType.GetTypeId() ); + // Set also the PixelTypeIO information since it is available after + // the changes in PixelType for Bug #12838 + imageIO->SetPixelType( pixelType.GetPixelTypeId() ); if(pixelType.GetNumberOfComponents() > 1) - imageIO->SetNumberOfComponents(pixelType.GetNumberOfComponents()); + imageIO->SetNumberOfComponents( pixelType.GetNumberOfComponents() ); itk::ImageIORegion ioRegion( dimension ); for(unsigned int i=0; iSetDimensions(i,dimensions[i]); imageIO->SetSpacing(i,spacing[i]); imageIO->SetOrigin(i,origin[i]); mitk::Vector3D direction; direction.Set_vnl_vector(image->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(i)); vnl_vector< double > axisDirection(dimension); for(unsigned int j=0; jSetDirection( i, axisDirection ); ioRegion.SetSize(i, image->GetLargestPossibleRegion().GetSize(i) ); ioRegion.SetIndex(i, image->GetLargestPossibleRegion().GetIndex(i) ); } //use compression if available imageIO->UseCompressionOn(); imageIO->SetIORegion(ioRegion); imageIO->SetFileName(fileName); const void * data = image->GetData(); imageIO->Write(data); } void mitk::ImageWriter::GenerateData() { const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, NULL ); if ( locale.compare(currLocale)!=0 ) { try { setlocale(LC_ALL, locale.c_str()); } catch(...) { MITK_INFO << "Could not set locale " << locale; } } if ( m_FileName == "" ) { itkWarningMacro( << "Sorry, filename has not been set!" ); return ; } FILE* tempFile = fopen(m_FileName.c_str(),"w"); if (tempFile==NULL) { itkExceptionMacro(<<"File location not writeable"); return; } fclose(tempFile); remove(m_FileName.c_str()); // Creating clone of input image, since i might change the geometry mitk::Image::Pointer input = const_cast(this->GetInput())->Clone(); // Check if geometry information will be lost if (input->GetDimension() == 2) { if (!input->GetGeometry()->Is2DConvertable()) { MITK_WARN << "Saving a 2D image with 3D geometry information. Geometry information will be lost! You might consider using Convert2Dto3DImageFilter before saving."; // set matrix to identity mitk::AffineTransform3D::Pointer affTrans = mitk::AffineTransform3D::New(); affTrans->SetIdentity(); mitk::Vector3D spacing = input->GetGeometry()->GetSpacing(); mitk::Point3D origin = input->GetGeometry()->GetOrigin(); input->GetGeometry()->SetIndexToWorldTransform(affTrans); input->GetGeometry()->SetSpacing(spacing); input->GetGeometry()->SetOrigin(origin); } } bool vti = (m_Extension.find(".vti") != std::string::npos); // If the extension is NOT .pic and NOT .nrrd and NOT .nii and NOT .nii.gz the following block is entered if ( m_Extension.find(".pic") == std::string::npos && m_Extension.find(".nrrd") == std::string::npos && m_Extension.find(".nii") == std::string::npos && m_Extension.find(".nii.gz") == std::string::npos ) { if(input->GetDimension() > 3) { int t, timesteps; timesteps = input->GetDimension(3); ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New(); timeSelector->SetInput(input); mitk::Image::Pointer image = timeSelector->GetOutput(); for(t = 0; t < timesteps; ++t) { ::itk::OStringStream filename; timeSelector->SetTimeNr(t); timeSelector->Update(); if(input->GetTimeSlicedGeometry()->IsValidTime(t)) { const mitk::TimeBounds& timebounds = input->GetTimeSlicedGeometry()->GetGeometry3D(t)->GetTimeBounds(); filename << m_FileName.c_str() << "_S" << std::setprecision(0) << timebounds[0] << "_E" << std::setprecision(0) << timebounds[1] << "_T" << t << m_Extension; } else { itkWarningMacro(<<"Error on write: TimeSlicedGeometry invalid of image " << filename << "."); filename << m_FileName.c_str() << "_T" << t << m_Extension; } if ( vti ) { writeVti(filename.str().c_str(), input, t); } else { WriteByITK(image, filename.str()); } } } else if ( vti ) { ::itk::OStringStream filename; filename << m_FileName.c_str() << m_Extension; writeVti(filename.str().c_str(), input); } else { ::itk::OStringStream filename; filename << m_FileName.c_str() << m_Extension; WriteByITK(input, filename.str()); } } else { // use the PicFileWriter for the .pic data type if( m_Extension.find(".pic") != std::string::npos ) { /* PicFileWriter::Pointer picWriter = PicFileWriter::New(); size_t found; found = m_FileName.find( m_Extension ); // !!! HAS to be at the very end of the filename (not somewhere in the middle) if( m_FileName.length() > 3 && found != m_FileName.length() - 4 ) { //if Extension not in Filename ::itk::OStringStream filename; filename << m_FileName.c_str() << m_Extension; picWriter->SetFileName( filename.str().c_str() ); } else { picWriter->SetFileName( m_FileName.c_str() ); } picWriter->SetInputImage( input ); picWriter->Write(); */ } // use the ITK .nrrd Image writer if( m_Extension.find(".nrrd") != std::string::npos || m_Extension.find(".nii") != std::string::npos || m_Extension.find(".nii.gz") != std::string::npos ) { ::itk::OStringStream filename; filename << this->m_FileName.c_str() << this->m_Extension; WriteByITK(input, filename.str()); } } m_MimeType = "application/MITK.Pic"; try { setlocale(LC_ALL, currLocale.c_str()); } catch(...) { MITK_INFO << "Could not reset locale " << currLocale; } } bool mitk::ImageWriter::CanWriteDataType( DataNode* input ) { if ( input ) { mitk::BaseData* data = input->GetData(); if ( data ) { mitk::Image::Pointer image = dynamic_cast( data ); if( image.IsNotNull() ) { //"SetDefaultExtension()" set m_Extension to ".mhd" ????? m_Extension = ".pic"; return true; } } } return false; } void mitk::ImageWriter::SetInput( DataNode* input ) { if( input && CanWriteDataType( input ) ) this->ProcessObject::SetNthInput( 0, dynamic_cast( input->GetData() ) ); } std::string mitk::ImageWriter::GetWritenMIMEType() { return m_MimeType; } std::vector mitk::ImageWriter::GetPossibleFileExtensions() { std::vector possibleFileExtensions; possibleFileExtensions.push_back(".pic"); possibleFileExtensions.push_back(".bmp"); possibleFileExtensions.push_back(".dcm"); possibleFileExtensions.push_back(".DCM"); possibleFileExtensions.push_back(".dicom"); possibleFileExtensions.push_back(".DICOM"); possibleFileExtensions.push_back(".gipl"); possibleFileExtensions.push_back(".gipl.gz"); possibleFileExtensions.push_back(".mha"); possibleFileExtensions.push_back(".nii"); possibleFileExtensions.push_back(".nii.gz"); possibleFileExtensions.push_back(".nrrd"); possibleFileExtensions.push_back(".nhdr"); possibleFileExtensions.push_back(".png"); possibleFileExtensions.push_back(".PNG"); possibleFileExtensions.push_back(".spr"); possibleFileExtensions.push_back(".mhd"); possibleFileExtensions.push_back(".vtk"); possibleFileExtensions.push_back(".vti"); possibleFileExtensions.push_back(".hdr"); possibleFileExtensions.push_back(".img"); possibleFileExtensions.push_back(".img.gz"); possibleFileExtensions.push_back(".png"); possibleFileExtensions.push_back(".tif"); possibleFileExtensions.push_back(".jpg"); return possibleFileExtensions; } std::string mitk::ImageWriter::GetFileExtension() { return m_Extension; } void mitk::ImageWriter::SetInput( mitk::Image* image ) { this->ProcessObject::SetNthInput( 0, image ); } const mitk::Image* mitk::ImageWriter::GetInput() { if ( this->GetNumberOfInputs() < 1 ) { return NULL; } else { return static_cast< const mitk::Image * >( this->ProcessObject::GetInput( 0 ) ); } } diff --git a/Core/Code/IO/mitkItkImageFileReader.cpp b/Core/Code/IO/mitkItkImageFileReader.cpp index 299fa5deef..a28499a329 100644 --- a/Core/Code/IO/mitkItkImageFileReader.cpp +++ b/Core/Code/IO/mitkItkImageFileReader.cpp @@ -1,209 +1,209 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkItkImageFileReader.h" #include "mitkConfig.h" #include "mitkException.h" #include #include #include #include //#include #include #include #include //#include //#include //#include //#include //#include //#include void mitk::ItkImageFileReader::GenerateData() { const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, NULL ); if ( locale.compare(currLocale)!=0 ) { try { setlocale(LC_ALL, locale.c_str()); } catch(...) { MITK_INFO << "Could not set locale " << locale; } } mitk::Image::Pointer image = this->GetOutput(); const unsigned int MINDIM = 2; const unsigned int MAXDIM = 4; MITK_INFO << "loading " << m_FileName << " via itk::ImageIOFactory... " << std::endl; // Check to see if we can read the file given the name or prefix if ( m_FileName == "" ) { mitkThrow() << "Empty filename in mitk::ItkImageFileReader "; return ; } itk::ImageIOBase::Pointer imageIO = itk::ImageIOFactory::CreateImageIO( m_FileName.c_str(), itk::ImageIOFactory::ReadMode ); if ( imageIO.IsNull() ) { //itkWarningMacro( << "File Type not supported!" ); mitkThrow() << "Could not create itk::ImageIOBase object for filename " << m_FileName; return ; } // Got to allocate space for the image. Determine the characteristics of // the image. imageIO->SetFileName( m_FileName.c_str() ); imageIO->ReadImageInformation(); unsigned int ndim = imageIO->GetNumberOfDimensions(); if ( ndim < MINDIM || ndim > MAXDIM ) { itkWarningMacro( << "Sorry, only dimensions 2, 3 and 4 are supported. The given file has " << ndim << " dimensions! Reading as 4D." ); ndim = MAXDIM; } itk::ImageIORegion ioRegion( ndim ); itk::ImageIORegion::SizeType ioSize = ioRegion.GetSize(); itk::ImageIORegion::IndexType ioStart = ioRegion.GetIndex(); unsigned int dimensions[ MAXDIM ]; dimensions[ 0 ] = 0; dimensions[ 1 ] = 0; dimensions[ 2 ] = 0; dimensions[ 3 ] = 0; float spacing[ MAXDIM ]; spacing[ 0 ] = 1.0f; spacing[ 1 ] = 1.0f; spacing[ 2 ] = 1.0f; spacing[ 3 ] = 1.0f; Point3D origin; origin.Fill(0); unsigned int i; for ( i = 0; i < ndim ; ++i ) { ioStart[ i ] = 0; ioSize[ i ] = imageIO->GetDimensions( i ); if(iGetDimensions( i ); spacing[ i ] = imageIO->GetSpacing( i ); if(spacing[ i ] <= 0) spacing[ i ] = 1.0f; } if(i<3) { origin[ i ] = imageIO->GetOrigin( i ); } } ioRegion.SetSize( ioSize ); ioRegion.SetIndex( ioStart ); MITK_INFO << "ioRegion: " << ioRegion << std::endl; imageIO->SetIORegion( ioRegion ); void* buffer = new unsigned char[imageIO->GetImageSizeInBytes()]; imageIO->Read( buffer ); - mitk::PixelType pixelType = mitk::PixelType(imageIO->GetComponentTypeInfo(), mitk::GetPixelTypeFromITKImageIO(imageIO), + mitk::PixelType pixelType = mitk::PixelType(imageIO->GetComponentTypeInfo(), imageIO->GetPixelType(), imageIO->GetComponentSize(), imageIO->GetNumberOfComponents(), imageIO->GetComponentTypeAsString( imageIO->GetComponentType() ).c_str(), imageIO->GetPixelTypeAsString( imageIO->GetPixelType() ).c_str() ); image->Initialize( pixelType, ndim, dimensions ); image->SetImportChannel( buffer, 0, Image::ManageMemory ); // access direction of itk::Image and include spacing mitk::Matrix3D matrix; matrix.SetIdentity(); unsigned int j, itkDimMax3 = (ndim >= 3? 3 : ndim); for ( i=0; i < itkDimMax3; ++i) for( j=0; j < itkDimMax3; ++j ) matrix[i][j] = imageIO->GetDirection(j)[i]; // re-initialize PlaneGeometry with origin and direction PlaneGeometry* planeGeometry = static_cast(image->GetSlicedGeometry(0)->GetGeometry2D(0)); planeGeometry->SetOrigin(origin); planeGeometry->GetIndexToWorldTransform()->SetMatrix(matrix); // re-initialize SlicedGeometry3D SlicedGeometry3D* slicedGeometry = image->GetSlicedGeometry(0); slicedGeometry->InitializeEvenlySpaced(planeGeometry, image->GetDimension(2)); slicedGeometry->SetSpacing(spacing); // re-initialize TimeSlicedGeometry image->GetTimeSlicedGeometry()->InitializeEvenlyTimed(slicedGeometry, image->GetDimension(3)); buffer = NULL; MITK_INFO << "number of image components: "<< image->GetPixelType().GetNumberOfComponents() << std::endl; // mitk::DataNode::Pointer node = this->GetOutput(); // node->SetData( image ); // add level-window property //if ( image->GetPixelType().GetNumberOfComponents() == 1 ) //{ // SetDefaultImageProperties( node ); //} MITK_INFO << "...finished!" << std::endl; try { setlocale(LC_ALL, currLocale.c_str()); } catch(...) { MITK_INFO << "Could not reset locale " << currLocale; } } bool mitk::ItkImageFileReader::CanReadFile(const std::string filename, const std::string filePrefix, const std::string filePattern) { // First check the extension if( filename == "" ) return false; // check if image is serie if( filePattern != "" && filePrefix != "" ) return false; itk::ImageIOBase::Pointer imageIO = itk::ImageIOFactory::CreateImageIO( filename.c_str(), itk::ImageIOFactory::ReadMode ); if ( imageIO.IsNull() ) return false; return true; } mitk::ItkImageFileReader::ItkImageFileReader() : m_FileName(""), m_FilePrefix(""), m_FilePattern("") { } mitk::ItkImageFileReader::~ItkImageFileReader() { } diff --git a/Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkExtDefaultPerspective.h b/Core/Code/IO/mitkItkLoggingAdapter.cpp old mode 100755 new mode 100644 similarity index 55% copy from Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkExtDefaultPerspective.h copy to Core/Code/IO/mitkItkLoggingAdapter.cpp index 48e98aae9f..eb6cd29237 --- a/Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkExtDefaultPerspective.h +++ b/Core/Code/IO/mitkItkLoggingAdapter.cpp @@ -1,36 +1,37 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkItkLoggingAdapter.h" +#include "mitkLogMacros.h" -#ifndef QMITKEXTDEFAULTPERSPECTIVE_H_ -#define QMITKEXTDEFAULTPERSPECTIVE_H_ - -#include - -class QmitkExtDefaultPerspective : public QObject, public berry::IPerspectiveFactory +void mitk::ItkLoggingAdapter::Initialize() { - Q_OBJECT - Q_INTERFACES(berry::IPerspectiveFactory) - -public: + itk::OutputWindow::SetInstance(mitk::ItkLoggingAdapter::New()); +} - QmitkExtDefaultPerspective(); +void mitk::ItkLoggingAdapter::DisplayText(const char* s) +{ + MITK_INFO("ItkLogging") << s; +} - void CreateInitialLayout(berry::IPageLayout::Pointer layout); +mitk::ItkLoggingAdapter::ItkLoggingAdapter() +{ +} -}; +mitk::ItkLoggingAdapter::~ItkLoggingAdapter() +{ +} -#endif /* QMITKEXTDEFAULTPERSPECTIVE_H_ */ diff --git a/Core/Code/IO/mitkItkLoggingAdapter.h b/Core/Code/IO/mitkItkLoggingAdapter.h new file mode 100644 index 0000000000..3e45955653 --- /dev/null +++ b/Core/Code/IO/mitkItkLoggingAdapter.h @@ -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. + +===================================================================*/ + + +#ifndef ItkLoggingAdapter_H_HEADER_INCLUDED +#define ItkLoggingAdapter_H_HEADER_INCLUDED + +#include +#include +#include + +namespace mitk { +//##Documentation +//## @brief Adapter that overwrites the standard itk logging output window and sends the logging messages to the MITK logging instead. +//## @ingroup IO + +// this class is used to send output to stdout and not the itk window +class MITK_CORE_EXPORT ItkLoggingAdapter : public itk::OutputWindow +{ +public: + typedef ItkLoggingAdapter Self; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Run-time type information (and related methods). */ + itkTypeMacro( ItkLoggingAdapter, itk::OutputWindow ); + + /** New macro for creation of through a Smart Pointer */ + itkNewMacro(ItkLoggingAdapter); + + /** @brief Initializes the logging adapter. Itk logging + * messages are redirected to MITK logging afterwards. + */ + static void Initialize(); + + virtual void DisplayText(const char* s); + +protected: + ItkLoggingAdapter(); + virtual ~ItkLoggingAdapter(); + +private: + ItkLoggingAdapter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented +}; + + +} + +#endif /* mitkItkLoggingAdapter_H_HEADER_INCLUDED */ diff --git a/Core/Code/IO/mitkPixelType.cpp b/Core/Code/IO/mitkPixelType.cpp index e719ee3853..b34b6ab6ff 100644 --- a/Core/Code/IO/mitkPixelType.cpp +++ b/Core/Code/IO/mitkPixelType.cpp @@ -1,175 +1,204 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkPixelType.h" #include #include #include #include #include #include "itkDiffusionTensor3D.h" #define HUNDRED_VECS(HUN) \ TEN_VECS(HUN) \ TEN_VECS(HUN+10) \ TEN_VECS(HUN+20) \ TEN_VECS(HUN+30) \ TEN_VECS(HUN+40) \ TEN_VECS(HUN+50) \ TEN_VECS(HUN+60) \ TEN_VECS(HUN+70) \ TEN_VECS(HUN+80) \ TEN_VECS(HUN+90) \ #define TEN_VECS(TEN) \ if(false){} \ N_VEC(TEN+ 1) \ N_VEC(TEN+ 2) \ N_VEC(TEN+ 3) \ N_VEC(TEN+ 4) \ N_VEC(TEN+ 5) \ N_VEC(TEN+ 6) \ N_VEC(TEN+ 7) \ N_VEC(TEN+ 8) \ N_VEC(TEN+ 9) \ N_VEC(TEN+10) \ #define N_VEC(N_DIRS) \ _N_VEC(N_DIRS,double) \ _N_VEC(N_DIRS,float) \ _N_VEC(N_DIRS,short) \ #define _N_VEC(N_DIRS,PIXTYPE) \ else if ( *m_TypeId == typeid( itk::Vector )) \ { \ found = true; \ m_TypeId = & typeid( PIXTYPE ); \ m_NumberOfComponents *= N_DIRS; \ m_Type = mitkIpPicFloat; \ m_Bpe = sizeof(PIXTYPE) * 8 * m_NumberOfComponents; \ m_ItkTypeId = &typeid( itk::Vector ); \ } \ const std::type_info &mitk::GetPixelTypeFromITKImageIO(const itk::ImageIOBase::Pointer imageIO) { // return the component type for scalar types if( imageIO->GetNumberOfComponents() == 1) { return imageIO->GetComponentTypeInfo(); } else { itk::ImageIOBase::IOPixelType ptype = imageIO->GetPixelType(); switch(ptype) { case itk::ImageIOBase::RGBA: return typeid( itk::RGBAPixel< unsigned char> ); break; case itk::ImageIOBase::RGB: return typeid( itk::RGBPixel< unsigned char>); break; default: return imageIO->GetComponentTypeInfo(); } } } mitk::PixelType::PixelType( const mitk::PixelType& other ) : m_ComponentType( other.m_ComponentType ), m_PixelType( other.m_PixelType), m_ComponentTypeName( other.m_ComponentTypeName ), m_PixelTypeName( other.m_PixelTypeName ), m_NumberOfComponents( other.m_NumberOfComponents ), m_BytesPerComponent( other.m_BytesPerComponent ) { } bool mitk::PixelType::operator==(const mitk::PixelType& rhs) const { MITK_DEBUG << "operator==" << std::endl; MITK_DEBUG << "m_NumberOfComponents = " << m_NumberOfComponents << " " << rhs.m_NumberOfComponents << std::endl; MITK_DEBUG << "m_BytesPerComponent = " << m_BytesPerComponent << " " << rhs.m_BytesPerComponent << std::endl; + MITK_DEBUG << "m_PixelTypeName = " << m_PixelTypeName << " " << rhs.m_PixelTypeName << std::endl; + MITK_DEBUG << "m_PixelType = " << m_PixelType << " " << rhs.m_PixelType << std::endl; - return ( this->m_PixelType == rhs.m_PixelType - && this->m_ComponentType == rhs.m_ComponentType - && this->m_NumberOfComponents == rhs.m_NumberOfComponents - && this->m_BytesPerComponent == rhs.m_BytesPerComponent - ); -} + bool returnValue = ( this->m_PixelType == rhs.m_PixelType + && this->m_ComponentType == rhs.m_ComponentType + && this->m_NumberOfComponents == rhs.m_NumberOfComponents + && this->m_BytesPerComponent == rhs.m_BytesPerComponent + ); -bool mitk::PixelType::operator ==(const std::type_info& typeId) const -{ - if( m_NumberOfComponents ==1 ) - return (m_ComponentType == typeId); + if(returnValue) + MITK_DEBUG << " [TRUE] "; else - return (m_PixelType == typeId); + MITK_DEBUG << " [FALSE] "; + + return returnValue; } bool mitk::PixelType::operator!=(const mitk::PixelType& rhs) const { return !(this->operator==(rhs)); } -bool mitk::PixelType::operator!=(const std::type_info& typeId) const +std::string mitk::PixelType::PixelNameFromItkIOType(ItkIOPixelType ptype) { - return !(this->operator==(typeId)); + std::string s; + switch(ptype) + { + case itk::ImageIOBase::SCALAR: + return (s = "scalar"); + case itk::ImageIOBase::VECTOR: + return (s = "vector"); + case itk::ImageIOBase::COVARIANTVECTOR: + return (s = "covariant_vector"); + case itk::ImageIOBase::POINT: + return (s = "point"); + case itk::ImageIOBase::OFFSET: + return (s = "offset"); + case itk::ImageIOBase::RGB: + return (s = "rgb"); + case itk::ImageIOBase::RGBA: + return (s = "rgba"); + case itk::ImageIOBase::SYMMETRICSECONDRANKTENSOR: + return (s = "symmetric_second_rank_tensor"); + case itk::ImageIOBase::DIFFUSIONTENSOR3D: + return (s = "diffusion_tensor_3D"); + case itk::ImageIOBase::COMPLEX: + return (s = "complex"); + case itk::ImageIOBase::UNKNOWNPIXELTYPE: + break; + default: + mitkThrow() << "Unknown pixel type "<< ptype; + } + return (s="unknown"); } #define SET_ITK_TYPE_ID(anItkIoPixelType_test, numberOfComponents_test, ITK_TYPE) \ if ( (itk::ImageIOBase::anItkIoPixelType_test == anItkIoPixelType ) && \ (numberOfComponents_test == m_NumberOfComponents) \ ) \ { * \ m_ItkTypeId = &typeid(ITK_TYPE); \ } #define SET_TYPE(TYPE, IPPIC_TYPE) \ if ( *m_TypeId == typeid( TYPE ) ) \ { \ m_Type = IPPIC_TYPE; \ m_Bpe = sizeof(TYPE) * 8 * m_NumberOfComponents; \ \ typedef itk::Vector Vector3Type; \ typedef itk::CovariantVector CovariantVector3Type; \ typedef itk::Point Point3Type; \ typedef itk::Vector Vector2Type; \ typedef itk::CovariantVector CovariantVector2Type; \ typedef itk::Point Point2Type; \ \ SET_ITK_TYPE_ID(UNKNOWNPIXELTYPE, 1, TYPE ) else \ SET_ITK_TYPE_ID(SCALAR, 1, TYPE ) else \ \ SET_ITK_TYPE_ID(VECTOR, 2, Vector2Type ) else \ SET_ITK_TYPE_ID(COVARIANTVECTOR, 2, CovariantVector2Type ) else \ SET_ITK_TYPE_ID(POINT, 2, Point2Type ) else \ \ SET_ITK_TYPE_ID(RGB, 3, itk::RGBPixel ) else \ /*SET_ITK_TYPE_ID(DIFFUSIONTENSOR3D, 6, itk::DiffusionTensor3D ) else */ \ SET_ITK_TYPE_ID(VECTOR, 3, Vector3Type ) else \ SET_ITK_TYPE_ID(COVARIANTVECTOR, 3, CovariantVector3Type ) else \ SET_ITK_TYPE_ID(POINT, 3, Point3Type ) else \ \ SET_ITK_TYPE_ID(RGBA, 4, itk::RGBAPixel ) else \ { \ } \ } \ else diff --git a/Core/Code/IO/mitkPixelType.h b/Core/Code/IO/mitkPixelType.h index 8fbc3111a2..ed3f69ba4a 100644 --- a/Core/Code/IO/mitkPixelType.h +++ b/Core/Code/IO/mitkPixelType.h @@ -1,270 +1,279 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 PIXELTYPE_H_HEADER_INCLUDED_C1EBF565 #define PIXELTYPE_H_HEADER_INCLUDED_C1EBF565 #include #include "mitkCommon.h" #include "mitkPixelTypeTraits.h" #include #include #include #include namespace mitk { template< typename ComponentT> const char* ComponentTypeToString() { return typeid(ComponentT).name(); } template const char* PixelTypeToString() { return typeid(PixelT).name(); } //##Documentation //## @brief Class for defining the data type of pixels //## //## To obtain additional type information not provided by this class //## itk::ImageIOBase can be used by passing the return value of //## PixelType::GetItkTypeId() to itk::ImageIOBase::SetPixelTypeInfo //## and using the itk::ImageIOBase methods GetComponentType, //## GetComponentTypeAsString, GetPixelType, GetPixelTypeAsString. //## @ingroup Data class MITK_CORE_EXPORT PixelType { public: typedef itk::ImageIOBase::IOPixelType ItkIOPixelType; PixelType(const mitk::PixelType & aPixelType); /** \brief Get the \a type_info of the scalar (!) type. Each element * may contain m_NumberOfComponents (more than one) of these scalars. * */ inline const std::type_info& GetTypeId() const { return m_ComponentType; } /** \brief Get the \a type_info of the whole pixel type. * * If you want the type information for the component of a compound type use the * GetTypeId() method */ - inline const std::type_info& GetPixelTypeId() const + /*inline const std::type_info& GetPixelTypeId() const + { + return m_PixelType; + } +*/ + inline itk::ImageIOBase::IOPixelType GetPixelTypeId() const { return m_PixelType; } /** \brief Returns a string containing the ItkTypeName, * * The string provides the same information as GetPixelTypeId.name() */ std::string GetItkTypeAsString() const { return m_PixelTypeName; } /** \brief Returns a string containing the type name of the component, * * The string provides the same information as GetTypeId.name() */ std::string GetComponentTypeAsString() const { return m_ComponentTypeName; } /** \brief Get size of the PixelType in bytes * * A RGBA PixelType of floats will return 4 * sizeof(float) */ size_t GetSize() const { return (m_NumberOfComponents * m_BytesPerComponent); } /** \brief Get the number of bits per element (of an * element) * * A vector of double with three components will return * 8*sizeof(double)*3. * \sa GetBitsPerComponent * \sa GetItkTypeId * \sa GetTypeId */ size_t GetBpe() const { return this->GetSize() * 8; } /** \brief Get the number of components of which each element consists * * Each pixel can consist of multiple components, e.g. RGB. */ inline size_t GetNumberOfComponents() const { return m_NumberOfComponents; } /** \brief Get the number of bits per components * \sa GetBitsPerComponent */ inline size_t GetBitsPerComponent() const { return m_BytesPerComponent * 8; } bool operator==(const PixelType& rhs) const; bool operator!=(const PixelType& rhs) const; - bool operator==(const std::type_info& typeId) const; - bool operator!=(const std::type_info& typeId) const; - ~PixelType() {} private: friend class ItkImageFileReader; friend class NrrdTbssImageReader; friend class NrrdTbssRoiImageReader; template< typename ComponentT, typename PixelT, std::size_t numberOfComponents > friend PixelType MakePixelType(); template< typename ItkImageType > friend PixelType MakePixelType(); PixelType( const std::type_info& componentType, - const std::type_info& pixelType, + //const std::type_info& pixelType, + const ItkIOPixelType pixelType, std::size_t bytesPerComponent, std::size_t numberOfComponents, const char* componentTypeName = 0, const char* pixelTypeName = 0 ) : m_ComponentType( componentType ), m_PixelType( pixelType ), m_NumberOfComponents( numberOfComponents ), m_BytesPerComponent( bytesPerComponent ) { if(componentTypeName) m_ComponentTypeName = componentTypeName; else m_ComponentTypeName = componentType.name(); if(pixelTypeName) m_PixelTypeName = pixelTypeName; - else m_PixelTypeName = pixelType.name(); + //else m_PixelTypeName = pixelType.name(); + else m_PixelTypeName = this->PixelNameFromItkIOType( pixelType ); } + std::string PixelNameFromItkIOType( ItkIOPixelType ptype); + // default constructor is disabled on purpose PixelType(void); // assignment operator declared private on purpose PixelType& operator=(const PixelType& other); /** \brief the \a type_info of the scalar (!) component type. Each element may contain m_NumberOfComponents (more than one) of these scalars. */ const std::type_info& m_ComponentType; - const std::type_info& m_PixelType; + const ItkIOPixelType m_PixelType; std::string m_ComponentTypeName; std::string m_PixelTypeName; std::size_t m_NumberOfComponents; std::size_t m_BytesPerComponent; }; /** \brief A template method for creating a pixel type. */ template< typename ComponentT, typename PixelT, std::size_t numOfComponents > PixelType MakePixelType() { typedef itk::Image< PixelT, numOfComponents> ItkImageType; - return PixelType( typeid(ComponentT), typeid(ItkImageType), + return PixelType( typeid(ComponentT), //typeid(ItkImageType), + MapPixelType::value >::IOType, sizeof(ComponentT), numOfComponents, ComponentTypeToString(), - PixelTypeToString() + 0//PixelTypeToString() ); } /** \brief A template method for creating a pixel type from an ItkImageType * * For fixed size vector images ( i.e. images of type itk::FixedArray<3,float> ) also the number of components * is propagated to the constructor */ template< typename ItkImageType > PixelType MakePixelType() { // define new type, since the ::PixelType is used to distinguish between simple and compound types typedef typename ItkImageType::PixelType ImportPixelType; // get the component type ( is either directly ImportPixelType or ImportPixelType::ValueType for compound types ) typedef typename GetComponentType::ComponentType ComponentT; // The PixelType is the same as the ComponentT for simple types typedef typename ItkImageType::PixelType PixelT; // Get the length of compound type ( initialized to 1 for simple types and variable-length vector images) size_t numComp = ComponentsTrait< (isPrimitiveType::value || isVectorImage::value), ItkImageType >::Size; // call the constructor return PixelType( - typeid(ComponentT), typeid(PixelT), + typeid(ComponentT), + MapPixelType::value >::IOType, + //MapCompositePixelType< PixelT >::IOType, sizeof(ComponentT), numComp, ComponentTypeToString(), - PixelTypeToString() + 0 ); } /** \brief An interface to the MakePixelType method for creating scalar pixel types. * * Usage: for example MakeScalarPixelType() for a scalar short image */ template< typename T> PixelType MakeScalarPixelType() { return MakePixelType(); } /** * @brief Translate the itk::ImageIOBase::IOType to a std::type_info * * The functionality is similar to the itk::ImageIOBase::GetComponentTypeInfo but this one can also handle composite pixel types. * * @param imageIO the ImageIO associated with an image to be read-in * @return the typeid() of the given type for composite types, calls internal GetComponentTypeInfo for simple types */ const std::type_info& GetPixelTypeFromITKImageIO( const itk::ImageIOBase::Pointer imageIO); } // namespace mitk #endif /* PIXELTYPE_H_HEADER_INCLUDED_C1EBF565 */ diff --git a/Core/Code/IO/mitkPixelTypeTraits.h b/Core/Code/IO/mitkPixelTypeTraits.h index 544da6f42c..179cc73712 100644 --- a/Core/Code/IO/mitkPixelTypeTraits.h +++ b/Core/Code/IO/mitkPixelTypeTraits.h @@ -1,127 +1,215 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 PIXELTYPETRAITS_H #define PIXELTYPETRAITS_H +#include +#include +#include +#include + /** \file mitkPixelTypeTraits.h * * The pixel type traits are in general used for compile time resolution of the component type and * the number of components for compound types like the ones in ItkImageType. * The default values are used to define the corresponding variable also for scalar types */ namespace itk { /** Forward declaration of the Variable Length Vector class from ITK */ template < typename TValueType > class VariableLengthVector; } /** \brief This is an implementation of a type trait to provide a compile-time check for PixelType used in the instantiation of an itk::Image */ template< typename T> struct isPrimitiveType { static const bool value = false; }; /** \def DEFINE_TYPE_PRIMITIVE macro which provides a partial specialization for the \sa isPrimitiveType object */ #define DEFINE_TYPE_PRIMITIVE(_TYPEIN) \ template<> struct isPrimitiveType<_TYPEIN>{ static const bool value = true; } /** \brief Partial specialization (unsigned char) for the isPrimitiveType object */ DEFINE_TYPE_PRIMITIVE(unsigned char); /** \brief Partial specialization (char) for the isPrimitiveType object */ DEFINE_TYPE_PRIMITIVE(char); /** \brief Partial specialization (signed char) for the isPrimitiveType object */ DEFINE_TYPE_PRIMITIVE(signed char); /** \brief Partial specialization (unsigned short) for the isPrimitiveType object */ DEFINE_TYPE_PRIMITIVE(unsigned short); /** \brief Partial specialization (short) for the isPrimitiveType object */ DEFINE_TYPE_PRIMITIVE(short); /** \brief Partial specialization (unsigned int) for the isPrimitiveType object */ DEFINE_TYPE_PRIMITIVE(unsigned int); /** \brief Partial specialization (int) for the isPrimitiveType object */ DEFINE_TYPE_PRIMITIVE(int); /** \brief Partial specialization (long int) for the isPrimitiveType object */ DEFINE_TYPE_PRIMITIVE(long int); /** \brief Partial specialization (long unsigned int) for the isPrimitiveType object */ DEFINE_TYPE_PRIMITIVE(long unsigned int); /** \brief Partial specialization (float) for the isPrimitiveType object */ DEFINE_TYPE_PRIMITIVE(float); /** \brief Partial specialization (double) for the isPrimitiveType object */ DEFINE_TYPE_PRIMITIVE(double); /** \brief Type trait to provide compile-time check for T ?= itk::VectorImage */ template< class T, typename TValueType > struct isVectorImage { static const bool value = false; }; /** \brief Partial specification for the isVectorImage trait. */ template< typename TValueType > struct isVectorImage< itk::VariableLengthVector, TValueType> { static const bool value = true; }; /** \brief Compile-time trait for resolving the ValueType from an ItkImageType */ template struct PixelTypeTrait { typedef T ValueType; }; /** \brief Partial specialization for the PixelTypeTrait * * Specialization for the false value. Used to define the value type for non-primitive pixel types */ template struct PixelTypeTrait { typedef typename T::ValueType ValueType; }; /** \brief Compile time resolving of the type of a component */ template struct GetComponentType { typedef typename PixelTypeTrait::value, T>::ValueType ComponentType; }; /** \brief Object for compile-time resolving of the number of components for given type. * * Default value for the component number is 1 */ template struct ComponentsTrait { static const size_t Size = 1; }; /** \brief Partial specialization for the ComponentsTraits in case of compound types */ template struct ComponentsTrait { static const size_t Size = T::ValueType::Length; }; +typedef itk::ImageIOBase::IOPixelType itkIOPixelType; + +/** \brief Object for compile-time translation of a composite pixel type into an itk::ImageIOBase::IOPixelType information + * + * The default value of the IOCompositeType is the UNKNOWNPIXELTYPE, the default value will be used for all but the + * types below with own partial specialization. The values of the IOCompositeType member in the specializations correspond + * to the values of the itk::ImageIOBase::IOPixelType enum values. + */ +template< class T> +struct MapCompositePixelType +{ + static const itkIOPixelType IOCompositeType = itk::ImageIOBase::UNKNOWNPIXELTYPE; +}; + +//------------------------ +// Partial template specialization for fixed-length types +//------------------------ + +template< class C> +struct MapCompositePixelType< itk::RGBPixel > +{ + static const itkIOPixelType IOCompositeType = itk::ImageIOBase::RGB; +}; + +template< class C> +struct MapCompositePixelType< itk::RGBAPixel > +{ + static const itkIOPixelType IOCompositeType = itk::ImageIOBase::RGBA; +}; + +template< class C> +struct MapCompositePixelType< itk::DiffusionTensor3D > +{ + static const itkIOPixelType IOCompositeType = itk::ImageIOBase::DIFFUSIONTENSOR3D; +}; + +//------------------------ +// Partial template specialization for variable-length types +//------------------------ +template< class C, unsigned int N> +struct MapCompositePixelType< itk::Vector< C,N > > +{ + static const itkIOPixelType IOCompositeType = itk::ImageIOBase::VECTOR; +}; + +template< class C, unsigned int N> +struct MapCompositePixelType< itk::FixedArray< C,N > > +{ + static const itkIOPixelType IOCompositeType = itk::ImageIOBase::COVARIANTVECTOR; +}; + +template< class C, unsigned int N> +struct MapCompositePixelType< itk::CovariantVector< C,N > > +{ + static const itkIOPixelType IOCompositeType = itk::ImageIOBase::COVARIANTVECTOR; +}; + +template< class C, unsigned int N> +struct MapCompositePixelType< itk::Matrix< C,N > > +{ + static const itkIOPixelType IOCompositeType = itk::ImageIOBase::MATRIX; +}; + +/** \brief Object for compile-time translation of a pixel type into an itk::ImageIOBase::IOPixelType information + * + * The first template parameter is the pixel type to be translated, the second parameter determines the processing + * way. For non-primitive types the first template parameter is passed to the MapCompositePixelType object to be resolved there + * for primitive types the value is set to SCALAR. + * + * To initalize the flag correctly in compile-time use the \sa isPrimitiveType trait. + */ +template< class T, bool Primitive> +struct MapPixelType +{ + static const itkIOPixelType IOType = MapCompositePixelType::IOCompositeType; +}; + +/** \brief Partial specialization for setting the IOPixelType for primitive types to SCALAR */ +template +struct MapPixelType< T, true> +{ + static const itkIOPixelType IOType = itk::ImageIOBase::SCALAR; +}; #endif // PIXELTYPETRAITS_H diff --git a/Core/Code/IO/mitkVtkLoggingAdapter.cpp b/Core/Code/IO/mitkVtkLoggingAdapter.cpp new file mode 100644 index 0000000000..a642d628f5 --- /dev/null +++ b/Core/Code/IO/mitkVtkLoggingAdapter.cpp @@ -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. + +===================================================================*/ + +#include "mitkVtkLoggingAdapter.h" +#include "mitkLogMacros.h" +#include + +namespace mitk +{ + vtkStandardNewMacro(VtkLoggingAdapter); +} + +void mitk::VtkLoggingAdapter::Initialize() +{ + mitk::VtkLoggingAdapter* vtklog = mitk::VtkLoggingAdapter::New(); + vtkOutputWindow::SetInstance(vtklog); + vtklog->Delete(); +} + +void mitk::VtkLoggingAdapter::DisplayText(const char* t) +{ + MITK_INFO("VtkText") << t; +} + +void mitk::VtkLoggingAdapter::DisplayErrorText(const char *t) +{ + MITK_ERROR("VtkError") << t; +} + +void mitk::VtkLoggingAdapter::DisplayWarningText(const char *t) +{ + MITK_WARN("VtkWarning") << t; +} + +void mitk::VtkLoggingAdapter::DisplayGenericWarningText(const char *t) +{ + MITK_WARN("VtkGenericWarning") << t; +} + +void mitk::VtkLoggingAdapter::DisplayDebugText(const char *t) +{ + MITK_DEBUG("VtkDebug") << t; +} diff --git a/Core/Code/IO/mitkVtkLoggingAdapter.h b/Core/Code/IO/mitkVtkLoggingAdapter.h new file mode 100644 index 0000000000..ba0b9a8613 --- /dev/null +++ b/Core/Code/IO/mitkVtkLoggingAdapter.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 VtkLoggingAdapter_H_HEADER_INCLUDED +#define VtkLoggingAdapter_H_HEADER_INCLUDED + +#include +#include +#include + +namespace mitk { +//##Documentation +//## @brief Adapter that overwrites the standard vtk logging output window and sends the logging messages to the MITK logging instead. +//## @ingroup IO +class MITK_CORE_EXPORT VtkLoggingAdapter : public vtkOutputWindow +{ +public: + + static VtkLoggingAdapter* New(); + + /** @brief Initializes the logging adapter. Vtk logging + * messages are redirected to MITK logging afterwards. + */ + static void Initialize(); + + virtual void DisplayText(const char* t); + + virtual void DisplayErrorText(const char *t); + + virtual void DisplayWarningText(const char *t); + + virtual void DisplayGenericWarningText(const char *t); + + virtual void DisplayDebugText(const char *t); + + +protected: + +}; + +} // namespace mitk + +#endif /* VtkLoggingAdapter_H_HEADER_INCLUDED */ diff --git a/Core/Code/Interactions/mitkDisplayVectorInteractor.cpp b/Core/Code/Interactions/mitkDisplayVectorInteractor.cpp index 909afd859a..2bec3f0dca 100644 --- a/Core/Code/Interactions/mitkDisplayVectorInteractor.cpp +++ b/Core/Code/Interactions/mitkDisplayVectorInteractor.cpp @@ -1,148 +1,166 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkDisplayVectorInteractor.h" #include "mitkOperation.h" #include "mitkDisplayCoordinateOperation.h" #include "mitkDisplayPositionEvent.h" #include "mitkUndoController.h" #include "mitkStateEvent.h" #include "mitkInteractionConst.h" #include "mitkAction.h" void mitk::DisplayVectorInteractor::ExecuteOperation(Operation* itkNotUsed( operation ) ) { /*DisplayCoordinateOperation* dcOperation = static_cast(operation); if(dcOperation==NULL) return; switch(operation->GetOperationType()) { case OpSELECTPOINT: m_Sender=dcOperation->GetRenderer(); m_StartDisplayCoordinate=dcOperation->GetStartDisplayCoordinate(); m_LastDisplayCoordinate=dcOperation->GetLastDisplayCoordinate(); m_CurrentDisplayCoordinate=dcOperation->GetCurrentDisplayCoordinate(); // MITK_INFO << m_CurrentDisplayCoordinate << std::endl; MITK_INFO<<"Message from DisplayVectorInteractor.cpp::ExecuteOperation() : " << "StartDisplayCoordinate:" << m_StartDisplayCoordinate << "LastDisplayCoordinate:" << m_LastDisplayCoordinate << "CurrentDisplayCoordinate:" << m_CurrentDisplayCoordinate << std::endl; break; }*/ } +float mitk::DisplayVectorInteractor::CanHandleEvent(const StateEvent *stateEvent) const +{ + const DisplayPositionEvent* posEvent=dynamic_cast(stateEvent->GetEvent()); + if(posEvent==NULL) return 0.0; + + //StateEvents from "moveNzoom", "alternativePan", "alternativeZoom" interaction pattern. If EventID can be handled by these statemachine patterns return a high value + 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 ) + { + return 0.9; + } + else + { + return 0.0; + } +} + bool mitk::DisplayVectorInteractor::ExecuteAction(Action* action, mitk::StateEvent const* stateEvent) { bool ok=false; const DisplayPositionEvent* posEvent=dynamic_cast(stateEvent->GetEvent()); if(posEvent==NULL) return false; int actionId = action->GetActionId(); //initzoom and initmove is the same! if (actionId == AcINITZOOM) actionId = AcINITMOVE; switch(actionId) { //case 0: // { // DisplayCoordinateOperation* doOp = new mitk::DisplayCoordinateOperation(OpTEST, posEvent->GetSender(), posEvent->GetDisplayPosition(), posEvent->GetDisplayPosition(), posEvent->GetDisplayPosition()); // // //execute the Operation // m_Destination->ExecuteOperation(doOp); // ok = true; // break; // } case AcSENDCOORDINATES: { DisplayCoordinateOperation* doOp = new mitk::DisplayCoordinateOperation(OpSENDCOORDINATES, posEvent->GetSender(), posEvent->GetDisplayPosition(), posEvent->GetDisplayPosition(), posEvent->GetDisplayPosition()); m_Destination->ExecuteOperation(doOp); ok = true; break; } case AcINITMOVE: { m_Sender=posEvent->GetSender(); mitk::Vector2D origin = m_Sender->GetDisplayGeometry()->GetOriginInMM(); double scaleFactorMMPerDisplayUnit = m_Sender->GetDisplayGeometry()->GetScaleFactorMMPerDisplayUnit(); m_StartDisplayCoordinate=posEvent->GetDisplayPosition(); m_LastDisplayCoordinate=posEvent->GetDisplayPosition(); m_CurrentDisplayCoordinate=posEvent->GetDisplayPosition(); m_StartCoordinateInMM=mitk::Point2D( ( origin+m_StartDisplayCoordinate.GetVectorFromOrigin()*scaleFactorMMPerDisplayUnit ).GetDataPointer() ); ok = true; break; } case AcMOVE: { DisplayCoordinateOperation* doOp = new DisplayCoordinateOperation(OpMOVE, m_Sender, m_StartDisplayCoordinate, m_CurrentDisplayCoordinate, posEvent->GetDisplayPosition()); //make Operation m_LastDisplayCoordinate=m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate=posEvent->GetDisplayPosition(); //execute the Operation m_Destination->ExecuteOperation(doOp); ok = true; break; } case AcFINISHMOVE: { ok = true; break; } case AcZOOM: { DisplayCoordinateOperation* doOp = new DisplayCoordinateOperation(OpZOOM, m_Sender, m_StartDisplayCoordinate, m_LastDisplayCoordinate, posEvent->GetDisplayPosition(),m_StartCoordinateInMM); //make Operation m_LastDisplayCoordinate=m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate=posEvent->GetDisplayPosition(); //MITK_INFO << m_CurrentDisplayCoordinate << std::endl; //execute the Operation m_Destination->ExecuteOperation(doOp); ok = true; break; } default: ok = false; break; } return ok; } mitk::DisplayVectorInteractor::DisplayVectorInteractor(const char * type, mitk::OperationActor* destination) : mitk::StateMachine(type), m_Sender(NULL), m_Destination(destination) { m_StartDisplayCoordinate.Fill(0); m_LastDisplayCoordinate.Fill(0); m_CurrentDisplayCoordinate.Fill(0); if(m_Destination==NULL) m_Destination=this; } mitk::DisplayVectorInteractor::~DisplayVectorInteractor() { } diff --git a/Core/Code/Interactions/mitkDisplayVectorInteractor.h b/Core/Code/Interactions/mitkDisplayVectorInteractor.h index 2facfac41c..7c829e0a09 100644 --- a/Core/Code/Interactions/mitkDisplayVectorInteractor.h +++ b/Core/Code/Interactions/mitkDisplayVectorInteractor.h @@ -1,79 +1,85 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKDISPLAYVECTORINTERACTOR_H_HEADER_INCLUDED_C10DC4EB #define MITKDISPLAYVECTORINTERACTOR_H_HEADER_INCLUDED_C10DC4EB #include #include "mitkBaseRenderer.h" #include "mitkStateMachine.h" namespace mitk { class Operation; class OperationActor; /** *@brief Interactor for displaying different slices in orthogonal views. * This includes the interaction of Zooming and Panning. * @ingroup Interaction **/ class MITK_CORE_EXPORT DisplayVectorInteractor : public StateMachine { public: mitkClassMacro(DisplayVectorInteractor, StateMachine); mitkNewMacro2Param(Self, const char*, OperationActor*); /** * @brief Method derived from OperationActor to recieve and execute operations **/ virtual void ExecuteOperation(Operation* operation); + /** + * @brief Method that returns how well this event can be handled by the DisplayVectorInteractor + * a right click into a 2D renderwindow can be handled very well! + **/ + float CanHandleEvent(const StateEvent *stateEvent) const; + protected: /** * @brief Default Constructor **/ DisplayVectorInteractor(const char * type, mitk::OperationActor* destination=NULL); /** * @brief Default Destructor **/ virtual ~DisplayVectorInteractor(); /** * @brief Method derived from StateMachine to implement the own actions **/ virtual bool ExecuteAction(Action* action, mitk::StateEvent const* stateEvent); private: BaseRenderer::Pointer m_Sender; mitk::Point2D m_StartDisplayCoordinate; mitk::Point2D m_LastDisplayCoordinate; mitk::Point2D m_CurrentDisplayCoordinate; mitk::Point2D m_StartCoordinateInMM; OperationActor* m_Destination; }; } // namespace mitk #endif /* MITKDISPLAYVECTORINTERACTOR_H_HEADER_INCLUDED_C10DC4EB */ diff --git a/Core/Code/Interactions/mitkGlobalInteraction.cpp b/Core/Code/Interactions/mitkGlobalInteraction.cpp index a73ccb5d74..3389c4461a 100755 --- a/Core/Code/Interactions/mitkGlobalInteraction.cpp +++ b/Core/Code/Interactions/mitkGlobalInteraction.cpp @@ -1,457 +1,510 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkGlobalInteraction.h" #include "mitkInteractionConst.h" #include "mitkStateEvent.h" #include "mitkPositionEvent.h" #include #include mitk::GlobalInteraction::GlobalInteraction() : StateMachine(NULL) , m_StateMachineFactory(NULL) , m_EventMapper(NULL) , m_CurrentlyInInformListenersLoop(false) , m_CurrentlyInInformInteractorsLoop(false) , m_IsInitialized(false) +, m_EventNotificationPolicy(INFORM_MULTIPLE) { } mitk::GlobalInteraction::~GlobalInteraction() { //s_GlobalInteraction doesn't have to be set = NULL; // StateMachineFactory and EventMapper have to be deleted explicitly, as they inherit from Vtk if (this->IsInitialized()) { m_StateMachineFactory->Delete(); m_StateMachineFactory = NULL; m_EventMapper->Delete(); m_EventMapper = NULL; } m_ListenerList.clear(); m_InteractorList.clear(); m_SelectedList.clear(); - m_JurisdictionMap.clear(); + m_InteractorRelevanceMap.clear(); + m_ListenerRelevanceMap.clear(); m_FocusManager = NULL; } inline mitk::StateEvent* GenerateEmptyStateEvent(int eventId) { mitk::Event *noEvent = new mitk::Event(NULL, mitk::Type_User, mitk::BS_NoButton, mitk::BS_NoButton, mitk::Key_none); mitk::StateEvent *stateEvent = new mitk::StateEvent(eventId, noEvent); return stateEvent; } void mitk::GlobalInteraction::AddListener(mitk::StateMachine* listener) { if(listener == NULL) return; if(dynamic_cast(listener)!=NULL) { MITK_WARN << "Trying to add an Interactor (" << listener->GetNameOfClass() << ") as a listener. " << "This will probably cause problems"; } if ( std::find(m_ListenerList.begin(), m_ListenerList.end(),listener) == m_ListenerList.end() ) { m_ListenerList.push_back(listener); } } bool mitk::GlobalInteraction::RemoveListener(mitk::StateMachine* listener) { // Defers removal to a time after the current event handling is finished. Otherwise the implementation of InformListeners would crash sometimes. m_ListenersFlaggedForRemoval.push_back(listener); StateMachineListIter position = std::find(m_ListenerList.begin(), m_ListenerList.end(),listener); bool removePossible = (position != m_ListenerList.end()); RemoveFlaggedListeners(); + //check if in RelevanceMap + for (StateMachineMapIter it = m_ListenerRelevanceMap.begin(); it != m_ListenerRelevanceMap.end(); it++) + { + if ((*it).second == listener) + { + m_ListenerRelevanceMap.erase(it); + break; + } + } + return removePossible; } void mitk::GlobalInteraction::RemoveFlaggedListeners() { if (m_CurrentlyInInformListenersLoop) return; // iterate flagged listeners, remove them if possible if (m_ListenersFlaggedForRemoval.empty()) return; for (StateMachineCPointerListIter it = m_ListenersFlaggedForRemoval.begin(); it != m_ListenersFlaggedForRemoval.end(); ++it) { StateMachineListIter foundPosition = std::find( m_ListenerList.begin(), m_ListenerList.end(), *it ); if (foundPosition != m_ListenerList.end()) { m_ListenerList.erase( foundPosition ); } } m_ListenersFlaggedForRemoval.clear(); } void mitk::GlobalInteraction::AddInteractor(mitk::Interactor* interactor) { if(interactor == NULL) return; if ( std::find(m_InteractorList.begin(), m_InteractorList.end(),interactor) == m_InteractorList.end() ) { m_InteractorList.push_back(interactor); //if Interactor already selected, then add to selected list if (interactor->GetMode()==Interactor::SMSELECTED) this->AddToSelectedInteractors(interactor); } } bool mitk::GlobalInteraction::InteractorRegistered (mitk::Interactor* interactor) { if ( std::find(m_InteractorList.begin(), m_InteractorList.end(), interactor) == m_InteractorList.end() ) return false; else return true; } bool mitk::GlobalInteraction::ListenerRegistered (mitk::StateMachine* listener) { if ( std::find(m_ListenerList.begin(), m_ListenerList.end(), listener) == m_ListenerList.end() ) return false; else return true; } bool mitk::GlobalInteraction::RemoveInteractor(mitk::Interactor* interactor) { InteractorListIter position = std::find(m_InteractorList.begin(), m_InteractorList.end(),interactor); if (position == m_InteractorList.end()) return false; position = m_InteractorList.erase(position); //check if the interactor is also held in SelectedList this->RemoveFromSelectedInteractors(interactor); - //check if in JurisdictionMap - for (InteractorMapIter it = m_JurisdictionMap.begin(); it != m_JurisdictionMap.end(); it++) + //check if in RelevanceMap + for (InteractorMapIter it = m_InteractorRelevanceMap.begin(); it != m_InteractorRelevanceMap.end(); it++) { if ((*it).second == interactor) { if (m_CurrentInteractorIter == it) - m_CurrentInteractorIter = m_JurisdictionMap.end(); - m_JurisdictionMap.erase(it); + m_CurrentInteractorIter = m_InteractorRelevanceMap.end(); + m_InteractorRelevanceMap.erase(it); break; } } return true; } void mitk::GlobalInteraction::InformListeners(mitk::StateEvent const* stateEvent) { m_CurrentlyInInformListenersLoop = true; for (StateMachineListIter it = m_ListenerList.begin(); it != m_ListenerList.end(); it++) { if((*it).IsNotNull()) (*it)->HandleEvent(stateEvent); } m_CurrentlyInInformListenersLoop = false; RemoveFlaggedListeners(); } bool mitk::GlobalInteraction::AskSelected(mitk::StateEvent const* stateEvent) { if (m_SelectedList.empty()) return false; bool ok = false, oneOk = false; //copy of m_SelectedList to be stable if an iterator gets removed during the following steps InteractorList copyOfSelectedList = m_SelectedList; InteractorListIter it = copyOfSelectedList.begin(); for (; it != copyOfSelectedList.end(); it++) { oneOk = (*it)->HandleEvent(stateEvent); //if one HandleEvent did succeed, then set returnvalue on true; if (oneOk) ok = true; } return ok; } -void mitk::GlobalInteraction::FillJurisdictionMap(mitk::StateEvent const* stateEvent, float threshold) +void mitk::GlobalInteraction::FillInteractorRelevanceMap(mitk::StateEvent const* stateEvent, float threshold) { - m_JurisdictionMap.clear(); + m_InteractorRelevanceMap.clear(); for (InteractorListIter it = m_InteractorList.begin(); it != m_InteractorList.end(); it++) { if ((*it).IsNotNull()) { //first ask for CanHandleEvent(..) and write it into the map if > 0 float value = (*it)->CanHandleEvent(stateEvent); if (value > threshold) { - m_JurisdictionMap.insert(InteractorMap::value_type(value, (*it))); + m_InteractorRelevanceMap.insert(InteractorMap::value_type(value, (*it))); } } } //set the iterator to the first element to start stepping through interactors - if (! m_JurisdictionMap.empty()) - m_CurrentInteractorIter = m_JurisdictionMap.begin(); + if (! m_InteractorRelevanceMap.empty()) + m_CurrentInteractorIter = m_InteractorRelevanceMap.begin(); else - m_CurrentInteractorIter = m_JurisdictionMap.end(); + m_CurrentInteractorIter = m_InteractorRelevanceMap.end(); +} + +void mitk::GlobalInteraction::FillListenerRelevanceMap(const mitk::StateEvent *stateEvent, float threshold) +{ + m_ListenerRelevanceMap.clear(); + + for (StateMachineListIter it = m_ListenerList.begin(); it != m_ListenerList.end(); it++) + { + if((*it).IsNotNull()) + { + float value = (*it)->CanHandleEvent(stateEvent); + if (value > threshold) + { + m_ListenerRelevanceMap.insert(StateMachineMap::value_type(value, (*it))); + } + } + } } /* * Go through the list of interactors, that could possibly handle an event and ask if it has handled the event. * If an interactor has handled an event, it should add itself to the list of selectedInteractors * Ask as long as no interactor answers, that it could be handled */ bool mitk::GlobalInteraction::AskCurrentInteractor(mitk::StateEvent const* stateEvent) { - //no need to check if we don't have any interactors. nearly equal to m_CurrentInteractorIter == m_JurisdictionMap.end - if (m_JurisdictionMap.empty()) + //no need to check if we don't have any interactors. nearly equal to m_CurrentInteractorIter == m_InteractorRelevanceMap.end + if (m_InteractorRelevanceMap.empty()) return false; bool handled = false; - while ( m_CurrentInteractorIter != m_JurisdictionMap.end()&& !handled) + while ( m_CurrentInteractorIter != m_InteractorRelevanceMap.end()&& !handled) { handled = (*m_CurrentInteractorIter).second->HandleEvent(stateEvent); if (!handled) m_CurrentInteractorIter++; } //loop for later usage - if (m_CurrentInteractorIter == m_JurisdictionMap.end()) - m_CurrentInteractorIter = m_JurisdictionMap.begin(); + if (m_CurrentInteractorIter == m_InteractorRelevanceMap.end()) + m_CurrentInteractorIter = m_InteractorRelevanceMap.begin(); return handled; } bool mitk::GlobalInteraction::AddFocusElement(mitk::FocusManager::FocusElement* element) { return m_FocusManager->AddElement(element); } bool mitk::GlobalInteraction::RemoveFocusElement(mitk::FocusManager::FocusElement* element) { return m_FocusManager->RemoveElement(element); } mitk::FocusManager::FocusElement* mitk::GlobalInteraction::GetFocus() { return m_FocusManager->GetFocused(); } bool mitk::GlobalInteraction::SetFocus(mitk::FocusManager::FocusElement* element) { return m_FocusManager->SetFocused(element); } mitk::FocusManager* mitk::GlobalInteraction::GetFocusManager() { return m_FocusManager.GetPointer(); } mitk::EventMapper* mitk::GlobalInteraction::GetEventMapper() { if (!this->IsInitialized()) { MITK_FATAL <<"Global Interaction needs initialization!\n"; return NULL; } return m_EventMapper; } bool mitk::GlobalInteraction::ExecuteAction(Action* action, mitk::StateEvent const* stateEvent) { bool ok = false; ok = false; switch (action->GetActionId()) { case AcDONOTHING: ok = true; break; case AcINFORMLISTENERS: - InformListeners(stateEvent); - ok = true; - break; + if (m_EventNotificationPolicy == INFORM_MULTIPLE) + { + InformListeners(stateEvent); + ok = true; + break; + } + else + { + //0.5 since this is the default value which is returned by the superclass implementation of statemachine + this->FillListenerRelevanceMap(stateEvent, 0.5); + if (!m_ListenerRelevanceMap.empty()) + { + StateMachineMapIter iter = m_ListenerRelevanceMap.begin(); + ok = (*iter).second->HandleEvent(stateEvent); + } + break; + } case AcASKINTERACTORS: if (! AskSelected(stateEvent))//no interactor selected anymore { - //fill the jurisdictionMap to ask them bit by bit. + //fill the RelevanceMap to ask them bit by bit. //currentInteractor is set here to the beginning - FillJurisdictionMap(stateEvent, 0); + FillInteractorRelevanceMap(stateEvent, 0); //ask the Interactors to handle that event AskCurrentInteractor(stateEvent); } ok = true; break; default: ok = true; } return ok; } mitk::GlobalInteraction* mitk::GlobalInteraction::GetInstance() { static mitk::GlobalInteraction::Pointer s_GlobalInteraction; if (s_GlobalInteraction.IsNull()) { s_GlobalInteraction = mitk::GlobalInteraction::New(); } return s_GlobalInteraction; } mitk::State* mitk::GlobalInteraction::GetStartState(const char* type) { if ( this->IsInitialized() ) return m_StateMachineFactory->GetStartState(type); MITK_FATAL << "Fatal Error in mitkGlobalInteraction.cpp: GlobalInteraction not initialized!\n"; return NULL; } bool mitk::GlobalInteraction::AddToSelectedInteractors(mitk::Interactor* interactor) { InteractorListIter position = std::find(m_SelectedList.begin(), m_SelectedList.end(),interactor); if (position != m_SelectedList.end()) { //already added so don't add once more! return true; } else m_SelectedList.push_back(interactor); return true; } bool mitk::GlobalInteraction::RemoveFromSelectedInteractors(mitk::Interactor* interactor) { if (interactor == NULL) return false; InteractorListIter position = std::find(m_SelectedList.begin(), m_SelectedList.end(),interactor); if (position != m_SelectedList.end()) { position = m_SelectedList.erase(position); return true; } else return false; } mitk::StateMachineFactory* mitk::GlobalInteraction::GetStateMachineFactory() { return m_StateMachineFactory; } bool mitk::GlobalInteraction::Initialize(const char* globalInteractionName, const std::string XMLBehaviorInput) { if (this->IsInitialized()) { MITK_WARN <<"Global Interaction has already been initialized.\n"; return false; } m_FocusManager = FocusManager::New(); // instantiates m_StateMachineFactory and load interaction patterns from XML string //if factory has been initialized before, delete it and initialize once more to not add patterns if (m_StateMachineFactory) m_StateMachineFactory->Delete(); m_StateMachineFactory = StateMachineFactory::New(); //if EventMapper was initialized before, delete it and initialize once more // to create new event descriptions and not to add them if (m_EventMapper) m_EventMapper->Delete(); m_EventMapper = EventMapper::New(); bool success = true; if (XMLBehaviorInput == "") { //load default behavior success &= m_StateMachineFactory->LoadStandardBehavior(); success &= m_EventMapper->LoadStandardBehavior(); } else if (itksys::SystemTools::FileExists(XMLBehaviorInput.c_str()) ) { // load standard behavior from file success &= m_StateMachineFactory->LoadBehavior(XMLBehaviorInput); success &= m_EventMapper->LoadBehavior(XMLBehaviorInput); } else { //load standard behavior from XML string success &= m_StateMachineFactory->LoadBehaviorString(XMLBehaviorInput); success &= m_EventMapper->LoadBehaviorString(XMLBehaviorInput); } if(!success) { MITK_FATAL << "Error initializing global interaction!\n"; return false; } //now instantiate what could not be done in InitializeStateStates because StateMachineFactory was not up yet: // (Re-) Initialize Superclass (StateMachine), because type was not given at time of construction m_Type = globalInteractionName; //get the start state of the pattern State::Pointer startState = m_StateMachineFactory->GetStartState(globalInteractionName); if (startState.IsNull()) { MITK_FATAL << "Fatal Error in mitkGlobalInteraction.cpp: No StartState recieved from StateMachineFactory!\n"; return false; } //clear the vector m_CurrentStateVector.clear(); //add the start state pointer for the first time step to the list m_CurrentStateVector.push_back(startState); m_IsInitialized = true; return true; } +void mitk::GlobalInteraction::SetEventNotificationPolicy(EVENT_NOTIFICATION_POLICY policy) +{ + this->m_EventNotificationPolicy = policy; +} + +mitk::GlobalInteraction::EVENT_NOTIFICATION_POLICY mitk::GlobalInteraction::GetEventNotificationPolicy() const +{ + return this->m_EventNotificationPolicy; +} + diff --git a/Core/Code/Interactions/mitkGlobalInteraction.h b/Core/Code/Interactions/mitkGlobalInteraction.h index 8947e9e0e7..44dfc86b15 100755 --- a/Core/Code/Interactions/mitkGlobalInteraction.h +++ b/Core/Code/Interactions/mitkGlobalInteraction.h @@ -1,274 +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. ===================================================================*/ #ifndef GLOBALINTERACTION_H_HEADER_INCLUDED_C152938A #define GLOBALINTERACTION_H_HEADER_INCLUDED_C152938A #include "mitkFocusManager.h" #include #include "mitkStateMachineFactory.h" #include "mitkEventMapper.h" #include "mitkInteractor.h" namespace mitk { class PositionEvent; //##Documentation //## @brief handles all global Events //## //## superior statemachine, that spreads the events to all other interactors //## //## Initialization //## Attention: GlobalInteraction must be initialized by the Initialize() method //## before usage by giving it an XML scheme. Possibilities are giving it an empty string (default), //## the filename of an XML file or the actual XML content as std::string. If an empty string is given, //## the content is tried to be loaded from the default file location. //## //## Concept of sending events: //## In this concept of interaction, the statemachines can be divided into two main statemachines: //## Listeners and interactors. //## Listeners only receive the event to process it, but don't change any data. They want to listen to all events. //## Interactors do change data according to the received event. They do not need to receive all events, only //## those they are interested in. + //## Additional to that a EVENT_NOTIFICATION_POLICY can be set. This can be either INFORM_MULTIPLE (the event is passed + //## to all listeners) or INFORM_ONE (event is passed to the listener which can handle the event best and only to this one). //## - //## To divide these two types of statemachine this class holds three lists and one map: - //## m_ListenerList, m_InteractorList, m_SelectedList and m_JurisdictionMap + //## To divide these two types of statemachine this class holds three lists and two maps: + //## m_ListenerList, m_InteractorList, m_SelectedList and m_InteractorRelevanceMap and m_ListenerRelevanceMap //## The list m_ListenerList holds all listeners. //## m_InteractorList holds all interactors, and the List m_SelectedList holds all machines, that were set to SELECTED or SUBSELECTED. - //## m_JurisdictionMap maps values returned from CanHandleEvent to the asked Interactors. - //## Through this map stepping through interactors, that were not selected and could handle that event, can be done. + //## m_InteractorRelevanceMap and m_ListenerRelevanceMap map values returned from CanHandleEvent to the asked Interactors and Listeners. + //## Through m_InteractorRelevanceMap stepping through interactors, that were not selected and could handle that event, can be done. + //## Through m_ListenerRelevanceMap the listener which can handle the event best can be determined. In case of the INFORM_ONE notification policy + //## the event is passed to just this listener //## //## First the listeners are informed with the event. //## Then the selected or subselected interactors are asked if they can handle that event. //## They can handle it, if the mode of the interactor after HandleEvent(..) is still in SMSELECTED or SMSUBSELECTED. //## They can't handle it, if the mode changed to SMDESELECTED. Then the interactor is removed from the selected-list. - //## In that case, all interactors are asked to calculate and return their area of jurisdiction. + //## In that case, all interactors are asked to calculate and return their area of Relevance. //## An iterator is held on one interactor in the map. With the iterator, the map can be looped through so //## so that several geometric objects, that lie on top of each other, can be selected. //## @ingroup Interaction class MITK_CORE_EXPORT GlobalInteraction : public StateMachine { public: mitkClassMacro(GlobalInteraction, StateMachine); itkNewMacro(Self); typedef std::vector StateMachineList; typedef std::vector StateMachineCPointerList; typedef StateMachineList::iterator StateMachineListIter; typedef StateMachineCPointerList::iterator StateMachineCPointerListIter; typedef std::vector InteractorList; typedef InteractorList::iterator InteractorListIter; typedef std::multimap > InteractorMap; + typedef std::multimap > StateMachineMap; typedef InteractorMap::iterator InteractorMapIter; + typedef StateMachineMap::iterator StateMachineMapIter; + + /** + * Enum for setting the event notification policy of the GlobalInteraction. + */ + enum EVENT_NOTIFICATION_POLICY + { + INFORM_MULTIPLE, /** For setting that all registered listeners are informed */ + INFORM_ONE /** For setting that just the listener that can handle the event best is informed */ + }; //##Documentation //## @brief add an Interactor to the list of all interactors that are asked for handling an event //## //## returns true in case of success void AddInteractor(Interactor* interactor); //##Documentation //## @brief remove a certain Interactor from the set of interactors that are asked for handling an event //## //## returns true in case of success bool RemoveInteractor(Interactor* interactor); //##Documentation //## @brief returns true, if the given interactor is already added to the Interactor-List bool InteractorRegistered (Interactor* interactor); //##Documentation //## @brief add a Listener to the list of all Listeners that are informed of an event //## //## returns true in case of success void AddListener(StateMachine* listener); //##Documentation //## @brief remove a certain Listener from the set of Listeners that are informed of an event //## //## returns true in case of success bool RemoveListener(StateMachine* listener); //##Documentation //## @brief returns true, if the given interactor is already added to the Listener-List bool ListenerRegistered (StateMachine* listener); //##Documentation //## @brief adds an element in the list in FocusManager //## //## true if success, false if the element is already in list bool AddFocusElement(FocusManager::FocusElement* element); //##Documentation //## @brief Removes an element in FocusManager //## //## true if success, false if the element was not in the list bool RemoveFocusElement(FocusManager::FocusElement* element); //##Documentation //## @brief Returns the focused Element in FocusManager FocusManager::FocusElement* GetFocus(); //##Documentation //## @brief Sets the given Element to focused //## //## returns true if the given element was found and focused bool SetFocus(FocusManager::FocusElement* element); //##Documentation //## @brief Returns the pointer to the FocusManager //## //## to add the observer for an event FocusManager* GetFocusManager(); //##Documentation //## @brief Returns the pointer to the EventMapper //## //## to add an addon EventMapper* GetEventMapper(); /** * @brief Return StateMachineFactory **/ StateMachineFactory* GetStateMachineFactory(); /** * @brief Returns the StartState of the StateMachine with the name type; * * Asks member StateMachineFactory for the StartState. * Returns NULL if no entry with name type is found. **/ State* GetStartState(const char* type); //##Documentation //## @brief Returns the global (singleton) instance of //## GlobalInteraction. Create it, if it does not exist. static GlobalInteraction* GetInstance(); //##Documentation //## @brief Initializes the global (singleton) instance of //## GlobalInteraction via an XML string. Must! be done before usage. Can be done only once. //## Can be used with an empty string (default), a file name with path, or the actual XML content as string. bool Initialize(const char* globalInteractionName, const std::string XMLBehaviorInput = ""); //##Documentation //## @brief Check if GlobalInteraction has already been initialized. Init must! be done before usage. - bool IsInitialized() {return m_IsInitialized;}; + bool IsInitialized() {return m_IsInitialized;} + + /** + * @brief Set the policy of how the global interaction informs listeners and interactors + * + * INFORM_MULTIPLE broadcasts the event to all listeners and interactors that can handle the event + * INFORM_ONE only informs the listener or interactor which can handle the event best + **/ + void SetEventNotificationPolicy(EVENT_NOTIFICATION_POLICY); + + /** + * Return the current set eventspreading policy + * @returns the current event spreading policy + **/ + EVENT_NOTIFICATION_POLICY GetEventNotificationPolicy() const; //so that the interactors can call AddToSelectedInteractors() and RemoveFromSelectedInteractors() friend class Interactor; protected: /** * @brief Default Constructor with type to load the StateMachinePattern of the StateMachine * @param XMLbehaviorFile the file which contains the statemachine and event patterns * @param type the name of the statemachine pattern this class shall use **/ GlobalInteraction(); /** * @brief Default destructor. **/ ~GlobalInteraction(); virtual bool ExecuteAction(Action* action, mitk::StateEvent const* stateEvent); /* *@brief adds the given interactor to the list of selected interactors. * This list is asked first to handle an event. */ virtual bool AddToSelectedInteractors(Interactor* interactor); /* *@brief removes the given interactor from the list of selected interactors * This list is asked first to handle an event. */ virtual bool RemoveFromSelectedInteractors(Interactor* interactor); private: //##Documentation //##@brief informing all statemachines that are held in the list m_ListenerList void InformListeners(mitk::StateEvent const* stateEvent); //##Documentation //##@brief asking the selected Interactor if an event can be handled //## //## returns false if no Interactor could handle the event bool AskSelected(mitk::StateEvent const* stateEvent); //##Documentation - //##@brief asking next interactor of m_JurisdictionMap + //##@brief asking next interactor of m_RelevanceMap bool AskCurrentInteractor(mitk::StateEvent const* stateEvent); //##Documentation - //##@brief filling m_JurisdictionMap + //##@brief filling m_InteractorRelevanceMap //## - //## @ params swell: if the calculated jurisdiction value is above swell, then add it to the map - void FillJurisdictionMap(mitk::StateEvent const* stateEvent, float threshold); + //## @ params threshold: if the calculated Relevance value is above threshold, then add it to the map + void FillInteractorRelevanceMap(mitk::StateEvent const* stateEvent, float threshold); + + //##Documentation + //##@brief filling m_ListenerRelevanceMap + //## + //## @ params threshold: if the calculated Relevance value is above threshold, then add it to the map + void FillListenerRelevanceMap(mitk::StateEvent const* stateEvent, float threshold); void RemoveFlaggedListeners(); StateMachineCPointerList m_ListenersFlaggedForRemoval; //##Documentation //## @brief list of all listening statemachines, that want to receive all events StateMachineList m_ListenerList; //##Documentation //## @brief list of all interactors (statemachine, that change data) InteractorList m_InteractorList; //##Documentation //## @brief list of all interactors, that are in Mode SELECTED or SUBSELECTED InteractorList m_SelectedList; //##Documentation //## @brief map for sorting all interactors by the value returned from CanHandleEvent(..). //## //## With that list certain interactors can be looped through like diving through layers - InteractorMap m_JurisdictionMap; + InteractorMap m_InteractorRelevanceMap; + + //##Documentation + //## @brief map for sorting all listeners by the value returned from CanHandleEvent(..). + //## + //## With that list certain listeners can be looped through like diving through layers + StateMachineMap m_ListenerRelevanceMap; //##Documentation - //## @brief iterator on an entry in m_JurisdictionMap for stepping through interactors + //## @brief iterator on an entry in m_RelevanceMap for stepping through interactors InteractorMapIter m_CurrentInteractorIter; //##Documentation //## @brief holds a list of BaseRenderer and one focused FocusManager::Pointer m_FocusManager; /** * @brief StatemachineFactory loads statemachine patterns and provides start states **/ StateMachineFactory* m_StateMachineFactory; /** * @brief EventMapper loads event patterns **/ EventMapper* m_EventMapper; bool m_CurrentlyInInformListenersLoop; bool m_CurrentlyInInformInteractorsLoop; bool m_IsInitialized; + + EVENT_NOTIFICATION_POLICY m_EventNotificationPolicy; }; } // namespace mitk #endif /* GLOBALINTERACTION_H_HEADER_INCLUDED_C152938A */ diff --git a/Core/Code/Interactions/mitkStateMachine.cpp b/Core/Code/Interactions/mitkStateMachine.cpp index f9bdf67199..8a9d56d08e 100644 --- a/Core/Code/Interactions/mitkStateMachine.cpp +++ b/Core/Code/Interactions/mitkStateMachine.cpp @@ -1,315 +1,320 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkStateMachine.h" #include "mitkStateTransitionOperation.h" #include "mitkInteractionConst.h" #include "mitkInteractor.h" #include "mitkTransition.h" #include "mitkOperationEvent.h" #include "mitkStateEvent.h" #include "mitkAction.h" #include "mitkUndoController.h" #include #include "mitkGlobalInteraction.h" #include /** * @brief Constructor * daclares a new StateMachine and connects * it to a StateMachine of Type type; * Also the undo mechanism is instanciated and enabled/disabled **/ mitk::StateMachine::StateMachine(const char * type) : m_UndoController(NULL), m_Type("") { if(type!=NULL) //no need to throw a warning here, because the statemachine yet here doesn't have to be set up. { m_Type = type; //the statemachine doesn't know yet anything about the number of timesteps of the data. So we initialize it with one element. this->InitializeStartStates(1); } if (!m_UndoController) { m_UndoController = new UndoController(UndoController::VERBOSE_LIMITEDLINEARUNDO);//switch to LLU or add LLU /** * here the Undo mechanism is enabled / disabled for all interactors. **/ m_UndoEnabled = true; } m_TimeStep = 0; } mitk::StateMachine::~StateMachine() { //clean up map using deletes for ( mitk::StateMachine::ActionFunctionsMapType::iterator iter = m_ActionFunctionsMap.begin(); iter != m_ActionFunctionsMap.end(); ++iter ) { delete iter->second; } delete m_UndoController; } std::string mitk::StateMachine::GetType() const { return m_Type; } const mitk::State* mitk::StateMachine::GetCurrentState(unsigned int timeStep) const { if (m_CurrentStateVector.size() > timeStep) //the size of the vector has to be one integer higher than the timeStep. return m_CurrentStateVector[timeStep].GetPointer(); return NULL; } void mitk::StateMachine::ResetStatemachineToStartState(unsigned int timeStep) { mitk::State* startState = mitk::GlobalInteraction::GetInstance()->GetStartState((const char *)(&m_Type[0])); if ( m_UndoEnabled ) //write to UndoMechanism if Undo is enabled { //UNDO for this statechange; StateTransitionOperation* doOp = new StateTransitionOperation(OpSTATECHANGE, startState, timeStep); StateTransitionOperation* undoOp = new StateTransitionOperation(OpSTATECHANGE, m_CurrentStateVector[timeStep], timeStep); OperationEvent *operationEvent = new OperationEvent(((mitk::OperationActor*)(this)), doOp, undoOp); m_UndoController->SetOperationEvent(operationEvent); } //can be done without calling this->ExecuteOperation() m_CurrentStateVector[timeStep] = startState; } +float mitk::StateMachine::CanHandleEvent(const StateEvent* /*stateEvent*/) const +{ + return 0.5; +} + bool mitk::StateMachine::HandleEvent(StateEvent const* stateEvent) { if (stateEvent == NULL) return false; if (m_CurrentStateVector.empty()) { STATEMACHINE_ERROR << "Error in mitkStateMachine.cpp: StateMachine not initialized!\n"; return false;//m_CurrentStateVector needs to be initialized! } if (m_TimeStep >= m_CurrentStateVector.size()) { STATEMACHINE_ERROR << "Error in mitkStateMachine.cpp: StateMachine not initialized for this time step!\n"; return false; } if (m_CurrentStateVector[m_TimeStep].IsNull()) { STATEMACHINE_ERROR << "Error in mitkStateMachine.cpp: StateMachine not initialized with the right temporal information!\n"; return false;//m_CurrentState needs to be initialized! } //get the Transition from m_CurrentState which waits for this EventId const Transition *tempTransition = m_CurrentStateVector[m_TimeStep]->GetTransition(stateEvent->GetId()); if (tempTransition == NULL) //no transition in this state for that EventId { return false; } //get next State State *tempNextState = tempTransition->GetNextState(); if (tempNextState == NULL) //wrong built up statemachine! { STATEMACHINE_ERROR << "Error in mitkStateMachine.cpp: StateMachinePattern not defined correctly!\n"; return false; } //and ActionId to execute later on if ( m_CurrentStateVector[m_TimeStep]->GetId() != tempNextState->GetId() )//statechange only if there is a real statechange { if ( m_UndoEnabled ) //write to UndoMechanism if Undo is enabled { //UNDO for this statechange; since we directly change the state, we don't need the do-Operation in case m_UndoEnables == false StateTransitionOperation* doOp = new StateTransitionOperation(OpSTATECHANGE, tempNextState, m_TimeStep); StateTransitionOperation* undoOp = new StateTransitionOperation(OpSTATECHANGE, m_CurrentStateVector[m_TimeStep], m_TimeStep); OperationEvent *operationEvent = new OperationEvent(((mitk::OperationActor*)(this)), doOp, undoOp); m_UndoController->SetOperationEvent(operationEvent); } STATEMACHINE_DEBUG << "from " << m_CurrentStateVector[m_TimeStep]->GetId() << " " << m_CurrentStateVector[m_TimeStep]->GetName() << " to " << tempNextState->GetId() <<" "<GetName(); //first following StateChange(or calling ExecuteOperation(tempNextStateOp)), then operation(action) m_CurrentStateVector[m_TimeStep] = tempNextState; } mitk::Transition::ActionVectorIterator actionIdIterator = tempTransition->GetActionBeginIterator(); mitk::Transition::ActionVectorConstIterator actionIdIteratorEnd = tempTransition->GetActionEndIterator(); bool ok = true; while ( actionIdIterator != actionIdIteratorEnd ) { if ( !ExecuteAction(*actionIdIterator, stateEvent) ) { ok = false; } actionIdIterator++; } return ok; } void mitk::StateMachine::EnableUndo(bool enable) { m_UndoEnabled = enable; } void mitk::StateMachine::IncCurrGroupEventId() { mitk::OperationEvent::IncCurrGroupEventId(); } /// look up which object method is associated to the given action and call the method bool mitk::StateMachine::ExecuteAction(Action* action, StateEvent const* stateEvent) { if (!action) return false; int actionId = action->GetActionId(); TStateMachineFunctor* actionFunction = m_ActionFunctionsMap[actionId]; if (!actionFunction) return false; bool retVal = actionFunction->DoAction(action, stateEvent); return retVal; } void mitk::StateMachine::AddActionFunction(int action, mitk::TStateMachineFunctor* functor) { if (!functor) return; // make sure double calls for same action won't cause memory leaks delete m_ActionFunctionsMap[action]; // delete NULL does no harm m_ActionFunctionsMap[action] = functor; } void mitk::StateMachine::ExecuteOperation(Operation* operation) { switch (operation->GetOperationType()) { case OpNOTHING: break; case OpSTATECHANGE: { mitk::StateTransitionOperation* stateTransOp = dynamic_cast(operation); if (stateTransOp == NULL) { STATEMACHINE_WARN<<"Error! see mitkStateMachine.cpp"; return; } unsigned int time = stateTransOp->GetTime(); m_CurrentStateVector[time] = stateTransOp->GetState(); } break; case OpTIMECHANGE: { mitk::StateTransitionOperation* stateTransOp = dynamic_cast(operation); if (stateTransOp == NULL) { STATEMACHINE_WARN<<"Error! see mitkStateMachine.cpp"; return; } m_TimeStep = stateTransOp->GetTime(); } break; case OpDELETE: { //delete this! //before all lower statemachines has to be deleted in a action //this->Delete();//might not work!!!check itk! } case OpUNDELETE: { //now the m_CurrentState has to be set on a special State //that way a delete of a StateMachine can be undone //IMPORTANT: The type has to be the same!!!Done by a higher instance, that creates this! mitk::StateTransitionOperation* stateTransOp = dynamic_cast(operation); if (stateTransOp != NULL) { unsigned int time = stateTransOp->GetTime(); m_CurrentStateVector[time] = stateTransOp->GetState(); } } default: ; } } void mitk::StateMachine::InitializeStartStates(unsigned int timeSteps) { //get the startstate of the pattern State::Pointer startState = mitk::GlobalInteraction::GetInstance()->GetStartState(m_Type.c_str()); if (startState.IsNull()) { STATEMACHINE_FATAL << "Fatal Error in mitkStateMachine.cpp: Initialization of statemachine unsuccessfull! Initialize GlobalInteraction!\n"; } //clear the vector m_CurrentStateVector.clear(); //add n=timesteps pointers pointing to to the startstate for (unsigned int i = 0; i < timeSteps; i++) m_CurrentStateVector.push_back(startState); } // Check if the vector is long enough to contain the new element // at the given position. If not, expand it with sufficient pre-initialized // elements. // // NOTE: This method will never REDUCE the vector size; it should only // be used to make sure that the vector has enough elements to include the // specified time step. void mitk::StateMachine::ExpandStartStateVector(unsigned int timeSteps) { unsigned int oldSize = m_CurrentStateVector.size(); if ( timeSteps > oldSize ) { State::Pointer startState = mitk::GlobalInteraction::GetInstance()->GetStartState(m_Type.c_str()); for ( unsigned int i = oldSize; i < timeSteps; ++i ) m_CurrentStateVector.insert(m_CurrentStateVector.end(), startState); } } void mitk::StateMachine::UpdateTimeStep(unsigned int timeStep) { //don't need to fill up the memory if the time is uptodate if (timeStep == m_TimeStep) return; //create an operation that changes the time and send it to undocontroller StateTransitionOperation* doOp = new StateTransitionOperation(OpTIMECHANGE, NULL, timeStep); if ( m_UndoEnabled ) //write to UndoMechanism if Undo is enabled { StateTransitionOperation* undoOp = new StateTransitionOperation(OpTIMECHANGE, NULL, m_TimeStep); OperationEvent *operationEvent = new OperationEvent(((mitk::OperationActor*)(this)), doOp, undoOp); m_UndoController->SetOperationEvent(operationEvent); } this->ExecuteOperation(doOp); } diff --git a/Core/Code/Interactions/mitkStateMachine.h b/Core/Code/Interactions/mitkStateMachine.h index 3816ecdfb6..d6f39af2a8 100644 --- a/Core/Code/Interactions/mitkStateMachine.h +++ b/Core/Code/Interactions/mitkStateMachine.h @@ -1,291 +1,301 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 STATEMACHINE_H_HEADER_INCLUDED_C18896BD #define STATEMACHINE_H_HEADER_INCLUDED_C18896BD #include #include #include "mitkOperationActor.h" #include #include "mitkState.h" #include "mitkUndoModel.h" namespace mitk { class Action; class StateEvent; class UndoController; // base class of statem machine functors class MITK_CORE_EXPORT TStateMachineFunctor { public: virtual bool DoAction(Action*, const StateEvent*)=0; // call using function virtual ~TStateMachineFunctor() {} }; // the template functor for arbitrary StateMachine derivations template class TSpecificStateMachineFunctor : public TStateMachineFunctor { public: // constructor - takes pointer to an object and pointer to a member and stores // them in two private variables TSpecificStateMachineFunctor(T* object, bool(T::*memberFunctionPointer)(Action*, const StateEvent*)) :m_Object(object), m_MemberFunctionPointer(memberFunctionPointer) { } virtual ~TSpecificStateMachineFunctor() {} // virtual destructor // override function "Call" virtual bool DoAction(Action* action, const StateEvent* stateEvent) { return (*m_Object.*m_MemberFunctionPointer)(action, stateEvent); // execute member function } private: T* m_Object; // pointer to object bool (T::*m_MemberFunctionPointer)(Action*, const StateEvent*); // pointer to member function }; /// Can be uses by derived classes of StateMachine to connect action IDs to methods /// Assumes that there is a typedef Classname Self in classes that use this macro #define CONNECT_ACTION(a, f) \ StateMachine::AddActionFunction(a, new TSpecificStateMachineFunctor(this, &Self::f)); #define STATEMACHINE_INFO MITK_INFO("StateMachine") << "[type: " << GetType() << "] " #define STATEMACHINE_WARN MITK_WARN("StateMachine") << "[type: " << GetType() << "] " #define STATEMACHINE_FATAL MITK_FATAL("StateMachine") << "[type: " << GetType() << "] " #define STATEMACHINE_ERROR MITK_ERROR("StateMachine") << "[type: " << GetType() << "] " #define STATEMACHINE_DEBUG MITK_DEBUG("StateMachine") << "[type: " << GetType() << "] " /** @brief Superior statemachine @ingroup Interaction Realizes the methods, that every statemachine has to have. Undo can be enabled and disabled through EnableUndo. To implement your own state machine, you have to derive a class from mitk::StateMachine and either - override ExecuteAction() or - Write bool methods that take (Action*, const StateEvent*) as parameter and use the CONNECT_ACTION macro in your constructor The second version is recommended, since it provides more structured code. The following piece of code demonstrates how to use the CONNECT_ACTION macro. The important detail is to provide a typedef classname Self \code class LightSwitch : public StateMachine { public: mitkClassMacro(LightSwitch, StateMachine); // this creates the Self typedef LightSwitch(const char*); bool DoSwitchOn(Action*, const StateEvent*); bool DoSwitchOff(Action*, const StateEvent*); } LightSwitch::LightSwitch(const char* type) :StateMachine(type) { // make sure that AcSWITCHON and AcSWITCHOFF are defined int constants somewhere (e.g. mitkInteractionConst.h) CONNECT_ACTION( AcSWITCHON, DoSwitchOn ); CONNECT_ACTION( AcSWITCHOFF, DoSwitchOff ); } bool LightSwitch::DoSwitchOn(Action*, const StateEvent*) { std::cout << "Enlightenment" << std::endl; } bool LightSwitch::DoSwitchOff(Action*, const StateEvent*) { std::cout << "Confusion" << std::endl; } \endcode What CONNECT_ACTION does, is call StateMachine::AddActionFunction(...) to add some function pointer wrapping class (functor) to a std::map of StateMachine. Whenever StateMachines ExecuteAction is called, StateMachine will lookup the desired Action in its map and call the appropriate method in your derived class. **/ class MITK_CORE_EXPORT StateMachine : public itk::Object, public mitk::OperationActor { public: mitkClassMacro(StateMachine,itk::Object); /** * @brief New Macro with one parameter for creating this object with static New(..) method **/ mitkNewMacro1Param(Self, const char*); /** * @brief Map to connect action IDs with method calls. Use AddActionFunction or (even better) the CONNECT_ACTION macro to fill the map. **/ typedef std::map ActionFunctionsMapType; /** * @brief Type for a vector of StartStatePointers **/ typedef std::vector StartStateVectorType; /** * @brief Get the name and with this the type of the StateMachine **/ std::string GetType() const; /** * @brief handles an Event accordingly to its current State * * Statechange with Undo functionality; * EventMapper gives each event a new objectEventId * and a StateMachine::ExecuteAction can descide weather it gets a * new GroupEventId or not, depending on its state (e.g. finishedNewObject then new GroupEventId). * Object- and group-EventId can also be accessed through static methods from OperationEvent **/ virtual bool HandleEvent(StateEvent const* stateEvent); + /** + * @brief calculates how good this statemachine can handle the event. + * + * Returns a value between 0 and 1 + * where 0 represents not responsible and 1 represents definitive responsible! + * Standard function to override if needed. + * (Used by GlobalInteraction to decide which DESELECTED statemachine to send the event to.) + **/ + virtual float CanHandleEvent(const StateEvent *) const; + /** * @brief Enables or disabled Undo. **/ void EnableUndo(bool enable); /** * @brief A statemachine is also an OperationActor due to the UndoMechanism. * * The statechange is done in ExecuteOperation, so that the statechange can be undone by UndoMechanism. * Is set private here and in superclass it is set public, so UndoController * can reach ist, but it can't be overwritten by a subclass * *ATTENTION*: THIS METHOD SHOULD NOT BE CALLED FROM OTHER CLASSES DIRECTLY! **/ virtual void ExecuteOperation(Operation* operation); /** * @brief Friend so that UndoModel can call ExecuteOperation for Undo. **/ friend class UndoModel; friend class GlobalInteraction; protected: /** * @brief Default Constructor. Obsolete to instanciate it with this method! Use ::New(..) method instead. Set the "type" and with this the pattern of the StateMachine **/ StateMachine(const char * type); /** * @brief Default Destructor **/ ~StateMachine(); /** * @brief Adds the Function to ActionList. **/ void AddActionFunction(int action, TStateMachineFunctor* functor); /** * @brief Method called in HandleEvent after Statechange. * * Each statechange has actions, which can be assigned by it's number. * If you are developing a new statemachine, declare all your operations here and send them to Undo-Controller and to the Data. * Object- and group-EventId can also be accessed through static methods from OperationEvent **/ virtual bool ExecuteAction(Action* action, StateEvent const* stateEvent); /** * @brief returns the current state **/ const State* GetCurrentState(unsigned int timeStep = 0) const; /** * @brief if true, then UndoFunctionality is enabled * * Default value is true; **/ bool m_UndoEnabled; /** * @brief Friend protected function of OperationEvent; that way all StateMachines can set GroupEventId to be incremented! **/ void IncCurrGroupEventId(); /** * @brief holds an UndoController, that can be accessed from all StateMachines. For ExecuteAction **/ UndoController* m_UndoController; /** * @brief Resets the current state from the given timeStep to the StartState with undo functionality! Use carefully! * @param[in] timeStep If the statemachine has several timesteps to take care of, specify the according timestep **/ void ResetStatemachineToStartState(unsigned int timeStep = 0); /** * @brief Check if the number of timeSteps is equal to the number of stored StartStates. Nothing is changed if the number is equal. **/ void ExpandStartStateVector(unsigned int timeSteps); /** * @brief initializes m_CurrentStateVector **/ void InitializeStartStates(unsigned int timeSteps); /** * @brief Update the TimeStep of the statemachine with undo-support if undo enabled **/ virtual void UpdateTimeStep(unsigned int timeStep); /** * @brief Current TimeStep if the data which is to be interacted on, has more than 1 TimeStep **/ unsigned int m_TimeStep; private: /** * @brief The type of the StateMachine. This string specifies the StateMachinePattern that is loaded from the StateMachineFactory. **/ std::string m_Type; /** * @brief Points to the current state. **/ StartStateVectorType m_CurrentStateVector; /** * @brief Map of the added Functions **/ ActionFunctionsMapType m_ActionFunctionsMap; }; } // namespace mitk #endif /* STATEMACHINE_H_HEADER_INCLUDED_C18896BD */ diff --git a/Core/Code/Rendering/mitkImageVtkMapper2D.cpp b/Core/Code/Rendering/mitkImageVtkMapper2D.cpp index 8d212b5118..5afe426f4f 100644 --- a/Core/Code/Rendering/mitkImageVtkMapper2D.cpp +++ b/Core/Code/Rendering/mitkImageVtkMapper2D.cpp @@ -1,1007 +1,1008 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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" //MITK Rendering #include "mitkImageVtkMapper2D.h" #include "vtkMitkThickSlicesFilter.h" #include "vtkMitkApplyLevelWindowToRGBFilter.h" //VTK #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //ITK #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 (transversal, coronal and saggital) afterwards. + //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 * >( this->GetData() ); } vtkProp* mitk::ImageVtkMapper2D::GetVtkProp(mitk::BaseRenderer* renderer) { //return the actor corresponding to the renderer return m_LSH.GetLocalStorage(renderer)->m_Actor; } void mitk::ImageVtkMapper2D::MitkRenderOverlay(BaseRenderer* renderer) { if ( this->IsVisible(renderer)==false ) return; if ( this->GetVtkProp(renderer)->GetVisibility() ) { this->GetVtkProp(renderer)->RenderOverlay(renderer->GetVtkRenderer()); } } void mitk::ImageVtkMapper2D::MitkRenderOpaqueGeometry(BaseRenderer* renderer) { if ( this->IsVisible( renderer )==false ) return; if ( this->GetVtkProp(renderer)->GetVisibility() ) { this->GetVtkProp(renderer)->RenderOpaqueGeometry( renderer->GetVtkRenderer() ); } } void mitk::ImageVtkMapper2D::MitkRenderTranslucentGeometry(BaseRenderer* renderer) { if ( this->IsVisible(renderer)==false ) return; if ( this->GetVtkProp(renderer)->GetVisibility() ) { this->GetVtkProp(renderer)->RenderTranslucentPolygonalGeometry(renderer->GetVtkRenderer()); } } void mitk::ImageVtkMapper2D::MitkRenderVolumetricGeometry(BaseRenderer* renderer) { if(IsVisible(renderer)==false) return; if ( GetVtkProp(renderer)->GetVisibility() ) { this->GetVtkProp(renderer)->RenderVolumetricGeometry(renderer->GetVtkRenderer()); } } 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() ) ) { 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" ); 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"; } } if(thickSlicesMode > 0) { double dataZSpacing = 1.0; Vector3D normInIndex, normal; const PlaneGeometry *planeGeometry = dynamic_cast< const PlaneGeometry * >( worldGeometry ); 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(); //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 ) ) { localStorage->m_Actor->GetProperty()->SetLineWidth(binaryOutlineWidth); } } else { binaryOutline = false; 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!"; } } this->ApplyLookuptable(renderer); //Interpret the values as binary values localStorage->m_Texture->MapColorScalarsThroughLookupTableOn(); } else if( numberOfComponents == 1 ) //gray images { //Interpret the values as gray values localStorage->m_Texture->MapColorScalarsThroughLookupTableOn(); this->ApplyLookuptable(renderer); } else if ( (numberOfComponents == 3) || (numberOfComponents == 4) ) //RBG(A) images { //Interpret the RGB(A) images values correctly localStorage->m_Texture->MapColorScalarsThroughLookupTableOff(); this->ApplyLookuptable(renderer); this->ApplyRBGALevelWindow(renderer); } else { MITK_ERROR << "2D Reindering Error: Unknown number of components!!! Please report to rendering task force or check your data!"; } this->ApplyColor( renderer ); this->ApplyOpacity( renderer ); this->TransformActor( renderer ); //connect mapper with the data if(binary && binaryOutline) //connect the mapper with the polyData which contains the lines { //We need the contour for the binary oultine property as actor localStorage->m_Mapper->SetInput(localStorage->m_OutlinePolyData); localStorage->m_Actor->SetTexture(NULL); //no texture for contours } 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); } // We have been modified => save this for next Update() localStorage->m_LastUpdateTime.Modified(); } void mitk::ImageVtkMapper2D::ApplyColor( mitk::BaseRenderer* renderer ) { LocalStorage *localStorage = this->GetLocalStorage( renderer ); // check for interpolation properties bool textureInterpolation = false; GetDataNode()->GetBoolProperty( "texture interpolation", textureInterpolation, renderer ); //set the interpolation modus according to the property localStorage->m_Texture->SetInterpolate(textureInterpolation); bool useColor = true; this->GetDataNode()->GetBoolProperty( "use color", useColor, renderer ); if( useColor ) { 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)); if(colorprop.IsNotNull()) { memcpy(rgb, colorprop->GetColor().GetDataPointer(), 3*sizeof(float)); } else { GetColor( rgb, renderer ); } } if(selected) { mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty ("binaryimage.selectedcolor", renderer)); if(colorprop.IsNotNull()) { memcpy(rgb, colorprop->GetColor().GetDataPointer(), 3*sizeof(float)); } else { GetColor( rgb, renderer ); } } if(!hover && !selected) { GetColor( rgb, renderer ); } double rgbConv[3] = {(double)rgb[0], (double)rgb[1], (double)rgb[2]}; //conversion to double for VTK localStorage->m_Actor->GetProperty()->SetColor(rgbConv); } else { //If the user defines a lut, we dont want to use the color and take white instead. localStorage->m_Actor->GetProperty()->SetColor(1.0, 1.0, 1.0); } } 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 GetOpacity( opacity, renderer ); //set the opacity according to the properties localStorage->m_Actor->GetProperty()->SetOpacity(opacity); } void mitk::ImageVtkMapper2D::ApplyLookuptable( mitk::BaseRenderer* renderer ) { bool binary = false; bool CTFcanBeApplied = false; this->GetDataNode()->GetBoolProperty( "binary", binary, renderer ); LocalStorage* localStorage = this->GetLocalStorage(renderer); float blackOpacity = 0.0; bool isBinary = false; bool foundBinaryProperty = false; foundBinaryProperty = this->GetDataNode()->GetBoolProperty("binary", isBinary, renderer); if (foundBinaryProperty && !isBinary) { this->GetDataNode()->GetFloatProperty( "black opacity", blackOpacity, renderer); } localStorage->m_LookupTable->SetTableValue(0, 0.0, 0.0, 0.0, blackOpacity); //default lookuptable localStorage->m_Texture->SetLookupTable( localStorage->m_LookupTable ); if(binary) { //default lookuptable for binary images localStorage->m_Texture->GetLookupTable()->SetRange(0.0, 1.0); } else { bool useColor = true; this->GetDataNode()->GetBoolProperty( "use color", useColor, renderer ); if((!useColor)) { //BEGIN PROPERTY user-defined lut //currently we do not allow a lookuptable if it is a binary image // If lookup table use is requested... mitk::LookupTableProperty::Pointer LookupTableProp; LookupTableProp = dynamic_cast (this->GetDataNode()->GetProperty("LookupTable")); //...check if there is a lookuptable provided by the user if ( LookupTableProp.IsNotNull() ) { // If lookup table use is requested and supplied by the user: // only update the lut, when the properties have changed... if( LookupTableProp->GetLookupTable()->GetMTime() <= this->GetDataNode()->GetPropertyList()->GetMTime() ) { LookupTableProp->GetLookupTable()->ChangeOpacityForAll( LookupTableProp->GetLookupTable()->GetVtkLookupTable()->GetAlpha()*localStorage->m_Actor->GetProperty()->GetOpacity() ); LookupTableProp->GetLookupTable()->ChangeOpacity(0, blackOpacity); } //we use the user-defined lookuptable localStorage->m_Texture->SetLookupTable( LookupTableProp->GetLookupTable()->GetVtkLookupTable() ); } else { CTFcanBeApplied = true; } }//END PROPERTY user-defined lut LevelWindow levelWindow; this->GetLevelWindow( levelWindow, renderer ); //set up the lookuptable with the level window range localStorage->m_Texture->GetLookupTable()->SetRange( levelWindow.GetLowerWindowBound(), levelWindow.GetUpperWindowBound() ); } //the color function can be applied if the user does not want to use color //and does not provide a lookuptable if(CTFcanBeApplied) { ApplyColorTransferFunction(renderer); } localStorage->m_Texture->SetInput( localStorage->m_ReslicedImage ); } void mitk::ImageVtkMapper2D::ApplyColorTransferFunction(mitk::BaseRenderer* renderer) { mitk::TransferFunctionProperty::Pointer transferFunctionProperty = dynamic_cast(this->GetDataNode()->GetProperty("Image Rendering.Transfer Function",renderer )); LocalStorage* localStorage = m_LSH.GetLocalStorage(renderer); if(transferFunctionProperty.IsNotNull()) { localStorage->m_Texture->SetLookupTable(transferFunctionProperty->GetValue()->GetColorTransferFunction()); } else { MITK_WARN << "Neither a lookuptable nor a transfer function is set and use color is off."; } } void mitk::ImageVtkMapper2D::ApplyRBGALevelWindow( mitk::BaseRenderer* renderer ) { LocalStorage* localStorage = this->GetLocalStorage( renderer ); //pass the LuT to the RBG filter localStorage->m_LevelWindowToRGBFilterObject->SetLookupTable(localStorage->m_Texture->GetLookupTable()); mitk::LevelWindow opacLevelWindow; if( this->GetLevelWindow( opacLevelWindow, renderer, "opaclevelwindow" ) ) {//pass the opaque level window to the filter localStorage->m_LevelWindowToRGBFilterObject->SetMinOpacity(opacLevelWindow.GetLowerWindowBound()); localStorage->m_LevelWindowToRGBFilterObject->SetMaxOpacity(opacLevelWindow.GetUpperWindowBound()); } else {//no opaque level window localStorage->m_LevelWindowToRGBFilterObject->SetMinOpacity(0.0); localStorage->m_LevelWindowToRGBFilterObject->SetMaxOpacity(255.0); } localStorage->m_LevelWindowToRGBFilterObject->SetInput(localStorage->m_ReslicedImage); //connect the texture with the output of the RGB filter localStorage->m_Texture->SetInputConnection(localStorage->m_LevelWindowToRGBFilterObject->GetOutputPort()); } void mitk::ImageVtkMapper2D::Update(mitk::BaseRenderer* renderer) { if ( !this->IsVisible( renderer ) ) { 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() ) ) ) { 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()) ) { 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( "use color", mitk::BoolProperty::New( true ), renderer, overwrite ); 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 ); 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 ) ); std::string modality; if ( node->GetStringProperty( "dicom.series.Modality", modality ) ) { // modality provided by DICOM or other reader if ( modality == "PT") // NOT a typo, PT is the abbreviation for PET used in DICOM { node->SetProperty( "use color", mitk::BoolProperty::New( false ), renderer ); node->SetProperty( "opacity", mitk::FloatProperty::New( 0.5 ), renderer ); } } 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 ( 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 ( node->GetStringProperty( "dicom.voilut.WindowCenter", sLevel ) && node->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 ( node->GetStringProperty( "dicom.series.SmallestPixelValueInSeries", sSmallestPixelValueInSeries ) && node->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); + contrast.SetLevelWindow( level, window, true ); node->SetProperty( "levelwindow", LevelWindowProperty::New( contrast ), renderer ); } } if(((overwrite) || (node->GetProperty("opaclevelwindow", renderer)==NULL)) - && image->GetPixelType().GetPixelTypeId() == typeid(itk::RGBAPixel)) + && (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 ); } if((overwrite) || (node->GetProperty("LookupTable", renderer)==NULL)) { // add a default rainbow lookup table for color mapping 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 ); } } 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 while (y <= yMax) { currentPixel = static_cast(localStorage->m_ReslicedImage->GetScalarPointer(x, y, 0)); //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++; } }//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 transversal, coronal or saggital + //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 (transversal, coronal or saggital) + //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); } 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() { //Do as much actions as possible in here to avoid double executions. m_Plane = vtkSmartPointer::New(); m_Texture = vtkSmartPointer::New(); m_LookupTable = vtkSmartPointer::New(); m_Mapper = vtkSmartPointer::New(); m_Actor = 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_LookupTable->SetRampToLinear(); m_LookupTable->SetSaturationRange( 0.0, 0.0 ); m_LookupTable->SetHueRange( 0.0, 0.0 ); m_LookupTable->SetValueRange( 0.0, 1.0 ); m_LookupTable->Build(); //do not repeat the texture (the image) m_Texture->RepeatOff(); //set the mapper for the actor m_Actor->SetMapper(m_Mapper); //filter for RGB(A) images m_LevelWindowToRGBFilterObject = new vtkMitkApplyLevelWindowToRGBFilter(); } diff --git a/Core/Code/Rendering/mitkPointSetGLMapper2D.cpp b/Core/Code/Rendering/mitkPointSetGLMapper2D.cpp index 84ad29129e..405d67353b 100644 --- a/Core/Code/Rendering/mitkPointSetGLMapper2D.cpp +++ b/Core/Code/Rendering/mitkPointSetGLMapper2D.cpp @@ -1,509 +1,534 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkPointSetGLMapper2D.h" #include "mitkPointSet.h" #include "mitkPlaneGeometry.h" #include "mitkColorProperty.h" #include "mitkProperties.h" #include "vtkLinearTransform.h" #include "mitkStringProperty.h" #include "mitkPointSet.h" #include "mitkVtkPropRenderer.h" #include "mitkGL.h" //const float selectedColor[]={1.0,0.0,0.6}; //for selected! mitk::PointSetGLMapper2D::PointSetGLMapper2D() : m_Polygon(false), m_ShowPoints(true), m_ShowDistances(false), m_DistancesDecimalDigits(1), m_ShowAngles(false), m_ShowDistantLines(true), m_LineWidth(1), m_ShowDistantPoints(true) { } mitk::PointSetGLMapper2D::~PointSetGLMapper2D() { } const mitk::PointSet *mitk::PointSetGLMapper2D::GetInput(void) { return static_cast ( GetData() ); } void mitk::PointSetGLMapper2D::ApplyProperties(mitk::BaseRenderer* renderer) { GLMapper2D::ApplyProperties( renderer ); const mitk::DataNode* node=GetDataNode(); if( node == NULL ) return; node->GetBoolProperty("show contour", m_Polygon); + node->GetBoolProperty("close contour", m_PolygonClosed); node->GetBoolProperty("show points", m_ShowPoints); node->GetBoolProperty("show distances", m_ShowDistances); node->GetIntProperty("distance decimal digits", m_DistancesDecimalDigits); node->GetBoolProperty("show angles", m_ShowAngles); node->GetBoolProperty("show distant lines", m_ShowDistantLines); node->GetIntProperty("line width", m_LineWidth); node->GetIntProperty("point line width", m_PointLineWidth); node->GetIntProperty("point 2D size", m_Point2DSize); node->GetBoolProperty("show distant points", m_ShowDistantPoints); } static bool makePerpendicularVector2D(const mitk::Vector2D& in, mitk::Vector2D& out) { if((fabs(in[0])>0) && ( (fabs(in[0])>fabs(in[1])) || (in[1] == 0) ) ) { out[0]=-in[1]/in[0]; out[1]=1; out.Normalize(); return true; } else if(fabs(in[1])>0) { out[0]=1; out[1]=-in[0]/in[1]; out.Normalize(); return true; } else return false; } void mitk::PointSetGLMapper2D::Paint( mitk::BaseRenderer *renderer ) { const mitk::DataNode* node=GetDataNode(); if( node == NULL ) return; const int text2dDistance = 10; if(IsVisible(renderer)==false) return; // @FIXME: Logik fuer update bool updateNeccesary=true; if (updateNeccesary) { // ok, das ist aus GenerateData kopiert mitk::PointSet::Pointer input = const_cast(this->GetInput()); // Get the TimeSlicedGeometry of the input object const TimeSlicedGeometry* inputTimeGeometry = input->GetTimeSlicedGeometry(); if (( inputTimeGeometry == NULL ) || ( inputTimeGeometry->GetTimeSteps() == 0 ) ) { return; } // // get the world time // const Geometry2D* worldGeometry = renderer->GetCurrentWorldGeometry2D(); assert( worldGeometry != NULL ); ScalarType time = worldGeometry->GetTimeBounds()[ 0 ]; // // convert the world time in time steps of the input object // int timeStep=0; if ( time > ScalarTypeNumericTraits::NonpositiveMin() ) timeStep = inputTimeGeometry->MSToTimeStep( time ); if ( inputTimeGeometry->IsValidTime( timeStep ) == false ) { return; } mitk::PointSet::DataType::Pointer itkPointSet = input->GetPointSet( timeStep ); if ( itkPointSet.GetPointer() == NULL) { return; } mitk::DisplayGeometry::Pointer displayGeometry = renderer->GetDisplayGeometry(); assert(displayGeometry.IsNotNull()); //apply color and opacity read from the PropertyList ApplyProperties(renderer); vtkLinearTransform* transform = GetDataNode()->GetVtkTransform(); //List of the Points PointSet::DataType::PointsContainerConstIterator it, end; it = itkPointSet->GetPoints()->Begin(); end = itkPointSet->GetPoints()->End(); //iterator on the additional data of each point PointSet::DataType::PointDataContainerIterator selIt, selEnd; bool pointDataBroken = (itkPointSet->GetPointData()->Size() != itkPointSet->GetPoints()->Size()); selIt = itkPointSet->GetPointData()->Begin(); selEnd = itkPointSet->GetPointData()->End(); int counter = 0; //for writing text int j = 0; //for switching back to old color after using selected color float recallColor[4]; glGetFloatv(GL_CURRENT_COLOR,recallColor); //get the properties for coloring the points float unselectedColor[4] = {1.0, 1.0, 0.0, 1.0};//yellow //check if there is an unselected property if (dynamic_cast(node->GetPropertyList(renderer)->GetProperty("unselectedcolor")) != NULL) { mitk::Color tmpColor = dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("unselectedcolor"))->GetValue(); unselectedColor[0] = tmpColor[0]; unselectedColor[1] = tmpColor[1]; unselectedColor[2] = tmpColor[2]; unselectedColor[3] = 1.0f; //!!define a new ColorProp to be able to pass alpha value } else if (dynamic_cast(node->GetPropertyList(NULL)->GetProperty("unselectedcolor")) != NULL) { mitk::Color tmpColor = dynamic_cast(this->GetDataNode()->GetPropertyList(NULL)->GetProperty("unselectedcolor"))->GetValue(); unselectedColor[0] = tmpColor[0]; unselectedColor[1] = tmpColor[1]; unselectedColor[2] = tmpColor[2]; unselectedColor[3] = 1.0f; //!!define a new ColorProp to be able to pass alpha value } else { //get the color from the dataNode node->GetColor(unselectedColor, NULL); } //get selected property float selectedColor[4] = {1.0, 0.0, 0.6, 1.0}; if (dynamic_cast(node->GetPropertyList(renderer)->GetProperty("selectedcolor")) != NULL) { mitk::Color tmpColor = dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("selectedcolor"))->GetValue(); selectedColor[0] = tmpColor[0]; selectedColor[1] = tmpColor[1]; selectedColor[2] = tmpColor[2]; selectedColor[3] = 1.0f; } else if (dynamic_cast(node->GetPropertyList(NULL)->GetProperty("selectedcolor")) != NULL) { mitk::Color tmpColor = dynamic_cast(this->GetDataNode()->GetPropertyList(NULL)->GetProperty("selectedcolor"))->GetValue(); selectedColor[0] = tmpColor[0]; selectedColor[1] = tmpColor[1]; selectedColor[2] = tmpColor[2]; selectedColor[3] = 1.0f; } //check if there is an pointLineWidth property if (dynamic_cast(node->GetPropertyList(renderer)->GetProperty("point line width")) != NULL) { m_PointLineWidth = dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("point line width"))->GetValue(); } else if (dynamic_cast(node->GetPropertyList(NULL)->GetProperty("point line width")) != NULL) { m_PointLineWidth = dynamic_cast(this->GetDataNode()->GetPropertyList(NULL)->GetProperty("point line width"))->GetValue(); } //check if there is an point 2D size property if (dynamic_cast(node->GetPropertyList(renderer)->GetProperty("point 2D size")) != NULL) { m_Point2DSize = dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("point 2D size"))->GetValue(); } else if (dynamic_cast(node->GetPropertyList(NULL)->GetProperty("point 2D size")) != NULL) { m_Point2DSize = dynamic_cast(this->GetDataNode()->GetPropertyList(NULL)->GetProperty("point 2D size"))->GetValue(); } Point3D p; // currently visited point Point3D lastP; // last visited point Vector3D vec; // p - lastP Vector3D lastVec; // lastP - point before lastP vec.Fill(0); mitk::Point3D projected_p; // p projected on viewplane Point2D pt2d; // projected_p in display coordinates Point2D lastPt2d; // last projected_p in display coordinates Point2D preLastPt2d;// projected_p in display coordinates before lastPt2d + Point2D lastPt2DInPointSet; // The last point in the pointset in display coordinates + mitk::PointSet::DataType::PointType plob; + plob.Fill(0); + itkPointSet->GetPoint( itkPointSet->GetNumberOfPoints()-1, &plob); + + //map lastPt2DInPointSet to display coordinates + float vtkp[3]; + + itk2vtk(plob, vtkp); + transform->TransformPoint(vtkp, vtkp); + vtk2itk(vtkp,p); + + displayGeometry->Project(p, projected_p); + + displayGeometry->Map(projected_p, lastPt2DInPointSet); + displayGeometry->WorldToDisplay(lastPt2DInPointSet, lastPt2DInPointSet); + while(it!=end) // iterate over all points { lastP = p; // valid only for counter > 0 lastVec = vec; // valid only for counter > 1 preLastPt2d = lastPt2d; // valid only for counter > 1 lastPt2d = pt2d; // valid only for counter > 0 - float vtkp[3]; itk2vtk(it->Value(), vtkp); transform->TransformPoint(vtkp, vtkp); vtk2itk(vtkp,p); vec = p-lastP; // valid only for counter > 0 displayGeometry->Project(p, projected_p); Vector3D diff=p-projected_p; ScalarType scalardiff = diff.GetSquaredNorm(); //MouseOrientation bool isInputDevice=false; double scalarDiffTolerance = 0.00001; //cause roundoff error bool isRendererSlice = scalardiff < scalarDiffTolerance; if(this->GetDataNode()->GetBoolProperty("inputdevice",isInputDevice) && isInputDevice && !isRendererSlice ) { displayGeometry->Map(projected_p, pt2d); displayGeometry->WorldToDisplay(pt2d, pt2d); //Point size depending of distance to slice /*float p_size = (1/scalardiff)*10*m_Point2DSize; if(p_size < m_Point2DSize * 0.6 ) p_size = m_Point2DSize * 0.6 ; else if ( p_size > m_Point2DSize ) p_size = m_Point2DSize;*/ float p_size = (1/scalardiff)*100.0; if(p_size < 6.0 ) p_size = 6.0 ; else if ( p_size > 10.0 ) p_size = 10.0; //draw Point float opacity = (p_size<8)?0.3:1.0;//don't get the opacity from the node? Feature not a bug! Otehrwise the 2D cross is hardly seen. glColor4f(unselectedColor[0],unselectedColor[1],unselectedColor[2],opacity); glPointSize(p_size); //glShadeModel(GL_FLAT); glBegin (GL_POINTS); glVertex2fv(&pt2d[0]); glEnd (); } //for point set if(!isInputDevice && ( (m_ShowDistantPoints && scalardiff < 4.0) || (!m_ShowDistantPoints && scalardiff < scalarDiffTolerance) || (m_Polygon) ) ) { Point2D tmp; displayGeometry->Map(projected_p, pt2d); displayGeometry->WorldToDisplay(pt2d, pt2d); Vector2D horz,vert; horz[0]=(float)m_Point2DSize-scalardiff*2; horz[1]=0; vert[0]=0; vert[1]=(float)m_Point2DSize-scalardiff*2; // now paint text if available if (dynamic_cast(this->GetDataNode() ->GetProperty("label")) != NULL) { const char * pointLabel = dynamic_cast( this->GetDataNode()->GetProperty("label"))->GetValue(); std::string l = pointLabel; if (input->GetSize()>1) { // char buffer[20]; // sprintf(buffer,"%d",it->Index()); std::stringstream ss; ss << it->Index(); l.append(ss.str()); } if (unselectedColor != NULL) { mitk::VtkPropRenderer* OpenGLrenderer = dynamic_cast( renderer ); float rgb[3];//yellow rgb[0] = unselectedColor[0]; rgb[1] = unselectedColor[1]; rgb[2] = unselectedColor[2]; OpenGLrenderer->WriteSimpleText(l, pt2d[0] + text2dDistance, pt2d[1] + text2dDistance,rgb[0], rgb[1],rgb[2]); } else { mitk::VtkPropRenderer* OpenGLrenderer = dynamic_cast( renderer ); OpenGLrenderer->WriteSimpleText(l, pt2d[0] + text2dDistance, pt2d[1] + text2dDistance,0.0,1.0,0.0); } } if((m_ShowPoints) && ( (m_ShowDistantPoints && scalardiff<4.0) || (!m_ShowDistantPoints && scalardiff < scalarDiffTolerance) ) ) { //check if the point is to be marked as selected if(selIt != selEnd || pointDataBroken) { bool addAsSelected = false; if (pointDataBroken) addAsSelected = false; else if (selIt->Value().selected) addAsSelected = true; else addAsSelected = false; if (addAsSelected) { horz[0]=(float)m_Point2DSize; vert[1]=(float)m_Point2DSize; glColor3f(selectedColor[0],selectedColor[1],selectedColor[2]); glLineWidth(m_PointLineWidth); //a diamond around the point with the selected color glBegin (GL_LINE_LOOP); tmp=pt2d-horz; glVertex2fv(&tmp[0]); tmp=pt2d+vert; glVertex2fv(&tmp[0]); tmp=pt2d+horz; glVertex2fv(&tmp[0]); tmp=pt2d-vert; glVertex2fv(&tmp[0]); glEnd (); glLineWidth(1); //the actual point in the specified color to see the usual color of the point glColor3f(unselectedColor[0],unselectedColor[1],unselectedColor[2]); glPointSize(1); glBegin (GL_POINTS); tmp=pt2d; glVertex2fv(&tmp[0]); glEnd (); } else //if not selected { glColor3f(unselectedColor[0],unselectedColor[1],unselectedColor[2]); glLineWidth(m_PointLineWidth); //drawing crosses glBegin (GL_LINES); tmp=pt2d-horz; glVertex2fv(&tmp[0]); tmp=pt2d+horz; glVertex2fv(&tmp[0]); tmp=pt2d-vert; glVertex2fv(&tmp[0]); tmp=pt2d+vert; glVertex2fv(&tmp[0]); glEnd (); glLineWidth(1); } } } bool drawLinesEtc = true; if (!m_ShowDistantLines && counter > 0) // check, whether this line should be drawn { ScalarType currentDistance = displayGeometry->GetWorldGeometry()->SignedDistance(p); ScalarType lastDistance = displayGeometry->GetWorldGeometry()->SignedDistance(lastP); if ( currentDistance * lastDistance > 0.5 ) // points on same side of plane drawLinesEtc = false; } - - if ( m_Polygon && counter > 0 && drawLinesEtc) // draw a line - { - //get contour color property - float contourColor[4] = {unselectedColor[0], unselectedColor[1], unselectedColor[2], unselectedColor[3]};//so if no property set, then use unselected color - if (dynamic_cast(node->GetPropertyList(renderer)->GetProperty("contourcolor")) != NULL) - { - mitk::Color tmpColor = dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("contourcolor"))->GetValue(); - contourColor[0] = tmpColor[0]; - contourColor[1] = tmpColor[1]; - contourColor[2] = tmpColor[2]; - contourColor[3] = 1.0f; - } - else if (dynamic_cast(node->GetPropertyList(NULL)->GetProperty("contourcolor")) != NULL) - { - mitk::Color tmpColor = dynamic_cast(this->GetDataNode()->GetPropertyList(NULL)->GetProperty("contourcolor"))->GetValue(); - contourColor[0] = tmpColor[0]; - contourColor[1] = tmpColor[1]; - contourColor[2] = tmpColor[2]; - contourColor[3] = 1.0f; - } - //set this color - glColor3f(contourColor[0],contourColor[1],contourColor[2]); - - glLineWidth( m_LineWidth ); - glBegin (GL_LINES); - glVertex2fv(&pt2d[0]); - glVertex2fv(&lastPt2d[0]); - glEnd (); - glLineWidth(1.0); - if(m_ShowDistances) // calculate and print a distance - { - std::stringstream buffer; - float distance = vec.GetNorm(); - buffer<( renderer ); - OpenGLrenderer->WriteSimpleText(buffer.str(), pos2d[0], pos2d[1]); - //this->WriteTextXY(pos2d[0], pos2d[1], buffer.str(),renderer); - } - - if(m_ShowAngles && counter > 1 ) // calculate and print the angle btw. two lines - { - std::stringstream buffer; - //buffer << angle(vec.Get_vnl_vector(), -lastVec.Get_vnl_vector())*180/vnl_math::pi << "�"; - buffer << angle(vec.Get_vnl_vector(), -lastVec.Get_vnl_vector())*180/vnl_math::pi << (char)176; - - Vector2D vec2d = pt2d-lastPt2d; - vec2d.Normalize(); - Vector2D lastVec2d = lastPt2d-preLastPt2d; - lastVec2d.Normalize(); - vec2d=vec2d-lastVec2d; - vec2d.Normalize(); - - Vector2D pos2d = lastPt2d.GetVectorFromOrigin()+vec2d*text2dDistance*text2dDistance; - - mitk::VtkPropRenderer* OpenGLrenderer = dynamic_cast( renderer ); - OpenGLrenderer->WriteSimpleText(buffer.str(), pos2d[0], pos2d[1]); - //this->WriteTextXY(pos2d[0], pos2d[1], buffer.str(),renderer); - } - } + // draw a line + if ((m_Polygon && counter>0 && drawLinesEtc) || + (m_Polygon && m_PolygonClosed && drawLinesEtc)) + { + if ((counter == 0) && ( m_PolygonClosed)) + { + lastPt2d = lastPt2DInPointSet; + } + + //get contour color property + float contourColor[4] = {unselectedColor[0], unselectedColor[1], unselectedColor[2], unselectedColor[3]};//so if no property set, then use unselected color + if (dynamic_cast(node->GetPropertyList(renderer)->GetProperty("contourcolor")) != NULL) + { + mitk::Color tmpColor = dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("contourcolor"))->GetValue(); + contourColor[0] = tmpColor[0]; + contourColor[1] = tmpColor[1]; + contourColor[2] = tmpColor[2]; + contourColor[3] = 1.0f; + } + else if (dynamic_cast(node->GetPropertyList(NULL)->GetProperty("contourcolor")) != NULL) + { + mitk::Color tmpColor = dynamic_cast(this->GetDataNode()->GetPropertyList(NULL)->GetProperty("contourcolor"))->GetValue(); + contourColor[0] = tmpColor[0]; + contourColor[1] = tmpColor[1]; + contourColor[2] = tmpColor[2]; + contourColor[3] = 1.0f; + } + //set this color + glColor3f(contourColor[0],contourColor[1],contourColor[2]); + + glLineWidth( m_LineWidth ); + glBegin (GL_LINES); + glVertex2fv(&pt2d[0]); + glVertex2fv(&lastPt2d[0]); + glEnd (); + glLineWidth(1.0); + if(m_ShowDistances) // calculate and print a distance + { + std::stringstream buffer; + float distance = vec.GetNorm(); + buffer<( renderer ); + OpenGLrenderer->WriteSimpleText(buffer.str(), pos2d[0], pos2d[1]); + //this->WriteTextXY(pos2d[0], pos2d[1], buffer.str(),renderer); + } + + if(m_ShowAngles && counter > 1 ) // calculate and print the angle btw. two lines + { + std::stringstream buffer; + //buffer << angle(vec.Get_vnl_vector(), -lastVec.Get_vnl_vector())*180/vnl_math::pi << "�"; + buffer << angle(vec.Get_vnl_vector(), -lastVec.Get_vnl_vector())*180/vnl_math::pi << (char)176; + + Vector2D vec2d = pt2d-lastPt2d; + vec2d.Normalize(); + Vector2D lastVec2d = lastPt2d-preLastPt2d; + lastVec2d.Normalize(); + vec2d=vec2d-lastVec2d; + vec2d.Normalize(); + + Vector2D pos2d = lastPt2d.GetVectorFromOrigin()+vec2d*text2dDistance*text2dDistance; + + mitk::VtkPropRenderer* OpenGLrenderer = dynamic_cast( renderer ); + OpenGLrenderer->WriteSimpleText(buffer.str(), pos2d[0], pos2d[1]); + //this->WriteTextXY(pos2d[0], pos2d[1], buffer.str(),renderer); + } + } counter++; } ++it; if(selIt != selEnd && !pointDataBroken) - ++selIt; + ++selIt; j++; } //recall the color to the same color before this drawing glColor3f(recallColor[0],recallColor[1],recallColor[2]); } } void mitk::PointSetGLMapper2D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { node->AddProperty( "line width", mitk::IntProperty::New(2), renderer, overwrite ); // width of the line from one point to another node->AddProperty( "point line width", mitk::IntProperty::New(1), renderer, overwrite ); //width of the cross marking a point node->AddProperty( "point 2D size", mitk::IntProperty::New(8), renderer, overwrite ); // length of the cross marking a point // length of an edge of the box marking a point node->AddProperty( "show contour", mitk::BoolProperty::New(false), renderer, overwrite ); // contour of the line between points + node->AddProperty( "close contour", mitk::BoolProperty::New(false), renderer, overwrite ); node->AddProperty( "show points", mitk::BoolProperty::New(true), renderer, overwrite ); //show or hide points node->AddProperty( "show distances", mitk::BoolProperty::New(false), renderer, overwrite ); //show or hide distance measure (not always available) node->AddProperty( "distance decimal digits", mitk::IntProperty::New(2), renderer, overwrite ); //set the number of decimal digits to be shown node->AddProperty( "show angles", mitk::BoolProperty::New(false), renderer, overwrite ); //show or hide angle measurement (not always available) node->AddProperty( "show distant lines", mitk::BoolProperty::New(false), renderer, overwrite ); //show the line between to points from a distant view (equals "always on top" option) node->AddProperty( "show distant points", mitk::BoolProperty::New(true), renderer, overwrite ); //show the point when at a certain distance above/below the 2D imaging plane. node->AddProperty( "layer", mitk::IntProperty::New(1), renderer, overwrite ); // default to draw pointset above images (they have a default layer of 0) Superclass::SetDefaultProperties(node, renderer, overwrite); } diff --git a/Core/Code/Rendering/mitkPointSetGLMapper2D.h b/Core/Code/Rendering/mitkPointSetGLMapper2D.h index fcdbfe28b7..82d503147d 100644 --- a/Core/Code/Rendering/mitkPointSetGLMapper2D.h +++ b/Core/Code/Rendering/mitkPointSetGLMapper2D.h @@ -1,94 +1,95 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 MITKPointSetMAPPER2D_H_HEADER_INCLUDED #define MITKPointSetMAPPER2D_H_HEADER_INCLUDED #include #include "mitkGLMapper2D.h" namespace mitk { class BaseRenderer; class PointSet; /** * @brief OpenGL-based mapper to display a mitk::PointSet in a 2D window. * * This mapper can actually more than just draw a number of points of a * mitk::PointSet. If you set the right properties of the mitk::DataNode, * which contains the point set, then this mapper will also draw lines * connecting the points, and calculate and display distances and angles * between adjacent points. Here is a complete list of boolean properties, * which might be of interest: * * - \b "show contour": Draw not only the points but also the connections between * them (default false) * - \b "line width": IntProperty which gives the width of the contour lines * - \b "show points": Wheter or not to draw the actual points (default true) * - \b "show distances": Wheter or not to calculate and print the distance * between adjacent points (default false) * - \b "show angles": Wheter or not to calculate and print the angle between * adjacent points (default false) * - \b "show distant lines": When true, the mapper will also draw contour * lines that are far away form the current slice (default true) * - \b "label": StringProperty with a label for this point set * * BUG 1321 - possible new features: * point-2d-size (length of lines in cross/diamond) * point-linewidth * * @ingroup Mapper */ class MITK_CORE_EXPORT PointSetGLMapper2D : public GLMapper2D { public: mitkClassMacro(PointSetGLMapper2D, GLMapper2D); itkNewMacro(Self); /** @brief Get the PointDataList to map */ virtual const mitk::PointSet * GetInput(void); virtual void Paint(mitk::BaseRenderer * renderer); virtual void ApplyProperties(mitk::BaseRenderer* renderer); static void SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer = NULL, bool overwrite = false); protected: PointSetGLMapper2D(); virtual ~PointSetGLMapper2D(); bool m_Polygon; + bool m_PolygonClosed; bool m_ShowPoints; bool m_ShowDistances; int m_DistancesDecimalDigits; bool m_ShowAngles; bool m_ShowDistantLines; int m_LineWidth; int m_PointLineWidth; int m_Point2DSize; bool m_ShowDistantPoints; }; } // namespace mitk #endif /* MITKPointSetMapper2D_H_HEADER_INCLUDED */ diff --git a/Core/Code/Rendering/mitkPointSetVtkMapper3D.cpp b/Core/Code/Rendering/mitkPointSetVtkMapper3D.cpp index 765a37df65..615a9fc51a 100644 --- a/Core/Code/Rendering/mitkPointSetVtkMapper3D.cpp +++ b/Core/Code/Rendering/mitkPointSetVtkMapper3D.cpp @@ -1,634 +1,628 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkPointSetVtkMapper3D.h" #include "mitkDataNode.h" #include "mitkProperties.h" #include "mitkColorProperty.h" #include "mitkVtkPropRenderer.h" #include "mitkPointSet.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const mitk::PointSet* mitk::PointSetVtkMapper3D::GetInput() { return static_cast ( GetData() ); } mitk::PointSetVtkMapper3D::PointSetVtkMapper3D() : m_vtkSelectedPointList(NULL), m_vtkUnselectedPointList(NULL), m_VtkSelectedPolyDataMapper(NULL), m_VtkUnselectedPolyDataMapper(NULL), m_vtkTextList(NULL), m_NumberOfSelectedAdded(0), m_NumberOfUnselectedAdded(0), m_PointSize(1.0), m_ContourRadius(0.5) { //propassembly m_PointsAssembly = vtkSmartPointer::New(); //creating actors to be able to set transform m_SelectedActor = vtkSmartPointer::New(); m_UnselectedActor = vtkSmartPointer::New(); m_ContourActor = vtkSmartPointer::New(); } mitk::PointSetVtkMapper3D::~PointSetVtkMapper3D() { } void mitk::PointSetVtkMapper3D::ReleaseGraphicsResources(vtkWindow *renWin) { m_PointsAssembly->ReleaseGraphicsResources(renWin); m_SelectedActor->ReleaseGraphicsResources(renWin); m_UnselectedActor->ReleaseGraphicsResources(renWin); m_ContourActor->ReleaseGraphicsResources(renWin); } void mitk::PointSetVtkMapper3D::CreateVTKRenderObjects() { m_vtkSelectedPointList = vtkSmartPointer::New(); m_vtkUnselectedPointList = vtkSmartPointer::New(); m_PointsAssembly->VisibilityOn(); if(m_PointsAssembly->GetParts()->IsItemPresent(m_SelectedActor)) m_PointsAssembly->RemovePart(m_SelectedActor); if(m_PointsAssembly->GetParts()->IsItemPresent(m_UnselectedActor)) m_PointsAssembly->RemovePart(m_UnselectedActor); if(m_PointsAssembly->GetParts()->IsItemPresent(m_ContourActor)) m_PointsAssembly->RemovePart(m_ContourActor); // exceptional displaying for PositionTracker -> MouseOrientationTool int mapperID; bool isInputDevice=false; if( this->GetDataNode()->GetBoolProperty("inputdevice",isInputDevice) && isInputDevice ) { if( this->GetDataNode()->GetIntProperty("BaseRendererMapperID",mapperID) && mapperID == 2) return; //The event for the PositionTracker came from the 3d widget and not needs to be displayed } // get and update the PointSet mitk::PointSet::Pointer input = const_cast(this->GetInput()); /* only update the input data, if the property tells us to */ bool update = true; this->GetDataNode()->GetBoolProperty("updateDataOnRender", update); if (update == true) input->Update(); int timestep = this->GetTimestep(); mitk::PointSet::DataType::Pointer itkPointSet = input->GetPointSet( timestep ); if ( itkPointSet.GetPointer() == NULL) { m_PointsAssembly->VisibilityOff(); return; } mitk::PointSet::PointsContainer::Iterator pointsIter; mitk::PointSet::PointDataContainer::Iterator pointDataIter; int j; m_NumberOfSelectedAdded = 0; m_NumberOfUnselectedAdded = 0; //create contour bool makeContour = false; this->GetDataNode()->GetBoolProperty("show contour", makeContour); if (makeContour) { - this->CreateContour(NULL); + this->CreateContour(); } //now fill selected and unselected pointList //get size of Points in Property m_PointSize = 2; mitk::FloatProperty::Pointer pointSizeProp = dynamic_cast(this->GetDataNode()->GetProperty("pointsize")); if ( pointSizeProp.IsNotNull() ) m_PointSize = pointSizeProp->GetValue(); //get the property for creating a label onto every point only once bool showLabel = true; this->GetDataNode()->GetBoolProperty("show label", showLabel); const char * pointLabel=NULL; if(showLabel) { if(dynamic_cast(this->GetDataNode()->GetPropertyList()->GetProperty("label")) != NULL) pointLabel =dynamic_cast(this->GetDataNode()->GetPropertyList()->GetProperty("label"))->GetValue(); else showLabel = false; } //check if the list for the PointDataContainer is the same size as the PointsContainer. Is not, then the points were inserted manually and can not be visualized according to the PointData (selected/unselected) bool pointDataBroken = (itkPointSet->GetPointData()->Size() != itkPointSet->GetPoints()->Size()); //now add an object for each point in data pointDataIter = itkPointSet->GetPointData()->Begin(); for (j=0, pointsIter=itkPointSet->GetPoints()->Begin(); pointsIter!=itkPointSet->GetPoints()->End(); pointsIter++, j++) { //check for the pointtype in data and decide which geom-object to take and then add to the selected or unselected list int pointType; if(itkPointSet->GetPointData()->size() == 0 || pointDataBroken) pointType = mitk::PTUNDEFINED; else pointType = pointDataIter.Value().pointSpec; vtkSmartPointer source; switch (pointType) { case mitk::PTUNDEFINED: { vtkSmartPointer sphere = vtkSmartPointer::New(); sphere->SetRadius(m_PointSize); itk::Point point1 = pointsIter->Value(); sphere->SetCenter(point1[0],point1[1],point1[2]); //sphere->SetCenter(pointsIter.Value()[0],pointsIter.Value()[1],pointsIter.Value()[2]); //MouseOrientation Tool (PositionTracker) if(isInputDevice) { sphere->SetThetaResolution(10); sphere->SetPhiResolution(10); } else { sphere->SetThetaResolution(20); sphere->SetPhiResolution(20); } source = sphere; } break; case mitk::PTSTART: { vtkSmartPointer cube = vtkSmartPointer::New(); cube->SetXLength(m_PointSize/2); cube->SetYLength(m_PointSize/2); cube->SetZLength(m_PointSize/2); itk::Point point1 = pointsIter->Value(); cube->SetCenter(point1[0],point1[1],point1[2]); source = cube; } break; case mitk::PTCORNER: { vtkSmartPointer cone = vtkSmartPointer::New(); cone->SetRadius(m_PointSize); itk::Point point1 = pointsIter->Value(); cone->SetCenter(point1[0],point1[1],point1[2]); cone->SetResolution(20); source = cone; } break; case mitk::PTEDGE: { vtkSmartPointer cylinder = vtkSmartPointer::New(); cylinder->SetRadius(m_PointSize); itk::Point point1 = pointsIter->Value(); cylinder->SetCenter(point1[0],point1[1],point1[2]); cylinder->SetResolution(20); source = cylinder; } break; case mitk::PTEND: { vtkSmartPointer sphere = vtkSmartPointer::New(); sphere->SetRadius(m_PointSize); //itk::Point point1 = pointsIter->Value(); sphere->SetThetaResolution(20); sphere->SetPhiResolution(20); source = sphere; } break; default: { vtkSmartPointer sphere = vtkSmartPointer::New(); sphere->SetRadius(m_PointSize); itk::Point point1 = pointsIter->Value(); sphere->SetCenter(point1[0],point1[1],point1[2]); sphere->SetThetaResolution(20); sphere->SetPhiResolution(20); source = sphere; } break; } if (!pointDataBroken) { if (pointDataIter.Value().selected) { m_vtkSelectedPointList->AddInput(source->GetOutput()); ++m_NumberOfSelectedAdded; } else { m_vtkUnselectedPointList->AddInput(source->GetOutput()); ++m_NumberOfUnselectedAdded; } } else { m_vtkUnselectedPointList->AddInput(source->GetOutput()); ++m_NumberOfUnselectedAdded; } if (showLabel) { char buffer[20]; std::string l = pointLabel; if ( input->GetSize()>1 ) { sprintf(buffer,"%d",j+1); l.append(buffer); } // Define the text for the label vtkSmartPointer label = vtkSmartPointer::New(); label->SetText(l.c_str()); //# Set up a transform to move the label to a new position. vtkSmartPointer aLabelTransform = vtkSmartPointer::New(); aLabelTransform->Identity(); itk::Point point1 = pointsIter->Value(); aLabelTransform->Translate(point1[0]+2,point1[1]+2,point1[2]); aLabelTransform->Scale(5.7,5.7,5.7); //# Move the label to a new position. vtkSmartPointer labelTransform = vtkSmartPointer::New(); labelTransform->SetTransform(aLabelTransform); labelTransform->SetInput(label->GetOutput()); //add it to the wright PointList if (pointType) { m_vtkSelectedPointList->AddInput(labelTransform->GetOutput()); ++m_NumberOfSelectedAdded; } else { m_vtkUnselectedPointList->AddInput(labelTransform->GetOutput()); ++m_NumberOfUnselectedAdded; } } if(pointDataIter != itkPointSet->GetPointData()->End()) pointDataIter++; } // end FOR //now according to number of elements added to selected or unselected, build up the rendering pipeline if (m_NumberOfSelectedAdded > 0) { m_VtkSelectedPolyDataMapper = vtkSmartPointer::New(); m_VtkSelectedPolyDataMapper->SetInput(m_vtkSelectedPointList->GetOutput()); //create a new instance of the actor m_SelectedActor = vtkSmartPointer::New(); m_SelectedActor->SetMapper(m_VtkSelectedPolyDataMapper); m_PointsAssembly->AddPart(m_SelectedActor); } if (m_NumberOfUnselectedAdded > 0) { m_VtkUnselectedPolyDataMapper = vtkSmartPointer::New(); m_VtkUnselectedPolyDataMapper->SetInput(m_vtkUnselectedPointList->GetOutput()); //create a new instance of the actor m_UnselectedActor = vtkSmartPointer::New(); m_UnselectedActor->SetMapper(m_VtkUnselectedPolyDataMapper); m_PointsAssembly->AddPart(m_UnselectedActor); } } void mitk::PointSetVtkMapper3D::GenerateData() { //create new vtk render objects (e.g. sphere for a point) this->CreateVTKRenderObjects(); //apply props this->ApplyProperties(m_ContourActor,NULL); } void mitk::PointSetVtkMapper3D::GenerateDataForRenderer( mitk::BaseRenderer *renderer ) { SetVtkMapperImmediateModeRendering(m_VtkSelectedPolyDataMapper); SetVtkMapperImmediateModeRendering(m_VtkUnselectedPolyDataMapper); mitk::FloatProperty::Pointer pointSizeProp = dynamic_cast(this->GetDataNode()->GetProperty("pointsize")); mitk::FloatProperty::Pointer contourSizeProp = dynamic_cast(this->GetDataNode()->GetProperty("contoursize")); // only create new vtk render objects if property values were changed if ( pointSizeProp.IsNotNull() && contourSizeProp.IsNotNull() ) { if (m_PointSize!=pointSizeProp->GetValue() || m_ContourRadius!= contourSizeProp->GetValue()) { this->CreateVTKRenderObjects(); } } this->ApplyProperties(m_ContourActor,renderer); if(IsVisible(renderer)==false) { m_UnselectedActor->VisibilityOff(); m_SelectedActor->VisibilityOff(); m_ContourActor->VisibilityOff(); return; } bool showPoints = true; this->GetDataNode()->GetBoolProperty("show points", showPoints); if(showPoints) { m_UnselectedActor->VisibilityOn(); m_SelectedActor->VisibilityOn(); } else { m_UnselectedActor->VisibilityOff(); m_SelectedActor->VisibilityOff(); } if(dynamic_cast(this->GetDataNode()->GetProperty("opacity")) != NULL) { mitk::FloatProperty::Pointer pointOpacity =dynamic_cast(this->GetDataNode()->GetProperty("opacity")); float opacity = pointOpacity->GetValue(); m_ContourActor->GetProperty()->SetOpacity(opacity); m_UnselectedActor->GetProperty()->SetOpacity(opacity); m_SelectedActor->GetProperty()->SetOpacity(opacity); } bool makeContour = false; this->GetDataNode()->GetBoolProperty("show contour", makeContour); if (makeContour) { m_ContourActor->VisibilityOn(); } else { m_ContourActor->VisibilityOff(); } } void mitk::PointSetVtkMapper3D::ResetMapper( BaseRenderer* /*renderer*/ ) { m_PointsAssembly->VisibilityOff(); } vtkProp* mitk::PointSetVtkMapper3D::GetVtkProp(mitk::BaseRenderer * /*renderer*/) { return m_PointsAssembly; } void mitk::PointSetVtkMapper3D::UpdateVtkTransform(mitk::BaseRenderer * /*renderer*/) { vtkSmartPointer vtktransform = this->GetDataNode()->GetVtkTransform(this->GetTimestep()); m_SelectedActor->SetUserTransform(vtktransform); m_UnselectedActor->SetUserTransform(vtktransform); m_ContourActor->SetUserTransform(vtktransform); } void mitk::PointSetVtkMapper3D::ApplyProperties(vtkActor* actor, mitk::BaseRenderer* renderer) { Superclass::ApplyProperties(actor,renderer); //check for color props and use it for rendering of selected/unselected points and contour //due to different params in VTK (double/float) we have to convert! //vars to convert to vtkFloatingPointType unselectedColor[4]={1.0f,1.0f,0.0f,1.0f};//yellow vtkFloatingPointType selectedColor[4]={1.0f,0.0f,0.0f,1.0f};//red vtkFloatingPointType contourColor[4]={1.0f,0.0f,0.0f,1.0f};//red //different types for color!!! mitk::Color tmpColor; double opacity = 1.0; //check if there is an unselected property if (dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("unselectedcolor")) != NULL) { tmpColor = dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("unselectedcolor"))->GetValue(); unselectedColor[0] = tmpColor[0]; unselectedColor[1] = tmpColor[1]; unselectedColor[2] = tmpColor[2]; unselectedColor[3] = 1.0f; //!!define a new ColorProp to be able to pass alpha value } else if (dynamic_cast(this->GetDataNode()->GetPropertyList(NULL)->GetProperty("unselectedcolor")) != NULL) { tmpColor = dynamic_cast(this->GetDataNode()->GetPropertyList(NULL)->GetProperty("unselectedcolor"))->GetValue(); unselectedColor[0] = tmpColor[0]; unselectedColor[1] = tmpColor[1]; unselectedColor[2] = tmpColor[2]; unselectedColor[3] = 1.0f; //!!define a new ColorProp to be able to pass alpha value } else { //check if the node has a color float unselectedColorTMP[4]={1.0f,1.0f,0.0f,1.0f};//yellow m_DataNode->GetColor(unselectedColorTMP, NULL); unselectedColor[0] = unselectedColorTMP[0]; unselectedColor[1] = unselectedColorTMP[1]; unselectedColor[2] = unselectedColorTMP[2]; //unselectedColor[3] stays 1.0f } //get selected property if (dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("selectedcolor")) != NULL) { tmpColor = dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("selectedcolor"))->GetValue(); selectedColor[0] = tmpColor[0]; selectedColor[1] = tmpColor[1]; selectedColor[2] = tmpColor[2]; selectedColor[3] = 1.0f; } else if (dynamic_cast(this->GetDataNode()->GetPropertyList(NULL)->GetProperty("selectedcolor")) != NULL) { tmpColor = dynamic_cast(this->GetDataNode()->GetPropertyList(NULL)->GetProperty("selectedcolor"))->GetValue(); selectedColor[0] = tmpColor[0]; selectedColor[1] = tmpColor[1]; selectedColor[2] = tmpColor[2]; selectedColor[3] = 1.0f; } //get contour property if (dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("contourcolor")) != NULL) { tmpColor = dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("contourcolor"))->GetValue(); contourColor[0] = tmpColor[0]; contourColor[1] = tmpColor[1]; contourColor[2] = tmpColor[2]; contourColor[3] = 1.0f; } else if (dynamic_cast(this->GetDataNode()->GetPropertyList(NULL)->GetProperty("contourcolor")) != NULL) { tmpColor = dynamic_cast(this->GetDataNode()->GetPropertyList(NULL)->GetProperty("contourcolor"))->GetValue(); contourColor[0] = tmpColor[0]; contourColor[1] = tmpColor[1]; contourColor[2] = tmpColor[2]; contourColor[3] = 1.0f; } if(dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("opacity")) != NULL) { mitk::FloatProperty::Pointer pointOpacity =dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("opacity")); opacity = pointOpacity->GetValue(); } else if(dynamic_cast(this->GetDataNode()->GetPropertyList(NULL)->GetProperty("opacity")) != NULL) { mitk::FloatProperty::Pointer pointOpacity =dynamic_cast(this->GetDataNode()->GetPropertyList(NULL)->GetProperty("opacity")); opacity = pointOpacity->GetValue(); } //finished color / opacity fishing! //check if a contour shall be drawn bool makeContour = false; this->GetDataNode()->GetBoolProperty("show contour", makeContour, renderer); - int visibleBefore = m_ContourActor->GetVisibility(); if(makeContour && (m_ContourActor != NULL) ) { - if ( visibleBefore == 0) - {//was not visible before, so create it. - this->CreateContour(renderer); - } + this->CreateContour(); m_ContourActor->GetProperty()->SetColor(contourColor); m_ContourActor->GetProperty()->SetOpacity(opacity); } m_SelectedActor->GetProperty()->SetColor(selectedColor); m_SelectedActor->GetProperty()->SetOpacity(opacity); m_UnselectedActor->GetProperty()->SetColor(unselectedColor); m_UnselectedActor->GetProperty()->SetOpacity(opacity); } -void mitk::PointSetVtkMapper3D::CreateContour(mitk::BaseRenderer* renderer) +void mitk::PointSetVtkMapper3D::CreateContour() { vtkSmartPointer vtkContourPolyData = vtkSmartPointer::New(); vtkSmartPointer vtkContourPolyDataMapper = vtkSmartPointer::New(); vtkSmartPointer points = vtkSmartPointer::New(); vtkSmartPointer polys = vtkSmartPointer::New(); mitk::PointSet::PointsContainer::Iterator pointsIter; // mitk::PointSet::PointDataContainer::Iterator pointDataIter; int j; // get and update the PointSet mitk::PointSet::Pointer input = const_cast(this->GetInput()); int timestep = this->GetTimestep(); mitk::PointSet::DataType::Pointer itkPointSet = input->GetPointSet( timestep ); if ( itkPointSet.GetPointer() == NULL) { return; } for (j=0, pointsIter=itkPointSet->GetPoints()->Begin(); pointsIter!=itkPointSet->GetPoints()->End() ; pointsIter++,j++) { vtkIdType cell[2] = {j-1,j}; itk::Point point1 = pointsIter->Value(); points->InsertPoint(j,point1[0],point1[1],point1[2]); if (j>0) polys->InsertNextCell(2,cell); } - bool close; - if (dynamic_cast(this->GetDataNode()->GetPropertyList()->GetProperty("close contour"), renderer) == NULL) - close = false; - else - close = dynamic_cast(this->GetDataNode()->GetPropertyList()->GetProperty("close contour"), renderer)->GetValue(); + bool close = false; + this->GetDataNode()->GetBoolProperty("close contour", close); if (close) { vtkIdType cell[2] = {j-1,0}; polys->InsertNextCell(2,cell); } vtkSmartPointer contour = vtkSmartPointer::New(); contour->SetPoints(points); contour->SetLines(polys); contour->Update(); vtkSmartPointer tubeFilter = vtkSmartPointer::New(); tubeFilter->SetNumberOfSides( 12 ); tubeFilter->SetInput(contour); //check for property contoursize. m_ContourRadius = 0.5; mitk::FloatProperty::Pointer contourSizeProp = dynamic_cast(this->GetDataNode()->GetProperty("contoursize") ); if (contourSizeProp.IsNotNull()) m_ContourRadius = contourSizeProp->GetValue(); tubeFilter->SetRadius( m_ContourRadius ); tubeFilter->Update(); //add to pipeline vtkContourPolyData->AddInput(tubeFilter->GetOutput()); vtkContourPolyDataMapper->SetInput(vtkContourPolyData->GetOutput()); m_ContourActor->SetMapper(vtkContourPolyDataMapper); m_PointsAssembly->AddPart(m_ContourActor); } void mitk::PointSetVtkMapper3D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { node->AddProperty( "line width", mitk::IntProperty::New(2), renderer, overwrite ); node->AddProperty( "pointsize", mitk::FloatProperty::New(1.0), renderer, overwrite); node->AddProperty( "selectedcolor", mitk::ColorProperty::New(1.0f, 0.0f, 0.0f), renderer, overwrite); //red node->AddProperty( "color", mitk::ColorProperty::New(1.0f, 1.0f, 0.0f), renderer, overwrite); //yellow node->AddProperty( "show contour", mitk::BoolProperty::New(false), renderer, overwrite ); + node->AddProperty( "close contour", mitk::BoolProperty::New(false), renderer, overwrite ); node->AddProperty( "contourcolor", mitk::ColorProperty::New(1.0f, 0.0f, 0.0f), renderer, overwrite); node->AddProperty( "contoursize", mitk::FloatProperty::New(0.5), renderer, overwrite ); node->AddProperty( "show points", mitk::BoolProperty::New(true), renderer, overwrite ); node->AddProperty( "updateDataOnRender", mitk::BoolProperty::New(true), renderer, overwrite ); Superclass::SetDefaultProperties(node, renderer, overwrite); } diff --git a/Core/Code/Rendering/mitkPointSetVtkMapper3D.h b/Core/Code/Rendering/mitkPointSetVtkMapper3D.h index ca748b2305..6d44ebf4c4 100644 --- a/Core/Code/Rendering/mitkPointSetVtkMapper3D.h +++ b/Core/Code/Rendering/mitkPointSetVtkMapper3D.h @@ -1,152 +1,152 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKPointSetVtkMAPPER3D_H_HEADER_INCLUDED_C1907273 #define MITKPointSetVtkMAPPER3D_H_HEADER_INCLUDED_C1907273 #include #include "mitkVtkMapper3D.h" #include "mitkBaseRenderer.h" #include class vtkActor; class vtkPropAssembly; class vtkAppendPolyData; class vtkPolyData; class vtkTubeFilter; class vtkPolyDataMapper; namespace mitk { class PointSet; /** * @brief Vtk-based mapper for PointSet * * Due to the need of different colors for selected * and unselected points and the facts, that we also have a contour and * labels for the points, the vtk structure is build up the following way: * * We have two AppendPolyData, one selected, and one unselected and one * for a contour between the points. Each one is connected to an own * PolyDaraMapper and an Actor. The different color for the unselected and * selected state and for the contour is read from properties. * * "unselectedcolor", "selectedcolor" and "contourcolor" are the strings, * that are looked for. Pointlabels are added besides the selected or the * deselected points. * * Then the three Actors are combined inside a vtkPropAssembly and this * object is returned in GetProp() and so hooked up into the rendering * pipeline. * Properties that can be set for point sets and influence the PointSetVTKMapper3D are: * * - \b "color": (ColorProperty*) Color of the point set * - \b "Opacity": (FloatProperty) Opacity of the point set * - \b "show contour": (BoolProperty) If the contour of the points are visible * - \b "contourSizeProp":(FloatProperty) Contour size of the points The default properties are: * - \b "line width": (IntProperty::New(2), renderer, overwrite ) * - \b "pointsize": (FloatProperty::New(1.0), renderer, overwrite) * - \b "selectedcolor": (ColorProperty::New(1.0f, 0.0f, 0.0f), renderer, overwrite) //red * - \b "color": (ColorProperty::New(1.0f, 1.0f, 0.0f), renderer, overwrite) //yellow * - \b "show contour": (BoolProperty::New(false), renderer, overwrite ) * - \b "contourcolor": (ColorProperty::New(1.0f, 0.0f, 0.0f), renderer, overwrite) * - \b "contoursize": (FloatProperty::New(0.5), renderer, overwrite ) * - \b "close contour": (BoolProperty::New(false), renderer, overwrite ) * - \b "show points": (BoolProperty::New(true), renderer, overwrite ) * - \b "updateDataOnRender": (BoolProperty::New(true), renderer, overwrite ) *Other properties looked for are: * * - \b "show contour": if set to on, lines between the points are shown * - \b "close contour": if set to on, the open strip is closed (first point * connected with last point) * - \b "pointsize": size of the points mapped * - \b "label": text of the Points to show besides points * - \b "contoursize": size of the contour drawn between the points * (if not set, the pointsize is taken) * * @ingroup Mapper */ class MITK_CORE_EXPORT PointSetVtkMapper3D : public VtkMapper3D { public: mitkClassMacro(PointSetVtkMapper3D, VtkMapper3D); itkNewMacro(Self); virtual const mitk::PointSet* GetInput(); //overwritten from VtkMapper3D to be able to return a //m_PointsAssembly which is much faster than a vtkAssembly virtual vtkProp* GetVtkProp(mitk::BaseRenderer* renderer); virtual void UpdateVtkTransform(mitk::BaseRenderer* renderer); static void SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer = NULL, bool overwrite = false); void ReleaseGraphicsResources(vtkWindow *renWin); protected: PointSetVtkMapper3D(); virtual ~PointSetVtkMapper3D(); virtual void GenerateData(); virtual void GenerateDataForRenderer(mitk::BaseRenderer* renderer); virtual void ResetMapper( BaseRenderer* renderer ); virtual void ApplyProperties(vtkActor* actor, mitk::BaseRenderer* renderer); - virtual void CreateContour(mitk::BaseRenderer* renderer); + virtual void CreateContour(); virtual void CreateVTKRenderObjects(); vtkSmartPointer m_vtkSelectedPointList; vtkSmartPointer m_vtkUnselectedPointList; vtkSmartPointer m_VtkSelectedPolyDataMapper; vtkSmartPointer m_VtkUnselectedPolyDataMapper; vtkSmartPointer m_SelectedActor; vtkSmartPointer m_UnselectedActor; vtkSmartPointer m_ContourActor; vtkSmartPointer m_PointsAssembly; //help for contour between points vtkSmartPointer m_vtkTextList; //variables to be able to log, how many inputs have been added to PolyDatas unsigned int m_NumberOfSelectedAdded; unsigned int m_NumberOfUnselectedAdded; //variables to check if an update of the vtk objects is needed ScalarType m_PointSize; ScalarType m_ContourRadius; }; } // namespace mitk #endif /* MITKPointSetVtkMAPPER3D_H_HEADER_INCLUDED_C1907273 */ diff --git a/Core/Code/Rendering/mitkVolumeDataVtkMapper3D.cpp b/Core/Code/Rendering/mitkVolumeDataVtkMapper3D.cpp index a55b41c982..c1a13605e4 100644 --- a/Core/Code/Rendering/mitkVolumeDataVtkMapper3D.cpp +++ b/Core/Code/Rendering/mitkVolumeDataVtkMapper3D.cpp @@ -1,703 +1,704 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkVolumeDataVtkMapper3D.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 #include #include #include "mitkVtkVolumeRenderingProperty.h" #include const mitk::Image* mitk::VolumeDataVtkMapper3D::GetInput() { return static_cast ( GetData() ); } mitk::VolumeDataVtkMapper3D::VolumeDataVtkMapper3D() : m_Mask( NULL ) { m_PlaneSet = false; m_ClippingPlane = vtkPlane::New(); m_PlaneWidget = vtkImplicitPlaneWidget::New(); /* m_T2DMapper = vtkVolumeTextureMapper2D::New(); m_T2DMapper->SetMaximumNumberOfPlanes( 100 ); */ m_HiResMapper = vtkVolumeRayCastMapper::New(); m_HiResMapper->SetSampleDistance(1.0); // 4 rays for every pixel m_HiResMapper->IntermixIntersectingGeometryOn(); m_HiResMapper->SetNumberOfThreads( itk::MultiThreader::GetGlobalDefaultNumberOfThreads() ); /* vtkVolumeRayCastCompositeFunction* compositeFunction = vtkVolumeRayCastCompositeFunction::New(); compositeFunction->SetCompositeMethodToClassifyFirst(); m_HiResMapper->SetVolumeRayCastFunction(compositeFunction); compositeFunction->Delete(); vtkVolumeRayCastMIPFunction* mipFunction = vtkVolumeRayCastMIPFunction::New(); m_HiResMapper->SetVolumeRayCastFunction(mipFunction); mipFunction->Delete(); */ vtkFiniteDifferenceGradientEstimator* gradientEstimator = vtkFiniteDifferenceGradientEstimator::New(); m_HiResMapper->SetGradientEstimator(gradientEstimator); gradientEstimator->Delete(); m_VolumePropertyLow = vtkVolumeProperty::New(); m_VolumePropertyMed = vtkVolumeProperty::New(); m_VolumePropertyHigh = vtkVolumeProperty::New(); m_VolumeLOD = vtkLODProp3D::New(); m_VolumeLOD->VisibilityOff(); m_HiResID = m_VolumeLOD->AddLOD(m_HiResMapper,m_VolumePropertyHigh,0.0); // RayCast // m_LowResID = m_VolumeLOD->AddLOD(m_T2DMapper,m_VolumePropertyLow,0.0); // TextureMapper2D m_MedResID = m_VolumeLOD->AddLOD(m_HiResMapper,m_VolumePropertyMed,0.0); // RayCast m_Resampler = vtkImageResample::New(); m_Resampler->SetAxisMagnificationFactor(0,0.25); m_Resampler->SetAxisMagnificationFactor(1,0.25); m_Resampler->SetAxisMagnificationFactor(2,0.25); // For abort rendering mechanism m_VolumeLOD->AutomaticLODSelectionOff(); m_BoundingBox = vtkCubeSource::New(); m_BoundingBox->SetXLength( 0.0 ); m_BoundingBox->SetYLength( 0.0 ); m_BoundingBox->SetZLength( 0.0 ); m_BoundingBoxMapper = vtkPolyDataMapper::New(); m_BoundingBoxMapper->SetInput( m_BoundingBox->GetOutput() ); m_BoundingBoxActor = vtkActor::New(); m_BoundingBoxActor->SetMapper( m_BoundingBoxMapper ); m_BoundingBoxActor->GetProperty()->SetColor( 1.0, 1.0, 1.0 ); m_BoundingBoxActor->GetProperty()->SetRepresentationToWireframe(); // BoundingBox rendering is not working due to problem with assembly // transformation; see bug #454 // If commenting in the following, do not forget to comment in the // m_Prop3DAssembly->Delete() line in the destructor. //m_Prop3DAssembly = vtkAssembly::New(); //m_Prop3DAssembly->AddPart( m_VolumeLOD ); //m_Prop3DAssembly->AddPart( m_BoundingBoxActor ); //m_Prop3D = m_Prop3DAssembly; m_ImageCast = vtkImageShiftScale::New(); m_ImageCast->SetOutputScalarTypeToUnsignedShort(); m_ImageCast->ClampOverflowOn(); m_UnitSpacingImageFilter = vtkImageChangeInformation::New(); m_UnitSpacingImageFilter->SetInput(m_ImageCast->GetOutput()); m_UnitSpacingImageFilter->SetOutputSpacing( 1.0, 1.0, 1.0 ); m_ImageMaskFilter = vtkImageMask::New(); m_ImageMaskFilter->SetMaskedOutputValue(0xffff); this->m_Resampler->SetInput( this->m_UnitSpacingImageFilter->GetOutput() ); this->m_HiResMapper->SetInput( this->m_UnitSpacingImageFilter->GetOutput() ); // m_T2DMapper->SetInput(m_Resampler->GetOutput()); this->CreateDefaultTransferFunctions(); } vtkProp *mitk::VolumeDataVtkMapper3D::GetVtkProp(mitk::BaseRenderer * /*renderer*/) { return m_VolumeLOD; } mitk::VolumeDataVtkMapper3D::~VolumeDataVtkMapper3D() { m_UnitSpacingImageFilter->Delete(); m_ImageCast->Delete(); // m_T2DMapper->Delete(); m_HiResMapper->Delete(); m_Resampler->Delete(); m_VolumePropertyLow->Delete(); m_VolumePropertyMed->Delete(); m_VolumePropertyHigh->Delete(); m_VolumeLOD->Delete(); m_ClippingPlane->Delete(); m_PlaneWidget->Delete(); // m_Prop3DAssembly->Delete(); m_BoundingBox->Delete(); m_BoundingBoxMapper->Delete(); m_BoundingBoxActor->Delete(); m_ImageMaskFilter->Delete(); m_DefaultColorTransferFunction->Delete(); m_DefaultOpacityTransferFunction->Delete(); m_DefaultGradientTransferFunction->Delete(); if (m_Mask) { m_Mask->Delete(); } } void mitk::VolumeDataVtkMapper3D::GenerateDataForRenderer( mitk::BaseRenderer *renderer ) { SetVtkMapperImmediateModeRendering(m_BoundingBoxMapper); mitk::Image *input = const_cast< mitk::Image * >( this->GetInput() ); if ( !input || !input->IsInitialized() ) return; vtkRenderWindow* renderWindow = renderer->GetRenderWindow(); bool volumeRenderingEnabled = true; if (this->IsVisible(renderer)==false || this->GetDataNode() == NULL || dynamic_cast(GetDataNode()->GetProperty("volumerendering",renderer))==NULL || dynamic_cast(GetDataNode()->GetProperty("volumerendering",renderer))->GetValue() == false ) { volumeRenderingEnabled = false; // Check if a bounding box should be displayed around the dataset // (even if volume rendering is disabled) bool hasBoundingBox = false; this->GetDataNode()->GetBoolProperty( "bounding box", hasBoundingBox ); if ( !hasBoundingBox ) { m_BoundingBoxActor->VisibilityOff(); } else { m_BoundingBoxActor->VisibilityOn(); const BoundingBox::BoundsArrayType &bounds = input->GetTimeSlicedGeometry()->GetBounds(); m_BoundingBox->SetBounds( bounds[0], bounds[1], bounds[2], bounds[3], bounds[4], bounds[5] ); ColorProperty *colorProperty; if ( this->GetDataNode()->GetProperty( colorProperty, "color" ) ) { const mitk::Color &color = colorProperty->GetColor(); m_BoundingBoxActor->GetProperty()->SetColor( color[0], color[1], color[2] ); } else { m_BoundingBoxActor->GetProperty()->SetColor( 1.0, 1.0, 1.0 ); } } } // Don't do anything if VR is disabled if ( !volumeRenderingEnabled ) { m_VolumeLOD->VisibilityOff(); return; } else { mitk::VtkVolumeRenderingProperty* vrp=dynamic_cast(GetDataNode()->GetProperty("volumerendering configuration",renderer)); if(vrp) { int renderingValue = vrp->GetValueAsId(); switch(renderingValue) { case VTK_VOLUME_RAY_CAST_MIP_FUNCTION: { vtkVolumeRayCastMIPFunction* mipFunction = vtkVolumeRayCastMIPFunction::New(); m_HiResMapper->SetVolumeRayCastFunction(mipFunction); mipFunction->Delete(); MITK_INFO <<"in switch" <SetCompositeMethodToClassifyFirst(); m_HiResMapper->SetVolumeRayCastFunction(compositeFunction); compositeFunction->Delete(); break; } default: MITK_ERROR <<"Warning: invalid volume rendering option. " << std::endl; } } m_VolumeLOD->VisibilityOn(); } this->SetPreferences(); /* switch ( mitk::RenderingManager::GetInstance()->GetNextLOD( renderer ) ) { case 0: m_VolumeLOD->SetSelectedLODID(m_MedResID); m_LowResID ); break; default: case 1: m_VolumeLOD->SetSelectedLODID( m_HiResID ); break; } */ m_VolumeLOD->SetSelectedLODID( m_HiResID ); assert(input->GetTimeSlicedGeometry()); const Geometry3D* worldgeometry = renderer->GetCurrentWorldGeometry(); if(worldgeometry==NULL) { GetDataNode()->SetProperty("volumerendering",mitk::BoolProperty::New(false)); return; } vtkImageData *inputData = input->GetVtkImageData( this->GetTimestep() ); if(inputData==NULL) return; m_ImageCast->SetInput( inputData ); //If mask exists, process mask before resampling. if (this->m_Mask) { this->m_ImageMaskFilter->SetImageInput(this->m_UnitSpacingImageFilter->GetOutput()); this->m_Resampler->SetInput(this->m_ImageMaskFilter->GetOutput()); this->m_HiResMapper->SetInput(this->m_ImageMaskFilter->GetOutput()); } else { this->m_Resampler->SetInput(this->m_UnitSpacingImageFilter->GetOutput()); this->m_HiResMapper->SetInput(this->m_UnitSpacingImageFilter->GetOutput()); } this->UpdateTransferFunctions( renderer ); vtkRenderWindowInteractor *interactor = renderWindow->GetInteractor(); float frameRate; if( this->GetDataNode()->GetFloatProperty( "framerate", frameRate ) && frameRate > 0 && frameRate <= 60) { interactor->SetDesiredUpdateRate( frameRate ); interactor->SetStillUpdateRate( frameRate ); } else if( frameRate > 60 ) { this->GetDataNode()->SetProperty( "framerate",mitk::FloatProperty::New(60)); interactor->SetDesiredUpdateRate( 60 ); interactor->SetStillUpdateRate( 60 ); } else { this->GetDataNode()->SetProperty( "framerate",mitk::FloatProperty::New(0.00001)); interactor->SetDesiredUpdateRate( 0.00001 ); interactor->SetStillUpdateRate( 0.00001 ); } if ( m_RenderWindowInitialized.find( renderWindow ) == m_RenderWindowInitialized.end() ) { m_RenderWindowInitialized.insert( renderWindow ); // mitk::RenderingManager::GetInstance()->SetNextLOD( 0, renderer ); mitk::RenderingManager::GetInstance()->SetShading( true, 0 ); mitk::RenderingManager::GetInstance()->SetShading( true, 1 ); //mitk::RenderingManager::GetInstance()->SetShading( true, 2 ); mitk::RenderingManager::GetInstance()->SetShadingValues( m_VolumePropertyHigh->GetAmbient(), m_VolumePropertyHigh->GetDiffuse(), m_VolumePropertyHigh->GetSpecular(), m_VolumePropertyHigh->GetSpecularPower()); mitk::RenderingManager::GetInstance()->SetClippingPlaneStatus(false); } this->SetClippingPlane( interactor ); } void mitk::VolumeDataVtkMapper3D::CreateDefaultTransferFunctions() { m_DefaultOpacityTransferFunction = vtkPiecewiseFunction::New(); m_DefaultOpacityTransferFunction->AddPoint( 0.0, 0.0 ); m_DefaultOpacityTransferFunction->AddPoint( 255.0, 0.8 ); m_DefaultOpacityTransferFunction->ClampingOn(); m_DefaultGradientTransferFunction = vtkPiecewiseFunction::New(); m_DefaultGradientTransferFunction->AddPoint( 0.0, 0.0 ); m_DefaultGradientTransferFunction->AddPoint( 255.0, 0.8 ); m_DefaultGradientTransferFunction->ClampingOn(); m_DefaultColorTransferFunction = vtkColorTransferFunction::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(); } void mitk::VolumeDataVtkMapper3D::UpdateTransferFunctions( mitk::BaseRenderer *renderer ) { vtkPiecewiseFunction *opacityTransferFunction = NULL; vtkPiecewiseFunction *gradientTransferFunction = NULL; vtkColorTransferFunction *colorTransferFunction = NULL; mitk::LookupTableProperty::Pointer lookupTableProp; lookupTableProp = dynamic_cast(this->GetDataNode()->GetProperty("LookupTable")); mitk::TransferFunctionProperty::Pointer transferFunctionProp = dynamic_cast(this->GetDataNode()->GetProperty("TransferFunction")); if ( transferFunctionProp.IsNotNull() ) { opacityTransferFunction = transferFunctionProp->GetValue()->GetScalarOpacityFunction(); gradientTransferFunction = transferFunctionProp->GetValue()->GetGradientOpacityFunction(); colorTransferFunction = transferFunctionProp->GetValue()->GetColorTransferFunction(); } else if (lookupTableProp.IsNotNull() ) { lookupTableProp->GetLookupTable()->CreateOpacityTransferFunction(opacityTransferFunction); opacityTransferFunction->ClampingOn(); lookupTableProp->GetLookupTable()->CreateGradientTransferFunction(gradientTransferFunction); gradientTransferFunction->ClampingOn(); lookupTableProp->GetLookupTable()->CreateColorTransferFunction(colorTransferFunction); colorTransferFunction->ClampingOn(); } else { opacityTransferFunction = m_DefaultOpacityTransferFunction; gradientTransferFunction = m_DefaultGradientTransferFunction; colorTransferFunction = m_DefaultColorTransferFunction; float rgb[3]={1.0f,1.0f,1.0f}; // check for color prop and use it for rendering if it exists if(GetColor(rgb, renderer)) { colorTransferFunction->AddRGBPoint( 0.0, 0.0, 0.0, 0.0 ); colorTransferFunction->AddRGBPoint( 127.5, rgb[0], rgb[1], rgb[2] ); colorTransferFunction->AddRGBPoint( 255.0, rgb[0], rgb[1], rgb[2] ); } } if (this->m_Mask) { opacityTransferFunction->AddPoint(0xffff, 0.0); } m_VolumePropertyLow->SetColor( colorTransferFunction ); m_VolumePropertyLow->SetScalarOpacity( opacityTransferFunction ); m_VolumePropertyLow->SetGradientOpacity( gradientTransferFunction ); m_VolumePropertyLow->SetInterpolationTypeToNearest(); m_VolumePropertyMed->SetColor( colorTransferFunction ); m_VolumePropertyMed->SetScalarOpacity( opacityTransferFunction ); m_VolumePropertyMed->SetGradientOpacity( gradientTransferFunction ); m_VolumePropertyMed->SetInterpolationTypeToNearest(); m_VolumePropertyHigh->SetColor( colorTransferFunction ); m_VolumePropertyHigh->SetScalarOpacity( opacityTransferFunction ); m_VolumePropertyHigh->SetGradientOpacity( gradientTransferFunction ); m_VolumePropertyHigh->SetInterpolationTypeToLinear(); } /* Shading enabled / disabled */ void mitk::VolumeDataVtkMapper3D::SetPreferences() { //LOD 0 /*if(mitk::RenderingManager::GetInstance()->GetShading(0)) { m_VolumePropertyLow->ShadeOn(); m_VolumePropertyLow->SetAmbient(mitk::RenderingManager::GetInstance()->GetShadingValues()[0]); m_VolumePropertyLow->SetDiffuse(mitk::RenderingManager::GetInstance()->GetShadingValues()[1]); m_VolumePropertyLow->SetSpecular(mitk::RenderingManager::GetInstance()->GetShadingValues()[2]); m_VolumePropertyLow->SetSpecularPower(mitk::RenderingManager::GetInstance()->GetShadingValues()[3]); } else*/ { m_VolumePropertyLow->ShadeOff(); } //LOD 1 /*if(mitk::RenderingManager::GetInstance()->GetShading(1)) { m_VolumePropertyMed->ShadeOn(); m_VolumePropertyMed->SetAmbient(mitk::RenderingManager::GetInstance()->GetShadingValues()[0]); m_VolumePropertyMed->SetDiffuse(mitk::RenderingManager::GetInstance()->GetShadingValues()[1]); m_VolumePropertyMed->SetSpecular(mitk::RenderingManager::GetInstance()->GetShadingValues()[2]); m_VolumePropertyMed->SetSpecularPower(mitk::RenderingManager::GetInstance()->GetShadingValues()[3]); } else*/ { m_VolumePropertyMed->ShadeOff(); } //LOD 2 /* if(mitk::RenderingManager::GetInstance()->GetShading(2)) { m_VolumePropertyHigh->ShadeOn(); //Shading Properties m_VolumePropertyHigh->SetAmbient(mitk::RenderingManager::GetInstance()->GetShadingValues()[0]); m_VolumePropertyHigh->SetDiffuse(mitk::RenderingManager::GetInstance()->GetShadingValues()[1]); m_VolumePropertyHigh->SetSpecular(mitk::RenderingManager::GetInstance()->GetShadingValues()[2]); m_VolumePropertyHigh->SetSpecularPower(mitk::RenderingManager::GetInstance()->GetShadingValues()[3]); } else { m_VolumePropertyHigh->ShadeOff(); } */ } /* Adds A Clipping Plane to the Mapper */ void mitk::VolumeDataVtkMapper3D::SetClippingPlane(vtkRenderWindowInteractor* interactor) { if(mitk::RenderingManager::GetInstance()->GetClippingPlaneStatus()) //if clipping plane is enabled { if(!m_PlaneSet) { m_PlaneWidget->SetInteractor(interactor); m_PlaneWidget->SetPlaceFactor(1.0); m_PlaneWidget->SetInput(m_UnitSpacingImageFilter->GetOutput()); m_PlaneWidget->OutlineTranslationOff(); //disables scaling of the bounding box m_PlaneWidget->ScaleEnabledOff(); //disables scaling of the bounding box m_PlaneWidget->DrawPlaneOff(); //clipping plane is transparent mitk::Image* input = const_cast(this->GetInput()); /*places the widget within the specified bounds*/ m_PlaneWidget->PlaceWidget( input->GetGeometry()->GetOrigin()[0],(input->GetGeometry()->GetOrigin()[0])+(input->GetDimension(0))*(input->GetVtkImageData()->GetSpacing()[0]), input->GetGeometry()->GetOrigin()[1],(input->GetGeometry()->GetOrigin()[1])+(input->GetDimension(1))*(input->GetVtkImageData()->GetSpacing()[1]), input->GetGeometry()->GetOrigin()[2],(input->GetGeometry()->GetOrigin()[2])+(input->GetDimension(2))*(input->GetVtkImageData()->GetSpacing()[2])); // m_T2DMapper->AddClippingPlane(m_ClippingPlane); m_HiResMapper->AddClippingPlane(m_ClippingPlane); } m_PlaneWidget->GetPlane(m_ClippingPlane); m_PlaneSet = true; } else //if clippingplane is disabled { if(m_PlaneSet) //if plane exists { DelClippingPlane(); } } } /* Removes the clipping plane */ void mitk::VolumeDataVtkMapper3D::DelClippingPlane() { // m_T2DMapper->RemoveAllClippingPlanes(); m_HiResMapper->RemoveAllClippingPlanes(); m_PlaneSet = false; } void mitk::VolumeDataVtkMapper3D::ApplyProperties(vtkActor* /*actor*/, mitk::BaseRenderer* /*renderer*/) { } void mitk::VolumeDataVtkMapper3D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { node->AddProperty( "volumerendering", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "volumerendering configuration", mitk::VtkVolumeRenderingProperty::New( 1 ), 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("LookupTable", renderer)==NULL)) { // add a default rainbow lookup table for color mapping 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((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::VolumeDataVtkMapper3D::IsLODEnabled( mitk::BaseRenderer * /*renderer*/ ) const { return false; // Volume mapper is LOD enabled if volumerendering is enabled /* return dynamic_cast(GetDataNode()->GetProperty("volumerendering",renderer)) != NULL && dynamic_cast(GetDataNode()->GetProperty("volumerendering",renderer))->GetValue() == true; */ } void mitk::VolumeDataVtkMapper3D::EnableMask() { if (!this->m_Mask) { const Image *orig_image = this->GetInput(); unsigned int *dimensions = orig_image->GetDimensions(); this->m_Mask = vtkImageData::New(); this->m_Mask->SetDimensions(dimensions[0], dimensions[1], dimensions[2]); this->m_Mask->SetScalarTypeToUnsignedChar(); this->m_Mask->SetNumberOfScalarComponents(1); this->m_Mask->AllocateScalars(); unsigned char *mask_data = static_cast(this->m_Mask->GetScalarPointer()); unsigned int size = dimensions[0] * dimensions[1] * dimensions[2]; for (unsigned int i = 0u; i < size; ++i) { *mask_data++ = 1u; } this->m_ImageMaskFilter->SetMaskInput(this->m_Mask); this->m_ImageMaskFilter->Modified(); } } void mitk::VolumeDataVtkMapper3D::DisableMask() { if (this->m_Mask) { this->m_Mask->Delete(); this->m_Mask = 0; } } mitk::Image::Pointer mitk::VolumeDataVtkMapper3D::GetMask() { if (this->m_Mask) { Image::Pointer mask = Image::New(); mask->Initialize(this->m_Mask); mask->SetImportVolume(this->m_Mask->GetScalarPointer(), 0, 0, Image::ReferenceMemory); mask->SetGeometry(this->GetInput()->GetGeometry()); return mask; } return 0; } void mitk::VolumeDataVtkMapper3D::UpdateMask() { if (this->m_Mask) { this->m_ImageMaskFilter->Modified(); } } bool mitk::VolumeDataVtkMapper3D::SetMask(const mitk::Image* mask) { if (this->m_Mask) { - if (mask->GetPixelType().GetPixelTypeId() == typeid(unsigned char)) + if ( (mask->GetPixelType().GetTypeId() == typeid(unsigned char)) + &&(mask->GetPixelType().GetPixelTypeId() == itk::ImageIOBase::SCALAR )) { Image *img = const_cast(mask); this->m_Mask->DeepCopy(img->GetVtkImageData()); this->m_ImageMaskFilter->Modified(); return true; } } return false; } diff --git a/Core/Code/Testing/CMakeLists.txt b/Core/Code/Testing/CMakeLists.txt index 0109b8f000..f18e543bdd 100644 --- a/Core/Code/Testing/CMakeLists.txt +++ b/Core/Code/Testing/CMakeLists.txt @@ -1,74 +1,74 @@ 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(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) 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 transversal slice +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 ) SET_PROPERTY(TEST mitkImageVtkMapper2D_rgbaImage640x480 mitkImageVtkMapper2D_pic3d640x480 mitkImageVtkMapper2D_pic3dColorBlue640x480 mitkImageVtkMapper2D_pic3dLevelWindow640x480 mitkImageVtkMapper2D_pic3dSwivel640x480 #mitkImageVtkMapper2D_pic3dOpacity640x480 PROPERTY RUN_SERIAL TRUE) endif() # see bug 9882 if(NOT APPLE) add_test(mitkPointSetLocaleTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkPointSetLocaleTest ${MITK_DATA_DIR}/pointSet.mps) set_property(TEST mitkPointSetLocaleTest PROPERTY LABELS MITK-Core) endif() 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/DICOMTesting/Testing/CMakeLists.txt b/Core/Code/Testing/DICOMTesting/Testing/CMakeLists.txt index 5a6abc3527..c99ef83c4c 100644 --- a/Core/Code/Testing/DICOMTesting/Testing/CMakeLists.txt +++ b/Core/Code/Testing/DICOMTesting/Testing/CMakeLists.txt @@ -1,77 +1,82 @@ MITK_CREATE_MODULE_TESTS(LABELS MITK-Core) include(mitkFunctionAddTestLabel) # verify minimum expectations: # files are recognized as DICOM # loading files results in a given number of images mitkAddCustomModuleTest(mitkDICOMTestingSanityTest_NoFiles mitkDICOMTestingSanityTest 0) mitkAddCustomModuleTest(mitkDICOMTestingSanityTest_CTImage mitkDICOMTestingSanityTest 1 ${MITK_DATA_DIR}/spacing-ok-ct.dcm) mitkAddCustomModuleTest(mitkDICOMTestingSanityTest_MRImage mitkDICOMTestingSanityTest 1 ${MITK_DATA_DIR}/spacing-ok-mr.dcm) mitkAddCustomModuleTest(mitkDICOMTestingSanityTest_SCImage mitkDICOMTestingSanityTest 1 ${MITK_DATA_DIR}/spacing-ok-sc.dcm) mitkAddCustomModuleTest(mitkDICOMTestingSanityTest_DefectImage mitkDICOMTestingSanityTest 0 ${MITK_DATA_DIR}/spacing-ok-sc-no2032.dcm) #see bug 8108 if(NOT APPLE) set(VERIFY_DUMP_CMD ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/VerifyDICOMMitkImageDump) set(CT_ABDOMEN_DIR ${MITK_DATA_DIR}/TinyCTAbdomen) -set(CT_TILT_DIR ${MITK_DATA_DIR}/TiltHead) +set(MR_HEART_DIR ${MITK_DATA_DIR}/3D+t-Heart) +set(CT_TILT_HEAD_DIR ${MITK_DATA_DIR}/TiltHead) +set(CT_TILT_DIR ${MITK_DATA_DIR}/TiltedData) + # these variables could be passed as parameters to a generic test creation function set(TESTS_DIR Tests) set(INPUT_LISTNAME input) set(EXPECTED_DUMP expected.dump) function(AddDicomTestsFromDataRepository CURRENT_DATASET_DIR TESTS_DIR INPUT_LISTNAME EXPECTED_DUMP) # find all test input lists file(GLOB_RECURSE allInputs ${CURRENT_DATASET_DIR}/${TESTS_DIR}/*/${INPUT_LISTNAME}) function(expectFileExists filename) if(NOT EXISTS ${filename}) message(SEND_ERROR "Test case expected file ${filename} which does not exist! Please fix your CMake code or file layout.") endif(NOT EXISTS ${filename}) endfunction(expectFileExists) foreach(input ${allInputs}) # extract only the name of the directory of this very test case string(REGEX REPLACE ".*${TESTS_DIR}/([^/]+)/.*" "\\1" input ${input}) set(inputfilelist "${CURRENT_DATASET_DIR}/${TESTS_DIR}/${input}/${INPUT_LISTNAME}") set(expecteddump "${CURRENT_DATASET_DIR}/${TESTS_DIR}/${input}/${EXPECTED_DUMP}") set(testname "DICOM_Load_${input}") message(STATUS "DICOM loading test case '${input}'") expectFileExists(${inputfilelist}) expectFileExists(${expecteddump}) # TODO provide error messages if input not valid set(dicomFiles) # clear list # read list of file names from file "input" file(STRINGS ${inputfilelist} rawDicomFiles) foreach(raw ${rawDicomFiles}) # prepend each file with an abosolute path set(fileWithFullPath ${CURRENT_DATASET_DIR}/${raw}) list(APPEND dicomFiles ${fileWithFullPath}) endforeach(raw ${rawDicomFiles}) #message(STATUS " Load ${dicomFiles}") add_test(${testname} ${VERIFY_DUMP_CMD} ${expecteddump} ${dicomFiles}) mitkFunctionAddTestLabel(${testname}) endforeach(input allInputs) endfunction(AddDicomTestsFromDataRepository CURRENT_DATASET_DIR TESTS_DIR INPUT_LISTNAME EXPECTED_DUMP) AddDicomTestsFromDataRepository(${CT_ABDOMEN_DIR} ${TESTS_DIR} ${INPUT_LISTNAME} ${EXPECTED_DUMP}) +AddDicomTestsFromDataRepository(${CT_TILT_HEAD_DIR} ${TESTS_DIR} ${INPUT_LISTNAME} ${EXPECTED_DUMP}) AddDicomTestsFromDataRepository(${CT_TILT_DIR} ${TESTS_DIR} ${INPUT_LISTNAME} ${EXPECTED_DUMP}) +AddDicomTestsFromDataRepository(${MR_HEART_DIR} ${TESTS_DIR} ${INPUT_LISTNAME} ${EXPECTED_DUMP}) endif() # apple diff --git a/Core/Code/Testing/files.cmake b/Core/Code/Testing/files.cmake index 9ac6730ccd..5adde09786 100644 --- a/Core/Code/Testing/files.cmake +++ b/Core/Code/Testing/files.cmake @@ -1,117 +1,118 @@ # tests with no extra command line parameter set(MODULE_TESTS mitkAccessByItkTest.cpp mitkCoreObjectFactoryTest.cpp mitkMaterialTest.cpp mitkActionTest.cpp mitkEnumerationPropertyTest.cpp mitkEventTest.cpp mitkFocusManagerTest.cpp mitkGenericPropertyTest.cpp mitkGeometry3DTest.cpp mitkGeometryDataToSurfaceFilterTest.cpp mitkGlobalInteractionTest.cpp mitkImageDataItemTest.cpp #mitkImageMapper2DTest.cpp mitkImageGeneratorTest.cpp mitkBaseDataTest.cpp #mitkImageToItkTest.cpp mitkInstantiateAccessFunctionTest.cpp mitkInteractorTest.cpp mitkITKThreadingTest.cpp # mitkLevelWindowManagerTest.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 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 ) # 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 ) # 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 ) # 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} mitkRenderingTestHelper.cpp) diff --git a/Core/Code/Testing/mitkExtractSliceFilterTest.cpp b/Core/Code/Testing/mitkExtractSliceFilterTest.cpp index 58142d5a83..d6191597c5 100644 --- a/Core/Code/Testing/mitkExtractSliceFilterTest.cpp +++ b/Core/Code/Testing/mitkExtractSliceFilterTest.cpp @@ -1,1160 +1,1160 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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; //the center of the straight lines typename InputImageType::IndexType centerX, 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::Transversal); + 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::Transversal) + 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 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); /* 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; - /* transversal plane */ - mitk::PlaneGeometry::Pointer geometryTransversal = mitk::PlaneGeometry::New(); - geometryTransversal->InitializeStandardPlane(planeSize, planeSize, spacing, mitk::PlaneGeometry::Transversal, sphereCenter, false, true); - geometryTransversal->ChangeImageGeometryConsideringOriginOffset(true); + /* 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 = geometryTransversal->GetOrigin(); + mitk::Point3D origin = geometryAxial->GetOrigin(); mitk::Vector3D normal; - normal = geometryTransversal->GetNormal(); + normal = geometryAxial->GetNormal(); normal.Normalize(); origin += normal * 0.5;//pixelspacing is 1, so half the spacing is 0.5 - //geometryTransversal->SetOrigin(origin); + //geometryAxial->SetOrigin(origin); - mitkExtractSliceFilterTestClass::TestSlice(geometryTransversal, "Testing transversal plane"); - /* end transversal plane */ + 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 (transversal, coronal and saggital) afterwards. + //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/mitkImageGeneratorTest.cpp b/Core/Code/Testing/mitkImageGeneratorTest.cpp index 115b299f9f..b14992672f 100644 --- a/Core/Code/Testing/mitkImageGeneratorTest.cpp +++ b/Core/Code/Testing/mitkImageGeneratorTest.cpp @@ -1,62 +1,70 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkImage.h" #include "mitkImageStatisticsHolder.h" #include "mitkImageGenerator.h" int mitkImageGeneratorTest(int /*argc*/, char* /*argv*/[]) { MITK_TEST_BEGIN("ToFImageWriter"); //create some images with arbitrary parameters (corner cases) mitk::Image::Pointer image2Da = mitk::ImageGenerator::GenerateRandomImage(120, 205, 0, 0, 577, 23); mitk::Image::Pointer image2Db = mitk::ImageGenerator::GenerateRandomImage(1, 1, 0, 0); mitk::Image::Pointer image3Da = mitk::ImageGenerator::GenerateRandomImage(512, 205, 1, 0); mitk::Image::Pointer image3Db = mitk::ImageGenerator::GenerateRandomImage(512, 532, 112, 0); mitk::Image::Pointer image4Da = mitk::ImageGenerator::GenerateRandomImage(120, 205, 78, 1); mitk::Image::Pointer image4Db = mitk::ImageGenerator::GenerateRandomImage(550, 33, 78, 150); MITK_TEST_CONDITION_REQUIRED(image2Da->GetDimension() == 2, "Testing if the dimension is set correctly."); MITK_TEST_CONDITION_REQUIRED(image2Db->GetDimension() == 2, "Testing if the dimension is set correctly."); MITK_TEST_CONDITION_REQUIRED(image3Da->GetDimension() == 2, "Testing if the dimension is set correctly."); MITK_TEST_CONDITION_REQUIRED(image3Db->GetDimension() == 3, "Testing if the dimension is set correctly."); MITK_TEST_CONDITION_REQUIRED(image4Da->GetDimension() == 3, "Testing if the dimension is set correctly."); MITK_TEST_CONDITION_REQUIRED(image4Db->GetDimension() == 4, "Testing if the dimension is set correctly."); MITK_TEST_CONDITION_REQUIRED(image2Da->GetDimension(0) == 120, "Testing if the dimensions are set correctly."); MITK_TEST_CONDITION_REQUIRED(image2Db->GetDimension(1) == 1, "Testing if the dimensions are set correctly."); MITK_TEST_CONDITION_REQUIRED(image3Da->GetDimension(2) == 1, "Testing if the dimensions are set correctly."); MITK_TEST_CONDITION_REQUIRED(image3Db->GetDimension(2) == 112, "Testing if the dimensions are set correctly."); MITK_TEST_CONDITION_REQUIRED(image4Da->GetDimension(3) == 1, "Testing if the dimensions are set correctly."); MITK_TEST_CONDITION_REQUIRED(image4Db->GetDimension(3) == 150, "Testing if the dimensions are set correctly."); - MITK_TEST_CONDITION_REQUIRED(image2Da->GetPixelType() == typeid(float), "Testing if the data type is set correctly."); - MITK_TEST_CONDITION_REQUIRED(image2Db->GetPixelType() == typeid(unsigned char), "Testing if the data type is set correctly."); - MITK_TEST_CONDITION_REQUIRED(image3Da->GetPixelType() == typeid(int), "Testing if the data type is set correctly."); - MITK_TEST_CONDITION_REQUIRED(image3Db->GetPixelType() == typeid(double), "Testing if the data type is set correctly."); - MITK_TEST_CONDITION_REQUIRED(image4Da->GetPixelType() == typeid(float), "Testing if the data type is set correctly."); - MITK_TEST_CONDITION_REQUIRED(image4Db->GetPixelType() == typeid(unsigned char), "Testing if the ddata type is set correctly."); + itk::ImageIOBase::IOPixelType scalarType = itk::ImageIOBase::SCALAR; + + MITK_TEST_CONDITION_REQUIRED(image2Da->GetPixelType().GetTypeId() == typeid(float), "Testing if the data type is set correctly."); + MITK_TEST_CONDITION_REQUIRED(image2Da->GetPixelType().GetPixelTypeId() == scalarType, "Testing if the pixel type is set correctly."); + MITK_TEST_CONDITION_REQUIRED(image2Db->GetPixelType().GetTypeId() == typeid(unsigned char), "Testing if the data type is set correctly."); + MITK_TEST_CONDITION_REQUIRED(image2Db->GetPixelType().GetPixelTypeId() == scalarType, "Testing if the data type is set correctly."); + MITK_TEST_CONDITION_REQUIRED(image3Da->GetPixelType().GetTypeId() == typeid(int), "Testing if the data type is set correctly."); + MITK_TEST_CONDITION_REQUIRED(image3Da->GetPixelType().GetPixelTypeId() == scalarType, "Testing if the pixel type is set correctly."); + MITK_TEST_CONDITION_REQUIRED(image3Db->GetPixelType().GetTypeId() == typeid(double), "Testing if the data type is set correctly."); + MITK_TEST_CONDITION_REQUIRED(image3Db->GetPixelType().GetPixelTypeId() == scalarType, "Testing if the pixel type is set correctly."); + MITK_TEST_CONDITION_REQUIRED(image4Da->GetPixelType().GetTypeId() == typeid(float), "Testing if the data type is set correctly."); + MITK_TEST_CONDITION_REQUIRED(image4Da->GetPixelType().GetPixelTypeId() == scalarType, "Testing if the pixel type is set correctly."); + MITK_TEST_CONDITION_REQUIRED(image4Db->GetPixelType().GetTypeId() == typeid(unsigned char), "Testing if the data type is set correctly."); + MITK_TEST_CONDITION_REQUIRED(image4Db->GetPixelType().GetPixelTypeId() == scalarType, "Testing if the pixel type is set correctly."); MITK_TEST_CONDITION_REQUIRED(image2Da->GetStatistics()->GetScalarValueMax() <= 577, "Testing if max value holds"); MITK_TEST_CONDITION_REQUIRED(image2Da->GetStatistics()->GetScalarValueMin() >= 23, "Testing if min value holds"); MITK_TEST_CONDITION_REQUIRED(image3Da->GetStatistics()->GetScalarValueMax() <= 1000, "Testing if max value holds"); MITK_TEST_CONDITION_REQUIRED(image3Da->GetStatistics()->GetScalarValueMin() >= 0, "Testing if min value holds"); MITK_TEST_END(); } diff --git a/Core/Code/Testing/mitkImageVtkMapper2DColorTest.cpp b/Core/Code/Testing/mitkImageVtkMapper2DColorTest.cpp index 0773680ad2..290c3d09d7 100644 --- a/Core/Code/Testing/mitkImageVtkMapper2DColorTest.cpp +++ b/Core/Code/Testing/mitkImageVtkMapper2DColorTest.cpp @@ -1,74 +1,74 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //MITK #include "mitkTestingMacros.h" #include "mitkRenderingTestHelper.h" //VTK #include int mitkImageVtkMapper2DColorTest(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("mitkImageVtkMapper2DTest") // enough parameters? if ( argc < 2 ) { MITK_TEST_OUTPUT( << "Usage: " << std::string(*argv) << " [file1 file2 ...] outputfile" ) - MITK_TEST_OUTPUT( << "Will render a central transversal slice of all given files into 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); //Set the opacity for all images renderingHelper.SetProperty("use color", mitk::BoolProperty::New(true)); renderingHelper.SetProperty("color", mitk::ColorProperty::New(0.0f, 0.0f, 255.0f)); //for now this test renders in sagittal view direction renderingHelper.SetViewDirection(mitk::SliceNavigationController::Sagittal); 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"); } //### Usage of vtkRegressionTestImage: //vtkRegressionTestImage( vtkRenderWindow ) //Set a vtkRenderWindow containing the desired scene. //vtkRegressionTestImage automatically searches in argc and argv[] //for a path a valid image with -V. If the test failed with the //first image (foo.png) check if there are images of the form //foo_N.png (where N=1,2,3...) and compare against them. int retVal = vtkRegressionTestImage( renderingHelper.GetVtkRenderWindow() ); //retVal meanings: (see VTK/Rendering/vtkTesting.h) //0 = test failed //1 = test passed //2 = test not run //3 = something with vtkInteraction MITK_TEST_CONDITION( retVal == 1, "VTK test result positive" ); MITK_TEST_END(); } diff --git a/Core/Code/Testing/mitkImageVtkMapper2DLevelWindowTest.cpp b/Core/Code/Testing/mitkImageVtkMapper2DLevelWindowTest.cpp index fd62b2a8f1..1ff13d9144 100644 --- a/Core/Code/Testing/mitkImageVtkMapper2DLevelWindowTest.cpp +++ b/Core/Code/Testing/mitkImageVtkMapper2DLevelWindowTest.cpp @@ -1,80 +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. ===================================================================*/ //MITK #include "mitkTestingMacros.h" #include "mitkRenderingTestHelper.h" #include #include //VTK #include int mitkImageVtkMapper2DLevelWindowTest(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("mitkImageVtkMapper2DTest") // enough parameters? if ( argc < 2 ) { MITK_TEST_OUTPUT( << "Usage: " << std::string(*argv) << " [file1 file2 ...] outputfile" ) - MITK_TEST_OUTPUT( << "Will render a central transversal slice of all given files into 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); //chose a level window: here we randomly chosen the blood preset. mitk::LevelWindowPreset* levelWindowPreset = mitk::LevelWindowPreset::New(); bool loadedPreset = levelWindowPreset->LoadPreset(); MITK_TEST_CONDITION_REQUIRED(loadedPreset == true, "Testing if level window preset could be loaded"); double level = levelWindowPreset->getLevel("Blood"); double window = levelWindowPreset->getWindow("Blood"); //apply level window to all images renderingHelper.SetProperty("levelwindow", mitk::LevelWindowProperty::New(mitk::LevelWindow(level, window)) ); //for now this test renders Sagittal renderingHelper.SetViewDirection(mitk::SliceNavigationController::Sagittal); 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"); } //### Usage of vtkRegressionTestImage: //vtkRegressionTestImage( vtkRenderWindow ) //Set a vtkRenderWindow containing the desired scene. //vtkRegressionTestImage automatically searches in argc and argv[] //for a path a valid image with -V. If the test failed with the //first image (foo.png) check if there are images of the form //foo_N.png (where N=1,2,3...) and compare against them. int retVal = vtkRegressionTestImage( renderingHelper.GetVtkRenderWindow() ); //retVal meanings: (see VTK/Rendering/vtkTesting.h) //0 = test failed //1 = test passed //2 = test not run //3 = something with vtkInteraction MITK_TEST_CONDITION( retVal == 1, "VTK test result positive" ); MITK_TEST_END(); } diff --git a/Core/Code/Testing/mitkImageVtkMapper2DOpacityTest.cpp b/Core/Code/Testing/mitkImageVtkMapper2DOpacityTest.cpp index 19bb96972b..f2f266bd5e 100644 --- a/Core/Code/Testing/mitkImageVtkMapper2DOpacityTest.cpp +++ b/Core/Code/Testing/mitkImageVtkMapper2DOpacityTest.cpp @@ -1,73 +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. ===================================================================*/ //MITK #include "mitkTestingMacros.h" #include "mitkRenderingTestHelper.h" //VTK #include int mitkImageVtkMapper2DOpacityTest(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("mitkImageVtkMapper2DTest") // enough parameters? if ( argc < 2 ) { MITK_TEST_OUTPUT( << "Usage: " << std::string(*argv) << " [file1 file2 ...] outputfile" ) - MITK_TEST_OUTPUT( << "Will render a central transversal slice of all given files into 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); //Set the opacity for all images renderingHelper.SetProperty("opacity", mitk::FloatProperty::New(0.5f)); //for now this test renders in coronal view direction renderingHelper.SetViewDirection(mitk::SliceNavigationController::Frontal); 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"); } //### Usage of vtkRegressionTestImage: //vtkRegressionTestImage( vtkRenderWindow ) //Set a vtkRenderWindow containing the desired scene. //vtkRegressionTestImage automatically searches in argc and argv[] //for a path a valid image with -V. If the test failed with the //first image (foo.png) check if there are images of the form //foo_N.png (where N=1,2,3...) and compare against them. int retVal = vtkRegressionTestImage( renderingHelper.GetVtkRenderWindow() ); //retVal meanings: (see VTK/Rendering/vtkTesting.h) //0 = test failed //1 = test passed //2 = test not run //3 = something with vtkInteraction MITK_TEST_CONDITION( retVal == 1, "VTK test result positive" ); MITK_TEST_END(); } diff --git a/Core/Code/Testing/mitkImageVtkMapper2DSwivelTest.cpp b/Core/Code/Testing/mitkImageVtkMapper2DSwivelTest.cpp index 135261f7a3..030cfce348 100644 --- a/Core/Code/Testing/mitkImageVtkMapper2DSwivelTest.cpp +++ b/Core/Code/Testing/mitkImageVtkMapper2DSwivelTest.cpp @@ -1,88 +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. ===================================================================*/ //MITK #include "mitkTestingMacros.h" #include "mitkRenderingTestHelper.h" #include //VTK #include int mitkImageVtkMapper2DSwivelTest(int argc, char* argv[]) { //load all arguments into a datastorage, take last argument as reference //setup a renderwindow of fixed size X*Y //render the datastorage //compare rendering to reference image MITK_TEST_BEGIN("mitkImageVtkMapper2DSwivelTest") // enough parameters? if ( argc < 2 ) { MITK_TEST_OUTPUT( << "Usage: " << std::string(*argv) << " [file1 file2 ...] outputfile" ) - MITK_TEST_OUTPUT( << "Will render a central transversal slice of all given files into 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); //center point for rotation mitk::Point3D centerPoint; centerPoint.Fill(0.0f); //vector for rotating the slice mitk::Vector3D rotationVector; rotationVector.SetElement(0, 0.2); rotationVector.SetElement(1, 0.3); rotationVector.SetElement(2, 0.5); //sets a swivel direction for the image //new version of setting the center point: mitk::Image::Pointer image = static_cast(renderingHelper.GetDataStorage()->GetNode(mitk::NodePredicateDataType::New("Image"))->GetData()); //get the center point of the image centerPoint = image->GetGeometry()->GetCenter(); //rotate the image arround its own center renderingHelper.ReorientSlices(centerPoint, rotationVector); renderingHelper.Render(); //use this to generate a reference screenshot or save the file: bool generateReferenceScreenshot = false; if(generateReferenceScreenshot) { renderingHelper.SaveAsPNG("/media/hdd/thomasHdd/Pictures/RenderingTestData/pic3dSwivel640x480REF.png"); } //### Usage of vtkRegressionTestImage: //vtkRegressionTestImage( vtkRenderWindow ) //Set a vtkRenderWindow containing the desired scene. //vtkRegressionTestImage automatically searches in argc and argv[] //for a path a valid image with -V. If the test failed with the //first image (foo.png) check if there are images of the form //foo_N.png (where N=1,2,3...) and compare against them. int retVal = vtkRegressionTestImage( renderingHelper.GetVtkRenderWindow() ); //retVal meanings: (see VTK/Rendering/vtkTesting.h) //0 = test failed //1 = test passed //2 = test not run //3 = something with vtkInteraction MITK_TEST_CONDITION( retVal == 1, "VTK test result positive" ); MITK_TEST_END(); } diff --git a/Core/Code/Testing/mitkImageVtkMapper2DTest.cpp b/Core/Code/Testing/mitkImageVtkMapper2DTest.cpp index 13f36691b6..7738aa4bc2 100644 --- a/Core/Code/Testing/mitkImageVtkMapper2DTest.cpp +++ b/Core/Code/Testing/mitkImageVtkMapper2DTest.cpp @@ -1,69 +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. ===================================================================*/ //MITK #include "mitkTestingMacros.h" #include "mitkRenderingTestHelper.h" //VTK #include int mitkImageVtkMapper2DTest(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("mitkImageVtkMapper2DTest") // enough parameters? if ( argc < 2 ) { MITK_TEST_OUTPUT( << "Usage: " << std::string(*argv) << " [file1 file2 ...] outputfile" ) - MITK_TEST_OUTPUT( << "Will render a central transversal slice of all given files into 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); 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"); } //### Usage of vtkRegressionTestImage: //vtkRegressionTestImage( vtkRenderWindow ) //Set a vtkRenderWindow containing the desired scene. //vtkRegressionTestImage automatically searches in argc and argv[] //for a path a valid image with -V. If the test failed with the //first image (foo.png) check if there are images of the form //foo_N.png (where N=1,2,3...) and compare against them. int retVal = vtkRegressionTestImage( renderingHelper.GetVtkRenderWindow() ); //retVal meanings: (see VTK/Rendering/vtkTesting.h) //0 = test failed //1 = test passed //2 = test not run //3 = something with vtkInteraction MITK_TEST_CONDITION( retVal == 1, "VTK test result positive" ); MITK_TEST_END(); } diff --git a/Core/Code/Testing/mitkLogTest.cpp b/Core/Code/Testing/mitkLogTest.cpp index 019d091d55..7f35ab327b 100644 --- a/Core/Code/Testing/mitkLogTest.cpp +++ b/Core/Code/Testing/mitkLogTest.cpp @@ -1,232 +1,242 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkCommon.h" #include "mitkTestingMacros.h" #include #include #include #include #include /** Documentation * * @brief Objects of this class can start an internal thread by calling the Start() method. * The thread is then logging messages until the method Stop() is called. The class * can be used to test if logging is thread-save by using multiple objects and let * them log simuntanously. */ -class mitkTestLoggingThread +class mitkTestLoggingThread : public itk::Object { +public: + +mitkClassMacro(mitkTestLoggingThread,itk::Object); +mitkNewMacro2Param(mitkTestLoggingThread,int,itk::MultiThreader::Pointer); + protected: +mitkTestLoggingThread(int number, itk::MultiThreader::Pointer MultiThreader) + { + ThreadID = number; + m_MultiThreader = MultiThreader; + } + bool LoggingRunning; int ThreadID; itk::MultiThreader::Pointer m_MultiThreader; void LogMessages() { while(LoggingRunning) { MITK_INFO << "Test info stream in thread " << ThreadID; MITK_WARN << "Test warning stream in thread " << ThreadID; MITK_DEBUG << "Test debugging stream in thread " << ThreadID; MITK_ERROR << "Test error stream in thread " << ThreadID; MITK_FATAL << "Test fatal stream in thread " << ThreadID; + } } static ITK_THREAD_RETURN_TYPE ThreadStartTracking(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; if (pInfo == NULL) { return ITK_THREAD_RETURN_VALUE; } if (pInfo->UserData == NULL) { return ITK_THREAD_RETURN_VALUE; } mitkTestLoggingThread *thisthread = (mitkTestLoggingThread*)pInfo->UserData; if (thisthread != NULL) thisthread->LogMessages(); return ITK_THREAD_RETURN_VALUE; } public: -mitkTestLoggingThread(int number, itk::MultiThreader::Pointer MultiThreader) - { - ThreadID = number; - m_MultiThreader = MultiThreader; - } - void Start() { LoggingRunning = true; m_MultiThreader->SpawnThread(this->ThreadStartTracking, this); + } void Stop() { LoggingRunning = false; } }; /** Documentation * * @brief This class holds static test methods to sturcture the test of the mitk logging mechanism. */ class mitkLogTestClass { public: static void TestSimpleLog() { bool testSucceded = true; try { MITK_INFO << "Test info stream."; MITK_WARN << "Test warning stream."; MITK_DEBUG << "Test debugging stream."; //only activated if cmake variable is on! //so no worries if you see no output for this line MITK_ERROR << "Test error stream."; MITK_FATAL << "Test fatal stream."; } catch(mitk::Exception e) { testSucceded = false; } MITK_TEST_CONDITION_REQUIRED(testSucceded,"Test logging streams."); } static void TestObjectInfoLogging() { bool testSucceded = true; try { int i = 123; float f = .32234; double d = 123123; std::string testString = "testString"; std::stringstream testStringStream; testStringStream << "test" << "String" << "Stream"; mitk::Point3D testMitkPoint; testMitkPoint.Fill(2); MITK_INFO << i; MITK_INFO << f; MITK_INFO << d; MITK_INFO << testString; MITK_INFO << testStringStream; MITK_INFO << testMitkPoint; } catch(mitk::Exception e) { testSucceded = false; } MITK_TEST_CONDITION_REQUIRED(testSucceded,"Test logging of object information."); } + + + static void TestThreadSaveLog() { bool testSucceded = true; - + try { //initialize two threads... - itk::MultiThreader::Pointer myThreader = itk::MultiThreader::New(); - mitkTestLoggingThread myThreadClass1 = mitkTestLoggingThread(1,myThreader); - mitkTestLoggingThread myThreadClass2 = mitkTestLoggingThread(2,myThreader); + itk::MultiThreader::Pointer multiThreader = itk::MultiThreader::New(); + mitkTestLoggingThread::Pointer myThreadClass1 = mitkTestLoggingThread::New(1,multiThreader); + mitkTestLoggingThread::Pointer myThreadClass2 = mitkTestLoggingThread::New(2,multiThreader); //start them - myThreadClass1.Start(); - myThreadClass2.Start(); - + myThreadClass1->Start(); + myThreadClass2->Start(); //wait for 500 ms itksys::SystemTools::Delay(500); //stop them - myThreadClass1.Stop(); - myThreadClass2.Stop(); + myThreadClass1->Stop(); + myThreadClass2->Stop(); - //sleep again to let all threads end - itksys::SystemTools::Delay(500); + //Wait for all threads to end + multiThreader->TerminateThread(1); + multiThreader->TerminateThread(2); } catch(...) { testSucceded = false; } //if no error occured until now, everything is ok MITK_TEST_CONDITION_REQUIRED(testSucceded,"Test logging in different threads."); } static void TestLoggingToFile() { std::string filename = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory() + "/testlog.log"; mitk::LoggingBackend::SetLogFile(filename.c_str()); MITK_INFO << "Test logging to default filename: " << mitk::LoggingBackend::GetLogFile(); MITK_TEST_CONDITION_REQUIRED(itksys::SystemTools::FileExists(filename.c_str()),"Testing if log file exists."); //TODO delete log file? } static void TestAddAndRemoveBackends() { mbilog::BackendCout myBackend = mbilog::BackendCout(); mbilog::RegisterBackend(&myBackend); MITK_INFO << "Test logging"; mbilog::UnregisterBackend(&myBackend); //if no error occured until now, everything is ok MITK_TEST_CONDITION_REQUIRED(true,"Test add/remove logging backend."); } static void TestDefaultBackend() { //not possible now, because we cannot unregister the mitk logging backend in the moment. If such a method is added to mbilog utility one may add this test. } }; int mitkLogTest(int /* argc */, char* /*argv*/[]) { // always start with this! MITK_TEST_BEGIN("Log") MITK_TEST_OUTPUT(<<"TESTING ALL LOGGING OUTPUTS, ERROR MESSAGES ARE ALSO TESTED AND NOT MEANING AN ERROR OCCURED!") mitkLogTestClass::TestSimpleLog(); mitkLogTestClass::TestObjectInfoLogging(); mitkLogTestClass::TestThreadSaveLog(); mitkLogTestClass::TestLoggingToFile(); mitkLogTestClass::TestAddAndRemoveBackends(); // always end with this! MITK_TEST_END() } diff --git a/Core/Code/Testing/mitkLoggingAdapterTest.cpp b/Core/Code/Testing/mitkLoggingAdapterTest.cpp new file mode 100644 index 0000000000..7b83cb6da1 --- /dev/null +++ b/Core/Code/Testing/mitkLoggingAdapterTest.cpp @@ -0,0 +1,86 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#include "mitkTestingMacros.h" +#include +#include +#include + +class ItkLoggingTestClass : public itk::Object + { + public: + + mitkClassMacro( ItkLoggingTestClass , itk::Object ); + itkNewMacro( ItkLoggingTestClass ); + + void TestItkWarningMessage() + { + itkWarningMacro("Test ITK Warning message"); + } + + }; + +/** @brief This test tests all logging adapters of MITK. */ +class LoggingAdapterTestClass +{ +public: + + static void TestVtkLoggingWithoutAdapter() + { + MITK_TEST_OUTPUT(<<"Testing vtk logging without adapter class: a separate window should open and display the logging messages.") + vtkOutputWindow::GetInstance()->DisplayText("Test VTK InfoMessage"); + vtkOutputWindow::GetInstance()->DisplayDebugText("Test Vtk Debug Message"); + vtkOutputWindow::GetInstance()->DisplayGenericWarningText("Test Vtk Generic Warning Message"); + vtkOutputWindow::GetInstance()->DisplayWarningText("Test Vtk Warning Message"); + vtkOutputWindow::GetInstance()->DisplayErrorText("Test Vtk Error Message"); + MITK_TEST_CONDITION_REQUIRED(true,"Testing if Vtk logging without adapter runs without errors."); + } + static void TestVtkLoggingWithAdapter() + { + MITK_TEST_OUTPUT(<<"Testing vtk logging with adapter class: Vtk logging messages should be logged as MITK logging messages.") + mitk::VtkLoggingAdapter::Initialize(); + vtkOutputWindow::GetInstance()->DisplayText("Test Vtk Info Message"); + vtkOutputWindow::GetInstance()->DisplayDebugText("Test Vtk Debug Message"); + vtkOutputWindow::GetInstance()->DisplayGenericWarningText("Test Vtk Generic Warning Message"); + vtkOutputWindow::GetInstance()->DisplayWarningText("Test Vtk Warning Message"); + vtkOutputWindow::GetInstance()->DisplayErrorText("Test Vtk Error Message"); + MITK_TEST_CONDITION_REQUIRED(true,"Testing if Vtk logging with MITK logging adapter runs without errors."); + } + + static void TestItkLoggingWithoutAdapter() + { + ItkLoggingTestClass::Pointer myItkLogger = ItkLoggingTestClass::New(); + myItkLogger->TestItkWarningMessage(); + } + + static void TestItkLoggingWithAdapter() + { + mitk::ItkLoggingAdapter::Initialize(); + ItkLoggingTestClass::Pointer myItkLogger = ItkLoggingTestClass::New(); + myItkLogger->TestItkWarningMessage(); + } +}; + +int mitkLoggingAdapterTest(int /*argc*/, char* /*argv*/[]) +{ + MITK_TEST_BEGIN("LoggingAdapters: VTK, ITK"); + LoggingAdapterTestClass::TestVtkLoggingWithoutAdapter(); + LoggingAdapterTestClass::TestVtkLoggingWithAdapter(); + LoggingAdapterTestClass::TestItkLoggingWithoutAdapter(); + LoggingAdapterTestClass::TestItkLoggingWithAdapter(); + MITK_TEST_END(); +} diff --git a/Core/Code/Testing/mitkPixelTypeTest.cpp b/Core/Code/Testing/mitkPixelTypeTest.cpp index fee4c650f0..463b35fad3 100644 --- a/Core/Code/Testing/mitkPixelTypeTest.cpp +++ b/Core/Code/Testing/mitkPixelTypeTest.cpp @@ -1,89 +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 "mitkTestingMacros.h" #include "mitkPixelType.h" #include #include +struct MyObscurePixelType +{ + typedef float ValueType; + static const size_t Length = 2; + + float val1; + int val2; +}; //## Documentation //## main testing method int mitkPixelTypeTest(int /*argc*/, char* /*argv*/[]) { MITK_TEST_BEGIN("PixelTypeTest"); MITK_INFO << "ptype = mitk::MakePixelType();"; MITK_INFO << "itkPtype = mitk::MakePixelType();\n with itk::Image, 3> ItkImageType"; mitk::PixelType ptype = mitk::MakePixelType(); typedef itk::Image, 3> ItkImageType; mitk::PixelType itkPtype = mitk::MakePixelType(); MITK_TEST_CONDITION_REQUIRED( ptype.GetTypeId() == typeid(int), "GetTypeId()"); // MITK_TEST_CONDITION( ptype.GetPixelTypeId() == typeid(ItkImageType), "GetPixelTypeId()"); - MITK_INFO << ptype.GetPixelTypeId().name(); + MITK_INFO << ptype.GetItkTypeAsString(); MITK_INFO << typeid(ItkImageType).name(); MITK_TEST_CONDITION_REQUIRED( ptype.GetBpe() == 8*sizeof(int)*5, "[ptype] GetBpe()"); MITK_TEST_CONDITION_REQUIRED( ptype.GetNumberOfComponents() == 5, "[ptype]GetNumberOfComponents()"); MITK_TEST_CONDITION_REQUIRED( ptype.GetBitsPerComponent() == 8*sizeof(int), "[ptype]GetBitsPerComponent()"); MITK_TEST_CONDITION_REQUIRED( itkPtype.GetBpe() == 8*sizeof(int)*5, "[itkPType] GetBpe()"); MITK_TEST_CONDITION_REQUIRED( itkPtype.GetNumberOfComponents() == 5, "[itkPType] GetNumberOfComponents()"); MITK_TEST_CONDITION_REQUIRED( itkPtype.GetBitsPerComponent() == 8*sizeof(int), "[itkPType] GetBitsPerComponent()"); // MITK_TEST_CONDITION_REQUIRED( itkPtype == ptype, "[itkPtype = ptype]"); //MITK_TEST_CONDITION( ptype.GetItkTypeAsString().compare("unknown") == 0, "GetItkTypeAsString()"); { { mitk::PixelType ptype2( ptype); MITK_TEST_CONDITION_REQUIRED( ptype2.GetTypeId() == typeid(int), "ptype2( ptype)- GetTypeId()"); MITK_TEST_CONDITION( ptype2.GetPixelTypeId() == ptype.GetPixelTypeId(), "ptype2( ptype)-GetPixelTypeId("); MITK_TEST_CONDITION_REQUIRED( ptype2.GetBpe() == 8*sizeof(int)*5, "ptype2( ptype)-GetBpe()"); MITK_TEST_CONDITION_REQUIRED( ptype2.GetNumberOfComponents() == 5, "ptype2( ptype)-GetNumberOfComponents()"); MITK_TEST_CONDITION_REQUIRED( ptype2.GetBitsPerComponent() == 8*sizeof(int), "ptype2( ptype)-GetBitsPerComponent()"); // MITK_TEST_CONDITION_REQUIRED( ptype.GetItkTypeAsString().compare("unknown") == 0, "ptype2( ptype)-GetItkTypeAsString()"); } { mitk::PixelType ptype2 = ptype; MITK_TEST_CONDITION_REQUIRED( ptype2.GetTypeId() == typeid(int), "ptype2 = ptype- GetTypeId()"); MITK_TEST_CONDITION( ptype2.GetPixelTypeId() == ptype.GetPixelTypeId(), "ptype2 = ptype- GetPixelTypeId("); MITK_TEST_CONDITION_REQUIRED( ptype2.GetBpe() == 8*sizeof(int)*5, "ptype2 = ptype- GetBpe()"); MITK_TEST_CONDITION_REQUIRED( ptype2.GetNumberOfComponents() == 5, "ptype2 = ptype- GetNumberOfComponents()"); MITK_TEST_CONDITION_REQUIRED( ptype2.GetBitsPerComponent() == 8*sizeof(int), "ptype2 = ptype- GetBitsPerComponent()"); // MITK_TEST_CONDITION_REQUIRED( ptype.GetItkTypeAsString().compare("unknown") == 0, "ptype2 = ptype- GetItkTypeAsString()"); } { mitk::PixelType ptype2 = ptype; MITK_TEST_CONDITION_REQUIRED( ptype == ptype2, "operator =="); //MITK_TEST_CONDITION_REQUIRED( ptype == typeid(int), "operator =="); //mitk::PixelType ptype3 = mitk::MakePixelType; //MITK_TEST_CONDITION_REQUIRED( ptype != ptype3, "operator !="); //MITK_TEST_CONDITION_REQUIRED( *ptype3 != typeid(int), "operator !="); } } + // test instantiation + typedef itk::Image< MyObscurePixelType > MyObscureImageType; + mitk::PixelType obscurePixelType = mitk::MakePixelType< MyObscureImageType >(); + + MITK_TEST_CONDITION( obscurePixelType.GetPixelTypeId() == itk::ImageIOBase::UNKNOWNPIXELTYPE, "PixelTypeId is 'UNKNOWN' "); + MITK_TEST_CONDITION( obscurePixelType.GetNumberOfComponents() == MyObscurePixelType::Length, "Lenght was set correctly"); + MITK_TEST_CONDITION( obscurePixelType.GetTypeId() == typeid(MyObscurePixelType::ValueType), "ValueType corresponds." ); + + + // test CastableTo + MITK_TEST_END(); } diff --git a/Core/Code/Testing/mitkPlaneGeometryTest.cpp b/Core/Code/Testing/mitkPlaneGeometryTest.cpp index 0a4f40b956..5d347433c1 100644 --- a/Core/Code/Testing/mitkPlaneGeometryTest.cpp +++ b/Core/Code/Testing/mitkPlaneGeometryTest.cpp @@ -1,1008 +1,1008 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkPlaneGeometry.h" #include "mitkRotationOperation.h" #include "mitkInteractionConst.h" #include "mitkLine.h" #include "mitkTestingMacros.h" #include #include #include int mappingTests2D(const mitk::PlaneGeometry* planegeometry, const mitk::ScalarType& width, const mitk::ScalarType& height, const mitk::ScalarType& widthInMM, const mitk::ScalarType& heightInMM, const mitk::Point3D& origin, const mitk::Vector3D& right, const mitk::Vector3D& bottom) { std::cout << "Testing mapping Map(pt2d_mm(x=widthInMM/2.3,y=heightInMM/2.5), pt3d_mm) and compare with expected: "; mitk::Point2D pt2d_mm; mitk::Point3D pt3d_mm, expected_pt3d_mm; pt2d_mm[0] = widthInMM/2.3; pt2d_mm[1] = heightInMM/2.5; expected_pt3d_mm = origin+right*(pt2d_mm[0]/right.GetNorm())+bottom*(pt2d_mm[1]/bottom.GetNorm()); planegeometry->Map(pt2d_mm, pt3d_mm); if(mitk::Equal(pt3d_mm, expected_pt3d_mm) == false) { std::cout<<"[FAILED]"<Map(pt3d_mm, testpt2d_mm); if(mitk::Equal(pt2d_mm, testpt2d_mm) == false) { std::cout<<"[FAILED]"<IndexToWorld(pt2d_units, testpt2d_mm); if(mitk::Equal(pt2d_mm, testpt2d_mm) == false) { std::cout<<"[FAILED]"<WorldToIndex(pt2d_mm, testpt2d_units); if(mitk::Equal(pt2d_units, testpt2d_units) == false) { std::cout<<"[FAILED]"<InitializeStandardPlane(right, down, &spacing); /* std::cout << "Testing width, height and thickness (in units): "; if((mitk::Equal(planegeometry->GetExtent(0),width)==false) || (mitk::Equal(planegeometry->GetExtent(1),height)==false) || (mitk::Equal(planegeometry->GetExtent(2),1)==false) ) { std::cout<<"[FAILED]"<GetExtentInMM(0),widthInMM)==false) || (mitk::Equal(planegeometry->GetExtentInMM(1),heightInMM)==false) || (mitk::Equal(planegeometry->GetExtentInMM(2),thicknessInMM)==false) ) { std::cout<<"[FAILED]"< 0. * */ int TestIntersectionPoint() { //init plane with its parameter mitk::PlaneGeometry::Pointer myPlaneGeometry = mitk::PlaneGeometry::New(); mitk::Point3D origin; origin[0] = 0.0; origin[1] = 2.0; origin[2] = 0.0; mitk::Vector3D normal; normal[0] = 0.0; normal[1] = 1.0; normal[2] = 0.0; myPlaneGeometry->InitializePlane(origin,normal); //generate points and line for intersection testing //point distance of given line > 1 mitk::Point3D pointP1; pointP1[0] = 2.0; pointP1[1] = 1.0; pointP1[2] = 0.0; mitk::Point3D pointP2; pointP2[0] = 2.0; pointP2[1] = 4.0; pointP2[2] = 0.0; mitk::Vector3D lineDirection; lineDirection[0] = pointP2[0] - pointP1[0]; lineDirection[1] = pointP2[1] - pointP1[1]; lineDirection[2] = pointP2[2] - pointP1[2]; mitk::Line3D xingline( pointP1, lineDirection ); mitk::Point3D calcXingPoint; myPlaneGeometry->IntersectionPoint(xingline, calcXingPoint); //point distance of given line < 1 mitk::Point3D pointP3; pointP3[0] = 2.0; pointP3[1] = 2.2; pointP3[2] = 0.0; mitk::Point3D pointP4; pointP4[0] = 2.0; pointP4[1] = 1.7; pointP4[2] = 0.0; mitk::Vector3D lineDirection2; lineDirection2[0] = pointP4[0] - pointP3[0]; lineDirection2[1] = pointP4[1] - pointP3[1]; lineDirection2[2] = pointP4[2] - pointP3[2]; mitk::Line3D xingline2( pointP3, lineDirection2 ); mitk::Point3D calcXingPoint2; myPlaneGeometry->IntersectionPoint( xingline2, calcXingPoint2 ); //intersection points must be the same if (calcXingPoint == calcXingPoint2) { return EXIT_SUCCESS; } else { return EXIT_FAILURE; } } /** * @brief This method tests method ProjectPointOntoPlane. * * See also bug #3409. */ int TestProjectPointOntoPlane() { mitk::PlaneGeometry::Pointer myPlaneGeometry = mitk::PlaneGeometry::New(); //create normal mitk::Vector3D normal; normal[0] = 0.0; normal[1] = 0.0; normal[2] = 1.0; //create origin mitk::Point3D origin; origin[0] = -27.582859; origin[1] = 50; origin[2] = 200.27742; //initialize plane geometry myPlaneGeometry->InitializePlane(origin,normal); //output to descripe the test std::cout << "Testing PlaneGeometry according to bug #3409" << std::endl; std::cout << "Our normal is: " << normal << std::endl; std::cout << "So ALL projected points should have exactly the same z-value!" << std::endl; //create a number of points mitk::Point3D myPoints[5]; myPoints[0][0] = -27.582859; myPoints[0][1] = 50.00; myPoints[0][2] = 200.27742; myPoints[1][0] = -26.58662; myPoints[1][1] = 50.00; myPoints[1][2] = 200.19026; myPoints[2][0] = -26.58662; myPoints[2][1] = 50.00; myPoints[2][2] = 200.33124; myPoints[3][0] = 104.58662; myPoints[3][1] = 452.12313; myPoints[3][2] = 866.41236; myPoints[4][0] = -207.58662; myPoints[4][1] = 312.00; myPoints[4][2] = -300.12346; //project points onto plane mitk::Point3D myProjectedPoints[5]; for ( unsigned int i = 0; i < 5; ++i ) { myProjectedPoints[i] = myPlaneGeometry->ProjectPointOntoPlane( myPoints[i] ); } //compare z-values with z-value of plane (should be equal) bool allPointsOnPlane = true; for ( unsigned int i = 0; i < 5; ++i ) { if ( fabs(myProjectedPoints[i][2] - origin[2]) > mitk::sqrteps ) { allPointsOnPlane = false; } } if (!allPointsOnPlane) { std::cout<<"[FAILED]"<InitializeStandardPlane(right.Get_vnl_vector(), bottom.Get_vnl_vector()); std::cout << "Testing width, height and thickness (in units): "; if((mitk::Equal(planegeometry->GetExtent(0),width)==false) || (mitk::Equal(planegeometry->GetExtent(1),height)==false) || (mitk::Equal(planegeometry->GetExtent(2),1)==false) ) { std::cout<<"[FAILED]"<GetExtentInMM(0),widthInMM)==false) || (mitk::Equal(planegeometry->GetExtentInMM(1),heightInMM)==false) || (mitk::Equal(planegeometry->GetExtentInMM(2),thicknessInMM)==false) ) { std::cout<<"[FAILED]"<GetAxisVector(0), right)==false) || (mitk::Equal(planegeometry->GetAxisVector(1), bottom)==false) || (mitk::Equal(planegeometry->GetAxisVector(2), normal)==false)) { std::cout<<"[FAILED]"<InitializeStandardPlane(right.Get_vnl_vector(), bottom.Get_vnl_vector(), &spacing); std::cout << "Testing width, height and thickness (in units): "; if((mitk::Equal(planegeometry->GetExtent(0),width)==false) || (mitk::Equal(planegeometry->GetExtent(1),height)==false) || (mitk::Equal(planegeometry->GetExtent(2),1)==false) ) { std::cout<<"[FAILED]"<GetExtentInMM(0),widthInMM)==false) || (mitk::Equal(planegeometry->GetExtentInMM(1),heightInMM)==false) || (mitk::Equal(planegeometry->GetExtentInMM(2),thicknessInMM)==false) ) { std::cout<<"[FAILED]"<GetAxisVector(0), right)==false) || (mitk::Equal(planegeometry->GetAxisVector(1), bottom)==false) || (mitk::Equal(planegeometry->GetAxisVector(2), normal)==false)) { std::cout<<"[FAILED]"<SetExtentInMM(2, thicknessInMM); if(mitk::Equal(planegeometry->GetExtentInMM(2),thicknessInMM)==false) { std::cout<<"[FAILED]"<GetAxisVector(2), normal)==false) { std::cout<<"[FAILED]"<SetOrigin(origin); if(mitk::Equal(planegeometry->GetOrigin(), origin)==false) { std::cout<<"[FAILED]"<GetAxisVector(0), right)==false) || (mitk::Equal(planegeometry->GetAxisVector(1), bottom)==false) || (mitk::Equal(planegeometry->GetAxisVector(2), normal)==false)) { std::cout<<"[FAILED]"<GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix(); mitk::VnlVector axis(3); mitk::FillVector3D(axis, 1.0, 1.0, 1.0); axis.normalize(); vnl_quaternion rotation(axis, 0.223); vnlmatrix = rotation.rotation_matrix_transpose()*vnlmatrix; mitk::Matrix3D matrix; matrix = vnlmatrix; transform->SetMatrix(matrix); transform->SetOffset(planegeometry->GetIndexToWorldTransform()->GetOffset()); right.Set_vnl_vector( rotation.rotation_matrix_transpose()*right.Get_vnl_vector() ); bottom.Set_vnl_vector(rotation.rotation_matrix_transpose()*bottom.Get_vnl_vector()); normal.Set_vnl_vector(rotation.rotation_matrix_transpose()*normal.Get_vnl_vector()); planegeometry->SetIndexToWorldTransform(transform); //The origin changed,because m_Origin=m_IndexToWorldTransform->GetOffset()+GetAxisVector(2)*0.5 //and the AxisVector changes due to the rotation. In other words: the rotation was done around //the corner of the box, not around the planes origin. Now change it to a rotation around //the origin, simply by re-setting the origin to the original one: planegeometry->SetOrigin(origin); mitk::Point3D cornerpoint0 = planegeometry->GetCornerPoint(0); std::cout << "Testing whether SetIndexToWorldTransform kept origin: "; if(mitk::Equal(planegeometry->GetOrigin(), origin)==false) { std::cout<<"[FAILED]"<WorldToIndex(point, dummy); planegeometry->IndexToWorld(dummy, dummy); MITK_TEST_CONDITION_REQUIRED(dummy == point, ""); std::cout<<"[PASSED]"<GetExtentInMM(0),widthInMM)==false) || (mitk::Equal(planegeometry->GetExtentInMM(1),heightInMM)==false) || (mitk::Equal(planegeometry->GetExtentInMM(2),thicknessInMM)==false) ) { std::cout<<"[FAILED]"<GetAxisVector(0), right)==false) || (mitk::Equal(planegeometry->GetAxisVector(1), bottom)==false) || (mitk::Equal(planegeometry->GetAxisVector(2), normal)==false)) { std::cout<<"[FAILED]"<GetExtentInMM(direction) of rotated version: "; if((mitk::Equal(planegeometry->GetAxisVector(0).GetNorm(),planegeometry->GetExtentInMM(0))==false) || (mitk::Equal(planegeometry->GetAxisVector(1).GetNorm(),planegeometry->GetExtentInMM(1))==false) || (mitk::Equal(planegeometry->GetAxisVector(2).GetNorm(),planegeometry->GetExtentInMM(2))==false) ) { std::cout<<"[FAILED]"<SetSizeInUnits(width, height); std::cout << "Testing width, height and thickness (in units): "; if((mitk::Equal(planegeometry->GetExtent(0),width)==false) || (mitk::Equal(planegeometry->GetExtent(1),height)==false) || (mitk::Equal(planegeometry->GetExtent(2),1)==false) ) { std::cout<<"[FAILED]"<GetExtentInMM(0), widthInMM) || !mitk::Equal(planegeometry->GetExtentInMM(1), heightInMM) || !mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM)) { std::cout<<"[FAILED]"<GetAxisVector(0), right)==false) || (mitk::Equal(planegeometry->GetAxisVector(1), bottom)==false) || (mitk::Equal(planegeometry->GetAxisVector(2), normal)==false)) { std::cout<<"[FAILED]"<GetExtentInMM(direction) of rotated version: "; if((mitk::Equal(planegeometry->GetAxisVector(0).GetNorm(),planegeometry->GetExtentInMM(0))==false) || (mitk::Equal(planegeometry->GetAxisVector(1).GetNorm(),planegeometry->GetExtentInMM(1))==false) || (mitk::Equal(planegeometry->GetAxisVector(2).GetNorm(),planegeometry->GetExtentInMM(2))==false) ) { std::cout<<"[FAILED]"<(planegeometry->Clone().GetPointer()); if((clonedplanegeometry.IsNull()) || (clonedplanegeometry->GetReferenceCount()!=1)) { std::cout<<"[FAILED]"<GetOrigin(), origin)==false) { std::cout<<"[FAILED]"<GetExtent(0),width)==false) || (mitk::Equal(clonedplanegeometry->GetExtent(1),height)==false) || (mitk::Equal(clonedplanegeometry->GetExtent(2),1)==false) ) { std::cout<<"[FAILED]"<GetExtentInMM(0), widthInMM) || !mitk::Equal(clonedplanegeometry->GetExtentInMM(1), heightInMM) || !mitk::Equal(clonedplanegeometry->GetExtentInMM(2), thicknessInMM)) { std::cout<<"[FAILED]"<GetAxisVector(0), right)==false) || (mitk::Equal(clonedplanegeometry->GetAxisVector(1), bottom)==false) || (mitk::Equal(clonedplanegeometry->GetAxisVector(2), normal)==false)) { std::cout<<"[FAILED]"<(planegeometry->Clone().GetPointer()); if((clonedplanegeometry2.IsNull()) || (clonedplanegeometry2->GetReferenceCount()!=1)) { std::cout<<"[FAILED]"<IsOnPlane(planegeometry), true) ==false) { std::cout<<"[FAILED]"<IsOnPlane(origin), true)==false) { std::cout<<"[FAILED]"< rotation2(newaxis, 0.0); mitk::Vector3D clonednormal = clonedplanegeometry2->GetNormal(); mitk::Point3D clonedorigin = clonedplanegeometry2->GetOrigin(); mitk::RotationOperation* planerot = new mitk::RotationOperation( mitk::OpROTATE, origin, clonedplanegeometry2->GetAxisVector( 0 ), 180.0 ); clonedplanegeometry2->ExecuteOperation( planerot ); std::cout << "Testing whether the flipped plane is still the original plane: "; if( mitk::Equal( clonedplanegeometry2->IsOnPlane(planegeometry), true )==false ) { std::cout<<"[FAILED]"<SetOrigin( clonedorigin ); std::cout << "Testing if the translated (cloned, flipped) plane is parallel to its origin plane: "; if( mitk::Equal( clonedplanegeometry2->IsParallel(planegeometry), true )==false ) { std::cout<<"[FAILED]"<GetAxisVector( 0 ), 0.5 ); clonedplanegeometry2->ExecuteOperation( planerot ); std::cout << "Testing if a non-paralell plane gets recognized as not paralell [rotation +0.5 degree] : "; if( mitk::Equal( clonedplanegeometry2->IsParallel(planegeometry), false )==false ) { std::cout<<"[FAILED]"<GetAxisVector( 0 ), -1.0 ); clonedplanegeometry2->ExecuteOperation( planerot ); std::cout << "Testing if a non-paralell plane gets recognized as not paralell [rotation -0.5 degree] : "; if( mitk::Equal( clonedplanegeometry2->IsParallel(planegeometry), false )==false ) { std::cout<<"[FAILED]"<GetAxisVector( 0 ), 360.5 ); clonedplanegeometry2->ExecuteOperation( planerot ); std::cout << "Testing if a non-paralell plane gets recognized as not paralell [rotation 360 degree] : "; if( mitk::Equal( clonedplanegeometry2->IsParallel(planegeometry), true )==false ) { std::cout<<"[FAILED]"<InitializeStandardPlane(clonedplanegeometry); - std::cout << "Testing origin of transversally initialized version: "; + std::cout << "Testing origin of axially initialized version: "; if(mitk::Equal(planegeometry->GetOrigin(), origin)==false) { std::cout<<"[FAILED]"<GetCornerPoint(0), cornerpoint0)==false) { std::cout<<"[FAILED]"<GetExtent(0), width) || !mitk::Equal(planegeometry->GetExtent(1), height) || !mitk::Equal(planegeometry->GetExtent(2), 1)) { std::cout<<"[FAILED]"<GetExtentInMM(0), widthInMM) || !mitk::Equal(planegeometry->GetExtentInMM(1), heightInMM) || !mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM)) { std::cout<<"[FAILED]"<GetAxisVector(0), right)==false) || (mitk::Equal(planegeometry->GetAxisVector(1), bottom)==false) || (mitk::Equal(planegeometry->GetAxisVector(2), normal)==false)) { std::cout<<"[FAILED]"<InitializeStandardPlane(clonedplanegeometry, mitk::PlaneGeometry::Frontal); newright = right; newbottom = normal; newbottom.Normalize(); newbottom *= thicknessInMM; newthicknessInMM = heightInMM/height*1.0/*extent in normal direction is 1*/; newnormal = -bottom; newnormal.Normalize(); newnormal *= newthicknessInMM; std::cout << "Testing GetCornerPoint(0) of frontally initialized version: "; if(mitk::Equal(planegeometry->GetCornerPoint(0), cornerpoint0)==false) { std::cout<<"[FAILED]"<GetOrigin(); std::cout << "Testing width, height and thickness (in units) of frontally initialized version: "; if(!mitk::Equal(planegeometry->GetExtent(0), width) || !mitk::Equal(planegeometry->GetExtent(1), 1) || !mitk::Equal(planegeometry->GetExtent(2), 1)) { std::cout<<"[FAILED]"<GetExtentInMM(0), widthInMM) || !mitk::Equal(planegeometry->GetExtentInMM(1), thicknessInMM) || !mitk::Equal(planegeometry->GetExtentInMM(2), newthicknessInMM)) { std::cout<<"[FAILED]"<GetAxisVector(0), newright)==false) || (mitk::Equal(planegeometry->GetAxisVector(1), newbottom)==false) || (mitk::Equal(planegeometry->GetAxisVector(2), newnormal)==false)) { std::cout<<"[FAILED]"<SetSizeInUnits(planegeometry->GetExtentInMM(0), planegeometry->GetExtentInMM(1)); std::cout << "Testing origin of unit spaced, frontally initialized version: "; if(mitk::Equal(planegeometry->GetOrigin(), origin)==false) { std::cout<<"[FAILED]"<GetExtent(0), widthInMM) || !mitk::Equal(planegeometry->GetExtent(1), thicknessInMM) || !mitk::Equal(planegeometry->GetExtent(2), 1)) { std::cout<<"[FAILED]"<GetExtentInMM(0), widthInMM) || !mitk::Equal(planegeometry->GetExtentInMM(1), thicknessInMM) || !mitk::Equal(planegeometry->GetExtentInMM(2), newthicknessInMM)) { std::cout<<"[FAILED]"<GetAxisVector(0), newright)==false) || (mitk::Equal(planegeometry->GetAxisVector(1), newbottom)==false) || (mitk::Equal(planegeometry->GetAxisVector(2), newnormal)==false)) { std::cout<<"[FAILED]"<SetExtentInMM(2, 1.0); newnormal.Normalize(); std::cout << "Testing origin of unit spaced, frontally initialized version: "; if(mitk::Equal(planegeometry->GetOrigin(), origin)==false) { std::cout<<"[FAILED]"<GetExtent(0), widthInMM) || !mitk::Equal(planegeometry->GetExtent(1), thicknessInMM) || !mitk::Equal(planegeometry->GetExtent(2), 1)) { std::cout<<"[FAILED]"<GetExtentInMM(0), widthInMM) || !mitk::Equal(planegeometry->GetExtentInMM(1), thicknessInMM) || !mitk::Equal(planegeometry->GetExtentInMM(2), 1.0)) { std::cout<<"[FAILED]"<GetAxisVector(0), newright)==false) || (mitk::Equal(planegeometry->GetAxisVector(1), newbottom)==false) || (mitk::Equal(planegeometry->GetAxisVector(2), newnormal)==false)) { std::cout<<"[FAILED]"<InitializeStandardPlane(clonedplanegeometry, mitk::PlaneGeometry::Sagittal); newright = bottom; newthicknessInMM = widthInMM/width*1.0/*extent in normal direction is 1*/; newnormal = right; newnormal.Normalize(); newnormal *= newthicknessInMM; std::cout << "Testing GetCornerPoint(0) of sagitally initialized version: "; if(mitk::Equal(planegeometry->GetCornerPoint(0), cornerpoint0)==false) { std::cout<<"[FAILED]"<GetOrigin(); std::cout << "Testing width, height and thickness (in units) of sagitally initialized version: "; if(!mitk::Equal(planegeometry->GetExtent(0), height) || !mitk::Equal(planegeometry->GetExtent(1), 1) || !mitk::Equal(planegeometry->GetExtent(2), 1)) { std::cout<<"[FAILED]"<GetExtentInMM(0), heightInMM) || !mitk::Equal(planegeometry->GetExtentInMM(1), thicknessInMM) || !mitk::Equal(planegeometry->GetExtentInMM(2), newthicknessInMM)) { std::cout<<"[FAILED]"<GetAxisVector(0), newright)==false) || (mitk::Equal(planegeometry->GetAxisVector(1), newbottom)==false) || (mitk::Equal(planegeometry->GetAxisVector(2), newnormal)==false)) { std::cout<<"[FAILED]"<GetOrigin(); - std::cout << "Testing backside initialization: InitializeStandardPlane(clonedplanegeometry, planeorientation = Transversal, zPosition = 0, frontside=false, rotated=true): " <InitializeStandardPlane(clonedplanegeometry, mitk::PlaneGeometry::Transversal, 0, false, true); + std::cout << "Testing backside initialization: InitializeStandardPlane(clonedplanegeometry, planeorientation = Axial, zPosition = 0, frontside=false, rotated=true): " <InitializeStandardPlane(clonedplanegeometry, mitk::PlaneGeometry::Axial, 0, false, true); mitk::Point3D backsideorigin; backsideorigin=origin+clonedplanegeometry->GetAxisVector(1);//+clonedplanegeometry->GetAxisVector(2); - std::cout << "Testing origin of backsidedly, transversally initialized version: "; + std::cout << "Testing origin of backsidedly, axially initialized version: "; if(mitk::Equal(planegeometry->GetOrigin(), backsideorigin)==false) { std::cout<<"[FAILED]"<GetAxisVector(1);//+clonedplanegeometry->GetAxisVector(2); if(mitk::Equal(planegeometry->GetCornerPoint(0), backsidecornerpoint0)==false) { std::cout<<"[FAILED]"<GetExtent(0), width) || !mitk::Equal(planegeometry->GetExtent(1), height) || !mitk::Equal(planegeometry->GetExtent(2), 1)) { std::cout<<"[FAILED]"<GetExtentInMM(0), widthInMM) || !mitk::Equal(planegeometry->GetExtentInMM(1), heightInMM) || !mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM)) { std::cout<<"[FAILED]"<GetAxisVector(0), right)==false) || (mitk::Equal(planegeometry->GetAxisVector(1), -bottom)==false) || (mitk::Equal(planegeometry->GetAxisVector(2), -normal)==false)) { std::cout<<"[FAILED]"< #include "mitkGetModuleContext.h" std::vector m_Geometries; std::vector m_SliceIndices; mitk::PlanePositionManagerService* m_Service; int SetUpBeforeTest() { //Getting Service mitk::ServiceReference serviceRef = mitk::GetModuleContext()->GetServiceReference(); m_Service = dynamic_cast(mitk::GetModuleContext()->GetService(serviceRef)); if (m_Service == 0) return EXIT_FAILURE; //Creating different Geometries m_Geometries.reserve(100); - mitk::PlaneGeometry::PlaneOrientation views[] = {mitk::PlaneGeometry::Transversal, mitk::PlaneGeometry::Sagittal, mitk::PlaneGeometry::Frontal}; + mitk::PlaneGeometry::PlaneOrientation views[] = {mitk::PlaneGeometry::Axial, mitk::PlaneGeometry::Sagittal, mitk::PlaneGeometry::Frontal}; for (unsigned int i = 0; i < 100; ++i) { mitk::PlaneGeometry::Pointer plane = mitk::PlaneGeometry::New(); mitk::ScalarType width = 256+(0.01*i); mitk::ScalarType height = 256+(0.002*i); mitk::Vector3D right; mitk::Vector3D down; right[0] = 1; right[1] = i; right[2] = 0.5; down[0] = i*0.02; down[1] = 1; down[2] = i*0.03; mitk::Vector3D spacing; mitk::FillVector3D(spacing, 1.0*0.02*i, 1.0*0.15*i, 1.0); mitk::Vector3D rightVector; mitk::FillVector3D(rightVector, 0.02*(i+1), 0+(0.05*i), 1.0); mitk::Vector3D downVector; mitk::FillVector3D(downVector, 1, 3-0.01*i, 0.0345*i); vnl_vector normal = vnl_cross_3d(rightVector.GetVnlVector(), downVector.GetVnlVector()); normal.normalize(); normal *= 1.5; mitk::Vector3D origin; origin.Fill(1); origin[0] = 12 + 0.03*i; mitk::AffineTransform3D::Pointer transform = mitk::AffineTransform3D::New(); mitk::Matrix3D matrix; matrix.GetVnlMatrix().set_column(0, rightVector.GetVnlVector()); matrix.GetVnlMatrix().set_column(1, downVector.GetVnlVector()); matrix.GetVnlMatrix().set_column(2, normal); transform->SetMatrix(matrix); transform->SetOffset(origin); plane->InitializeStandardPlane(width, height, transform, views[i%3], i, true, false); m_Geometries.push_back(plane); } return EXIT_SUCCESS; } int testAddPlanePosition() { MITK_TEST_OUTPUT(<<"Starting Test: ######### A d d P l a n e P o s i t i o n #########"); MITK_TEST_CONDITION(m_Service != NULL, "Testing getting of PlanePositionManagerService"); unsigned int currentID(m_Service->AddNewPlanePosition(m_Geometries.at(0),0)); bool error = ((m_Service->GetNumberOfPlanePositions() != 1)||(currentID != 0)); if(error) { MITK_TEST_CONDITION(m_Service->GetNumberOfPlanePositions() == 1,"Checking for correct number of planepositions"); MITK_TEST_CONDITION(currentID == 0, "Testing for correct ID"); return EXIT_FAILURE; } //Adding new planes for(unsigned int i = 1; i < m_Geometries.size(); ++i) { unsigned int newID = m_Service->AddNewPlanePosition(m_Geometries.at(i),i); error = ((m_Service->GetNumberOfPlanePositions() != i+1)||(newID != (currentID+1))); if (error) { MITK_TEST_CONDITION(m_Service->GetNumberOfPlanePositions() == i+1,"Checking for correct number of planepositions"); MITK_TEST_CONDITION(newID == (currentID+1), "Testing for correct ID"); MITK_TEST_OUTPUT(<<"New: "<GetNumberOfPlanePositions(); //Adding existing planes -> nothing should change for(unsigned int i = 0; i < (m_Geometries.size()-1)*0.5; ++i) { unsigned int newID = m_Service->AddNewPlanePosition(m_Geometries.at(i*2),i*2); error = ((m_Service->GetNumberOfPlanePositions() != numberOfPlanePos)||(newID != i*2)); if (error) { MITK_TEST_CONDITION( m_Service->GetNumberOfPlanePositions() == numberOfPlanePos, "Checking for correct number of planepositions"); MITK_TEST_CONDITION(newID == i*2, "Testing for correct ID"); return EXIT_FAILURE; } } return EXIT_SUCCESS; } int testGetPlanePosition() { mitk::PlaneGeometry* plane; mitk::RestorePlanePositionOperation* op; bool error(true); MITK_TEST_OUTPUT(<<"Starting Test: ######### G e t P l a n e P o s i t i o n #########"); //Testing for existing planepositions for (unsigned int i = 0; i < m_Geometries.size(); ++i) { plane = m_Geometries.at(i); op = m_Service->GetPlanePosition(i); error = ( !mitk::Equal(op->GetHeight(),plane->GetExtent(1)) || !mitk::Equal(op->GetWidth(),plane->GetExtent(0)) || !mitk::Equal(op->GetSpacing(),plane->GetSpacing()) || !mitk::Equal(op->GetTransform()->GetOffset(),plane->GetIndexToWorldTransform()->GetOffset()) || !mitk::Equal(op->GetDirectionVector().Get_vnl_vector(),plane->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2).normalize()) || !mitk::MatrixEqualElementWise(op->GetTransform()->GetMatrix(), plane->GetIndexToWorldTransform()->GetMatrix()) ); if( error ) { MITK_TEST_OUTPUT(<<"Iteration: "<GetHeight(),plane->GetExtent(1)) && mitk::Equal(op->GetWidth(),plane->GetExtent(0)), "Checking for correct extent"); MITK_TEST_CONDITION( mitk::Equal(op->GetSpacing(),plane->GetSpacing()), "Checking for correct spacing"); MITK_TEST_CONDITION( mitk::Equal(op->GetTransform()->GetOffset(),plane->GetIndexToWorldTransform()->GetOffset()), "Checking for correct offset"); MITK_INFO<<"Op: "<GetDirectionVector()<<" plane: "<GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2)<<"\n"; MITK_TEST_CONDITION( mitk::Equal(op->GetDirectionVector().Get_vnl_vector(),plane->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2)), "Checking for correct direction"); MITK_TEST_CONDITION( mitk::MatrixEqualElementWise(op->GetTransform()->GetMatrix(), plane->GetIndexToWorldTransform()->GetMatrix()), "Checking for correct matrix"); return EXIT_FAILURE; } } //Testing for not existing planepositions error = ( m_Service->GetPlanePosition(100000000) != 0 || m_Service->GetPlanePosition(-1) != 0 ); if (error) { MITK_TEST_CONDITION(m_Service->GetPlanePosition(100000000) == 0, "Trying to get non existing pos"); MITK_TEST_CONDITION(m_Service->GetPlanePosition(-1) == 0, "Trying to get non existing pos"); return EXIT_FAILURE; } return EXIT_SUCCESS; } int testRemovePlanePosition() { MITK_TEST_OUTPUT(<<"Starting Test: ######### R e m o v e P l a n e P o s i t i o n #########"); unsigned int size = m_Service->GetNumberOfPlanePositions(); bool removed (true); //Testing for invalid IDs removed = m_Service->RemovePlanePosition( -1 ); removed = m_Service->RemovePlanePosition( 1000000 ); unsigned int size2 = m_Service->GetNumberOfPlanePositions(); if (removed) { MITK_TEST_CONDITION(removed == false, "Testing remove not existing planepositions"); MITK_TEST_CONDITION(size == size2, "Testing remove not existing planepositions"); return EXIT_FAILURE; } //Testing for valid IDs for (unsigned int i = 0; i < m_Geometries.size()*0.5; i++) { removed = m_Service->RemovePlanePosition( i ); unsigned int size2 = m_Service->GetNumberOfPlanePositions(); removed = (size2 == (size-(i+1))); if (!removed) { MITK_TEST_CONDITION(removed == true, "Testing remove existing planepositions"); MITK_TEST_CONDITION(size == (size-i+1), "Testing remove existing planepositions"); return EXIT_FAILURE; } } return EXIT_SUCCESS; } int testRemoveAll() { MITK_TEST_OUTPUT(<<"Starting Test: ######### R e m o v e A l l #########"); unsigned int numPos = m_Service->GetNumberOfPlanePositions(); MITK_INFO<RemoveAllPlanePositions(); bool error (true); error = (m_Service->GetNumberOfPlanePositions() != 0 || m_Service->GetPlanePosition(60) != 0); if (error) { MITK_TEST_CONDITION(m_Service->GetNumberOfPlanePositions() == 0, "Testing remove all pos"); MITK_TEST_CONDITION(m_Service->GetPlanePosition(60) == 0, "Testing remove all pos"); return EXIT_FAILURE; } return EXIT_SUCCESS; } int mitkPlanePositionManagerTest(int, char* []) { MITK_TEST_OUTPUT(<<"Starting Test PlanePositionManager"); SetUpBeforeTest(); int result; MITK_TEST_CONDITION_REQUIRED( (result = testAddPlanePosition()) == EXIT_SUCCESS, ""); MITK_TEST_CONDITION_REQUIRED( (result = testGetPlanePosition()) == EXIT_SUCCESS, ""); MITK_TEST_CONDITION_REQUIRED( (result = testRemovePlanePosition()) == EXIT_SUCCESS, ""); MITK_TEST_CONDITION_REQUIRED( (result = testRemoveAll()) == EXIT_SUCCESS, ""); return EXIT_SUCCESS; } diff --git a/Core/Code/Testing/mitkRenderingTestHelper.h b/Core/Code/Testing/mitkRenderingTestHelper.h index 57607e9edd..5a4b4405c0 100644 --- a/Core/Code/Testing/mitkRenderingTestHelper.h +++ b/Core/Code/Testing/mitkRenderingTestHelper.h @@ -1,92 +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 mitkRenderingTestHelper_h #define mitkRenderingTestHelper_h #include #include #include #include class vtkRenderWindow; class vtkRenderer; class mitkRenderingTestHelper { public: /** @brief Generate a rendering test helper object including a render window of the size width * height (in pixel). @param argc Number of parameters. (here: Images) "Usage: [filename1 filenam2 -V referenceScreenshot (optional -T /directory/to/save/differenceImage)] @param argv Given parameters. **/ mitkRenderingTestHelper(int width, int height, int argc, char *argv[]); ~mitkRenderingTestHelper(); /** @brief Getter for the vtkRenderer. **/ vtkRenderer* GetVtkRenderer(); /** @brief Getter for the vtkRenderWindow which should be used to call vtkRegressionTestImage. **/ vtkRenderWindow* GetVtkRenderWindow(); /** @brief Method can be used to save a screenshot (e.g. reference screenshot as a .png file. @param fileName The filename of the new screenshot (including path). **/ void SaveAsPNG(std::string fileName); /** @brief This method set the property of the member datastorage @param property Set a property for each image in the datastorage m_DataStorage. **/ void SetProperty(const char *propertyKey, mitk::BaseProperty *property); - /** @brief Set the view direction of the renderwindow (e.g. sagittal, coronal, transversal) + /** @brief Set the view direction of the renderwindow (e.g. sagittal, coronal, axial) **/ void SetViewDirection(mitk::SliceNavigationController::ViewDirection viewDirection); /** @brief Reorient the slice (e.g. rotation and translation like the swivel mode). **/ void ReorientSlices(mitk::Point3D origin, mitk::Vector3D rotation); /** @brief Render everything into an mitkRenderWindow. Call SetViewDirection() and SetProperty() before this method. **/ void Render(); /** @brief Returns the datastorage, in order to modify the data inside a rendering test. **/ mitk::DataStorage::Pointer GetDataStorage(); protected: /** @brief This method tries to load the given file into a member datastorage, in order to render it. @param fileName The filename of the file to be loaded (including path). **/ void AddToStorage(const std::string& filename); /** @brief This method tries to parse the given argv for files (e.g. images) and load them into a member datastorage, in order to render it. @param argc Number of parameters. @param argv Given parameters. **/ void SetInputFileNames(int argc, char *argv[]); mitk::RenderWindow::Pointer m_RenderWindow; //<< Contains the mitkRenderWindow into which the test renders the data mitk::DataStorage::Pointer m_DataStorage; //<< Contains the mitkDataStorage which contains the data to be rendered }; #endif diff --git a/Core/Code/Testing/mitkSliceNavigationControllerTest.cpp b/Core/Code/Testing/mitkSliceNavigationControllerTest.cpp index 3371465cc7..2a59610633 100644 --- a/Core/Code/Testing/mitkSliceNavigationControllerTest.cpp +++ b/Core/Code/Testing/mitkSliceNavigationControllerTest.cpp @@ -1,416 +1,416 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkPlaneGeometry.h" #include "mitkSlicedGeometry3D.h" #include "mitkTimeSlicedGeometry.h" #include "mitkRotationOperation.h" #include "mitkInteractionConst.h" #include "mitkPlanePositionManager.h" #include "mitkTestingMacros.h" #include "mitkGetModuleContext.h" #include #include #include bool operator==(const mitk::Geometry3D & left, const mitk::Geometry3D & right) { mitk::BoundingBox::BoundsArrayType leftbounds, rightbounds; leftbounds =left.GetBounds(); rightbounds=right.GetBounds(); unsigned int i; for(i=0;i<6;++i) if(mitk::Equal(leftbounds[i],rightbounds[i])==false) return false; const mitk::Geometry3D::TransformType::MatrixType & leftmatrix = left.GetIndexToWorldTransform()->GetMatrix(); const mitk::Geometry3D::TransformType::MatrixType & rightmatrix = right.GetIndexToWorldTransform()->GetMatrix(); unsigned int j; for(i=0;i<3;++i) { const mitk::Geometry3D::TransformType::MatrixType::ValueType* leftvector = leftmatrix[i]; const mitk::Geometry3D::TransformType::MatrixType::ValueType* rightvector = rightmatrix[i]; for(j=0;j<3;++j) if(mitk::Equal(leftvector[i],rightvector[i])==false) return false; } const mitk::Geometry3D::TransformType::OffsetType & leftoffset = left.GetIndexToWorldTransform()->GetOffset(); const mitk::Geometry3D::TransformType::OffsetType & rightoffset = right.GetIndexToWorldTransform()->GetOffset(); for(i=0;i<3;++i) if(mitk::Equal(leftoffset[i],rightoffset[i])==false) return false; return true; } int compareGeometry(const mitk::Geometry3D & geometry, const mitk::ScalarType& width, const mitk::ScalarType& height, const mitk::ScalarType& numSlices, const mitk::ScalarType& widthInMM, const mitk::ScalarType& heightInMM, const mitk::ScalarType& thicknessInMM, const mitk::Point3D& cornerpoint0, const mitk::Vector3D& right, const mitk::Vector3D& bottom, const mitk::Vector3D& normal) { std::cout << "Testing width, height and thickness (in units): "; if((mitk::Equal(geometry.GetExtent(0),width)==false) || (mitk::Equal(geometry.GetExtent(1),height)==false) || (mitk::Equal(geometry.GetExtent(2),numSlices)==false) ) { std::cout<<"[FAILED]"<GetCornerPoint(0), cornerpoint0)==false) { std::cout<<"[FAILED]"<SetInputWorldGeometry(geometry); std::cout<<"[PASSED]"<SetViewDirection(mitk::SliceNavigationController::Transversal); + std::cout << "Testing SetViewDirection(mitk::SliceNavigationController::Axial): "; + sliceCtrl->SetViewDirection(mitk::SliceNavigationController::Axial); std::cout<<"[PASSED]"<Update(); std::cout<<"[PASSED]"<GetCreatedWorldGeometry(), width, height, numSlices, widthInMM, heightInMM, thicknessInMM*numSlices, transversalcornerpoint0, right, bottom*(-1.0), normal*(-1.0)); + mitk::Point3D axialcornerpoint0; + axialcornerpoint0 = cornerpoint0+bottom+normal*(numSlices-1+0.5); //really -1? + result = compareGeometry(*sliceCtrl->GetCreatedWorldGeometry(), width, height, numSlices, widthInMM, heightInMM, thicknessInMM*numSlices, axialcornerpoint0, right, bottom*(-1.0), normal*(-1.0)); if(result!=EXIT_SUCCESS) { std::cout<<"[FAILED]"<SetViewDirection(mitk::SliceNavigationController::Frontal); std::cout<<"[PASSED]"<Update(); std::cout<<"[PASSED]"<GetAxisVector(1)*(+0.5/geometry->GetExtent(1)); result = compareGeometry(*sliceCtrl->GetCreatedWorldGeometry(), width, numSlices, height, widthInMM, thicknessInMM*numSlices, heightInMM, frontalcornerpoint0, right, normal, bottom); if(result!=EXIT_SUCCESS) { std::cout<<"[FAILED]"<SetViewDirection(mitk::SliceNavigationController::Sagittal); std::cout<<"[PASSED]"<Update(); std::cout<<"[PASSED]"<GetAxisVector(0)*(+0.5/geometry->GetExtent(0)); result = compareGeometry(*sliceCtrl->GetCreatedWorldGeometry(), height, numSlices, width, heightInMM, thicknessInMM*numSlices, widthInMM, sagittalcornerpoint0, bottom, normal, right); if(result!=EXIT_SUCCESS) { std::cout<<"[FAILED]"<InitializeStandardPlane(right.Get_vnl_vector(), bottom.Get_vnl_vector(), &spacing); planegeometry->SetOrigin(origin); //Create SlicedGeometry3D out of planeGeometry mitk::SlicedGeometry3D::Pointer slicedgeometry1 = mitk::SlicedGeometry3D::New(); unsigned int numSlices = 300; slicedgeometry1->InitializeEvenlySpaced(planegeometry, thicknessInMM, numSlices, false); //Create another slicedgeo which will be rotated mitk::SlicedGeometry3D::Pointer slicedgeometry2 = mitk::SlicedGeometry3D::New(); slicedgeometry2->InitializeEvenlySpaced(planegeometry, thicknessInMM, numSlices, false); //Create geo3D as reference mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); geometry->SetBounds(slicedgeometry1->GetBounds()); geometry->SetIndexToWorldTransform(slicedgeometry1->GetIndexToWorldTransform()); //Initialize planes for (int i=0; i < (int)numSlices; i++) { mitk::PlaneGeometry::Pointer geo2d = mitk::PlaneGeometry::New(); geo2d->Initialize(); geo2d->SetReferenceGeometry(geometry); slicedgeometry1->SetGeometry2D(geo2d,i); } for (int i=0; i < (int)numSlices; i++) { mitk::PlaneGeometry::Pointer geo2d = mitk::PlaneGeometry::New(); geo2d->Initialize(); geo2d->SetReferenceGeometry(geometry); slicedgeometry2->SetGeometry2D(geo2d,i); } slicedgeometry1->SetReferenceGeometry(geometry); slicedgeometry2->SetReferenceGeometry(geometry); //Create SNC mitk::SliceNavigationController::Pointer sliceCtrl1 = mitk::SliceNavigationController::New(); sliceCtrl1->SetInputWorldGeometry(slicedgeometry1); sliceCtrl1->Update(); mitk::SliceNavigationController::Pointer sliceCtrl2 = mitk::SliceNavigationController::New(); sliceCtrl2->SetInputWorldGeometry(slicedgeometry2); sliceCtrl2->Update(); slicedgeometry1->SetSliceNavigationController(sliceCtrl1); slicedgeometry2->SetSliceNavigationController(sliceCtrl2); //Rotate slicedgeo2 double angle = 63.84; mitk::Vector3D rotationVector; mitk::FillVector3D( rotationVector, 0.5, 0.95, 0.23 ); mitk::Point3D center = slicedgeometry2->GetCenter(); mitk::RotationOperation* op = new mitk::RotationOperation( mitk::OpROTATE, center, rotationVector, angle ); slicedgeometry2->ExecuteOperation(op); sliceCtrl2->Update(); mitk::ServiceReference serviceRef = mitk::GetModuleContext()->GetServiceReference(); mitk::PlanePositionManagerService* service = dynamic_cast(mitk::GetModuleContext()->GetService(serviceRef)); service->AddNewPlanePosition(slicedgeometry2->GetGeometry2D(0), 178); sliceCtrl1->ExecuteOperation(service->GetPlanePosition(0)); sliceCtrl1->Update(); mitk::Geometry2D* planeRotated = slicedgeometry2->GetGeometry2D(178); mitk::Geometry2D* planeRestored = dynamic_cast< const mitk::SlicedGeometry3D*>(sliceCtrl1->GetCurrentGeometry3D())->GetGeometry2D(178); bool error = ( !mitk::MatrixEqualElementWise(planeRotated->GetIndexToWorldTransform()->GetMatrix(), planeRestored->GetIndexToWorldTransform()->GetMatrix()) || !mitk::Equal(planeRotated->GetOrigin(), planeRestored->GetOrigin()) || !mitk::Equal(planeRotated->GetSpacing(), planeRestored->GetSpacing()) || !mitk::Equal(slicedgeometry2->GetDirectionVector(), dynamic_cast< const mitk::SlicedGeometry3D*>(sliceCtrl1->GetCurrentGeometry3D())->GetDirectionVector()) || !mitk::Equal(slicedgeometry2->GetSlices(), dynamic_cast< const mitk::SlicedGeometry3D*>(sliceCtrl1->GetCurrentGeometry3D())->GetSlices()) || !mitk::MatrixEqualElementWise(slicedgeometry2->GetIndexToWorldTransform()->GetMatrix(), dynamic_cast< const mitk::SlicedGeometry3D*>(sliceCtrl1->GetCurrentGeometry3D())->GetIndexToWorldTransform()->GetMatrix()) ); if (error) { MITK_TEST_CONDITION(mitk::MatrixEqualElementWise(planeRotated->GetIndexToWorldTransform()->GetMatrix(), planeRestored->GetIndexToWorldTransform()->GetMatrix()),"Testing for IndexToWorld"); MITK_INFO<<"Rotated: \n"<GetIndexToWorldTransform()->GetMatrix()<<" Restored: \n"<GetIndexToWorldTransform()->GetMatrix(); MITK_TEST_CONDITION(mitk::Equal(planeRotated->GetOrigin(), planeRestored->GetOrigin()),"Testing for origin"); MITK_INFO<<"Rotated: \n"<GetOrigin()<<" Restored: \n"<GetOrigin(); MITK_TEST_CONDITION(mitk::Equal(planeRotated->GetSpacing(), planeRestored->GetSpacing()),"Testing for spacing"); MITK_INFO<<"Rotated: \n"<GetSpacing()<<" Restored: \n"<GetSpacing(); MITK_TEST_CONDITION(mitk::Equal(slicedgeometry2->GetDirectionVector(), dynamic_cast< const mitk::SlicedGeometry3D*>(sliceCtrl1->GetCurrentGeometry3D())->GetDirectionVector()),"Testing for directionvector"); MITK_INFO<<"Rotated: \n"<GetDirectionVector()<<" Restored: \n"<(sliceCtrl1->GetCurrentGeometry3D())->GetDirectionVector(); MITK_TEST_CONDITION(mitk::Equal(slicedgeometry2->GetSlices(), dynamic_cast< const mitk::SlicedGeometry3D*>(sliceCtrl1->GetCurrentGeometry3D())->GetSlices()),"Testing for numslices"); MITK_INFO<<"Rotated: \n"<GetSlices()<<" Restored: \n"<(sliceCtrl1->GetCurrentGeometry3D())->GetSlices(); MITK_TEST_CONDITION(mitk::MatrixEqualElementWise(slicedgeometry2->GetIndexToWorldTransform()->GetMatrix(), dynamic_cast< const mitk::SlicedGeometry3D*>(sliceCtrl1->GetCurrentGeometry3D())->GetIndexToWorldTransform()->GetMatrix()),"Testing for IndexToWorld"); MITK_INFO<<"Rotated: \n"<GetIndexToWorldTransform()->GetMatrix()<<" Restored: \n"<(sliceCtrl1->GetCurrentGeometry3D())->GetIndexToWorldTransform()->GetMatrix(); return EXIT_FAILURE; } return EXIT_SUCCESS; } int mitkSliceNavigationControllerTest(int /*argc*/, char* /*argv*/[]) { int result=EXIT_FAILURE; std::cout << "Creating and initializing a PlaneGeometry: "; mitk::PlaneGeometry::Pointer planegeometry = mitk::PlaneGeometry::New(); mitk::Point3D origin; mitk::Vector3D right, bottom, normal; mitk::ScalarType width, height; mitk::ScalarType widthInMM, heightInMM, thicknessInMM; width = 100; widthInMM = width; height = 200; heightInMM = height; thicknessInMM = 1.5; // mitk::FillVector3D(origin, 0, 0, thicknessInMM*0.5); mitk::FillVector3D(origin, 4.5, 7.3, 11.2); mitk::FillVector3D(right, widthInMM, 0, 0); mitk::FillVector3D(bottom, 0, heightInMM, 0); mitk::FillVector3D(normal, 0, 0, thicknessInMM); mitk::Vector3D spacing; normal.Normalize(); normal *= thicknessInMM; mitk::FillVector3D(spacing, 1.0, 1.0, thicknessInMM); planegeometry->InitializeStandardPlane(right.Get_vnl_vector(), bottom.Get_vnl_vector(), &spacing); planegeometry->SetOrigin(origin); std::cout<<"[PASSED]"<InitializeEvenlySpaced(planegeometry, thicknessInMM, numSlices, false); std::cout<<"[PASSED]"<SetBounds(slicedgeometry->GetBounds()); geometry->SetIndexToWorldTransform(slicedgeometry->GetIndexToWorldTransform()); std::cout<<"[PASSED]"<GetCornerPoint(0); result=testGeometry(geometry, width, height, numSlices, widthInMM, heightInMM, thicknessInMM, cornerpoint0, right, bottom, normal); if(result!=EXIT_SUCCESS) return result; mitk::AffineTransform3D::Pointer transform = mitk::AffineTransform3D::New(); transform->SetMatrix(geometry->GetIndexToWorldTransform()->GetMatrix()); mitk::BoundingBox::Pointer boundingbox = geometry->CalculateBoundingBoxRelativeToTransform(transform); geometry->SetBounds(boundingbox->GetBounds()); cornerpoint0 = geometry->GetCornerPoint(0); result=testGeometry(geometry, width, height, numSlices, widthInMM, heightInMM, thicknessInMM, cornerpoint0, right, bottom, normal); if(result!=EXIT_SUCCESS) return result; std::cout << "Changing the IndexToWorldTransform of the geometry to a rotated version by SetIndexToWorldTransform() (keep cornerpoint0): "; transform = mitk::AffineTransform3D::New(); mitk::AffineTransform3D::MatrixType::InternalMatrixType vnlmatrix; vnlmatrix = planegeometry->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix(); mitk::VnlVector axis(3); mitk::FillVector3D(axis, 1.0, 1.0, 1.0); axis.normalize(); vnl_quaternion rotation(axis, 0.223); vnlmatrix = rotation.rotation_matrix_transpose()*vnlmatrix; mitk::Matrix3D matrix; matrix = vnlmatrix; transform->SetMatrix(matrix); transform->SetOffset(cornerpoint0.GetVectorFromOrigin()); right.Set_vnl_vector( rotation.rotation_matrix_transpose()*right.Get_vnl_vector() ); bottom.Set_vnl_vector(rotation.rotation_matrix_transpose()*bottom.Get_vnl_vector()); normal.Set_vnl_vector(rotation.rotation_matrix_transpose()*normal.Get_vnl_vector()); geometry->SetIndexToWorldTransform(transform); std::cout<<"[PASSED]"<GetCornerPoint(0); result = testGeometry(geometry, width, height, numSlices, widthInMM, heightInMM, thicknessInMM, cornerpoint0, right, bottom, normal); if(result!=EXIT_SUCCESS) return result; //Testing Execute RestorePlanePositionOperation result = testRestorePlanePostionOperation(); if(result!=EXIT_SUCCESS) return result; std::cout<<"[TEST DONE]"< #include #include void mitkSlicedGeometry3D_ChangeImageGeometryConsideringOriginOffset_Test() { //Tests for Offset MITK_TEST_OUTPUT( << "====== NOW RUNNING: Tests for pixel-center-based offset concerns ========"); // create a SlicedGeometry3D mitk::SlicedGeometry3D::Pointer slicedGeo3D=mitk::SlicedGeometry3D::New(); int num_slices = 5; slicedGeo3D->InitializeSlicedGeometry(num_slices); // 5 slices mitk::Point3D newOrigin; newOrigin[0] = 91.3; newOrigin[1] = -13.3; newOrigin[2] = 0; slicedGeo3D->SetOrigin(newOrigin); mitk::Vector3D newSpacing; newSpacing[0] = 1.0f; newSpacing[1] = 0.9f; newSpacing[2] = 0.3f; slicedGeo3D->SetSpacing(newSpacing); // create subslices as well for (int i=0; i < num_slices; i++) { mitk::Geometry2D::Pointer geo2d = mitk::Geometry2D::New(); geo2d->Initialize(); slicedGeo3D->SetGeometry2D(geo2d,i); } // now run tests MITK_TEST_OUTPUT( << "Testing whether slicedGeo3D->GetImageGeometry() is false by default"); MITK_TEST_CONDITION_REQUIRED( slicedGeo3D->GetImageGeometry()==false, ""); MITK_TEST_OUTPUT( << "Testing whether first and last geometry in the SlicedGeometry3D have GetImageGeometry()==false by default"); mitk::Geometry3D* subSliceGeo2D_first = slicedGeo3D->GetGeometry2D(0); mitk::Geometry3D* subSliceGeo2D_last = slicedGeo3D->GetGeometry2D(num_slices-1); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_first->GetImageGeometry()==false, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_last->GetImageGeometry()==false, ""); // Save some Origins and cornerpoints mitk::Point3D OriginSlicedGeo( slicedGeo3D->GetOrigin() ); mitk::Point3D OriginFirstGeo( subSliceGeo2D_first->GetOrigin() ); mitk::Point3D OriginLastGeo( subSliceGeo2D_last->GetOrigin() ); mitk::Point3D CornerPoint0SlicedGeo(slicedGeo3D->GetCornerPoint(0)); mitk::Point3D CornerPoint1FirstGeo(subSliceGeo2D_first->GetCornerPoint(1)); mitk::Point3D CornerPoint2LastGeo(subSliceGeo2D_last->GetCornerPoint(2)); MITK_TEST_OUTPUT( << "Calling slicedGeo3D->ChangeImageGeometryConsideringOriginOffset(true)"); //std::cout << "vorher Origin: " << subSliceGeo2D_first->GetOrigin() << std::endl; //std::cout << "vorher Corner: " << subSliceGeo2D_first->GetCornerPoint(0) << std::endl; slicedGeo3D->ChangeImageGeometryConsideringOriginOffset(true); //std::cout << "nachher Origin: " << subSliceGeo2D_first->GetOrigin() << std::endl; //std::cout << "nachher Corner: " << subSliceGeo2D_first->GetCornerPoint(0) << std::endl; MITK_TEST_OUTPUT( << "Testing whether slicedGeo3D->GetImageGeometry() is now true"); MITK_TEST_CONDITION_REQUIRED( slicedGeo3D->GetImageGeometry()==true, ""); MITK_TEST_OUTPUT( << "Testing whether first and last geometry in the SlicedGeometry3D have GetImageGeometry()==true now"); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_first->GetImageGeometry()==true, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_last->GetImageGeometry()==true, ""); MITK_TEST_OUTPUT( << "Testing wether offset has been added to origins"); // Manually adding Offset. OriginSlicedGeo[0] += (slicedGeo3D->GetSpacing()[0]) / 2; OriginSlicedGeo[1] += (slicedGeo3D->GetSpacing()[1]) / 2; OriginSlicedGeo[2] += (slicedGeo3D->GetSpacing()[2]) / 2; OriginFirstGeo[0] += (subSliceGeo2D_first->GetSpacing()[0]) / 2; OriginFirstGeo[1] += (subSliceGeo2D_first->GetSpacing()[1]) / 2; OriginFirstGeo[2] += (subSliceGeo2D_first->GetSpacing()[2]) / 2; OriginLastGeo[0] += (subSliceGeo2D_last->GetSpacing()[0]) / 2; OriginLastGeo[1] += (subSliceGeo2D_last->GetSpacing()[1]) / 2; OriginLastGeo[2] += (subSliceGeo2D_last->GetSpacing()[2]) / 2; MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_first->GetCornerPoint(1)==CornerPoint1FirstGeo, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_last->GetCornerPoint(2)==CornerPoint2LastGeo, ""); MITK_TEST_CONDITION_REQUIRED( slicedGeo3D->GetCornerPoint(0)==CornerPoint0SlicedGeo, ""); MITK_TEST_CONDITION_REQUIRED( slicedGeo3D->GetOrigin()==OriginSlicedGeo, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_first->GetOrigin()==OriginFirstGeo, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_last->GetOrigin()==OriginLastGeo, ""); MITK_TEST_OUTPUT( << "Calling slicedGeo3D->ChangeImageGeometryConsideringOriginOffset(false)"); slicedGeo3D->ChangeImageGeometryConsideringOriginOffset(false); MITK_TEST_OUTPUT( << "Testing whether slicedGeo3D->GetImageGeometry() is now false"); MITK_TEST_CONDITION_REQUIRED( slicedGeo3D->GetImageGeometry()==false, ""); MITK_TEST_OUTPUT( << "Testing whether first and last geometry in the SlicedGeometry3D have GetImageGeometry()==false now"); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_first->GetImageGeometry()==false, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_last->GetImageGeometry()==false, ""); MITK_TEST_OUTPUT( << "Testing wether offset has been added to origins of geometry"); // Manually substracting Offset. OriginSlicedGeo[0] -= (slicedGeo3D->GetSpacing()[0]) / 2; OriginSlicedGeo[1] -= (slicedGeo3D->GetSpacing()[1]) / 2; OriginSlicedGeo[2] -= (slicedGeo3D->GetSpacing()[2]) / 2; OriginFirstGeo[0] -= (subSliceGeo2D_first->GetSpacing()[0]) / 2; OriginFirstGeo[1] -= (subSliceGeo2D_first->GetSpacing()[1]) / 2; OriginFirstGeo[2] -= (subSliceGeo2D_first->GetSpacing()[2]) / 2; OriginLastGeo[0] -= (subSliceGeo2D_last->GetSpacing()[0]) / 2; OriginLastGeo[1] -= (subSliceGeo2D_last->GetSpacing()[1]) / 2; OriginLastGeo[2] -= (subSliceGeo2D_last->GetSpacing()[2]) / 2; MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_first->GetCornerPoint(1)==CornerPoint1FirstGeo, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_last->GetCornerPoint(2)==CornerPoint2LastGeo, ""); MITK_TEST_CONDITION_REQUIRED( slicedGeo3D->GetCornerPoint(0)==CornerPoint0SlicedGeo, ""); MITK_TEST_CONDITION_REQUIRED( slicedGeo3D->GetOrigin()==OriginSlicedGeo, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_first->GetOrigin()==OriginFirstGeo, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_last->GetOrigin()==OriginLastGeo, ""); MITK_TEST_OUTPUT( << "ALL SUCCESSFULLY!"); } int mitkSlicedGeometry3DTest(int /*argc*/, char* /*argv*/[]) { mitk::PlaneGeometry::Pointer planegeometry1 = mitk::PlaneGeometry::New(); mitk::Point3D origin; mitk::Vector3D right, bottom, normal; mitk::ScalarType width, height; mitk::ScalarType widthInMM, heightInMM, thicknessInMM; width = 100; widthInMM = width; height = 200; heightInMM = height; thicknessInMM = 3.5; mitk::FillVector3D(origin, 4.5, 7.3, 11.2); mitk::FillVector3D(right, widthInMM, 0, 0); mitk::FillVector3D(bottom, 0, heightInMM, 0); mitk::FillVector3D(normal, 0, 0, thicknessInMM); std::cout << "Initializing planegeometry1 by InitializeStandardPlane(rightVector, downVector, spacing = NULL): "<InitializeStandardPlane(right.Get_vnl_vector(), bottom.Get_vnl_vector()); std::cout << "Setting planegeometry2 to a cloned version of planegeometry1: "<(planegeometry1->Clone().GetPointer());; std::cout << "Changing the IndexToWorldTransform of planegeometry2 to a rotated version by SetIndexToWorldTransform() (keep origin): "<GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix(); mitk::VnlVector axis(3); mitk::FillVector3D(axis, 1.0, 1.0, 1.0); axis.normalize(); vnl_quaternion rotation(axis, 0.123); vnlmatrix = rotation.rotation_matrix_transpose()*vnlmatrix; mitk::Matrix3D matrix; matrix = vnlmatrix; transform->SetMatrix(matrix); transform->SetOffset(planegeometry2->GetIndexToWorldTransform()->GetOffset()); right.Set_vnl_vector( rotation.rotation_matrix_transpose()*right.Get_vnl_vector() ); bottom.Set_vnl_vector(rotation.rotation_matrix_transpose()*bottom.Get_vnl_vector()); normal.Set_vnl_vector(rotation.rotation_matrix_transpose()*normal.Get_vnl_vector()); planegeometry2->SetIndexToWorldTransform(transform); std::cout << "Setting planegeometry3 to the backside of planegeometry2: " <InitializeStandardPlane(planegeometry2, mitk::PlaneGeometry::Transversal, 0, false); + planegeometry3->InitializeStandardPlane(planegeometry2, mitk::PlaneGeometry::Axial, 0, false); std::cout << "Testing SlicedGeometry3D::InitializeEvenlySpaced(planegeometry3, zSpacing = 1, slices = 5, flipped = false): " <InitializeEvenlySpaced(planegeometry3, 1, numSlices, false); std::cout << "Testing availability and type (PlaneGeometry) of first geometry in the SlicedGeometry3D: "; mitk::PlaneGeometry* accessedplanegeometry3 = dynamic_cast(slicedWorldGeometry->GetGeometry2D(0)); if(accessedplanegeometry3==NULL) { std::cout<<"[FAILED]"<GetAxisVector(0), planegeometry3->GetAxisVector(0))==false) || (mitk::Equal(accessedplanegeometry3->GetAxisVector(1), planegeometry3->GetAxisVector(1))==false) || (mitk::Equal(accessedplanegeometry3->GetAxisVector(2), planegeometry3->GetAxisVector(2))==false) || (mitk::Equal(accessedplanegeometry3->GetOrigin(), planegeometry3->GetOrigin())==false)) { std::cout<<"[FAILED]"<(slicedWorldGeometry->GetGeometry2D(numSlices-1)); mitk::Point3D origin3last; origin3last = planegeometry3->GetOrigin()+slicedWorldGeometry->GetDirectionVector()*(numSlices-1); if(accessedplanegeometry3last==NULL) { std::cout<<"[FAILED]"<GetAxisVector(0), planegeometry3->GetAxisVector(0))==false) || (mitk::Equal(accessedplanegeometry3last->GetAxisVector(1), planegeometry3->GetAxisVector(1))==false) || (mitk::Equal(accessedplanegeometry3last->GetAxisVector(2), planegeometry3->GetAxisVector(2))==false) || (mitk::Equal(accessedplanegeometry3last->GetOrigin(), origin3last)==false) || (mitk::Equal(accessedplanegeometry3last->GetIndexToWorldTransform()->GetOffset(), origin3last.GetVectorFromOrigin())==false)) { std::cout<<"[FAILED]"<(slicedWorldGeometry->GetGeometry2D(0)); if(accessedplanegeometry3==NULL) { std::cout<<"[FAILED]"<GetAxisVector(0), planegeometry3->GetAxisVector(0))==false) || (mitk::Equal(accessedplanegeometry3->GetAxisVector(1), planegeometry3->GetAxisVector(1))==false) || (mitk::Equal(accessedplanegeometry3->GetAxisVector(2), planegeometry3->GetAxisVector(2))==false) || (mitk::Equal(accessedplanegeometry3->GetOrigin(), planegeometry3->GetOrigin())==false) || (mitk::Equal(accessedplanegeometry3->GetIndexToWorldTransform()->GetOffset(), planegeometry3->GetOrigin().GetVectorFromOrigin())==false)) { std::cout<<"[FAILED]"<Initialize(old); // new no has the geometry information from old image +new->Initialize(old); // new now has the geometry information from old image new->SetVolume(old->GetData()); // new now additionally contains the old images visual data new->SetPropertyList(old->GetPropertyList()) // new now additionally contains the old image's properties \endverbatim \subsection MitkImagePage_Inheriting Inheriting from MITK Image In general, one should try to avoid inheriting from mitk Image. The simple reason for this is that your derived class will not cleanly work together with the Filters already implemented (See the chapter on Pipelining for Details). If however, mitk Image does not offer the functionality you require it is possible to do so. See the documentation for various examples of classes that inherit from image. -*/ \ No newline at end of file +*/ diff --git a/Core/Documentation/Doxygen/Concepts/QVTKRendering.dox b/Core/Documentation/Doxygen/Concepts/QVTKRendering.dox index 6b59d650e6..ea919df38c 100644 --- a/Core/Documentation/Doxygen/Concepts/QVTKRendering.dox +++ b/Core/Documentation/Doxygen/Concepts/QVTKRendering.dox @@ -1,83 +1,83 @@ /** \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. 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.. 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: \image html qVtkRenderingSequence.png "Sequence overview MITK scene rendering" \section QVTKRendering_programmerGuide User Guide: Programming hints for rendering related stuff (in plugins) -\li The QmitkRenderWindow can be accessed like this: this->GetRenderWindowPart()->GetRenderWindow("transversal"); -\li The vtkRenderWindow can be accessed like this: this->GetRenderWindowPart()->GetRenderWindow("transversal")->GetVtkRenderWindow(); +\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("transversal")->GetVtkRenderWindow()); +\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/images/tilt-correction.jpg b/Core/Documentation/images/tilt-correction.jpg new file mode 100644 index 0000000000..46712f6c86 Binary files /dev/null and b/Core/Documentation/images/tilt-correction.jpg differ diff --git a/Documentation/Doxygen/Tutorial/Step04.dox b/Documentation/Doxygen/Tutorial/Step04.dox index 1e830fa813..6696f2e96d 100644 --- a/Documentation/Doxygen/Tutorial/Step04.dox +++ b/Documentation/Doxygen/Tutorial/Step04.dox @@ -1,66 +1,66 @@ /** \page Step04Page MITK Tutorial - Step 4: Use several views to explore data As in Step 2 and Step 3 one or more data sets may be loaded. Now 3 views on the data are created. The QmitkRenderWindow is used for displaying a 3D view as in Step 3, but without volume-rendering. Furthermore two 2D views for slicing through the data are created. The class QmitkSliceWidget is used, which is based on the class QmitkRenderWindow, but additionally provides sliders to slice through the data. We create two instances of -QmitkSliceWidget, one for transversal and one for sagittal slicing. Step 4b enhances the program in that the two slices are also shown at their correct position in 3D as well as intersection-line, each in the other 2D view. +QmitkSliceWidget, one for axial and one for sagittal slicing. Step 4b enhances the program in that the two slices are also shown at their correct position in 3D as well as intersection-line, each in the other 2D view. As in the previous steps, to obtain the result the program has to be executed using the image file bin/CMakeExternals/Source/MITK-Data/Pic3D.nrrd and the surface file src/MITK/Modules/MitkExt/Testing/Data/lungs.vtk. \li \ref Step4.cpp "Step4.cpp"\n Contains the code of step 4a + b. -\section Step4aSection Step 4a - Create transversal and sagittal view +\section Step4aSection Step 4a - Create axial and sagittal view \image html step4a_result.png \dontinclude Step4.cpp Create a Qt horizontal box for the layout: \skipline QHBox Then create a renderwindow: \skipline QmitkRenderWindow \until SetMapperID -Create a 2D view for slicing transversally: +Create a 2D view for slicing axially: \skipline view2 \until view2.SetData Then create a 2D view for slicing sagitally. \skipline view3 \until view3.SetData The toplevelWidget is now the new main widget: \skipline qtapplication \skipline toplevelWidget.show \section Step4bSection Step 4b - Display slice positions \image html step4b_result.png We now want to see the position of the slice in 2D and the slice itself in 3D. Therefore it has to be added to the tree: \dontinclude Step4.cpp \skipline ds->Add(view2.GetRenderer() \skipline ds->Add(view3.GetRenderer() Slice positions are now displayed as can be seen in the picture. \dontinclude Step4.cpp \ref Step03Page "[Previous step]" \ref Step05Page "[Next step]" \ref TutorialPage "[Main tutorial page]" */ diff --git a/Documentation/Doxygen/Tutorial/Step08.dox b/Documentation/Doxygen/Tutorial/Step08.dox index 6aaee4f3cf..21884dce4b 100644 --- a/Documentation/Doxygen/Tutorial/Step08.dox +++ b/Documentation/Doxygen/Tutorial/Step08.dox @@ -1,24 +1,24 @@ /** \page Step08Page MITK Tutorial - Step 8: Use QmitkStdMultiWidget as widget In this step a QmitkStdMultiWidget is used. It offers four views on the data. - From top left to bottom the views are initialized as transversal, sagittal and coronar. The bottom right view is initialized as 3D view. + From top left to bottom the views are initialized as axial, sagittal and coronar. The bottom right view is initialized as 3D view. \image html step8_result.png \li \ref Step8.cpp "Step8.cpp"\n \li \ref Step8.h "Step8.h"\n \li \ref Step8main.cpp "Step8main.cpp"\n Step8 inherits from Step6. The method SetupWidgets() is changed: A QmitkStdMultiWidget is used instead of one QmitkRenderWindow and two instances of QmitkSliceWidget. \dontinclude Step8.cpp \skipline Part Ia \until EnableNavigationControllerEventListening \ref Step07Page "[Previous step]" \ref Step09Page "[Next step]" */ diff --git a/Documentation/Doxygen/Tutorial/Step09.dox b/Documentation/Doxygen/Tutorial/Step09.dox index d60e22c07a..8033628aa3 100644 --- a/Documentation/Doxygen/Tutorial/Step09.dox +++ b/Documentation/Doxygen/Tutorial/Step09.dox @@ -1,219 +1,219 @@ /** \page Step09Page MITK Tutorial - Step 9: A plug-in -MITK uses a very modular concept to maximize reusability and portability. You start an application (for example ExtApp, the sample application provided by MITK). An application has several bundles (or plug-ins). A bundle can be a functionality, which in turn can be a view, each of these terms specifying certain behaviour and attributes. +MITK uses a very modular concept to maximize reusability and portability. You start an application (for example mitkWorkbench, the sample application provided by MITK). An application has several bundles (or plug-ins). A bundle can be a functionality, which in turn can be a view, each of these terms specifying certain behaviour and attributes. The creation of a MITK plug-in is considerably facilitated by using the MITK BundleGenerator as described in \ref NewPluginPage . The mentioned tool was used to create a plug-in QmitkRegionGrowing. Let's first look at what files the BundleGenerator created: \verbatim documentation\doxygen\ modules.dox............................. Doxygen file for documenting your plug-in resources\ icon.xpm................................ The icon of your plug-in. GIMP or other programs (including your text editor) can be used to change this src\internal\ QmitkMITKRegionGrowingView.cpp.......... The most important file, implementing behaviour QmitkMITKRegionGrowingView.h............ Header file of the functionality QmitkMITKRegionGrowingViewControls.ui... XML file of the Qt Designer, describes buttons, combo boxes, etc. of your controls CMakeLists.txt \.......................... Build system related files for CMake files.cmake / manifest_headers.cmake.................... Information about your plug-in plugin.xml ............................... BlueBerry integration \endverbatim If you are not familiar with Qt development, please look into this Trolltech page describing .ui files (no, forget about the please, DO it!) The C++ files implement a subclass of QmitkAbstractView. In this special case of QmitkRegionGrowing, we added the ability to set some seed points and run a region grower. If you are interested in the concrete changes necessary to turn a freshly generated QmitkRegionGrowing into an integrated one: Since an access to the StdMultiWidget is needed, manifest_headers.cmake has to be edited: \verbatim set(Require-Plugin org.mitk.gui.qt.common org.mitk.gui.qt.stdmultiwidgeteditor) \endverbatim To add a PointSet for the seed points: QmitkRegionGrowingView.h Add includes: \verbatim #include "QmitkPointListWidget.h" #include "QmitkStdMultiWidget.h" #include "QmitkStdMultiWidgetEditor.h" \endverbatim Add the point set as protected object and add Pointers for a QmitkPointListWidget and a QmitkStdMultiWidget: \verbatim /// \brief This is the actual seed point data object mitk::PointSet::Pointer m_PointSet; QmitkPointListWidget* lstPoints; QmitkStdMultiWidget* m_MultiWidget; \endverbatim QmitkRegionGrowingView.cpp CreateQtPartControl(): \verbatim // create a QmitkPointListWidget and add it to the widget created from .ui file lstPoints = new QmitkPointListWidget(); m_Controls.verticalLayout->addWidget(lstPoints); // get access to StdMultiWidget by using RenderWindowPart QmitkStdMultiWidgetEditor* qSMWE = dynamic_cast(GetRenderWindowPart()); m_MultiWidget = qSMWE->GetStdMultiWidget(); // let the point set widget know about the multi widget (crosshair updates) lstPoints->SetMultiWidget( m_MultiWidget ); // create a new DataTreeNode containing a PointSet with some interaction m_PointSet = mitk::PointSet::New(); mitk::DataNode::Pointer pointSetNode = mitk::DataNode::New(); pointSetNode->SetData( m_PointSet ); pointSetNode->SetName("seed points for region growing"); pointSetNode->SetProperty("helper object", mitk::BoolProperty::New(true) ); pointSetNode->SetProperty("layer", mitk::IntProperty::New(1024) ); // add the pointset to the data tree (for rendering and access by other modules) GetDataStorage()->Add( pointSetNode ); // tell the GUI widget about out point set lstPoints->SetPointSetNode( pointSetNode ); \endverbatim To use the ITK region grower: QmitkRegionGrowingView.h Add protected method: \verbatim /*! \brief ITK image processing function This function is templated like an ITK image. The MITK-Macro AccessByItk determines the actual pixel type and dimensionality of a given MITK image and calls this function for further processing (in our case region growing) */ template < typename TPixel, unsigned int VImageDimension > void ItkImageProcessing( itk::Image< TPixel, VImageDimension >* itkImage, mitk::Geometry3D* imageGeometry ); \endverbatim QmitkRegionGrowingView.cpp Add includes: \verbatim // MITK #include "mitkImageAccessByItk.h" #include "mitkITKImageImport.h" #include "mitkProperties.h" #include "mitkColorProperty.h" // ITK #include \endverbatim DoImageProcessing(); \verbatim // So we have an image. Let's see if the user has set some seed points already if ( m_PointSet->GetSize() == 0 ) { // no points there. Not good for region growing QMessageBox::information( NULL, "Region growing functionality", "Please set some seed points inside the image first.\n" "(hold Shift key and click left mouse button inside the image.)" ); return; } // actually perform region growing. Here we have both an image and some seed points AccessByItk_1( image, ItkImageProcessing, image->GetGeometry() ); // some magic to call the correctly templated function \endverbatim And add the new method: \verbatim template < typename TPixel, unsigned int VImageDimension > void QmitkRegionGrowingView::ItkImageProcessing( itk::Image< TPixel, VImageDimension >* itkImage, mitk::Geometry3D* imageGeometry ) { typedef itk::Image< TPixel, VImageDimension > InputImageType; typedef typename InputImageType::IndexType IndexType; // instantiate an ITK region growing filter, set its parameters typedef itk::ConnectedThresholdImageFilter RegionGrowingFilterType; typename RegionGrowingFilterType::Pointer regionGrower = RegionGrowingFilterType::New(); regionGrower->SetInput( itkImage ); // don't forget this // determine a thresholding interval IndexType seedIndex; TPixel min( std::numeric_limits::max() ); TPixel max( std::numeric_limits::min() ); mitk::PointSet::PointsContainer* points = m_PointSet->GetPointSet()->GetPoints(); for ( mitk::PointSet::PointsConstIterator pointsIterator = points->Begin(); pointsIterator != points->End(); ++pointsIterator ) { // first test if this point is inside the image at all if ( !imageGeometry->IsInside( pointsIterator.Value()) ) { continue; } // convert world coordinates to image indices imageGeometry->WorldToIndex( pointsIterator.Value(), seedIndex); // get the pixel value at this point TPixel currentPixelValue = itkImage->GetPixel( seedIndex ); // adjust minimum and maximum values if (currentPixelValue > max) max = currentPixelValue; if (currentPixelValue < min) min = currentPixelValue; regionGrower->AddSeed( seedIndex ); } std::cout << "Values between " << min << " and " << max << std::endl; min -= 30; max += 30; // set thresholds and execute filter regionGrower->SetLower( min ); regionGrower->SetUpper( max ); regionGrower->Update(); mitk::Image::Pointer resultImage = mitk::ImportItkImage( regionGrower->GetOutput() ); mitk::DataTreeNode::Pointer newNode = mitk::DataTreeNode::New(); newNode->SetData( resultImage ); // set some properties newNode->SetProperty("binary", mitk::BoolProperty::New(true)); newNode->SetProperty("name", mitk::StringProperty::New("dumb segmentation")); newNode->SetProperty("color", mitk::ColorProperty::New(1.0,0.0,0.0)); newNode->SetProperty("volumerendering", mitk::BoolProperty::New(true)); newNode->SetProperty("layer", mitk::IntProperty::New(1)); newNode->SetProperty("opacity", mitk::FloatProperty::New(0.5)); // add result to data tree this->GetDefaultDataStorage()->Add( newNode ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } \endverbatim Have fun using MITK! If you meet any difficulties during your first steps, don't hesitate to ask on the MITK mailing list mitk-users@lists.sourceforge.net! People there are kind and will try to help you. \ref Step08Page "[Previous step]" \ref Step10Page "[Next Step]" \ref TutorialPage "[Main tutorial page]" */ diff --git a/Documentation/Doxygen/UserManual/Applications.dox b/Documentation/Doxygen/UserManual/Applications.dox index 65f1b1e6c6..fc0c286f5d 100644 --- a/Documentation/Doxygen/UserManual/Applications.dox +++ b/Documentation/Doxygen/UserManual/Applications.dox @@ -1,30 +1,30 @@ /** \page ApplicationsPage Using MITK and Applications Available sections: - \ref ApplicationsPageUsingMITK - \ref ApplicationsPageApplications - \ref ApplicationsPageApplicationsList \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 ModuleListPage . The basic usage information on MITK can be found in \subpage 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_extapplication +
  • \subpage org_mitkworkbench
  • \subpage org_dti_atlas_application -
  • \subpage org_diffusionapplication +
  • \subpage org_mitk_gui_qt_diffusionimagingapp
*/ \ No newline at end of file diff --git a/Documentation/Doxygen/UserManual/ModuleList.dox b/Documentation/Doxygen/UserManual/ModuleList.dox index 7e7c4e61f1..de720208ee 100644 --- a/Documentation/Doxygen/UserManual/ModuleList.dox +++ b/Documentation/Doxygen/UserManual/ModuleList.dox @@ -1,34 +1,34 @@ /** \page ModuleListPage MITK Modules \section ModuleListPageOverview Overview The modules 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 modules as needed. The distinction between developer and end user use is for convenience only and mainly distinguishes which group a module is primarily aimed at. \section ModuleListPageEndUserModuleList List of Modules for End User Use - \li \subpage org_basicimageprocessing - \li \subpage org_datamanager - \li \subpage org_diffusion + \li \subpage org_mitk_views_basicimageprocessing + \li \subpage org_mitk_views_datamanager + \li \subpage org_mitk_gui_qt_diffusionimaging \li \subpage IGTGeneralModulePage - \li \subpage org_imagecropper - \li \subpage org_imagenavigator - \li \subpage org_measurementtoolbox - \li \subpage org_moviemaker - \li \subpage org_meshdecimation - \li \subpage org_pointsetinteraction - \li \subpage RegistrationModuleOverviewPage - \li \subpage org_segment - \li \subpage org_volvis + \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 \section ModuleListPageDevModuleList List of Modules for Developer Use and Examples \li \subpage org_surfacematerialeditor \li \subpage org_toftutorial - \li \subpage org_mitkexamples + \li \subpage org_mitk_gui_qt_examples \li \subpage org_mitkexamplesopencv */ diff --git a/Documentation/doxygen.conf.in b/Documentation/doxygen.conf.in index abd2b937c4..f6eb26cfe3 100644 --- a/Documentation/doxygen.conf.in +++ b/Documentation/doxygen.conf.in @@ -1,1904 +1,1912 @@ -# Doxyfile 1.8.1 +# Doxyfile 1.8.0 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" "). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or sequence of words) that should # identify the project. Note that if you do not use Doxywizard you need # to put quotes around the project name if it contains spaces. PROJECT_NAME = MITK # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = @MITK_VERSION_STRING@ # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer # a quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = "Medical Imaging Interaction Toolkit" # With the PROJECT_LOGO tag one can specify an logo or icon that is # included in the documentation. The maximum height of the logo should not # exceed 55 pixels and the maximum width should not exceed 200 pixels. # Doxygen will copy the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = @MITK_DOXYGEN_OUTPUT_DIR@ # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful if your file system # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = "FIXME=\par Fix Me's:\n" \ "BlueBerry=\if BLUEBERRY" \ "endBlueBerry=\endif" \ "bundlemainpage{1}=\page \1" \ "embmainpage{1}=\page \1" # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding # "class=itcl::class" will allow you to use the command class in the # itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given extension. # Doxygen has a built-in mapping, but you can override or extend it using this # tag. The format is ext=language, where ext is a file extension, and language # is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, # C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C # (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions # you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. EXTENSION_MAPPING = # If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all # comments according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you # can mix doxygen, HTML, and XML commands with Markdown formatting. # Disable only in case of backward compatibilities issues. MARKDOWN_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also makes the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = YES # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and # unions are shown inside the group in which they are included (e.g. using # @ingroup) instead of on a separate page (for HTML and Man pages) or # section (for LaTeX and RTF). INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and # unions with only public data fields will be shown inline in the documentation # of the scope in which they are defined (i.e. file, namespace, or group # documentation), provided this scope is documented. If set to NO (the default), # structs, classes, and unions are shown on a separate page (for HTML and Man # pages) or section (for LaTeX and RTF). INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penalty. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will roughly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols. SYMBOL_CACHE_SIZE = 0 # Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be # set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given # their name and scope. Since this can be an expensive process and often the # same symbol appear multiple times in the code, doxygen keeps a cache of # pre-resolved symbols. If the cache is too small doxygen will become slower. # If the cache is too large, memory is wasted. The cache size is given by this # formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal scope will be included in the documentation. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = @MITK_DOXYGEN_INTERNAL_DOCS@ # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespaces are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = @MITK_DOXYGEN_HIDE_FRIEND_COMPOUNDS@ # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = @MITK_DOXYGEN_INTERNAL_DOCS@ # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = YES # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to # do proper type resolution of all parameters of a function it will reject a # match between the prototype and the implementation of a member function even # if there is only one candidate or it is obvious which candidate to choose # by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen # will still accept a match between prototype and implementation in such cases. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = @MITK_DOXYGEN_GENERATE_TODOLIST@ # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = @MITK_DOXYGEN_GENERATE_BUGLIST@ # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= @MITK_DOXYGEN_GENERATE_DEPRECATEDLIST@ # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = @MITK_DOXYGEN_ENABLED_SECTIONS@ # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or macro consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and macros in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 0 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. # This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. The create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files # containing the references data. This must be a list of .bib files. The # .bib extension is automatically appended if omitted. Using this command # requires the bibtex tool to be installed. See also # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this # feature you need bibtex and perl available in the search path. CITE_BIB_FILES = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_NO_PARAMDOC option can be enabled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = @MITK_SOURCE_DIR@ \ @MITK_BINARY_DIR@ \ @MITK_DOXYGEN_ADDITIONAL_INPUT_DIRS@ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py # *.f90 *.f *.for *.vhd *.vhdl FILE_PATTERNS = *.h \ *.cpp \ *.dox \ *.md \ *.txx \ *.tpp \ *.cxx \ *.cmake # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = @MITK_SOURCE_DIR@/Utilities/ann/ \ @MITK_SOURCE_DIR@/Utilities/glew/ \ @MITK_SOURCE_DIR@/Utilities/ipFunc/ \ @MITK_SOURCE_DIR@/Utilities/ipSegmentation/ \ @MITK_SOURCE_DIR@/Utilities/KWStyle/ \ @MITK_SOURCE_DIR@/Utilities/pic2vtk/ \ @MITK_SOURCE_DIR@/Utilities/Poco/ \ @MITK_SOURCE_DIR@/Utilities/qtsingleapplication/ \ @MITK_SOURCE_DIR@/Utilities/qwt/ \ @MITK_SOURCE_DIR@/Utilities/qxt/ \ @MITK_SOURCE_DIR@/Utilities/tinyxml/ \ @MITK_SOURCE_DIR@/Utilities/vecmath/ \ @MITK_SOURCE_DIR@/Applications/PluginGenerator/ \ @MITK_SOURCE_DIR@/BlueBerry/ \ @MITK_SOURCE_DIR@/Core/Code/CppMicroServices/README.md \ @MITK_SOURCE_DIR@/Core/Code/CppMicroServices/documentation/snippets/ \ @MITK_SOURCE_DIR@/Core/Code/CppMicroServices/documentation/doxygen/standalone/ \ @MITK_SOURCE_DIR@/Core/Code/CppMicroServices/test/ \ @MITK_SOURCE_DIR@/Deprecated/ \ @MITK_SOURCE_DIR@/Build/ \ @MITK_SOURCE_DIR@/CMake/PackageDepends \ @MITK_SOURCE_DIR@/CMake/QBundleTemplate \ @MITK_SOURCE_DIR@/CMakeExternals \ @MITK_SOURCE_DIR@/Modules/QmitkExt/vtkQtChartHeaders/ \ @MITK_BINARY_DIR@/PT/ \ @MITK_BINARY_DIR@/GP/ \ @MITK_BINARY_DIR@/Core/Code/CppMicroServices/ \ @MITK_DOXYGEN_ADDITIONAL_EXCLUDE_DIRS@ # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = moc_* \ Register* \ */files.cmake \ */.git/* \ *_p.h \ *Private.* \ */Snippets/* \ */snippets/* \ */testing/* \ */Testing/* \ @MITK_BINARY_DIR@/*.cmake \ @MITK_DOXYGEN_EXCLUDE_PATTERNS@ # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = @MITK_SOURCE_DIR@/Examples/ \ @MITK_SOURCE_DIR@/Examples/Tutorial/ \ @MITK_SOURCE_DIR@/Examples/QtFreeRender/ \ @MITK_SOURCE_DIR@/Core/Code/ \ @MITK_SOURCE_DIR@/Core/Code/CppMicroServices/Documentation/Snippets/ \ @MITK_DOXYGEN_OUTPUT_DIR@/html/extension-points/html/ \ @MITK_SOURCE_DIR@/Documentation/Snippets/ \ @MITK_SOURCE_DIR@/Documentation/Doxygen/ExampleCode/ # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = YES # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = @MITK_SOURCE_DIR@/Documentation/Doxygen/ \ @MITK_SOURCE_DIR@/Documentation/Doxygen/Modules/ \ @MITK_SOURCE_DIR@/Documentation/Doxygen/Tutorial/ \ @MITK_SOURCE_DIR@ # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. # If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. # Doxygen will compare the file name with each pattern and apply the # filter if there is a match. # The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty or if # non of the patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = *.cmake=@CMakeDoxygenFilter_EXECUTABLE@ # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) # and it is also possible to disable source filtering for a specific pattern # using *.ext= (so without naming a filter). This option only has effect when # FILTER_SOURCE_FILES is enabled. FILTER_SOURCE_PATTERNS = #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. # Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 3 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. Note that when using a custom header you are responsible # for the proper inclusion of any scripts and style sheets that doxygen # needs, which is dependent on the configuration options used. # It is advised to generate a default header using "doxygen -w html # header.html footer.html stylesheet.css YourConfigFile" and then modify # that header. Note that the header is subject to change so you typically # have to redo this when upgrading to a newer version of doxygen or when # changing the value of configuration settings such as GENERATE_TREEVIEW! HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # style sheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = @MITK_DOXYGEN_STYLESHEET@ # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that # the files will be copied as-is; there are no commands or markers available. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the style sheet and background images # according to this color. Hue is specified as an angle on a colorwheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below # 100 gradually make the output lighter, whereas values above 100 make # the output darker. The value divided by 100 is the actual gamma applied, # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the -# page has loaded. +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = @MITK_DOXYGEN_HTML_DYNAMIC_SECTIONS@ -# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of -# entries shown in the various tree structured indices initially; the user -# can expand and collapse entries dynamically later on. Doxygen will expand -# the tree to such a level that at most the specified number of entries are -# visible (unless a fully collapsed tree already exceeds this amount). -# So setting the number of entries 1 will produce a full collapsed tree by -# default. 0 is a special value representing an infinite number of entries -# and will result in a full expanded tree by default. - -HTML_INDEX_NUM_ENTRIES = 100 - # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated # that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = @MITK_DOXYGEN_GENERATE_QHP@ # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = @MITK_DOXYGEN_QCH_FILE@ # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = "org.mitk" # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = MITK # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to # add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see # # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's # filter section matches. # # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = @QT_HELPGENERATOR_EXECUTABLE@ # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project # The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) # at top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. Since the tabs have the same information as the # navigation tree you can set this option to NO if you already set # GENERATE_TREEVIEW to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. # Since the tree basically has the same information as the tab index you # could consider to set DISABLE_INDEX to NO when enabling this option. GENERATE_TREEVIEW = YES # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values # (range [0,1..20]) that doxygen will group on one line in the generated HTML # documentation. Note that a value of 0 will completely suppress the enum # values from appearing in the overview section. ENUM_VALUES_PER_LINE = 4 +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 300 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are # not supported properly for IE 6.0, but are supported on all modern browsers. # Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax # (see http://www.mathjax.org) which uses client side Javascript for the # rendering instead of using prerendered bitmaps. Use this if you do not # have LaTeX installed or if you want to formulas look prettier in the HTML # output. When enabled you may also need to install MathJax separately and # configure the path to it using the MATHJAX_RELPATH option. USE_MATHJAX = NO # When MathJax is enabled you need to specify the location relative to the # HTML output directory using the MATHJAX_RELPATH option. The destination # directory should contain the MathJax.js script. For instance, if the mathjax # directory is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to # the MathJax Content Delivery Network so you can quickly see the result without # installing MathJax. # However, it is strongly recommended to install a local # copy of MathJax from http://www.mathjax.org before deployment. MATHJAX_RELPATH = http://www.mathjax.org/mathjax # The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension # names that should be enabled during MathJax rendering. MATHJAX_EXTENSIONS = # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a PHP enabled web server instead of at the web client # using Javascript. Doxygen will generate the search PHP script and index # file to put on the web server. The advantage of the server # based approach is that it scales better to large projects and allows # full text search. The disadvantages are that it is more difficult to setup # and does not have live searching capabilities. SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = amssymb # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for # the generated latex document. The footer should contain everything after # the last chapter. If it is left blank doxygen will generate a # standard footer. Notice: only use this tag if you know what you are doing! LATEX_FOOTER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See # http://en.wikipedia.org/wiki/BibTeX for more info. LATEX_BIB_STYLE = plain #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load style sheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. # This is useful # if you want to understand what is going on. # On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # pointed to by INCLUDE_PATH will be searched when a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = itkNotUsed(x)= \ "itkSetMacro(name,type)= virtual void Set##name (type _arg);" \ "itkGetMacro(name,type)= virtual type Get##name ();" \ "itkGetConstMacro(name,type)= virtual type Get##name () const;" \ "itkSetStringMacro(name)= virtual void Set##name (const char* _arg);" \ "itkGetStringMacro(name)= virtual const char* Get##name () const;" \ "itkSetClampMacro(name,type,min,max)= virtual void Set##name (type _arg);" \ "itkSetObjectMacro(name,type)= virtual void Set##name (type* _arg);" \ "itkGetObjectMacro(name,type)= virtual type* Get##name ();" \ "itkSetConstObjectMacro(name,type)= virtual void Set##name ( const type* _arg);" \ "itkGetConstObjectMacro(name,type)= virtual const type* Get##name ();" \ "itkGetConstReferenceMacro(name,type)= virtual const type& Get##name ();" \ "itkGetConstReferenceObjectMacro(name,type)= virtual const type::Pointer& Get##name () const;" \ "itkBooleanMacro(name)= virtual void name##On (); virtual void name##Off ();" \ "itkSetVector2Macro(name,type)= virtual void Set##name (type _arg1, type _arg2) virtual void Set##name (type _arg[2]);" \ "itkGetVector2Macro(name,type)= virtual type* Get##name () const; virtual void Get##name (type& _arg1, type& _arg2) const; virtual void Get##name (type _arg[2]) const;" \ "itkSetVector3Macro(name,type)= virtual void Set##name (type _arg1, type _arg2, type _arg3) virtual void Set##name (type _arg[3]);" \ "itkGetVector3Macro(name,type)= virtual type* Get##name () const; virtual void Get##name (type& _arg1, type& _arg2, type& _arg3) const; virtual void Get##name (type _arg[3]) const;" \ "itkSetVector4Macro(name,type)= virtual void Set##name (type _arg1, type _arg2, type _arg3, type _arg4) virtual void Set##name (type _arg[4]);" \ "itkGetVector4Macro(name,type)= virtual type* Get##name () const; virtual void Get##name (type& _arg1, type& _arg2, type& _arg3, type& _arg4) const; virtual void Get##name (type _arg[4]) const;" \ "itkSetVector6Macro(name,type)= virtual void Set##name (type _arg1, type _arg2, type _arg3, type _arg4, type _arg5, type _arg6) virtual void Set##name (type _arg[6]);" \ "itkGetVector6Macro(name,type)= virtual type* Get##name () const; virtual void Get##name (type& _arg1, type& _arg2, type& _arg3, type& _arg4, type& _arg5, type& _arg6) const; virtual void Get##name (type _arg[6]) const;" \ "itkSetVectorMacro(name,type,count)= virtual void Set##name(type data[]);" \ "itkGetVectorMacro(name,type,count)= virtual type* Get##name () const;" \ "itkNewMacro(type)= static Pointer New();" \ "itkTypeMacro(thisClass,superclass)= virtual const char *GetClassName() const;" \ "itkConceptMacro(name,concept)= enum { name = 0 };" \ "ITK_NUMERIC_LIMITS= std::numeric_limits" \ "ITK_TYPENAME= typename" \ "FEM_ABSTRACT_CLASS(thisClass,parentClass)= public: /** Standard Self typedef.*/ typedef thisClass Self; /** Standard Superclass typedef. */ typedef parentClass Superclass; /** Pointer or SmartPointer to an object. */ typedef Self* Pointer; /** Const pointer or SmartPointer to an object. */ typedef const Self* ConstPointer; private:" \ "FEM_CLASS(thisClass,parentClass)= FEM_ABSTRACT_CLASS(thisClass,parentClass) public: /** Create a new object from the existing one */ virtual Baseclass::Pointer Clone() const; /** Class ID for FEM object factory */ static const int CLID; /** Virtual function to access the class ID */ virtual int ClassID() const { return CLID; } /** Object creation in an itk compatible way */ static Self::Pointer New() { return new Self(); } private:" \ FREEVERSION \ ERROR_CHECKING \ HAS_TIFF \ HAS_JPEG \ HAS_NETLIB \ HAS_PNG \ HAS_ZLIB \ HAS_GLUT \ HAS_QT \ VCL_USE_NATIVE_STL=1 \ VCL_USE_NATIVE_COMPLEX=1 \ VCL_HAS_BOOL=1 \ VXL_BIG_ENDIAN=1 \ VXL_LITTLE_ENDIAN=0 \ VNL_DLL_DATA= \ size_t=vcl_size_t \ "US_PREPEND_NAMESPACE(x)=mitk::x" \ "US_BEGIN_NAMESPACE= namespace mitk {" \ "US_END_NAMESPACE=}" \ "US_BASECLASS_NAME=itk::LightObject" \ US_EXPORT= # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition that # overrules the definition found in the source code. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all references to function-like macros # that are alone on a line, have an all uppercase name, and do not end with a # semicolon, because these will confuse the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. For each # tag file the location of the external documentation should be added. The # format of a tag file without this location is as follows: # # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths # or URLs. Note that each tag file must have a unique name (where the name does # NOT include the path). If a tag file is not located in the directory in which # doxygen is run, you must also specify the path to the tagfile here. TAGFILES = @BLUEBERRY_DOXYGEN_TAGFILE@ # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = @MITK_DOXYGEN_TAGFILE_NAME@ # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = NO # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option also works with HAVE_DOT disabled, but it is recommended to # install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = @HAVE_DOT@ # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is # allowed to run in parallel. When set to 0 (the default) doxygen will # base this on the number of processors available in the system. You can set it # explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. DOT_NUM_THREADS = @MITK_DOXYGEN_DOT_NUM_THREADS@ # By default doxygen will use the Helvetica font for all dot files that # doxygen generates. When you want a differently looking font you can specify # the font name using DOT_FONTNAME. You need to make sure dot is able to find # the font, which can be done by putting it in a standard location or by setting # the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the # directory containing the font. DOT_FONTNAME = FreeSans.ttf # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the Helvetica font. # If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to # set the path where dot can find it. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = @MITK_DOXYGEN_UML_LOOK@ # If the UML_LOOK tag is enabled, the fields and methods are shown inside # the class node. If there are many fields or methods and many nodes the # graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS # threshold limits the number of items for each type to make the size more # managable. Set this to 0 for no limit. Note that the threshold may be # exceeded by 50% before the limit is enforced. UML_LIMIT_NUM_FIELDS = 10 # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = NO # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will generate a graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = NO -# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are svg, png, jpg, or gif. # If left blank png will be used. If you choose svg you need to set # HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible in IE 9+ (other browsers do not have this requirement). DOT_IMAGE_FORMAT = png # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. # Note that this requires a modern browser other than Internet Explorer. # Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you # need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible. Older versions of IE do not have SVG support. INTERACTIVE_SVG = NO # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = @DOXYGEN_DOT_PATH@ # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the # \mscfile command). MSCFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES diff --git a/Examples/QtFreeRender/QtFreeRender.cpp b/Examples/QtFreeRender/QtFreeRender.cpp index 1b96bed5ef..732945f444 100644 --- a/Examples/QtFreeRender/QtFreeRender.cpp +++ b/Examples/QtFreeRender/QtFreeRender.cpp @@ -1,395 +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 "mitkRenderWindow.h" #include #include #include #include #include #include #include #include "mitkProperties.h" #include "mitkGeometry2DDataMapper2D.h" #include "mitkGlobalInteraction.h" #include "mitkDisplayInteractor.h" #include "mitkPositionEvent.h" #include "mitkStateEvent.h" #include "mitkLine.h" #include "mitkInteractionConst.h" #include "mitkVtkLayerController.h" #include "mitkPositionTracker.h" #include "mitkDisplayVectorInteractor.h" #include "mitkSlicesRotator.h" #include "mitkSlicesSwiveller.h" #include "mitkRenderWindowFrame.h" #include "mitkGradientBackground.h" #include "mitkCoordinateSupplier.h" #include "mitkDataStorage.h" #include "vtkTextProperty.h" #include "vtkCornerAnnotation.h" #include "vtkRenderWindow.h" #include "vtkRenderWindowInteractor.h" #include "vtkAnnotatedCubeActor.h" #include "vtkOrientationMarkerWidget.h" #include "vtkProperty.h" //##Documentation //## @brief Example of a NON QT DEPENDENT MITK RENDERING APPLICATION. + +mitk::RenderWindow::Pointer mitkWidget1; +mitk::RenderWindow::Pointer mitkWidget2; +mitk::RenderWindow::Pointer mitkWidget3; +mitk::RenderWindow::Pointer mitkWidget4; + mitk::DisplayVectorInteractor::Pointer m_MoveAndZoomInteractor; mitk::CoordinateSupplier::Pointer m_LastLeftClickPositionSupplier; mitk::GradientBackground::Pointer m_GradientBackground4; mitk::RenderWindowFrame::Pointer m_RectangleRendering1; mitk::RenderWindowFrame::Pointer m_RectangleRendering2; mitk::RenderWindowFrame::Pointer m_RectangleRendering3; mitk::RenderWindowFrame::Pointer m_RectangleRendering4; -mitk::SliceNavigationController::Pointer m_TimeNavigationController; +mitk::SliceNavigationController* m_TimeNavigationController = NULL; mitk::DataStorage::Pointer m_DataStorage; mitk::DataNode::Pointer m_PlaneNode1; mitk::DataNode::Pointer m_PlaneNode2; mitk::DataNode::Pointer m_PlaneNode3; mitk::DataNode::Pointer m_Node; -mitk::RenderWindow::Pointer mitkWidget1; -mitk::RenderWindow::Pointer mitkWidget2; -mitk::RenderWindow::Pointer mitkWidget3; -mitk::RenderWindow::Pointer mitkWidget4; void InitializeWindows() { // Set default view directions for SNCs mitkWidget1->GetSliceNavigationController()->SetDefaultViewDirection( - mitk::SliceNavigationController::Transversal ); + mitk::SliceNavigationController::Axial ); mitkWidget2->GetSliceNavigationController()->SetDefaultViewDirection( mitk::SliceNavigationController::Sagittal ); mitkWidget3->GetSliceNavigationController()->SetDefaultViewDirection( mitk::SliceNavigationController::Frontal ); mitkWidget4->GetSliceNavigationController()->SetDefaultViewDirection( mitk::SliceNavigationController::Original ); //initialize m_TimeNavigationController: send time via sliceNavigationControllers - m_TimeNavigationController = mitk::SliceNavigationController::New("dummy"); + m_TimeNavigationController = mitk::RenderingManager::GetInstance()->GetTimeNavigationController(); 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->GetVtkRenderWindow())); - // Set TimeNavigationController to RenderingManager - // (which uses it internally for views initialization!) - mitk::RenderingManager::GetInstance()->SetTimeNavigationController( - m_TimeNavigationController ); - //reverse connection between sliceNavigationControllers and m_TimeNavigationController mitkWidget1->GetSliceNavigationController() - ->ConnectGeometryTimeEvent(m_TimeNavigationController.GetPointer(), false); + ->ConnectGeometryTimeEvent(m_TimeNavigationController, false); mitkWidget2->GetSliceNavigationController() - ->ConnectGeometryTimeEvent(m_TimeNavigationController.GetPointer(), false); + ->ConnectGeometryTimeEvent(m_TimeNavigationController, false); mitkWidget3->GetSliceNavigationController() - ->ConnectGeometryTimeEvent(m_TimeNavigationController.GetPointer(), false); + ->ConnectGeometryTimeEvent(m_TimeNavigationController, false); mitkWidget4->GetSliceNavigationController() - ->ConnectGeometryTimeEvent(m_TimeNavigationController.GetPointer(), false); + ->ConnectGeometryTimeEvent(m_TimeNavigationController, false); // Let NavigationControllers listen to GlobalInteraction mitk::GlobalInteraction *gi = mitk::GlobalInteraction::GetInstance(); gi->AddListener( m_TimeNavigationController ); m_LastLeftClickPositionSupplier = mitk::CoordinateSupplier::New("navigation", NULL); mitk::GlobalInteraction::GetInstance()->AddListener( m_LastLeftClickPositionSupplier ); m_GradientBackground4 = mitk::GradientBackground::New(); m_GradientBackground4->SetRenderWindow( mitkWidget4->GetVtkRenderWindow() ); m_GradientBackground4->SetGradientColors(0.1,0.1,0.1,0.5,0.5,0.5); m_GradientBackground4->Enable(); m_RectangleRendering1 = mitk::RenderWindowFrame::New(); m_RectangleRendering1->SetRenderWindow( mitkWidget1->GetVtkRenderWindow() ); m_RectangleRendering1->Enable(1.0,0.0,0.0); m_RectangleRendering2 = mitk::RenderWindowFrame::New(); m_RectangleRendering2->SetRenderWindow( mitkWidget2->GetVtkRenderWindow() ); m_RectangleRendering2->Enable(0.0,1.0,0.0); m_RectangleRendering3 = mitk::RenderWindowFrame::New(); m_RectangleRendering3->SetRenderWindow( mitkWidget3->GetVtkRenderWindow() ); m_RectangleRendering3->Enable(0.0,0.0,1.0); m_RectangleRendering4 = mitk::RenderWindowFrame::New(); m_RectangleRendering4->SetRenderWindow( mitkWidget4->GetVtkRenderWindow() ); m_RectangleRendering4->Enable(1.0,1.0,0.0); } void 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; mitk::IntProperty::Pointer layer = mitk::IntProperty::New(1000); // ... of widget 1 m_PlaneNode1 = (mitk::BaseRenderer::GetInstance(mitkWidget1->GetVtkRenderWindow()))->GetCurrentWorldGeometry2DNode(); m_PlaneNode1->SetColor(white, mitk::BaseRenderer::GetInstance(mitkWidget4->GetVtkRenderWindow())); 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)); m_PlaneNode1->SetProperty("layer",layer); m_PlaneNode1->SetColor(1.0,0.0,0.0); mapper = mitk::Geometry2DDataMapper2D::New(); m_PlaneNode1->SetMapper(mitk::BaseRenderer::Standard2D, mapper); // ... of widget 2 m_PlaneNode2 =( mitk::BaseRenderer::GetInstance(mitkWidget2->GetVtkRenderWindow()))->GetCurrentWorldGeometry2DNode(); m_PlaneNode2->SetColor(white, mitk::BaseRenderer::GetInstance(mitkWidget4->GetVtkRenderWindow())); 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)); m_PlaneNode2->SetProperty("layer",layer); m_PlaneNode2->SetColor(0.0,1.0,0.0); mapper = mitk::Geometry2DDataMapper2D::New(); m_PlaneNode2->SetMapper(mitk::BaseRenderer::Standard2D, mapper); // ... of widget 3 m_PlaneNode3 = (mitk::BaseRenderer::GetInstance(mitkWidget3->GetVtkRenderWindow()))->GetCurrentWorldGeometry2DNode(); m_PlaneNode3->SetColor(white, mitk::BaseRenderer::GetInstance(mitkWidget4->GetVtkRenderWindow())); 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)); m_PlaneNode3->SetProperty("layer",layer); m_PlaneNode3->SetColor(0.0,0.0,1.0); 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)); //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 Fit() { vtkRenderer * vtkrenderer; mitk::BaseRenderer::GetInstance(mitkWidget1->GetVtkRenderWindow())->GetDisplayGeometry()->Fit(); mitk::BaseRenderer::GetInstance(mitkWidget2->GetVtkRenderWindow())->GetDisplayGeometry()->Fit(); mitk::BaseRenderer::GetInstance(mitkWidget3->GetVtkRenderWindow())->GetDisplayGeometry()->Fit(); mitk::BaseRenderer::GetInstance(mitkWidget4->GetVtkRenderWindow())->GetDisplayGeometry()->Fit(); int w = vtkObject::GetGlobalWarningDisplay(); vtkObject::GlobalWarningDisplayOff(); vtkrenderer = mitk::BaseRenderer::GetInstance(mitkWidget1->GetVtkRenderWindow())->GetVtkRenderer(); if ( vtkrenderer!= NULL ) vtkrenderer->ResetCamera(); vtkrenderer = mitk::BaseRenderer::GetInstance(mitkWidget2->GetVtkRenderWindow())->GetVtkRenderer(); if ( vtkrenderer!= NULL ) vtkrenderer->ResetCamera(); vtkrenderer = mitk::BaseRenderer::GetInstance(mitkWidget3->GetVtkRenderWindow())->GetVtkRenderer(); if ( vtkrenderer!= NULL ) vtkrenderer->ResetCamera(); vtkrenderer = mitk::BaseRenderer::GetInstance(mitkWidget4->GetVtkRenderWindow())->GetVtkRenderer(); if ( vtkrenderer!= NULL ) vtkrenderer->ResetCamera(); vtkObject::SetGlobalWarningDisplay(w); } int main(int argc, char* argv[]) { if(argc<2) { fprintf( stderr, "Usage: %s [filename1] [filename2] ...\n\n", "" ); return 1; } // Create a DataStorage m_DataStorage = mitk::StandaloneDataStorage::New(); //************************************************************************* // Part II: Create some data by reading files //************************************************************************* int i; for(i=1; iSetFileName(filename); nodeReader->Update(); // Since the DataNodeFactory directly creates a node, // use the datastorage to add the read node mitk::DataNode::Pointer node = nodeReader->GetOutput(); m_DataStorage->Add(node); mitk::Image::Pointer image = dynamic_cast(node->GetData()); if(image.IsNotNull()) { // Set the property "volumerendering" to the Boolean value "true" node->SetProperty("volumerendering", mitk::BoolProperty::New(false)); node->SetProperty("name", mitk::StringProperty::New("testimage")); node->SetProperty("layer",mitk::IntProperty::New(1)); } } catch(...) { fprintf( stderr, "Could not open file %s \n\n", filename ); exit(2); } } //************************************************************************* // Part V: Create window and pass the tree to it //************************************************************************* // Global Interaction initialize mitk::GlobalInteraction::GetInstance()->Initialize("global"); // instantiate display interactor m_MoveAndZoomInteractor = mitk::DisplayVectorInteractor::New( "moveNzoom", new mitk::DisplayInteractor() ); mitk::GlobalInteraction::GetInstance()->AddListener(m_MoveAndZoomInteractor); // Create renderwindows mitkWidget1 = mitk::RenderWindow::New(); mitkWidget2 = mitk::RenderWindow::New(); mitkWidget3 = mitk::RenderWindow::New(); mitkWidget4 = mitk::RenderWindow::New(); // Tell the renderwindow which (part of) the datastorage to render mitkWidget1->GetRenderer()->SetDataStorage(m_DataStorage); mitkWidget2->GetRenderer()->SetDataStorage(m_DataStorage); mitkWidget3->GetRenderer()->SetDataStorage(m_DataStorage); mitkWidget4->GetRenderer()->SetDataStorage(m_DataStorage); // Let NavigationControllers listen to GlobalInteraction mitk::GlobalInteraction *gi = mitk::GlobalInteraction::GetInstance(); gi->AddListener( mitkWidget1->GetSliceNavigationController() ); gi->AddListener( mitkWidget2->GetSliceNavigationController() ); gi->AddListener( mitkWidget3->GetSliceNavigationController() ); gi->AddListener( mitkWidget4->GetSliceNavigationController() ); // Use it as a 2D View mitkWidget1->GetRenderer()->SetMapperID(mitk::BaseRenderer::Standard2D); mitkWidget2->GetRenderer()->SetMapperID(mitk::BaseRenderer::Standard2D); mitkWidget3->GetRenderer()->SetMapperID(mitk::BaseRenderer::Standard2D); mitkWidget4->GetRenderer()->SetMapperID(mitk::BaseRenderer::Standard3D); mitkWidget1->SetSize(400, 400); mitkWidget2->GetVtkRenderWindow()->SetPosition(mitkWidget1->GetVtkRenderWindow()->GetPosition()[0]+420, mitkWidget1->GetVtkRenderWindow()->GetPosition()[1]); mitkWidget2->SetSize(400, 400); mitkWidget3->GetVtkRenderWindow()->SetPosition(mitkWidget1->GetVtkRenderWindow()->GetPosition()[0], mitkWidget1->GetVtkRenderWindow()->GetPosition()[1]+450); mitkWidget3->SetSize(400, 400); mitkWidget4->GetVtkRenderWindow()->SetPosition(mitkWidget1->GetVtkRenderWindow()->GetPosition()[0]+420, mitkWidget1->GetVtkRenderWindow()->GetPosition()[1]+450); mitkWidget4->SetSize(400, 400); InitializeWindows(); AddDisplayPlaneSubTree(); Fit(); // Initialize the RenderWindows mitk::TimeSlicedGeometry::Pointer geo = m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll()); mitk::RenderingManager::GetInstance()->InitializeViews( geo ); m_DataStorage->Print( std::cout ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); // reinit the mitkVTKEventProvider; // this is only necessary once after calling // ForceImmediateUpdateAll() for the first time mitkWidget1->ReinitEventProvider(); mitkWidget2->ReinitEventProvider(); mitkWidget3->ReinitEventProvider(); mitkWidget1->GetVtkRenderWindow()->Render(); mitkWidget2->GetVtkRenderWindow()->Render(); mitkWidget3->GetVtkRenderWindow()->Render(); mitkWidget4->GetVtkRenderWindow()->Render(); mitkWidget4->GetVtkRenderWindowInteractor()->Start(); return 0; } diff --git a/Examples/Tutorial/Step4.cpp b/Examples/Tutorial/Step4.cpp index 5f775199f2..028ed4377a 100644 --- a/Examples/Tutorial/Step4.cpp +++ b/Examples/Tutorial/Step4.cpp @@ -1,180 +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 "QmitkRegisterClasses.h" #include "QmitkRenderWindow.h" #include "QmitkSliceWidget.h" #include "mitkDataNodeFactory.h" #include "mitkProperties.h" #include "mitkRenderingManager.h" #include "mitkStandaloneDataStorage.h" #include #include #include //##Documentation //## @brief Use several views to explore data //## //## As in Step2 and Step3, load one or more data sets (many image, //## surface and other formats), but create 3 views on the data. //## The QmitkRenderWindow is used for displaying a 3D view as in Step3, //## but without volume-rendering. //## Furthermore, we create two 2D views for slicing through the data. //## We use the class QmitkSliceWidget, which is based on the class //## QmitkRenderWindow, but additionally provides sliders //## to slice through the data. We create two instances of -//## QmitkSliceWidget, one for transversal and one for sagittal slicing. +//## QmitkSliceWidget, one for axial and one for sagittal slicing. //## The two slices are also shown at their correct position in 3D as //## well as intersection-line, each in the other 2D view. int main(int argc, char* argv[]) { QApplication qtapplication( argc, argv ); if(argc<2) { fprintf( stderr, "Usage: %s [filename1] [filename2] ...\n\n", itksys::SystemTools::GetFilenameName(argv[0]).c_str() ); return 1; } // Register Qmitk-dependent global instances QmitkRegisterClasses(); //************************************************************************* // Part I: Basic initialization //************************************************************************* // Create a DataStorage mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); //************************************************************************* // Part II: Create some data by reading files //************************************************************************* int i; for(i=1; iSetFileName(filename); nodeReader->Update(); //********************************************************************* //Part III: Put the data into the datastorage //********************************************************************* // Since the DataNodeFactory directly creates a node, // use the datastorage to add the read node mitk::DataNode::Pointer node = nodeReader->GetOutput(); ds->Add(node); } catch(...) { fprintf( stderr, "Could not open file %s \n\n", filename ); exit(2); } } //************************************************************************* // Part IV: Create windows and pass the tree to it //************************************************************************* // Create toplevel widget with horizontal layout QWidget toplevelWidget; QHBoxLayout layout; layout.setSpacing(2); layout.setMargin(0); toplevelWidget.setLayout(&layout); //************************************************************************* // Part IVa: 3D view //************************************************************************* // Create a renderwindow QmitkRenderWindow renderWindow(&toplevelWidget); layout.addWidget(&renderWindow); // Tell the renderwindow which (part of) the datastorage to render renderWindow.GetRenderer()->SetDataStorage(ds); // Use it as a 3D view renderWindow.GetRenderer()->SetMapperID(mitk::BaseRenderer::Standard3D); // ******************************************************* // ****************** START OF NEW PART ****************** // ******************************************************* //************************************************************************* - // Part IVb: 2D view for slicing transversally + // Part IVb: 2D view for slicing axially //************************************************************************* // Create QmitkSliceWidget, which is based on the class // QmitkRenderWindow, but additionally provides sliders QmitkSliceWidget view2(&toplevelWidget); layout.addWidget(&view2); view2.SetLevelWindowEnabled(true); // Tell the QmitkSliceWidget which (part of) the tree to render. - // By default, it slices the data transversally + // By default, it slices the data axially view2.SetDataStorage(ds); mitk::DataStorage::SetOfObjects::ConstPointer rs = ds->GetAll(); - view2.SetData(rs->Begin(),mitk::SliceNavigationController::Transversal); + view2.SetData(rs->Begin(),mitk::SliceNavigationController::Axial); // We want to see the position of the slice in 2D and the // slice itself in 3D: add it to the datastorage! ds->Add(view2.GetRenderer()->GetCurrentWorldGeometry2DNode()); //************************************************************************* // Part IVc: 2D view for slicing sagitally //************************************************************************* // Create QmitkSliceWidget, which is based on the class // QmitkRenderWindow, but additionally provides sliders QmitkSliceWidget view3(&toplevelWidget); layout.addWidget(&view3); view3.SetDataStorage(ds); // Tell the QmitkSliceWidget which (part of) the datastorage to render // and to slice sagitally view3.SetData(rs->Begin(), mitk::SliceNavigationController::Sagittal); // We want to see the position of the slice in 2D and the // slice itself in 3D: add it to the datastorage! ds->Add(view3.GetRenderer()->GetCurrentWorldGeometry2DNode()); // ******************************************************* // ******************* END OF NEW PART ******************* // ******************************************************* //************************************************************************* // Part V: Qt-specific initialization //************************************************************************* toplevelWidget.show(); // for testing #include "QtTesting.h" if(strcmp(argv[argc-1], "-testing")!=0) return qtapplication.exec(); else return QtTesting(); } /** \example Step4.cpp */ diff --git a/Examples/Tutorial/Step5.cpp b/Examples/Tutorial/Step5.cpp index 8278eff323..c3689880cf 100644 --- a/Examples/Tutorial/Step5.cpp +++ b/Examples/Tutorial/Step5.cpp @@ -1,203 +1,203 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "QmitkRegisterClasses.h" #include "QmitkRenderWindow.h" #include "QmitkSliceWidget.h" #include "mitkDataNodeFactory.h" #include "mitkProperties.h" #include "mitkRenderingManager.h" #include "mitkStandaloneDataStorage.h" #include "mitkGlobalInteraction.h" #include "mitkPointSet.h" #include "mitkPointSetInteractor.h" #include #include #include //##Documentation //## @brief Interactively add points //## //## As in Step4, load one or more data sets (many image, //## surface and other formats) and create 3 views on the data. //## Additionally, we want to interactively add points. A node containing //## a PointSet as data is added to the data tree and a PointSetInteractor //## is associated with the node, which handles the interaction. The //## @em interaction @em pattern is defined in a state-machine, stored in an //## external XML file. Thus, we need to load a state-machine //## The interaction patterns defines the @em events, //## on which the interactor reacts (e.g., which mouse buttons are used to //## set a point), the @em transition to the next state (e.g., the initial //## may be "empty point set") and associated @a actions (e.g., add a point //## at the position where the mouse-click occured). int main(int argc, char* argv[]) { QApplication qtapplication( argc, argv ); if(argc<2) { fprintf( stderr, "Usage: %s [filename1] [filename2] ...\n\n", itksys::SystemTools::GetFilenameName(argv[0]).c_str() ); return 1; } // Register Qmitk-dependent global instances QmitkRegisterClasses(); //************************************************************************* // Part I: Basic initialization //************************************************************************* // Create a DataStorage mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); //************************************************************************* // Part II: Create some data by reading files //************************************************************************* int i; for(i=1; iSetFileName(filename); nodeReader->Update(); //********************************************************************* // Part III: Put the data into the datastorage //********************************************************************* // Since the DataNodeFactory directly creates a node, // use the iterator to add the read node to the tree mitk::DataNode::Pointer node = nodeReader->GetOutput(); ds->Add(node); } catch(...) { fprintf( stderr, "Could not open file %s \n\n", filename ); exit(2); } } // ******************************************************* // ****************** START OF NEW PART ****************** // ******************************************************* //************************************************************************* // Part VI: For allowing to interactively add points ... //************************************************************************* // Create PointSet and a node for it mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); mitk::DataNode::Pointer pointSetNode = mitk::DataNode::New(); pointSetNode->SetData(pointSet); // Add the node to the tree ds->Add(pointSetNode); // Create PointSetInteractor, associate to pointSetNode and add as // interactor to GlobalInteraction mitk::GlobalInteraction::GetInstance()->AddInteractor( mitk::PointSetInteractor::New("pointsetinteractor", pointSetNode) ); // ******************************************************* // ******************* END OF NEW PART ******************* // ******************************************************* //************************************************************************* // Part V: Create windows and pass the tree to it //************************************************************************* // Create toplevel widget with horizontal layout QWidget toplevelWidget; QHBoxLayout layout; layout.setSpacing(2); layout.setMargin(0); toplevelWidget.setLayout(&layout); //************************************************************************* // Part Va: 3D view //************************************************************************* // Create a renderwindow QmitkRenderWindow renderWindow(&toplevelWidget); layout.addWidget(&renderWindow); // Tell the renderwindow which (part of) the tree to render renderWindow.GetRenderer()->SetDataStorage(ds); // Use it as a 3D view renderWindow.GetRenderer()->SetMapperID(mitk::BaseRenderer::Standard3D); //************************************************************************* - // Part Vb: 2D view for slicing transversally + // Part Vb: 2D view for slicing axially //************************************************************************* // Create QmitkSliceWidget, which is based on the class // QmitkRenderWindow, but additionally provides sliders QmitkSliceWidget view2(&toplevelWidget); layout.addWidget(&view2); // Tell the QmitkSliceWidget which (part of) the tree to render. - // By default, it slices the data transversally + // By default, it slices the data axially view2.SetDataStorage(ds); mitk::DataStorage::SetOfObjects::ConstPointer rs = ds->GetAll(); - view2.SetData(rs->Begin(), mitk::SliceNavigationController::Transversal); + view2.SetData(rs->Begin(), mitk::SliceNavigationController::Axial); // We want to see the position of the slice in 2D and the // slice itself in 3D: add it to the tree! ds->Add(view2.GetRenderer()->GetCurrentWorldGeometry2DNode()); //************************************************************************* // Part Vc: 2D view for slicing sagitally //************************************************************************* // Create QmitkSliceWidget, which is based on the class // QmitkRenderWindow, but additionally provides sliders QmitkSliceWidget view3(&toplevelWidget); layout.addWidget(&view3); // Tell the QmitkSliceWidget which (part of) the tree to render // and to slice sagitall view3.SetDataStorage(ds); view3.SetData(rs->Begin(), mitk::SliceNavigationController::Sagittal); // We want to see the position of the slice in 2D and the // slice itself in 3D: add it to the tree! ds->Add(view3.GetRenderer()->GetCurrentWorldGeometry2DNode()); //************************************************************************* //Part VII: Qt-specific initialization //************************************************************************* toplevelWidget.show(); // For testing #include "QtTesting.h" if(strcmp(argv[argc-1], "-testing")!=0) return qtapplication.exec(); else return QtTesting(); } /** \example Step5.cpp */ diff --git a/Examples/Tutorial/Step6.cpp b/Examples/Tutorial/Step6.cpp index 3419dd4950..714b34f5e1 100644 --- a/Examples/Tutorial/Step6.cpp +++ b/Examples/Tutorial/Step6.cpp @@ -1,247 +1,247 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "Step6.h" #include "QmitkRenderWindow.h" #include "QmitkSliceWidget.h" #include "mitkDataNodeFactory.h" #include "mitkProperties.h" #include "mitkRenderingManager.h" #include "mitkGlobalInteraction.h" #include "mitkPointSet.h" #include "mitkPointSetInteractor.h" #include "mitkImageAccessByItk.h" #include "mitkRenderingManager.h" #include #include #include #include #include #include //##Documentation //## @brief Start region-grower at interactively added points Step6::Step6(int argc, char* argv[], QWidget *parent) : QWidget(parent) { // load data as in the previous steps; a reference to the first loaded // image is kept in the member m_FirstImage and used as input for the // region growing Load(argc, argv); } void Step6::Initialize() { // setup the widgets as in the previous steps, but with an additional // QVBox for a button to start the segmentation this->SetupWidgets(); // Create controlsParent widget with horizontal layout QWidget *controlsParent = new QWidget(this); this->layout()->addWidget(controlsParent); QHBoxLayout* hlayout = new QHBoxLayout(controlsParent); hlayout->setSpacing(2); QLabel *labelThresholdMin = new QLabel("Lower Threshold:", controlsParent); hlayout->addWidget(labelThresholdMin); m_LineEditThresholdMin = new QLineEdit("-1000", controlsParent); hlayout->addWidget(m_LineEditThresholdMin); QLabel *labelThresholdMax = new QLabel("Upper Threshold:", controlsParent); hlayout->addWidget(labelThresholdMax); m_LineEditThresholdMax = new QLineEdit("-400", controlsParent); hlayout->addWidget(m_LineEditThresholdMax); // create button to start the segmentation and connect its clicked() // signal to method StartRegionGrowing QPushButton* startButton = new QPushButton("start region growing", controlsParent); hlayout->addWidget(startButton); connect(startButton, SIGNAL(clicked()), this, SLOT(StartRegionGrowing())); if (m_FirstImage.IsNull()) startButton->setEnabled(false); // as in Step5, create PointSet (now as a member m_Seeds) and // associate a interactor to it m_Seeds = mitk::PointSet::New(); mitk::DataNode::Pointer pointSetNode = mitk::DataNode::New(); pointSetNode->SetData(m_Seeds); pointSetNode->SetProperty("layer", mitk::IntProperty::New(2)); m_DataStorage->Add(pointSetNode); mitk::GlobalInteraction::GetInstance()->AddInteractor( mitk::PointSetInteractor::New("pointsetinteractor", pointSetNode)); } int Step6::GetThresholdMin() { return m_LineEditThresholdMin->text().toInt(); } int Step6::GetThresholdMax() { return m_LineEditThresholdMax->text().toInt(); } void Step6::StartRegionGrowing() { AccessByItk_1(m_FirstImage, RegionGrowing, this); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void Step6::Load(int argc, char* argv[]) { //************************************************************************* // Part I: Basic initialization //************************************************************************* m_DataStorage = mitk::StandaloneDataStorage::New(); //************************************************************************* // Part II: Create some data by reading files //************************************************************************* int i; for (i = 1; i < argc; ++i) { // For testing if (strcmp(argv[i], "-testing") == 0) continue; // Create a DataNodeFactory to read a data format supported // by the DataNodeFactory (many image formats, surface formats, etc.) mitk::DataNodeFactory::Pointer nodeReader = mitk::DataNodeFactory::New(); const char * filename = argv[i]; try { nodeReader->SetFileName(filename); nodeReader->Update(); //********************************************************************* // Part III: Put the data into the datastorage //********************************************************************* // Since the DataNodeFactory directly creates a node, // use the iterator to add the read node to the tree mitk::DataNode::Pointer node = nodeReader->GetOutput(); m_DataStorage->Add(node); mitk::Image::Pointer image = dynamic_cast (node->GetData()); if ((m_FirstImage.IsNull()) && (image.IsNotNull())) m_FirstImage = image; } catch (...) { fprintf(stderr, "Could not open file %s \n\n", filename); exit(2); } } } void Step6::SetupWidgets() { //************************************************************************* // Part I: Create windows and pass the datastorage to it //************************************************************************* // Create toplevel widget with vertical layout QVBoxLayout* vlayout = new QVBoxLayout(this); vlayout->setMargin(0); vlayout->setSpacing(2); // Create viewParent widget with horizontal layout QWidget* viewParent = new QWidget(this); vlayout->addWidget(viewParent); QHBoxLayout* hlayout = new QHBoxLayout(viewParent); hlayout->setMargin(0); hlayout->setSpacing(2); //************************************************************************* // Part Ia: 3D view //************************************************************************* // Create a renderwindow QmitkRenderWindow* renderWindow = new QmitkRenderWindow(viewParent); hlayout->addWidget(renderWindow); // Tell the renderwindow which (part of) the tree to render renderWindow->GetRenderer()->SetDataStorage(m_DataStorage); // Use it as a 3D view renderWindow->GetRenderer()->SetMapperID(mitk::BaseRenderer::Standard3D); //************************************************************************* - // Part Ib: 2D view for slicing transversally + // Part Ib: 2D view for slicing axially //************************************************************************* // Create QmitkSliceWidget, which is based on the class // QmitkRenderWindow, but additionally provides sliders QmitkSliceWidget *view2 = new QmitkSliceWidget(viewParent); hlayout->addWidget(view2); // Tell the QmitkSliceWidget which (part of) the tree to render. - // By default, it slices the data transversally + // By default, it slices the data axially view2->SetDataStorage(m_DataStorage); mitk::DataStorage::SetOfObjects::ConstPointer rs = m_DataStorage->GetAll(); - view2->SetData(rs->Begin(), mitk::SliceNavigationController::Transversal); + view2->SetData(rs->Begin(), mitk::SliceNavigationController::Axial); // We want to see the position of the slice in 2D and the // slice itself in 3D: add it to the tree! m_DataStorage->Add(view2->GetRenderer()->GetCurrentWorldGeometry2DNode()); //************************************************************************* // Part Ic: 2D view for slicing sagitally //************************************************************************* // Create QmitkSliceWidget, which is based on the class // QmitkRenderWindow, but additionally provides sliders QmitkSliceWidget *view3 = new QmitkSliceWidget(viewParent); hlayout->addWidget(view3); // Tell the QmitkSliceWidget which (part of) the tree to render // and to slice sagitally view3->SetDataStorage(m_DataStorage); view3->SetData(rs->Begin(), mitk::SliceNavigationController::Sagittal); // We want to see the position of the slice in 2D and the // slice itself in 3D: add it to the tree! m_DataStorage->Add(view3->GetRenderer()->GetCurrentWorldGeometry2DNode()); //************************************************************************* // Part II: handle updates: To avoid unnecessary updates, we have to //************************************************************************* // define when to update. The RenderingManager serves this purpose, and // each RenderWindow has to be registered to it. /*mitk::RenderingManager *renderingManager = mitk::RenderingManager::GetInstance(); renderingManager->AddRenderWindow( renderWindow ); renderingManager->AddRenderWindow( view2->GetRenderWindow() ); renderingManager->AddRenderWindow( view3->GetRenderWindow() );*/ } /** \example Step6.cpp */ diff --git a/Examples/Tutorial/Step8.cpp b/Examples/Tutorial/Step8.cpp index 52756fd946..fa378c4c64 100644 --- a/Examples/Tutorial/Step8.cpp +++ b/Examples/Tutorial/Step8.cpp @@ -1,88 +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 "Step8.h" #include "QmitkStdMultiWidget.h" #include "mitkGlobalInteraction.h" #include "mitkRenderingManager.h" #include #include //##Documentation //## @brief As Step6, but with QmitkStdMultiWidget as widget Step8::Step8(int argc, char* argv[], QWidget *parent) : Step6(argc, argv, parent) { } void Step8::SetupWidgets() { //************************************************************************* // Part I: Create windows and pass the tree to it //************************************************************************* // Create toplevel widget with vertical layout QVBoxLayout* vlayout = new QVBoxLayout(this); vlayout->setMargin(0); vlayout->setSpacing(2); // Create viewParent widget with horizontal layout QWidget* viewParent = new QWidget(this); vlayout->addWidget(viewParent); QHBoxLayout* hlayout = new QHBoxLayout(viewParent); hlayout->setMargin(0); //************************************************************************* // Part Ia: create and initialize QmitkStdMultiWidget //************************************************************************* QmitkStdMultiWidget* multiWidget = new QmitkStdMultiWidget(viewParent); hlayout->addWidget(multiWidget); // Tell the multiWidget which DataStorage to render multiWidget->SetDataStorage(m_DataStorage); - // Initialize views as transversal, sagittal, coronar (from + // Initialize views as axial, sagittal, coronar (from // top-left to bottom) mitk::TimeSlicedGeometry::Pointer geo = m_DataStorage->ComputeBoundingGeometry3D( m_DataStorage->GetAll()); mitk::RenderingManager::GetInstance()->InitializeViews(geo); // Initialize bottom-right view as 3D view multiWidget->GetRenderWindow4()->GetRenderer()->SetMapperID( mitk::BaseRenderer::Standard3D); // Enable standard handler for levelwindow-slider multiWidget->EnableStandardLevelWindow(); // Add the displayed views to the DataStorage to see their positions in 2D and 3D multiWidget->AddDisplayPlaneSubTree(); multiWidget->AddPlanesToDataStorage(); multiWidget->SetWidgetPlanesVisibility(true); //************************************************************************* // Part II: Setup standard interaction with the mouse //************************************************************************* // Moving the cut-planes to click-point multiWidget->EnableNavigationControllerEventListening(); } /** \example Step8.cpp */ diff --git a/LICENSE.txt b/LICENSE.txt index 8761edc246..6497b058db 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,29 +1,36 @@ -Copyright (c) 2003-2012 German Cancer Research Center, Division of Medical -and Biological Informatics +Copyright (c) 2003-2012 German Cancer Research Center, +Division of Medical and Biological Informatics All rights reserved. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: +Redistribution and use in source and binary forms, with or +without modification, are permitted provided that the +following conditions are met: - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. - * Neither the name of the German Cancer Research Center, nor the names of - its contributors may be used to endorse or promote products derived from - this software without specific prior written permission. + * Neither the name of the German Cancer Research Center, + nor the names of its contributors may be used to endorse + or promote products derived from this software without + specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Modules/DicomUI/Qmitk/QmitkDicomExternalDataWidget.cpp b/Modules/DicomUI/Qmitk/QmitkDicomExternalDataWidget.cpp index f110e6e786..c2d12d58a1 100644 --- a/Modules/DicomUI/Qmitk/QmitkDicomExternalDataWidget.cpp +++ b/Modules/DicomUI/Qmitk/QmitkDicomExternalDataWidget.cpp @@ -1,241 +1,181 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 // Qmitk #include "QmitkDicomExternalDataWidget.h" #include // Qt #include #include #include #include // CTK #include const std::string QmitkDicomExternalDataWidget::Widget_ID = "org.mitk.Widgets.QmitkDicomExternalDataWidget"; QmitkDicomExternalDataWidget::QmitkDicomExternalDataWidget(QWidget *parent) : m_Controls( 0 ) -, m_DirectoryName(new QString()) { Initialize(); CreateQtPartControl(this); } QmitkDicomExternalDataWidget::~QmitkDicomExternalDataWidget() { - delete m_ImportDialog; delete m_ExternalDatabase; delete m_ExternalModel; delete m_ExternalIndexer; delete m_Controls; - delete m_DirectoryName; - delete m_ProgressDialogLabel; } void QmitkDicomExternalDataWidget::CreateQtPartControl( QWidget *parent ) { // build up qt Widget, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkDicomExternalDataWidgetControls; m_Controls->setupUi( parent ); m_Controls->cancelButton->setVisible(false); - m_Controls->viewExternalDataButton->setVisible(false); + m_Controls->viewExternalDataButton->setVisible(true); // m_Controls->ExternalDataTreeView->setSortingEnabled(true); m_Controls->ExternalDataTreeView->setSelectionBehavior(QAbstractItemView::SelectRows); m_Controls->ExternalDataTreeView->setModel(m_ExternalModel); //connect Buttons connect(m_Controls->downloadButton, SIGNAL(clicked()),this,SLOT(OnDownloadButtonClicked())); connect(m_Controls->viewExternalDataButton, SIGNAL(clicked()),this,SLOT(OnViewButtonClicked())); connect(m_Controls->cancelButton, SIGNAL(clicked()),this,SLOT(OnDownloadButtonClicked())); - //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(OnFileSelectedAddExternalData(QString))); - - m_ProgressDialog= new QProgressDialog ("DICOM Import", "Cancel", 0, 100, this,Qt::WindowTitleHint | Qt::WindowSystemMenuHint); - // We don't want the m_ProgressDialog dialog to resize itself, so we bypass the label - // by creating our own - 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_ExternalIndexer, SLOT(cancel())); - connect(m_ExternalIndexer, SIGNAL(indexingFilePath(QString)), - m_ProgressDialogLabel, SLOT(setText(QString))); - connect(m_ExternalIndexer, SIGNAL(progress(int)), - m_ProgressDialog, SLOT(setValue(int))); - connect(m_ExternalIndexer, SIGNAL(progress(int)), - this, SLOT(OnProgress(int))); + connect(m_ExternalIndexer, SIGNAL(indexingComplete()),this, SLOT(OnFinishedImport())); + connect(m_ExternalIndexer, SIGNAL(indexingComplete()),this, SIGNAL(SignalFinishedImport())); + + connect(m_ExternalIndexer, SIGNAL(indexingFilePath(QString)),this, SIGNAL(SignalProcessingFile(QString))); + connect(m_ExternalIndexer, SIGNAL(progress(int)),this, SIGNAL(SignalProgress(int))); + connect(this, SIGNAL(SignalCancelImport()),m_ExternalIndexer, SLOT(cancel())); } } void QmitkDicomExternalDataWidget::Initialize() { m_ExternalDatabase = new ctkDICOMDatabase(); //m_ExternalDatabase->initializeDatabase(); try{ m_ExternalDatabase->openDatabase(QString(":memory:"),QString( "EXTERNAL-DB")); }catch(std::exception e){ MITK_ERROR <<"Database error: "<< m_ExternalDatabase->lastError().toStdString(); m_ExternalDatabase->closeDatabase(); return; } m_ExternalModel = new ctkDICOMModel(); m_ExternalModel->setDatabase(m_ExternalDatabase->database()); m_ExternalModel->setEndLevel(ctkDICOMModel::SeriesType); m_ExternalIndexer = new ctkDICOMIndexer(); } -void QmitkDicomExternalDataWidget::OnFolderCDImport() -{ - m_ImportDialog->show(); - m_ImportDialog->raise(); -} - -void QmitkDicomExternalDataWidget::OnFileSelectedAddExternalData(QString directory) +void QmitkDicomExternalDataWidget::OnFinishedImport() { - if (QDir(directory).exists()) - { - m_DirectoryName = new QString(directory); - QCheckBox* copyOnImport = qobject_cast(m_ImportDialog->bottomWidget()); - - if (copyOnImport->isChecked()) - { - emit SignalAddDicomData(directory); - }else{ - AddDicomTemporary(directory); - emit SignalChangePage(1); - } - } + m_ExternalModel->setDatabase(m_ExternalDatabase->database()); } void QmitkDicomExternalDataWidget::OnDownloadButtonClicked() { - QStringList* filePaths= new QStringList(); - GetFileNamesFromIndex(*filePaths); - emit SignalAddDicomData(*filePaths); + emit SignalStartDicomImport(GetFileNamesFromIndex()); } void QmitkDicomExternalDataWidget::OnViewButtonClicked() { QModelIndex currentIndex = m_Controls->ExternalDataTreeView->currentIndex(); if(m_ExternalModel->data(currentIndex,ctkDICOMModel::TypeRole)==static_cast(ctkDICOMModel::SeriesType)) { QString seriesUID = m_ExternalModel->data(currentIndex,ctkDICOMModel::UIDRole).toString(); QString seriesName = m_ExternalModel->data(currentIndex).toString(); QModelIndex studyIndex = m_ExternalModel->parent(currentIndex); QString studyUID = m_ExternalModel->data(studyIndex,ctkDICOMModel::UIDRole).toString(); QString studyName = m_ExternalModel->data(studyIndex).toString(); QModelIndex patientIndex = m_ExternalModel->parent(studyIndex); QString patientName = m_ExternalModel->data(patientIndex).toString(); QStringList eventProperties; - eventProperties << patientName << studyUID << studyName << seriesUID << seriesName << *m_DirectoryName; + eventProperties << patientName << studyUID << studyName << seriesUID << seriesName << m_LastImportDirectory; emit SignalDicomToDataManager(eventProperties); } } -void QmitkDicomExternalDataWidget::OnCancelButtonClicked() -{ - m_Watcher.cancel(); - m_Watcher.waitForFinished(); -} - -void QmitkDicomExternalDataWidget::GetFileNamesFromIndex(QStringList& filePaths) +QStringList QmitkDicomExternalDataWidget::GetFileNamesFromIndex() { + QStringList filePaths = QStringList(); QModelIndex currentIndex = m_Controls->ExternalDataTreeView->currentIndex(); QString currentUID = m_ExternalModel->data(currentIndex,ctkDICOMModel::UIDRole).toString(); if(m_ExternalModel->data(currentIndex,ctkDICOMModel::TypeRole)==static_cast(ctkDICOMModel::SeriesType)) { filePaths.append(m_ExternalDatabase->filesForSeries(currentUID)); } else if(m_ExternalModel->data(currentIndex,ctkDICOMModel::TypeRole)==static_cast(ctkDICOMModel::StudyType)) { QStringList seriesList; seriesList.append( m_ExternalDatabase->seriesForStudy(currentUID) ); QStringList::Iterator serieIt; for(serieIt=seriesList.begin();serieIt!=seriesList.end();++serieIt) { filePaths.append(m_ExternalDatabase->filesForSeries(*serieIt)); } } else if(m_ExternalModel->data(currentIndex,ctkDICOMModel::TypeRole)==static_cast(ctkDICOMModel::PatientType)) { QStringList studiesList,seriesList; studiesList.append( m_ExternalDatabase->studiesForPatient(currentUID) ); QStringList::Iterator studyIt,serieIt; for(studyIt=studiesList.begin();studyIt!=studiesList.end();++studyIt) { seriesList.append( m_ExternalDatabase->seriesForStudy(*studyIt) ); for(serieIt=seriesList.begin();serieIt!=seriesList.end();++serieIt) { filePaths.append(m_ExternalDatabase->filesForSeries(*serieIt)); } } } + return filePaths; } -void QmitkDicomExternalDataWidget::AddDicomTemporary(QString directory) -{ - m_ProgressDialog->setMinimumDuration(0); - m_ProgressDialog->setValue(0); - m_ProgressDialog->show(); - m_ExternalIndexer->addDirectory(*m_ExternalDatabase,directory); - m_ExternalModel->reset(); -} - -void QmitkDicomExternalDataWidget::OnProgress(int progress) +void QmitkDicomExternalDataWidget::OnStartDicomImport(const QString& directory) { - Q_UNUSED(progress); - QApplication::processEvents(); + m_LastImportDirectory = directory; + m_ExternalIndexer->addDirectory(*m_ExternalDatabase,m_LastImportDirectory); } void QmitkDicomExternalDataWidget::OnSearchParameterChanged() { m_ExternalModel->setDatabase(m_ExternalDatabase->database(),m_Controls->SearchOption_2->parameters()); } diff --git a/Modules/DicomUI/Qmitk/QmitkDicomExternalDataWidget.h b/Modules/DicomUI/Qmitk/QmitkDicomExternalDataWidget.h index 3ec7a98203..47056bffd7 100644 --- a/Modules/DicomUI/Qmitk/QmitkDicomExternalDataWidget.h +++ b/Modules/DicomUI/Qmitk/QmitkDicomExternalDataWidget.h @@ -1,129 +1,123 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 QmitkDicomExternalDataWidget_h #define QmitkDicomExternalDataWidget_h // #include #include "ui_QmitkDicomExternalDataWidgetControls.h" #include "mitkDicomUIExports.h" // include ctk #include #include #include -#include //include QT #include #include #include #include //For running dicom import in background #include #include #include #include #include #include /*! \brief QmitkDicomExternalDataWidget \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 MITK_DICOMUI_EXPORT QmitkDicomExternalDataWidget : 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: static const std::string Widget_ID; QmitkDicomExternalDataWidget(QWidget *parent); virtual ~QmitkDicomExternalDataWidget(); virtual void CreateQtPartControl(QWidget *parent); /* @brief Initializes the widget. This method has to be called before widget can start. * @param dataStorage The data storage the widget should work with. * @param multiWidget The corresponding multiwidget were the ct Image is displayed and the user should define his path. * @param imageNode The image node which will be the base of mitral processing */ void Initialize(); signals: - void SignalChangePage(int); - void SignalAddDicomData(const QString&); - void SignalAddDicomData(const QStringList&); - void SignalDicomToDataManager(const QStringList&); - public slots: + /// @brief emitted when import into database is finished. + void SignalStartDicomImport(const QStringList&); + + /// @brief emitted when import into database is finished. + void SignalFinishedImport(); - /// @brief Called when import CD or import Folder was clicked. - void OnFolderCDImport(); + /// @brief emitted when view button is clicked. + void SignalDicomToDataManager(const QStringList&); + void SignalProgress(int); + void SignalProcessingFile(QString); + void SignalCancelImport(); - /// @brief Called when import directory was selected. - void OnFileSelectedAddExternalData(QString); +public slots: - /// @brief Called when download button was clicked. - void OnDownloadButtonClicked(); + /// @brief Called when download button was clicked. + void OnDownloadButtonClicked(); - /// @brief Called when view button was clicked. - void OnViewButtonClicked(); - - /// @brief Called when cancel button was clicked. - void OnCancelButtonClicked(); + /// @brief Called when view button was clicked. + void OnViewButtonClicked(); - /// @brief Called when search parameters change. - void OnSearchParameterChanged(); + /// @brief Called when search parameters change. + void OnSearchParameterChanged(); - /// @brief Called when import progress change. - void OnProgress(int progress); + /// @brief Called when adding a dicom directory. Starts a thread adding the directory. + void OnStartDicomImport(const QString&); + + /// @brief Called when indexing into database is finished. + /// In this slot the models database with new imports is set. + /// This causes a model update. + void OnFinishedImport(); protected: /// \brief Get the list of filepath from current selected index in TreeView. All file paths referring to the index will be returned. - void GetFileNamesFromIndex(QStringList& filePaths); - - void AddDicomTemporary(QString directory); + QStringList GetFileNamesFromIndex(); ctkDICOMDatabase* m_ExternalDatabase; ctkDICOMModel* m_ExternalModel; ctkDICOMIndexer* m_ExternalIndexer; - - ctkFileDialog* m_ImportDialog; - QProgressDialog* m_ProgressDialog; - QLabel* m_ProgressDialogLabel; Ui::QmitkDicomExternalDataWidgetControls* m_Controls; - QFuture m_Future; - QFutureWatcher m_Watcher; - QTimer* m_Timer; - QString* m_DirectoryName; + QString m_LastImportDirectory; }; #endif // _QmitkDicomExternalDataWidget_H_INCLUDED diff --git a/Modules/DicomUI/Qmitk/QmitkDicomLocalStorageWidget.cpp b/Modules/DicomUI/Qmitk/QmitkDicomLocalStorageWidget.cpp index 7ed05ee4e6..f5ba524b62 100644 --- a/Modules/DicomUI/Qmitk/QmitkDicomLocalStorageWidget.cpp +++ b/Modules/DicomUI/Qmitk/QmitkDicomLocalStorageWidget.cpp @@ -1,220 +1,164 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 #include "QmitkDicomLocalStorageWidget.h" #include #include #include // Qt #include #include #include #include const std::string QmitkDicomLocalStorageWidget::Widget_ID = "org.mitk.Widgets.QmitkDicomLocalStorageWidget"; QmitkDicomLocalStorageWidget::QmitkDicomLocalStorageWidget(QWidget *parent) : m_Controls( 0 ) ,m_LocalIndexer(new ctkDICOMIndexer()) ,m_LocalModel(new ctkDICOMModel()) { CreateQtPartControl(this); } QmitkDicomLocalStorageWidget::~QmitkDicomLocalStorageWidget() { m_LocalDatabase->closeDatabase(); delete m_LocalDatabase; delete m_LocalIndexer; delete m_LocalModel; delete m_Controls; } void QmitkDicomLocalStorageWidget::CreateQtPartControl( QWidget *parent ) { if ( !m_Controls ) { m_Controls = new Ui::QmitkDicomLocalStorageWidgetControls; m_Controls->setupUi( parent ); m_Controls->groupBox->setVisible(false); m_Controls->CancelButton->setVisible(false); m_Controls->addSortingTagButton_2->setVisible(false); m_Controls->deleteSortingTagButton_2->setVisible(false); m_Controls->InternalDataTreeView->setSortingEnabled(true); m_Controls->InternalDataTreeView->setSelectionBehavior(QAbstractItemView::SelectRows); m_Controls->InternalDataTreeView->setModel(m_LocalModel); connect(m_Controls->deleteButton,SIGNAL(clicked()),this,SLOT(OnDeleteButtonClicked())); connect(m_Controls->CancelButton, SIGNAL(clicked()), this , SLOT(OnCancelButtonClicked())); connect(m_Controls->viewInternalDataButton, SIGNAL(clicked()), this , SLOT(OnViewButtonClicked())); connect(m_Controls->SearchOption, SIGNAL(parameterChanged()), this, SLOT(OnSearchParameterChanged())); - } -} -void QmitkDicomLocalStorageWidget::StartDicomImport(const QString& dicomData) -{ - if (m_Watcher.isRunning()){ - m_Watcher.waitForFinished(); - } - SetupProgressDialog(); - m_Future = QtConcurrent::run(this,(void (QmitkDicomLocalStorageWidget::*)(const QString&)) &QmitkDicomLocalStorageWidget::AddDICOMData,dicomData); - m_Watcher.setFuture(m_Future); -} + connect(m_LocalIndexer, SIGNAL(indexingComplete()),this, SLOT(OnFinishedImport())); + connect(m_LocalIndexer, SIGNAL(indexingComplete()),this, SIGNAL(SignalFinishedImport())); -void QmitkDicomLocalStorageWidget::StartDicomImport(const QStringList& dicomData) -{ - mitk::ProgressBar::GetInstance()->AddStepsToDo(dicomData.count()); - if (m_Watcher.isRunning()) - { - m_Watcher.waitForFinished(); + connect(m_LocalIndexer, SIGNAL(indexingFilePath(QString)),this, SIGNAL(SignalProcessingFile(QString))); + connect(m_LocalIndexer, SIGNAL(progress(int)),this, SIGNAL(SignalProgress(int))); + connect(this, SIGNAL(SignalCancelImport()),m_LocalIndexer, SLOT(cancel())); } - m_Future = QtConcurrent::run(this,(void (QmitkDicomLocalStorageWidget::*)(const QStringList&)) &QmitkDicomLocalStorageWidget::AddDICOMData,dicomData); - m_Watcher.setFuture(m_Future); } -void QmitkDicomLocalStorageWidget::AddDICOMData(const QString& directory) +void QmitkDicomLocalStorageWidget::OnStartDicomImport(const QString& dicomData) { if(m_LocalDatabase->isOpen()) { - m_LocalIndexer->addDirectory(*m_LocalDatabase,directory,m_LocalDatabase->databaseDirectory()); + m_LocalIndexer->addDirectory(*m_LocalDatabase,dicomData,m_LocalDatabase->databaseDirectory()); } - m_LocalModel->setDatabase(m_LocalDatabase->database()); - emit FinishedImport(directory); } -void QmitkDicomLocalStorageWidget::AddDICOMData(const QStringList& patientFiles) +void QmitkDicomLocalStorageWidget::OnStartDicomImport(const QStringList& dicomData) { if(m_LocalDatabase->isOpen()) { - QStringListIterator fileIterator(patientFiles); - while(fileIterator.hasNext()) - { - m_LocalIndexer->addFile(*m_LocalDatabase,fileIterator.next(),m_LocalDatabase->databaseDirectory()); - mitk::ProgressBar::GetInstance()->Progress(); - } + m_LocalIndexer->addListOfFiles(*m_LocalDatabase,dicomData,m_LocalDatabase->databaseDirectory()); } - m_LocalModel->setDatabase(m_LocalDatabase->database()); - emit FinishedImport(patientFiles); } -void QmitkDicomLocalStorageWidget::SetupProgressDialog() +void QmitkDicomLocalStorageWidget::OnFinishedImport() { - m_ProgressDialog = new QProgressDialog("DICOM Import", "Cancel", 0, 100, this,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 - - m_ProgressDialog->setMinimumDuration(0); - m_ProgressDialog->setValue(0); - m_ProgressDialog->show(); - - connect(m_ProgressDialog, SIGNAL(canceled()), m_LocalIndexer, SLOT(cancel())); - connect(m_LocalIndexer, SIGNAL(indexingFilePath(QString)), - m_ProgressDialogLabel, SLOT(setText(QString))); - connect(m_LocalIndexer, SIGNAL(progress(int)), - m_ProgressDialog, SLOT(setValue(int))); - connect(m_LocalIndexer, SIGNAL(progress(int)), - this, SLOT(OnProgress(int))); -} - -void QmitkDicomLocalStorageWidget::OnProgress(int progress) -{ - Q_UNUSED(progress); - QApplication::processEvents(); + m_LocalModel->setDatabase(m_LocalDatabase->database()); } void QmitkDicomLocalStorageWidget::OnDeleteButtonClicked() { QModelIndex currentIndex = m_Controls->InternalDataTreeView->currentIndex(); QString currentUID = m_LocalModel->data(currentIndex,ctkDICOMModel::UIDRole).toString(); if(m_LocalModel->data(currentIndex,ctkDICOMModel::TypeRole)==static_cast(ctkDICOMModel::SeriesType)) { m_LocalDatabase->removeSeries(currentUID); } else if(m_LocalModel->data(currentIndex,ctkDICOMModel::TypeRole)==static_cast(ctkDICOMModel::StudyType)) { m_LocalDatabase->removeStudy(currentUID); } else if(m_LocalModel->data(currentIndex,ctkDICOMModel::TypeRole)==static_cast(ctkDICOMModel::PatientType)) { m_LocalDatabase->removePatient(currentUID); } m_LocalModel->reset(); } -void QmitkDicomLocalStorageWidget::OnCancelButtonClicked() -{ - m_Watcher.cancel(); - m_Watcher.waitForFinished(); - m_LocalDatabase->closeDatabase(); -} - void QmitkDicomLocalStorageWidget::OnViewButtonClicked() { QModelIndex currentIndex = m_Controls->InternalDataTreeView->currentIndex(); if(m_LocalModel->data(currentIndex,ctkDICOMModel::TypeRole)==static_cast(ctkDICOMModel::SeriesType)) { QString seriesUID = m_LocalModel->data(currentIndex,ctkDICOMModel::UIDRole).toString(); QString seriesName = m_LocalModel->data(currentIndex).toString(); QModelIndex studyIndex = m_LocalModel->parent(currentIndex); QString studyUID = m_LocalModel->data(studyIndex,ctkDICOMModel::UIDRole).toString(); QString studyName = m_LocalModel->data(studyIndex).toString(); QModelIndex patientIndex = m_LocalModel->parent(studyIndex); - QString patientName = m_LocalModel->data(patientIndex).toString(); + QString patientName = m_LocalModel->data(patientIndex).toString(); QString filePath; filePath.append(m_LocalDatabase->databaseDirectory()); filePath.append("/dicom/"); filePath.append(studyUID); filePath.append("/"); filePath.append(seriesUID); filePath.append("/"); QStringList eventProperties; eventProperties << patientName << studyUID <setDatabase(m_LocalDatabase->database(),m_Controls->SearchOption->parameters()); } void QmitkDicomLocalStorageWidget::SetDatabaseDirectory(QString newDatatbaseDirectory) { QDir databaseDirecory = QDir(newDatatbaseDirectory); if(!databaseDirecory.exists()) { databaseDirecory.mkpath(databaseDirecory.absolutePath()); } QString newDatatbaseFile = databaseDirecory.absolutePath() + QString("/ctkDICOM.sql"); this->SetDatabase(newDatatbaseFile); } void QmitkDicomLocalStorageWidget::SetDatabase(QString databaseFile) { m_LocalDatabase = new ctkDICOMDatabase(databaseFile); m_LocalModel->setEndLevel(ctkDICOMModel::SeriesType); m_LocalModel->setDatabase(m_LocalDatabase->database()); } diff --git a/Modules/DicomUI/Qmitk/QmitkDicomLocalStorageWidget.h b/Modules/DicomUI/Qmitk/QmitkDicomLocalStorageWidget.h index c103241b2e..fe3c6b808d 100644 --- a/Modules/DicomUI/Qmitk/QmitkDicomLocalStorageWidget.h +++ b/Modules/DicomUI/Qmitk/QmitkDicomLocalStorageWidget.h @@ -1,119 +1,106 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 QmitkDicomLocalStorageWidget_h #define QmitkDicomLocalStorageWidget_h // #include #include "ui_QmitkDicomLocalStorageWidgetControls.h" #include "mitkDicomUIExports.h" // include ctk #include #include #include #include //include QT #include #include #include -//For running dicom import in background -#include -#include -#include -#include -#include -#include + /*! \brief QmitkDicomLocalStorageWidget \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 MITK_DICOMUI_EXPORT QmitkDicomLocalStorageWidget : 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: static const std::string Widget_ID; QmitkDicomLocalStorageWidget(QWidget *parent); + virtual ~QmitkDicomLocalStorageWidget(); virtual void CreateQtPartControl(QWidget *parent); void SetDatabaseDirectory(QString newDatabaseDirectory); signals: - void FinishedImport(const QString&); - void FinishedImport(const QStringList&); - void SignalDicomToDataManager(const QStringList&); - - public slots: - /// @brief Called when cancel button was clicked. - void OnViewButtonClicked(); + /// @brief emitted when import into database is finished. + void SignalFinishedImport(); - /// @brief Called when cancel button was clicked. - void OnCancelButtonClicked(); + /// @brief emitted when view button is clicked. + void SignalDicomToDataManager(const QStringList&); + void SignalProgress(int); + void SignalProcessingFile(QString); + void SignalCancelImport(); - /// @brief Called delete button was clicked. - void OnDeleteButtonClicked(); +public slots: - /// @brief Called when adding a dicom directory. Starts a thread adding the directory. - void StartDicomImport(const QString& dicomData); + /// @brief Called when indexing into database is finished. + /// In this slot the models database with new imports is set. + /// This causes a model update. + void OnFinishedImport(); - /// @brief Called when adding a list of dicom files. Starts a thread adding the dicom files. - void StartDicomImport(const QStringList& dicomData); + /// @brief Called when view button was clicked. + void OnViewButtonClicked(); - /// @brief Called when search parameters change. - void OnSearchParameterChanged(); + /// @brief Called delete button was clicked. + void OnDeleteButtonClicked(); - void OnProgress(int progress); + /// @brief Called when adding a dicom directory. Starts a thread adding the directory. + void OnStartDicomImport(const QString& dicomData); -protected: + /// @brief Called when adding a list of dicom files. Starts a thread adding the dicom files. + void OnStartDicomImport(const QStringList& dicomData); - // adds dicom files from a directory containing dicom files to the local storage. - void AddDICOMData(const QString& dicomDirectory); + /// @brief Called when search parameters change. + void OnSearchParameterChanged(); - // adds dicom files from a string list containing the filepath to the local storage. - void AddDICOMData(const QStringList& dicomFiles); +protected: void SetDatabase(QString databaseFile); - void SetupProgressDialog(); - - QProgressDialog* m_ProgressDialog; - QLabel* m_ProgressDialogLabel; - ctkDICOMDatabase* m_LocalDatabase; ctkDICOMModel* m_LocalModel; ctkDICOMIndexer* m_LocalIndexer; Ui::QmitkDicomLocalStorageWidgetControls* m_Controls; - - QFuture m_Future; - QFutureWatcher m_Watcher; }; #endif // _QmitkDicomLocalStorageWidget_H_INCLUDED diff --git a/Modules/DiffusionImaging/Algorithms/mitkPartialVolumeAnalysisHistogramCalculator.h b/Modules/DiffusionImaging/Algorithms/mitkPartialVolumeAnalysisHistogramCalculator.h index f6989088e1..014ff6d0fa 100644 --- a/Modules/DiffusionImaging/Algorithms/mitkPartialVolumeAnalysisHistogramCalculator.h +++ b/Modules/DiffusionImaging/Algorithms/mitkPartialVolumeAnalysisHistogramCalculator.h @@ -1,383 +1,383 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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_PartialVolumeAnalysisHistogramCalculator_H #define _MITK_PartialVolumeAnalysisHistogramCalculator_H #include "MitkDiffusionImagingExports.h" #include #include #include #include "mitkImage.h" #include "mitkImageTimeSelector.h" #include "mitkPlanarFigure.h" namespace mitk { /** * \brief Class for calculating statistics and histogram for an (optionally * masked) image. * * Images can be masked by either a (binary) 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 (transversal, sagittal, coronal). Planar figures on arbitrary + * 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 MitkDiffusionImaging_EXPORT PartialVolumeAnalysisHistogramCalculator : public itk::Object { public: enum { MASKING_MODE_NONE = 0, MASKING_MODE_IMAGE, MASKING_MODE_PLANARFIGURE }; typedef mitk::Image::HistogramType HistogramType; typedef mitk::Image::HistogramType::ConstIterator HistogramConstIteratorType; struct Statistics { unsigned int N; double Min; double Max; double Mean; double Median; double Variance; double Sigma; double RMS; void Reset() { N = 0; Min = 0.0; Max = 0.0; Mean = 0.0; Median = 0.0; Variance = 0.0; Sigma = 0.0; RMS = 0.0; } }; typedef Statistics StatisticsType; typedef itk::TimeStamp TimeStampType; typedef bool BoolType; typedef itk::Image< unsigned char, 3 > MaskImage3DType; typedef itk::Image< unsigned char, 2 > MaskImage2DType; typedef itk::Image< float, 2 > InternalImage2DType; mitkClassMacro( PartialVolumeAnalysisHistogramCalculator, itk::Object ) itkNewMacro( PartialVolumeAnalysisHistogramCalculator ) /** \brief Set image from which to compute statistics. */ void SetImage( const mitk::Image *image ); /** \brief Set binary image for masking. */ void SetImageMask( const mitk::Image *imageMask ); /** \brief Set planar figure for masking. */ void SetPlanarFigure( const mitk::PlanarFigure *planarFigure ); /** \brief Set image for which the same resampling will be applied. and available via GetAdditionalResampledImage() */ void AddAdditionalResamplingImage( const mitk::Image *image ); /** \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 histogram number of bins. */ void SetNumberOfBins( unsigned int number ) { if(m_NumberOfBins != number) { m_NumberOfBins = number; SetModified(); } } /** \brief Get histogram number of bins. */ unsigned int GetNumberOfBins( ) { return m_NumberOfBins; } /** \brief Set upsampling factor. */ void SetUpsamplingFactor( float number ) { if(m_UpsamplingFactor != number) { m_UpsamplingFactor = number; SetModified(); } } /** \brief Get upsampling factor. */ float GetUpsamplingFactor( ) { return m_UpsamplingFactor; } /** \brief Set gaussian sigma. */ void SetGaussianSigma( float number ) { if(m_GaussianSigma != number) { m_GaussianSigma = number; SetModified(); } } /** \brief Get thickness of planar figure. */ unsigned int GetPlanarFigureThickness( ) { return m_PlanarFigureThickness; } /** \brief Set thickness of planar figure. */ void SetPlanarFigureThickness( unsigned int number ) { if(m_PlanarFigureThickness != number) { m_PlanarFigureThickness = number; SetModified(); } } /** \brief Get histogram number of bins. */ float GetGaussianSigma( ) { return m_GaussianSigma; } void SetModified(); /** \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( ); /** \brief Retrieve the histogram depending on the current masking mode. */ const HistogramType *GetHistogram( ) const; /** \brief Retrieve statistics depending on the current masking mode. */ const Statistics &GetStatistics( ) const; const Image::Pointer GetInternalImage() { return m_InternalImage; } const Image::Pointer GetInternalAdditionalResampledImage(unsigned int i) { if(i < m_InternalAdditionalResamplingImages.size()) { return m_InternalAdditionalResamplingImages[i]; } else { return NULL; } } void SetForceUpdate(bool b) { m_ForceUpdate = b; } protected: PartialVolumeAnalysisHistogramCalculator(); virtual ~PartialVolumeAnalysisHistogramCalculator(); /** \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( ); /** \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, Statistics &statistics, typename HistogramType::ConstPointer *histogram ); template < typename TPixel, unsigned int VImageDimension > void InternalCalculateStatisticsMasked( const itk::Image< TPixel, VImageDimension > *image, itk::Image< unsigned char, VImageDimension > *maskImage, Statistics &statistics, typename HistogramType::ConstPointer *histogram ); template < typename TPixel, unsigned int VImageDimension > void InternalCalculateMaskFromPlanarFigure( itk::Image< TPixel, VImageDimension > *image, unsigned int axis ); template < typename TPixel, unsigned int VImageDimension > void InternalReorientImagePlane( const itk::Image< TPixel, VImageDimension > *image, mitk::Geometry3D* imggeo, mitk::Geometry3D* planegeo3D, int additionalIndex ); template < typename TPixel, unsigned int VImageDimension > void InternalResampleImageFromMask( const itk::Image< TPixel, VImageDimension > *image, int additionalIndex ); void InternalResampleImage( const MaskImage3DType *image/*, mitk::Geometry3D* imggeo*/ ); template < typename TPixel, unsigned int VImageDimension > void InternalCropAdditionalImage( itk::Image< TPixel, VImageDimension > *image, int additionalIndex ); void InternalMaskImage( mitk::Image *image ); /** Connection from ITK to VTK */ 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()); } /** 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()); } void UnmaskedStatisticsProgressUpdate(); void MaskedStatisticsProgressUpdate(); mitk::Image::ConstPointer m_Image; mitk::Image::ConstPointer m_ImageMask; mitk::PlanarFigure::ConstPointer m_PlanarFigure; HistogramType::ConstPointer m_ImageHistogram; HistogramType::ConstPointer m_MaskedImageHistogram; HistogramType::ConstPointer m_PlanarFigureHistogram; HistogramType::Pointer m_EmptyHistogram; StatisticsType m_ImageStatistics; StatisticsType m_MaskedImageStatistics; StatisticsType m_PlanarFigureStatistics; Statistics m_EmptyStatistics; unsigned int m_MaskingMode; bool m_MaskingModeChanged; mitk::Image::Pointer m_InternalImage; MaskImage3DType::Pointer m_InternalImageMask3D; MaskImage2DType::Pointer m_InternalImageMask2D; itk::ImageRegion<3> m_InternalMask3D; std::vector m_AdditionalResamplingImages; std::vector m_InternalAdditionalResamplingImages; TimeStampType m_ImageStatisticsTimeStamp; TimeStampType m_MaskedImageStatisticsTimeStamp; TimeStampType m_PlanarFigureStatisticsTimeStamp; BoolType m_ImageStatisticsCalculationTriggerBool; BoolType m_MaskedImageStatisticsCalculationTriggerBool; BoolType m_PlanarFigureStatisticsCalculationTriggerBool; unsigned int m_NumberOfBins; float m_UpsamplingFactor; float m_GaussianSigma; itk::ImageRegion<3> m_CropRegion; bool m_ForceUpdate; unsigned int m_PlanarFigureThickness; }; } #endif // #define _MITK_PartialVolumeAnalysisHistogramCalculator_H diff --git a/Modules/DiffusionImaging/Documentation/doxygen/DiffusionImagingProperties.dox b/Modules/DiffusionImaging/Documentation/doxygen/DiffusionImagingProperties.dox index 2626821ffa..9e0750f8b9 100644 --- a/Modules/DiffusionImaging/Documentation/doxygen/DiffusionImagingProperties.dox +++ b/Modules/DiffusionImaging/Documentation/doxygen/DiffusionImagingProperties.dox @@ -1,22 +1,22 @@ /** \page DiffusionImagingPropertiesPage The Diffusion Imaging Properties These properties govern the rendering of diffusion imaging data and the visualization of its analysis.
  • opaclevelwindow - controls the maximal/minimal opacity value
  • DisplayChannel - selectes which channel is to be displayed
  • DoRefresh - Do GL/VTK Refresh
  • IndexParam1 - These are used to safe parameters depending on the chosen method
  • IndexParam2 - as IndexParam1
  • Normalization - stores the normalization for the mitkOdfVtkMapper2D
  • ScaleBy - Toggles wether the ODFs should be scaled with the FA or GFA
  • Scaling - Global scaling factor, eg for rendering all ODFs 1.23 as big
  • ShowMaxNumber - The maximum number of glyphs to render in a window
  • VisibleOdfs - are there visible glyphs
  • VisibleOdfs_C - Toggles coronally visible glyphs
  • VisibleOdfs_S - Toggles sagittally visible glyphs -
  • VisibleOdfs_T - Toggles transversally visible glyphs +
  • VisibleOdfs_T - Toggles transversely visible glyphs
*/ \ No newline at end of file diff --git a/Modules/DiffusionImaging/IODataStructures/TbssImages/mitkNrrdTbssRoiImageReader.cpp b/Modules/DiffusionImaging/IODataStructures/TbssImages/mitkNrrdTbssRoiImageReader.cpp index 77e3c61c48..8b30f95254 100644 --- a/Modules/DiffusionImaging/IODataStructures/TbssImages/mitkNrrdTbssRoiImageReader.cpp +++ b/Modules/DiffusionImaging/IODataStructures/TbssImages/mitkNrrdTbssRoiImageReader.cpp @@ -1,363 +1,363 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkNrrdTbssRoiReader_cpp #define __mitkNrrdTbssRoiReader_cpp #include "mitkNrrdTbssRoiImageReader.h" #include "itkImageFileReader.h" #include "itkMetaDataObject.h" #include "itkNrrdImageIO.h" #include "itkNiftiImageIO.h" #include #include #include #include "itksys/SystemTools.hxx" namespace mitk { void NrrdTbssRoiImageReader ::GenerateData() { try { // Change locale if needed 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; } } // READ IMAGE INFORMATION const unsigned int MINDIM = 3; const unsigned int MAXDIM = 4; MITK_INFO << "loading " << m_FileName << " via mitk::NrrdTbssImageReader... " << std::endl; // Check to see if we can read the file given the name or prefix if ( m_FileName == "" ) { itkWarningMacro( << "Filename is empty!" ) return; } itk::NrrdImageIO::Pointer imageIO = itk::NrrdImageIO::New(); imageIO->SetFileName( m_FileName.c_str() ); imageIO->ReadImageInformation(); unsigned int ndim = imageIO->GetNumberOfDimensions(); if ( ndim < MINDIM || ndim > MAXDIM ) { itkWarningMacro( << "Sorry, only dimensions 3 is supported. The given file has " << ndim << " dimensions!" ) return; } itk::ImageIORegion ioRegion( ndim ); itk::ImageIORegion::SizeType ioSize = ioRegion.GetSize(); itk::ImageIORegion::IndexType ioStart = ioRegion.GetIndex(); unsigned int dimensions[ MAXDIM ]; dimensions[ 0 ] = 0; dimensions[ 1 ] = 0; dimensions[ 2 ] = 0; dimensions[ 3 ] = 0; float spacing[ MAXDIM ]; spacing[ 0 ] = 1.0f; spacing[ 1 ] = 1.0f; spacing[ 2 ] = 1.0f; spacing[ 3 ] = 1.0f; Point3D origin; origin.Fill(0); unsigned int i; for ( i = 0; i < ndim ; ++i ) { ioStart[ i ] = 0; ioSize[ i ] = imageIO->GetDimensions( i ); if(iGetDimensions( i ); spacing[ i ] = imageIO->GetSpacing( i ); if(spacing[ i ] <= 0) spacing[ i ] = 1.0f; } if(i<3) { origin[ i ] = imageIO->GetOrigin( i ); } } ioRegion.SetSize( ioSize ); ioRegion.SetIndex( ioStart ); MITK_INFO << "ioRegion: " << ioRegion << std::endl; imageIO->SetIORegion( ioRegion ); void* buffer = new unsigned char[imageIO->GetImageSizeInBytes()]; imageIO->Read( buffer ); //mitk::Image::Pointer static_cast(this->GetOutput())image = mitk::Image::New(); if((ndim==4) && (dimensions[3]<=1)) ndim = 3; if((ndim==3) && (dimensions[2]<=1)) ndim = 2; - mitk::PixelType pixelType = mitk::PixelType(imageIO->GetComponentTypeInfo(), imageIO->GetComponentTypeInfo(), + mitk::PixelType pixelType = mitk::PixelType(imageIO->GetComponentTypeInfo(), imageIO->GetPixelType(), imageIO->GetComponentSize(), imageIO->GetNumberOfComponents(), imageIO->GetComponentTypeAsString( imageIO->GetComponentType() ).c_str(), imageIO->GetPixelTypeAsString( imageIO->GetPixelType() ).c_str() ); //pixelType.Initialize( imageIO->GetComponentTypeInfo(), imageIO->GetNumberOfComponents(), imageIO->GetPixelType() ); static_cast(this->GetOutput(0))->Initialize( pixelType, ndim, dimensions ); static_cast(this->GetOutput(0))->SetImportChannel( buffer, 0, Image::ManageMemory ); // access direction of itk::Image and include spacing mitk::Matrix3D matrix; matrix.SetIdentity(); unsigned int j, itkDimMax3 = (ndim >= 3? 3 : ndim); for ( i=0; i < itkDimMax3; ++i) for( j=0; j < itkDimMax3; ++j ) matrix[i][j] = imageIO->GetDirection(j)[i]; // re-initialize PlaneGeometry with origin and direction PlaneGeometry* planeGeometry = static_cast (static_cast (this->GetOutput(0))->GetSlicedGeometry(0)->GetGeometry2D(0)); planeGeometry->SetOrigin(origin); planeGeometry->GetIndexToWorldTransform()->SetMatrix(matrix); // re-initialize SlicedGeometry3D SlicedGeometry3D* slicedGeometry = static_cast(this->GetOutput(0))->GetSlicedGeometry(0); slicedGeometry->InitializeEvenlySpaced(planeGeometry, static_cast(this->GetOutput(0))->GetDimension(2)); slicedGeometry->SetSpacing(spacing); // re-initialize TimeSlicedGeometry static_cast(this->GetOutput(0))->GetTimeSlicedGeometry()->InitializeEvenlyTimed(slicedGeometry, static_cast(this->GetOutput(0))->GetDimension(3)); buffer = NULL; MITK_INFO << "number of image components: "<< static_cast(this->GetOutput(0))->GetPixelType().GetNumberOfComponents() << std::endl; // READ TBSS HEADER INFORMATION ImageType::Pointer img; std::string ext = itksys::SystemTools::GetFilenameLastExtension(m_FileName); ext = itksys::SystemTools::LowerCase(ext); if (ext == ".roi") { typedef itk::ImageFileReader FileReaderType; FileReaderType::Pointer reader = FileReaderType::New(); reader->SetFileName(this->m_FileName); reader->SetImageIO(imageIO); reader->Update(); img = reader->GetOutput(); static_cast(this->GetOutput(0))->SetImage(img); itk::MetaDataDictionary imgMetaDictionary = img->GetMetaDataDictionary(); ReadRoiInfo(imgMetaDictionary); } // RESET LOCALE 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; } MITK_INFO << "...finished!" << std::endl; } catch(std::exception& e) { MITK_INFO << "Std::Exception while reading file!!"; MITK_INFO << e.what(); throw itk::ImageFileReaderException(__FILE__, __LINE__, e.what()); } catch(...) { MITK_INFO << "Exception while reading file!!"; throw itk::ImageFileReaderException(__FILE__, __LINE__, "Sorry, an error occurred while reading the requested vessel tree file!"); } } void NrrdTbssRoiImageReader ::ReadRoiInfo(itk::MetaDataDictionary dict) { std::vector imgMetaKeys = dict.GetKeys(); std::vector::const_iterator itKey = imgMetaKeys.begin(); std::string metaString; std::vector< itk::Index<3> > roi; for (; itKey != imgMetaKeys.end(); itKey ++) { double x,y,z; itk::Index<3> ix; itk::ExposeMetaData (dict, *itKey, metaString); if (itKey->find("ROI_index") != std::string::npos) { MITK_INFO << *itKey << " ---> " << metaString; sscanf(metaString.c_str(), "%lf %lf %lf\n", &x, &y, &z); ix[0] = x; ix[1] = y; ix[2] = z; roi.push_back(ix); } else if(itKey->find("preprocessed FA") != std::string::npos) { MITK_INFO << *itKey << " ---> " << metaString; static_cast(this->GetOutput(0))->SetPreprocessedFA(true); static_cast(this->GetOutput(0))->SetPreprocessedFAFile(metaString); } // Name of structure if (itKey->find("structure") != std::string::npos) { MITK_INFO << *itKey << " ---> " << metaString; static_cast(this->GetOutput(0))->SetStructure(metaString); } } static_cast(this->GetOutput(0))->SetRoi(roi); } const char* NrrdTbssRoiImageReader ::GetFileName() const { return m_FileName.c_str(); } void NrrdTbssRoiImageReader ::SetFileName(const char* aFileName) { m_FileName = aFileName; } const char* NrrdTbssRoiImageReader ::GetFilePrefix() const { return m_FilePrefix.c_str(); } void NrrdTbssRoiImageReader ::SetFilePrefix(const char* aFilePrefix) { m_FilePrefix = aFilePrefix; } const char* NrrdTbssRoiImageReader ::GetFilePattern() const { return m_FilePattern.c_str(); } void NrrdTbssRoiImageReader ::SetFilePattern(const char* aFilePattern) { m_FilePattern = aFilePattern; } bool NrrdTbssRoiImageReader ::CanReadFile(const std::string filename, const std::string filePrefix, const std::string filePattern) { // First check the extension if( filename == "" ) return false; // check if image is serie if( filePattern != "" && filePrefix != "" ) return false; std::string ext = itksys::SystemTools::GetFilenameLastExtension(filename); ext = itksys::SystemTools::LowerCase(ext); if (ext == ".roi") { itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New(); typedef itk::ImageFileReader FileReaderType; FileReaderType::Pointer reader = FileReaderType::New(); reader->SetImageIO(io); reader->SetFileName(filename); try { reader->Update(); } catch(itk::ExceptionObject e) { MITK_INFO << e.GetDescription(); return false; } return true; } return false; } } //namespace MITK #endif diff --git a/Modules/FLApplications/MITKFLExample/MITKFltkExample.cpp b/Modules/FLApplications/MITKFLExample/MITKFltkExample.cpp index 5bbf3ac146..639e0cb92b 100644 --- a/Modules/FLApplications/MITKFLExample/MITKFltkExample.cpp +++ b/Modules/FLApplications/MITKFLExample/MITKFltkExample.cpp @@ -1,94 +1,94 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "FLmitkRenderWindow/FLmitkRenderWindow.h" // #include "mitkIpPic.h" #include "mitkPicFileReader.h" #include "mitkStringProperty.h" #include "mitkLevelWindowProperty.h" #include "mitkSliceNavigationController.h" #include "mitkDataNodeFactory.h" #include "mitkSample.h" int main(int argc, char **argv) { const char* fileName = NULL; if (argc == 2 && argv[1]) { fileName = argv[1]; } else { fileName = fl_file_chooser("Open file","*.dcm;*.png;*.jog;*.tiff;*.dcm;*.DCM;*.seq;*.pic;*.pic.gz;*.seq.gz;*.pic;*.pic.gz;*.png;*.stl",NULL); } if (!fileName) { exit(0);} UserInterface ui; mitk::SliceNavigationController::Pointer &sliceCtrl = ui.mainWid->sliceCtrl; sliceCtrl = mitk::SliceNavigationController::New("navigation"); ui.mainWid->InitRenderer(); ui.mainWid->GetRenderer()->SetMapperID(1); mitk::DataTree::Pointer tree = mitk::DataTree::New(); mitk::DataNodeFactory::Pointer factory = mitk::DataNodeFactory::New(); factory->SetFileName( fileName ); factory->Update(); if (factory->GetNumberOfOutputs() > 1) { fl_alert("WARNING: More than one image in file. Only showing first one."); } mitk::DataTreePreOrderIterator it(tree); mitk::DataNode::Pointer node = factory->GetOutput( 0 ); assert(node.IsNotNull()); { it.Add( node ); ui.mainWid->SetNode(node); } ui.mainWid->GetRenderer()->SetData(&it); ui.mainWid->RequestUpdate(); mitk::BoundingBox::Pointer bb = mitk::DataTree::ComputeVisibleBoundingBox(&it); mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); geometry->Initialize(); geometry->SetBounds(bb->GetBounds()); //tell the navigator the geometry to be sliced (with geometry a Geometry3D::ConstPointer) sliceCtrl->SetInputWorldGeometry(geometry.GetPointer()); //tell the navigator in which direction it shall slice the data - sliceCtrl->SetViewDirection(mitk::SliceNavigationController::Transversal); + sliceCtrl->SetViewDirection(mitk::SliceNavigationController::Axial); //Connect one or more BaseRenderer to this navigator, i.e.: events sent //by the navigator when stepping through the slices (e.g. by //sliceCtrl->GetSlice()->Next()) will be received by the BaseRenderer //(in this example only slice-changes, see also ConnectGeometryTimeEvent //and ConnectGeometryEvents.) sliceCtrl->ConnectGeometrySliceEvent(ui.mainWid->GetRenderer()); //create a world geometry and send the information to the connected renderer(s) sliceCtrl->Update(); sliceCtrl->GetSlice()->SetPos(3); ui.sliceSlider->bounds(0,sliceCtrl->GetSlice()->GetSteps()-1); ui.sliceSlider->precision(0); ui.mainWid->RequestUpdate(); ui.mainWin->show(argc, argv); return Fl::run(); } diff --git a/Modules/IGT/CMakeLists.txt b/Modules/IGT/CMakeLists.txt index 7067c79cd6..a874c8e69b 100644 --- a/Modules/IGT/CMakeLists.txt +++ b/Modules/IGT/CMakeLists.txt @@ -1,46 +1,48 @@ include(MITKIGTHardware.cmake) if(MITK_USE_MICRON_TRACKER) set(INCLUDE_DIRS_INTERNAL ${INCLUDE_DIRS_INTERNAL} ${MITK_MICRON_TRACKER_INCLUDE_DIR}) set(ADDITIONAL_LIBS ${ADDITIONAL_LIBS} ${MITK_MICRON_TRACKER_LIB}) endif(MITK_USE_MICRON_TRACKER) if(MITK_USE_MICROBIRD_TRACKER) set(INCLUDE_DIRS_INTERNAL ${INCLUDE_DIRS_INTERNAL} ${MITK_USE_MICROBIRD_TRACKER_INCLUDE_DIR}) set(ADDITIONAL_LIBS ${ADDITIONAL_LIBS} ${MITK_USE_MICROBIRD_TRACKER_LIB}) endif(MITK_USE_MICROBIRD_TRACKER) MITK_CREATE_MODULE(MitkIGT SUBPROJECTS MITK-IGT INCLUDE_DIRS IGTFilters IGTTrackingDevices IGTToolManagement IGTExceptionHandling INTERNAL_INCLUDE_DIRS ${INCLUDE_DIRS_INTERNAL} DEPENDS Mitk tinyxml SceneSerialization ADDITIONAL_LIBS "${ADDITIONAL_LIBS}" ) -MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/ClaronMicron.stl ) -MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/IntuitiveDaVinci.stl ) -MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/NDIAurora.stl ) -MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/NDIAurora_Dome.stl ) -MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/NDIAuroraCompactFG_Dome.stl ) -MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/NDIAuroraPlanarFG_Dome.stl ) -MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/NDIAuroraTabletopFG_Dome.stl ) -MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/NDIAuroraTabletopFG_Prototype_Dome.stl ) -MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/NDIPolaris.stl ) -MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/NDIPolarisVicra.stl ) -MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/StandardVolume.stl ) +if(MitkIGT_IS_ENABLED) + MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/ClaronMicron.stl ) + MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/IntuitiveDaVinci.stl ) + MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/NDIAurora.stl ) + MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/NDIAurora_Dome.stl ) + MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/NDIAuroraCompactFG_Dome.stl ) + MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/NDIAuroraPlanarFG_Dome.stl ) + MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/NDIAuroraTabletopFG_Dome.stl ) + MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/NDIAuroraTabletopFG_Prototype_Dome.stl ) + MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/NDIPolaris.stl ) + MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/NDIPolarisVicra.stl ) + MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/StandardVolume.stl ) +endif() MITK_CHECK_MODULE(_RESULT MitkIGT) if(_RESULT) message(STATUS "IGTTutorialStep1 won't be built. Missing: ${_RESULT}") else(_RESULT) ## create IGT config configure_file(mitkIGTConfig.h.in ${PROJECT_BINARY_DIR}/mitkIGTConfig.h @ONLY) # add test programm for serial communication classADD_EXECUTABLE(SerialCommunicationTest IGTTrackingDevices/mitkSerialCommunicationTest.cpp)target_link_libraries(SerialCommunicationTest mitkIGT Mitk tinyxml PocoXML) add_subdirectory(IGTTutorial) add_subdirectory(Testing) endif(_RESULT) diff --git a/Modules/IGTUI/Qmitk/QmitkFiducialRegistrationWidget.cpp b/Modules/IGTUI/Qmitk/QmitkFiducialRegistrationWidget.cpp index 563e8603d5..d3c1c698b5 100644 --- a/Modules/IGTUI/Qmitk/QmitkFiducialRegistrationWidget.cpp +++ b/Modules/IGTUI/Qmitk/QmitkFiducialRegistrationWidget.cpp @@ -1,179 +1,225 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "QmitkFiducialRegistrationWidget.h" #define FRW_LOG MITK_INFO("Fiducial Registration Widget") #define FRW_WARN MITK_WARN("Fiducial Registration Widget") #define FRW_DEBUG MITK_DEBUG("Fiducial Registration Widget") /* VIEW MANAGEMENT */ QmitkFiducialRegistrationWidget::QmitkFiducialRegistrationWidget(QWidget* parent) : QWidget(parent), m_Controls(NULL),m_MultiWidget(NULL), m_ImageFiducialsNode(NULL), m_TrackerFiducialsNode(NULL) { CreateQtPartControl(this); } QmitkFiducialRegistrationWidget::~QmitkFiducialRegistrationWidget() { m_Controls = NULL; } void QmitkFiducialRegistrationWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkFiducialRegistrationWidget; m_Controls->setupUi(parent); // hide additional image fiducial button m_Controls->m_AddImageFiducialBtn->setHidden(true); + m_Controls->m_spaceHolderGroupBox->setStyleSheet("QGroupBox {border: 0px transparent;}"); + m_Controls->m_spaceHolderGroupBox2->setStyleSheet("QGroupBox {border: 0px transparent;}"); + this->CreateConnections(); } } void QmitkFiducialRegistrationWidget::CreateConnections() { connect( (QObject*)(m_Controls->m_AddTrackingFiducialBtn), SIGNAL(clicked()), this, SIGNAL(AddedTrackingFiducial()) ); connect( (QObject*)(m_Controls->m_AddImageFiducialBtn), SIGNAL(clicked()), this, SIGNAL(AddedImageFiducial()) ); connect( (QObject*)(m_Controls->m_RegisterFiducialsBtn), SIGNAL(clicked()), this, SIGNAL(PerformFiducialRegistration()) ); connect( (QObject*)(m_Controls->m_UseICPRegistration), SIGNAL(toggled(bool)), this, SIGNAL(FindFiducialCorrespondences(bool)) ); + + //unselects the edit button of the other widget if one is selected + connect( (QObject*)(m_Controls->m_RegistrationImagePoints), SIGNAL(EditPointSets(bool)), this, SLOT(DisableEditButtonRegistrationTrackingPoints(bool))); + connect( (QObject*)(m_Controls->m_RegistrationTrackingPoints), SIGNAL(EditPointSets(bool)), this, SLOT(DisableEditButtonRegistrationImagePoints(bool))); +} + +void QmitkFiducialRegistrationWidget::DisableEditButtonRegistrationImagePoints(bool activated) +{ +if (activated) m_Controls->m_RegistrationImagePoints->UnselectEditButton(); +} +void QmitkFiducialRegistrationWidget::DisableEditButtonRegistrationTrackingPoints(bool activated) +{ +if (activated) m_Controls->m_RegistrationTrackingPoints->UnselectEditButton(); } void QmitkFiducialRegistrationWidget::SetWidgetAppearanceMode(WidgetAppearanceMode widgetMode) { if (widgetMode==LANDMARKMODE) { this->HideContinousRegistrationRadioButton(true); this->HideStaticRegistrationRadioButton(true); + this->HideFiducialRegistrationGroupBox(); this->HideUseICPRegistrationCheckbox(true); this->HideImageFiducialButton(false); - this->m_Controls->registrationGroupBox->setTitle(""); this->m_Controls->sourceLandmarksGroupBox->setTitle("Target/Reference landmarks"); this->m_Controls->targetLandmarksGroupBox->setTitle("Source Landmarks"); this->m_Controls->m_AddImageFiducialBtn->setText("Add target landmark"); this->m_Controls->m_AddTrackingFiducialBtn->setText("Add source landmark"); } else if (widgetMode==FIDUCIALMODE) { this->HideContinousRegistrationRadioButton(false); this->HideStaticRegistrationRadioButton(false); + this->HideFiducialRegistrationGroupBox(); this->HideUseICPRegistrationCheckbox(false); this->HideImageFiducialButton(true); - this->m_Controls->registrationGroupBox->setTitle("Select fiducials in image and OR (world)"); this->m_Controls->sourceLandmarksGroupBox->setTitle("Image fiducials"); this->m_Controls->targetLandmarksGroupBox->setTitle("OR fiducials"); this->m_Controls->m_AddImageFiducialBtn->setText("Add image fiducial"); this->m_Controls->m_AddTrackingFiducialBtn->setText("Add current instrument position"); } } void QmitkFiducialRegistrationWidget::SetQualityDisplayText( QString text ) { if (text == NULL) return; m_Controls->m_RegistrationQualityDisplay->setText(text); // set text on the QLabel } bool QmitkFiducialRegistrationWidget::UseICPIsChecked() { if(m_Controls->m_UseICPRegistration->isChecked()) return true; else return false; } void QmitkFiducialRegistrationWidget::SetImageFiducialsNode( mitk::DataNode::Pointer imageFiducialsNode ) { if(imageFiducialsNode.IsNull()) { FRW_WARN<< "tracker fiducial node is NULL"; return; } if(m_MultiWidget == NULL) { FRW_WARN<< "stdMultiWidget is NULL"; return; } m_Controls->m_RegistrationImagePoints->SetMultiWidget(m_MultiWidget); // pass multiWidget to pointListWidget m_Controls->m_RegistrationImagePoints->SetPointSetNode(imageFiducialsNode); // pass node to pointListWidget } void QmitkFiducialRegistrationWidget::SetTrackerFiducialsNode( mitk::DataNode::Pointer trackerFiducialsNode ) { if(trackerFiducialsNode.IsNull()) { FRW_WARN<< "tracker fiducial node is NULL"; return; } if(m_MultiWidget == NULL) { FRW_WARN<< "stdMultiWidget is NULL"; return; } m_Controls->m_RegistrationTrackingPoints->SetMultiWidget(m_MultiWidget); // pass multiWidget to pointListWidget m_Controls->m_RegistrationTrackingPoints->SetPointSetNode(trackerFiducialsNode); // pass node to pointListWidget } void QmitkFiducialRegistrationWidget::SetMultiWidget( QmitkStdMultiWidget* multiWidget ) { m_MultiWidget=multiWidget; } mitk::DataNode::Pointer QmitkFiducialRegistrationWidget::GetImageFiducialsNode() { return m_ImageFiducialsNode; } mitk::DataNode::Pointer QmitkFiducialRegistrationWidget::GetTrackerFiducialsNode() { return m_TrackerFiducialsNode; } void QmitkFiducialRegistrationWidget::HideStaticRegistrationRadioButton( bool on ) { m_Controls->m_rbStaticRegistration->setHidden(on); + HideFiducialRegistrationGroupBox(); } void QmitkFiducialRegistrationWidget::HideContinousRegistrationRadioButton( bool on ) { m_Controls->m_rbContinousRegistration->setHidden(on); + HideFiducialRegistrationGroupBox(); +} + +void QmitkFiducialRegistrationWidget::HideFiducialRegistrationGroupBox() +{ + if (m_Controls->m_rbStaticRegistration->isHidden() && m_Controls->m_rbContinousRegistration->isHidden()) + { + m_Controls->m_gbFiducialRegistration->setHidden(true); + } + else + { + m_Controls->m_gbFiducialRegistration->setHidden(false); + } } void QmitkFiducialRegistrationWidget::HideUseICPRegistrationCheckbox( bool on ) { m_Controls->m_UseICPRegistration->setHidden(on); } void QmitkFiducialRegistrationWidget::HideImageFiducialButton( bool on ) { m_Controls->m_AddImageFiducialBtn->setHidden(on); + AdjustButtonSpacing(); + } void QmitkFiducialRegistrationWidget::HideTrackingFiducialButton( bool on ) { m_Controls->m_AddTrackingFiducialBtn->setHidden(on); + AdjustButtonSpacing(); } +void QmitkFiducialRegistrationWidget::AdjustButtonSpacing() +{ + if (m_Controls->m_AddImageFiducialBtn->isHidden() && m_Controls->m_AddTrackingFiducialBtn->isHidden()) + { + m_Controls->m_spaceHolderGroupBox->setHidden(true); + m_Controls->m_spaceHolderGroupBox2->setHidden(true); + } + else + { + m_Controls->m_spaceHolderGroupBox->setHidden(false); + m_Controls->m_spaceHolderGroupBox2->setHidden(false); + } +} diff --git a/Modules/IGTUI/Qmitk/QmitkFiducialRegistrationWidget.h b/Modules/IGTUI/Qmitk/QmitkFiducialRegistrationWidget.h index 736898bacb..4feffdeff6 100644 --- a/Modules/IGTUI/Qmitk/QmitkFiducialRegistrationWidget.h +++ b/Modules/IGTUI/Qmitk/QmitkFiducialRegistrationWidget.h @@ -1,93 +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. ===================================================================*/ #ifndef _QmitkFiducialRegistrationWidget_H_INCLUDED #define _QmitkFiducialRegistrationWidget_H_INCLUDED #include "ui_QmitkFiducialRegistrationWidget.h" #include "QmitkStdMultiWidget.h" #include "MitkIGTUIExports.h" /*! * \brief IGT Fiducial Registration Widget * * Widget used to set fiducial landmarks in the image and to confirm the corresponding landmarks on the world object (patient/phantom). * * SetImageFiducialsNode(), SetTrackerFiducialsNode() and SetMultiWidget() must be called, otherwise QmitkPointListWidget can not work. * * * * \sa IGT */ class MitkIGTUI_EXPORT QmitkFiducialRegistrationWidget : public QWidget { Q_OBJECT // this is needed for all Qt objects that should have a MOC object (everything that derives from QObject) public: QmitkFiducialRegistrationWidget(QWidget* parent); virtual ~QmitkFiducialRegistrationWidget(); /*! \brief enumeration to specify the appearance of the widget. 'FIDUCIALMODE' is likely to be used for (tracking) fiducial based registration purposes 'LANDMARKMODE' can be used for any kind of landmark based registration (source landmarks -> target/reference landmarks) */ enum WidgetAppearanceMode { FIDUCIALMODE, LANDMARKMODE }; /*! \brief set the appearance mode of this widget 'FIDUCIALMODE' adapts the widget for (tracking) fiducial based registration purposes 'LANDMARKMODE' adapts the widget for landmark based registration (source landmarks -> target/reference landmarks) */ void SetWidgetAppearanceMode(WidgetAppearanceMode widgetMode); void SetMultiWidget(QmitkStdMultiWidget* multiWidget); ///< Set the default stdMultiWidget (needed for the PointListwidget) void SetImageFiducialsNode(mitk::DataNode::Pointer imageFiducialsNode); ///< specify data tree node for the image fiducials void SetTrackerFiducialsNode(mitk::DataNode::Pointer trackerFiducialsNode); ///< specify data tree node for the tracker fiducials mitk::DataNode::Pointer GetImageFiducialsNode(); ///< returns data tree node for the image fiducials mitk::DataNode::Pointer GetTrackerFiducialsNode(); ///< returns data tree node for the tracker fiducials void SetQualityDisplayText(QString text); ///< sets specific text on the UI (useful to display FRE/TRE...) bool UseICPIsChecked(); ///< returns true if automatic correspondences search is activated else false void HideStaticRegistrationRadioButton(bool on); ///< show or hide "static Fiducial Registration" radio button in the UI void HideContinousRegistrationRadioButton(bool on); ///< show or hide "hybrid continuous Fiducial Registration" radio button in the UI + void HideFiducialRegistrationGroupBox(); ///< show or hide "Fiducial Registration method" groupbox in the UI, depending on the visibility of the radio buttons void HideUseICPRegistrationCheckbox(bool on); ///< show or hide "Find fiducial correspondences (needs 6+ fiducial pairs)" check box in the UI void HideImageFiducialButton(bool on); ///< show or hide "Add image fiducial" button in the UI void HideTrackingFiducialButton(bool on); ///< show or hide "Add tracking fiducial" button in the UI - - + void AdjustButtonSpacing(); ///< Rearrange spacing when buttons are turned on or off + signals: void AddedTrackingFiducial(); ///< signal if a world instrument position was added to a tracking space fiducial void AddedImageFiducial(); ///< signal if an image position was added to a image space fiducial void PerformFiducialRegistration(); ///< signal if all fiducial were added and registration can be performed void FindFiducialCorrespondences(bool on); ///< signal if automatic correspondences search is toggled + protected slots: + void DisableEditButtonRegistrationImagePoints(bool);///< Disables the edit button of the widget RegistrationImagePoints if the activated variable is true. + void DisableEditButtonRegistrationTrackingPoints(bool);///< Disables the edit button of the widget RegistrationTrackingPoints if the activated variable is true. + protected: void CreateQtPartControl(QWidget *parent); void CreateConnections(); Ui::QmitkFiducialRegistrationWidget* m_Controls; ///< gui widget QmitkStdMultiWidget* m_MultiWidget; mitk::DataNode::Pointer m_ImageFiducialsNode; mitk::DataNode::Pointer m_TrackerFiducialsNode; }; #endif // _QmitkFiducialRegistrationWidget_H_INCLUDED diff --git a/Modules/IGTUI/Qmitk/QmitkFiducialRegistrationWidget.ui b/Modules/IGTUI/Qmitk/QmitkFiducialRegistrationWidget.ui index ada3fda7b6..ebf96a766e 100644 --- a/Modules/IGTUI/Qmitk/QmitkFiducialRegistrationWidget.ui +++ b/Modules/IGTUI/Qmitk/QmitkFiducialRegistrationWidget.ui @@ -1,130 +1,321 @@ QmitkFiducialRegistrationWidget 0 0 - 411 - 358 + 568 + 388 + + + 0 + 0 + + Form - + - - - true - - - static Fiducial Registration - - - true - - - - - - - true - - - hybrid continuous Fiducial Registration - - - false - - - - - + - Select fiducials in image and OR (world) + Fiducial Registration method - - - - - Image fiducials + + + + + true + + + Static + + + true - - - - - - 0 - 0 - - - - - - - - Add image fiducial - - - - - - - - OR fiducials + + + + true + + + Hybrid Continuous + + + false - - - - - - - - &Add current -instrument position - - - - - - - - Execute Fiducial Registration - - - - + + + + 0 + 40 + + + + <html><head/><body><p>Find fiducial correspondences (needs 6+ fiducial pairs)</p></body></html> + - Find fiducial correspondences (needs 6+ fiducial pairs) + Find fiducial + correspondences - - + + + + + 0 + 0 + + + + + 0 + 40 + + - Registration still pending... + Register + Fiducials + + + + + + + 0 + 0 + + + + Image fiducials + + + + 6 + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + 0 + 37 + + + + + 16777215 + 37 + + + + + + + Qt::AlignCenter + + + false + + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 35 + + + + Add image fiducial + + + + + + + + + + + + + + 0 + 0 + + + + Real world fiducials + + + + 6 + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + 0 + 37 + + + + + 16777215 + 37 + + + + + + + Qt::AlignCenter + + + false + + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 35 + + + + &Add current +instrument position + + + + + + + + + + + + + + + + + + 0 + 0 + + + + Status: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + + + Qt::AlignCenter + + + + + + m_RegisterFiducialsBtn + m_UseICPRegistration + m_gbFiducialRegistration + sourceLandmarksGroupBox + targetLandmarksGroupBox + statusLabel + m_RegistrationQualityDisplay + statusLabel QmitkPointListWidget QListWidget
QmitkPointListWidget.h
diff --git a/Modules/ImageExtraction/Testing/mitkExtractDirectedPlaneImageFilterTest.cpp b/Modules/ImageExtraction/Testing/mitkExtractDirectedPlaneImageFilterTest.cpp index 0e77e3f920..e5b1a7710c 100644 --- a/Modules/ImageExtraction/Testing/mitkExtractDirectedPlaneImageFilterTest.cpp +++ b/Modules/ImageExtraction/Testing/mitkExtractDirectedPlaneImageFilterTest.cpp @@ -1,296 +1,296 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkExtractDirectedPlaneImageFilter.h" //#include "mitkStandardFileLocations.h" // //#include //#include //#include //#include //#include // //#include "mitkTestingMacros.h" // //#include // // //class ExtractionTesting{ // //public: // // struct Testcase // { // int number; // std::string name; // std::string imageFilename; // std::string referenceImageFilename; // bool success; // mitk::Geometry2D::Pointer (*GetPlane) (void); // }; // // static void DoTesting(Testcase &testcase) // { // mitk::Image::Pointer image = GetImageToTest(testcase.imageFilename); // if ( image.IsNull){ // testcase.success = false; // return; // } // // /*mitk::Image::Pointer referenceImage = GetImageToTest(testcase.referenceImageFilename); // if ( referenceImage.IsNull){ // testcase.success = false; // return; // } // // mitk::Geometry2D::Pointer directedGeometry2D = testcase.GetPlane(); // if(directedGeometry2D.IsNull){ // testcase.success = false;*/ // } // // //put testing here // //TODO vtkIMageREslice setup // //vtkSmartPointer colorImage = image->GetVtkImageData(); // // vtkSmartPointer imageMapper = vtkSmartPointer::New(); // imageMapper->SetInput(colorImage); // // // vtkSmartPointer imageActor = vtkSmartPointer::New(); // imageActor->SetMapper(imageMapper); // //imageActor->SetPosition(20, 20); // // // Setup renderers // vtkSmartPointer renderer = vtkSmartPointer::New(); // // // 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); // renderer->AddActor(imageActor); // // renderWindow->Render(); // renderWindowInteractor->Start(); // } // // // static std::vector InitializeTestCases() // { // int testcounter = 0; // std::vector tests= // // //#BEGIN setup TestCases // // { // { // ++testcounter, // "TestCoronal", // "image.nrrd", // "coronalReference.nrrd", // false, // &TestCoronal // }, // { // ++testcounter, // "TestSagital", // "image.nrrd", // "sagitalReference.nrrd", // false, // &TestSagital // }, // { // ++testcounter, // "TestCoronal", // "image.nrrd", // "coronalReference.nrrd", // false, // &TestCoronal // }, // { // ++testcounter, // "Test_u_Rotation", // "image.nrrd", // "uRotationReference.nrrd", // false, // &Test_u_Rotation // }, // { // ++testcounter, // "Test_v_Rotation", // "image.nrrd", // "vRotationReference.nrrd", // false, // &Test_v_Rotation // }, // { // ++testcounter, // "TestTwoDirectionalRation", // "image.nrrd", // "twoDirectionalRationReference.nrrd", // false, // &TestTwoDirectionalRotation // }, // { // ++testcounter, // "Test4D", // "image.nrrd", // "twoDirectionalRationReference.nrrd", // false, // &Test4D // }, // { // ++testcounter, // "Test2D", // "coronalReference.nrrd", // "coronalReference.nrrd", // false, // &Test2D // }, // { // ++testcounter, // "Test2D", // NULL, // NULL, // false, // &Test1D // } // // }; // // //#END setup TestCases // // return tests; // } // //protected: // // static mitk::Image::Pointer GetImageToTest(std::string filename){ // //retrieve referenceImage // //// mitk::StandardFileLocations::Pointer locator = mitk::StandardFileLocations::GetInstance(); //// //// const std::string filepath = locator->FindFile(filename, "Modules/MitkExt/Testing/Data"); //// //// if (filepath.empty()) //// { //// return NULL; //// } //// //////TODO read imge from file //// itk::FilenamesContainer file; //// file.push_back( filename ); // mitk::ItkImageFileReader::Pointer reader = mitk::ItkImageFileReader::New(); // reader->SetFileName("C:\home\Pics\Pic3D.nrrd"); // // reader->Update(); // // mitk::Image::Pointer image = reader->GetOutput(); // // return image; // } // // // static mitk::Geometry2D::Pointer TestSagital() // { // // return NULL; // } // // static mitk::Geometry2D::Pointer TestCoronal() // { //return NULL; // } // -// static mitk::Geometry2D::Pointer TestTransversal() +// static mitk::Geometry2D::Pointer TestAxial() // { //return NULL; // } // // static mitk::Geometry2D::Pointer Test_u_Rotation() // { //return NULL; // } // // static mitk::Geometry2D::Pointer Test_v_Rotation() // { //return NULL; // } // // static mitk::Geometry2D::Pointer TestTwoDirectionalRotation() // { //return NULL; // } // // static mitk::Geometry2D::Pointer Test4DImage() // {return NULL; // // } // // static mitk::Geometry2D::Pointer Test2DImage() // { //return NULL; // } // // static mitk::Geometry2D::Pointer Test1DImage() // { //return NULL; // } // //}; // // //** // * Tests for the class "mitkExtractDirectedPlaneImageFilter". // * // * argc and argv are the command line parameters which were passed to // * the ADD_TEST command in the CMakeLists.txt file. For the automatic // * tests, argv is either empty for the simple tests or contains the filename // * of a test image for the image tests (see CMakeLists.txt). // */ //int mitkExtractDirectedPlaneImageFilterTest(int /* argc */, char* /*argv*/[]) //{ // // always start with this! // MITK_TEST_BEGIN("mitkExtractDirectedPlaneImageFilter") // // // mitk::ExtractDirectedPlaneImageFilter::Pointer extractor = mitk::ExtractDirectedPlaneImageFilter::New(); // MITK_TEST_CONDITION_REQUIRED(extractor.IsNotNull(),"Testing instantiation") // // // std::vector allTests = ExtractionTesting::InitializeTestCases(); // // for( int i = 0; i < allTests.size(); i++);{ // // ExtractionTesting::Testcase testCase = allTest[i]; // // ExtractionTesting::DoTesting(testCase); // // MITK_TEST_CONDITION(testCase.success, "Testcase #'" << testCase.number << " " << testCase.name); // } // // // always end with this! // MITK_TEST_END() //} diff --git a/Modules/ImageExtraction/mitkExtractImageFilter.cpp b/Modules/ImageExtraction/mitkExtractImageFilter.cpp index 40cb6bc7ff..bbadbd83b3 100644 --- a/Modules/ImageExtraction/mitkExtractImageFilter.cpp +++ b/Modules/ImageExtraction/mitkExtractImageFilter.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. ===================================================================*/ #include "mitkExtractImageFilter.h" #include "mitkImageCast.h" #include "mitkPlaneGeometry.h" #include "mitkITKImageImport.h" #include "mitkImageTimeSelector.h" #include #include mitk::ExtractImageFilter::ExtractImageFilter() :m_SliceIndex(0), m_SliceDimension(0), m_TimeStep(0) { MITK_WARN << "Class ExtractImageFilter is deprecated! Use ExtractSliceFilter instead."; } mitk::ExtractImageFilter::~ExtractImageFilter() { } void mitk::ExtractImageFilter::GenerateData() { Image::ConstPointer input = ImageToImageFilter::GetInput(0); if ( (input->GetDimension() > 4) || (input->GetDimension() < 2) ) { MITK_ERROR << "mitk::ExtractImageFilter:GenerateData works only with 3D and 3D+t images, sorry." << std::endl; itkExceptionMacro("mitk::ExtractImageFilter works only with 3D and 3D+t images, sorry."); return; } else if (input->GetDimension() == 4) { ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New(); timeSelector->SetInput( input ); timeSelector->SetTimeNr( m_TimeStep ); timeSelector->UpdateLargestPossibleRegion(); input = timeSelector->GetOutput(); } else if (input->GetDimension() == 2) { Image::Pointer resultImage = ImageToImageFilter::GetOutput(); resultImage = const_cast(input.GetPointer()); ImageToImageFilter::SetNthOutput( 0, resultImage ); return; } if ( m_SliceDimension >= input->GetDimension() ) { MITK_ERROR << "mitk::ExtractImageFilter:GenerateData m_SliceDimension == " << m_SliceDimension << " makes no sense with an " << input->GetDimension() << "D image." << std::endl; itkExceptionMacro("This is not a sensible value for m_SliceDimension."); return; } AccessFixedDimensionByItk( input, ItkImageProcessing, 3 ); // set a nice geometry for display and point transformations Geometry3D* inputImageGeometry = ImageToImageFilter::GetInput(0)->GetGeometry(); if (!inputImageGeometry) { MITK_ERROR << "In ExtractImageFilter::ItkImageProcessing: Input image has no geometry!" << std::endl; return; } - PlaneGeometry::PlaneOrientation orientation = PlaneGeometry::Transversal; + PlaneGeometry::PlaneOrientation orientation = PlaneGeometry::Axial; switch ( m_SliceDimension ) { default: case 2: - orientation = PlaneGeometry::Transversal; + orientation = PlaneGeometry::Axial; break; case 1: orientation = PlaneGeometry::Frontal; break; case 0: orientation = PlaneGeometry::Sagittal; break; } PlaneGeometry::Pointer planeGeometry = PlaneGeometry::New(); planeGeometry->InitializeStandardPlane( inputImageGeometry, orientation, (ScalarType)m_SliceIndex, true, false ); Image::Pointer resultImage = ImageToImageFilter::GetOutput(); planeGeometry->ChangeImageGeometryConsideringOriginOffset(true); resultImage->SetGeometry( planeGeometry ); } template void mitk::ExtractImageFilter::ItkImageProcessing( itk::Image* itkImage ) { // use the itk::ExtractImageFilter to get a 2D image typedef itk::Image< TPixel, VImageDimension > ImageType3D; typedef itk::Image< TPixel, VImageDimension-1 > ImageType2D; typename ImageType3D::RegionType inSliceRegion = itkImage->GetLargestPossibleRegion(); inSliceRegion.SetSize( m_SliceDimension, 0 ); typedef itk::ExtractImageFilter ExtractImageFilterType; typename ExtractImageFilterType::Pointer sliceExtractor = ExtractImageFilterType::New(); sliceExtractor->SetInput( itkImage ); inSliceRegion.SetIndex( m_SliceDimension, m_SliceIndex ); sliceExtractor->SetExtractionRegion( inSliceRegion ); // calculate the output sliceExtractor->UpdateLargestPossibleRegion(); typename ImageType2D::Pointer slice = sliceExtractor->GetOutput(); // re-import to MITK Image::Pointer resultImage = ImageToImageFilter::GetOutput(); GrabItkImageMemory(slice, resultImage, NULL, false); } /* * What is the input requested region that is required to produce the output * requested region? By default, the largest possible region is always * required but this is overridden in many subclasses. For instance, for an * image processing filter where an output pixel is a simple function of an * input pixel, the input requested region will be set to the output * requested region. For an image processing filter where an output pixel is * a function of the pixels in a neighborhood of an input pixel, then the * input requested region will need to be larger than the output requested * region (to avoid introducing artificial boundary conditions). This * function should never request an input region that is outside the the * input largest possible region (i.e. implementations of this method should * crop the input requested region at the boundaries of the input largest * possible region). */ void mitk::ExtractImageFilter::GenerateInputRequestedRegion() { Superclass::GenerateInputRequestedRegion(); ImageToImageFilter::InputImagePointer input = const_cast< ImageToImageFilter::InputImageType* > ( this->GetInput() ); Image::Pointer output = this->GetOutput(); if (input->GetDimension() == 2) { input->SetRequestedRegionToLargestPossibleRegion(); return; } Image::RegionType requestedRegion; requestedRegion = output->GetRequestedRegion(); requestedRegion.SetIndex(0, 0); requestedRegion.SetIndex(1, 0); requestedRegion.SetIndex(2, 0); requestedRegion.SetSize(0, input->GetDimension(0)); requestedRegion.SetSize(1, input->GetDimension(1)); requestedRegion.SetSize(2, input->GetDimension(2)); requestedRegion.SetIndex( m_SliceDimension, m_SliceIndex ); // only one slice needed requestedRegion.SetSize( m_SliceDimension, 1 ); input->SetRequestedRegion( &requestedRegion ); } /* * Generate the information decribing the output data. The default * implementation of this method will copy information from the input to the * output. A filter may override this method if its output will have different * information than its input. For instance, a filter that shrinks an image will * need to provide an implementation for this method that changes the spacing of * the pixels. Such filters should call their superclass' implementation of this * method prior to changing the information values they need (i.e. * GenerateOutputInformation() should call * Superclass::GenerateOutputInformation() prior to changing the information. */ void mitk::ExtractImageFilter::GenerateOutputInformation() { Image::Pointer output = this->GetOutput(); Image::ConstPointer input = this->GetInput(); if (input.IsNull()) return; if ( m_SliceDimension >= input->GetDimension() && input->GetDimension() != 2 ) { MITK_ERROR << "mitk::ExtractImageFilter:GenerateOutputInformation m_SliceDimension == " << m_SliceDimension << " makes no sense with an " << input->GetDimension() << "D image." << std::endl; itkExceptionMacro("This is not a sensible value for m_SliceDimension."); return; } unsigned int sliceDimension( m_SliceDimension ); if ( input->GetDimension() == 2) { sliceDimension = 2; } unsigned int tmpDimensions[2]; switch ( sliceDimension ) { default: case 2: - // orientation = PlaneGeometry::Transversal; + // orientation = PlaneGeometry::Axial; tmpDimensions[0] = input->GetDimension(0); tmpDimensions[1] = input->GetDimension(1); break; case 1: // orientation = PlaneGeometry::Frontal; tmpDimensions[0] = input->GetDimension(0); tmpDimensions[1] = input->GetDimension(2); break; case 0: // orientation = PlaneGeometry::Sagittal; tmpDimensions[0] = input->GetDimension(1); tmpDimensions[1] = input->GetDimension(2); break; } output->Initialize(input->GetPixelType(), 2, tmpDimensions, 1 /*input->GetNumberOfChannels()*/); // initialize the spacing of the output /* Vector3D spacing = input->GetSlicedGeometry()->GetSpacing(); if(input->GetDimension()>=2) spacing[2]=spacing[1]; else spacing[2] = 1.0; output->GetSlicedGeometry()->SetSpacing(spacing); */ output->SetPropertyList(input->GetPropertyList()->Clone()); } diff --git a/Modules/ImageExtraction/mitkExtractImageFilter.h b/Modules/ImageExtraction/mitkExtractImageFilter.h index 8196563b7f..27c716b705 100644 --- a/Modules/ImageExtraction/mitkExtractImageFilter.h +++ b/Modules/ImageExtraction/mitkExtractImageFilter.h @@ -1,101 +1,101 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 mitkExtractImageFilter_h_Included #define mitkExtractImageFilter_h_Included #include "mitkCommon.h" #include "ImageExtractionExports.h" #include "mitkImageToImageFilter.h" #include "itkImage.h" namespace mitk { /** \deprecated This class is deprecated. Use mitk::ExtractSliceFilter instead. \sa ExtractSliceFilter \brief Extracts a 2D slice from a 3D image. \sa SegTool2D \sa OverwriteSliceImageFilter \ingroup Process \ingroup ToolManagerEtAl There is a separate page describing the general design of QmitkInteractiveSegmentation: \ref QmitkSegmentationTechnicalPage This class takes a 3D mitk::Image as input and tries to extract one slice from it. - Two parameters determine which slice is extracted: the "slice dimension" is that one, which is constant for all points in the plane, e.g. transversal would mean 2. + Two parameters determine which slice is extracted: the "slice dimension" is that one, which is constant for all points in the plane, e.g. axial would mean 2. The "slice index" is the slice index in the image direction you specified with "affected dimension". Indices count from zero. Output will not be set if there was a problem extracting the desired slice. Last contributor: $Author$ */ class ImageExtraction_EXPORT ExtractImageFilter : public ImageToImageFilter { public: mitkClassMacro(ExtractImageFilter, ImageToImageFilter); itkNewMacro(ExtractImageFilter); /** \brief Which slice to extract (first one has index 0). */ itkSetMacro(SliceIndex, unsigned int); itkGetConstMacro(SliceIndex, unsigned int); /** \brief The orientation of the slice to be extracted. - \a Parameter SliceDimension Number of the dimension which is constant for all pixels of the desired slice (e.g. 2 for transversal) + \a Parameter SliceDimension Number of the dimension which is constant for all pixels of the desired slice (e.g. 2 for axial) */ itkSetMacro(SliceDimension, unsigned int); itkGetConstMacro(SliceDimension, unsigned int); /** \brief Time step of the image to be extracted. */ itkSetMacro(TimeStep, unsigned int); itkGetConstMacro(TimeStep, unsigned int); protected: ExtractImageFilter(); // purposely hidden virtual ~ExtractImageFilter(); virtual void GenerateOutputInformation(); virtual void GenerateInputRequestedRegion(); virtual void GenerateData(); template void ItkImageProcessing( itk::Image* image ); unsigned int m_SliceIndex; unsigned int m_SliceDimension; unsigned int m_TimeStep; }; } // namespace #endif diff --git a/Modules/ImageStatistics/mitkImageStatisticsCalculator.h b/Modules/ImageStatistics/mitkImageStatisticsCalculator.h index ab82e87c96..8ee23bc246 100644 --- a/Modules/ImageStatistics/mitkImageStatisticsCalculator.h +++ b/Modules/ImageStatistics/mitkImageStatisticsCalculator.h @@ -1,320 +1,320 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 (transversal, sagittal, coronal). Planar figures on arbitrary + * 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; 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; }; } #endif // #define _MITK_IMAGESTATISTICSCALCULATOR_H diff --git a/Modules/InputDevices/WiiMote/mitkWiiMoteVtkCameraController.cpp b/Modules/InputDevices/WiiMote/mitkWiiMoteVtkCameraController.cpp index 6fb89db473..e1423338da 100644 --- a/Modules/InputDevices/WiiMote/mitkWiiMoteVtkCameraController.cpp +++ b/Modules/InputDevices/WiiMote/mitkWiiMoteVtkCameraController.cpp @@ -1,437 +1,437 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkWiiMoteVtkCameraController.h" #include "mitkGlobalInteraction.h" #include "mitkInteractionConst.h" #include "mitkStateEvent.h" #include "mitkSurface.h" #include "mitkVtkPropRenderer.h" #include "vtkRenderer.h" #include "vtkCamera.h" // factor derived from the asumption that // the field of view in the virtual reality // is limited to an angle of 45° const double CALIBRATIONFACTORY = 0.125; const double CALIBRATIONFACTORX = 0.125; // max resolution of the cam 1024x768 const double XMIN = 0; const double XMAX = 1024; const double YMIN = 0; const double YMAX = 768; // initial scroll value const int UPDATEFREQUENCY = 5; mitk::WiiMoteVtkCameraController::WiiMoteVtkCameraController() : CameraController("WiiMoteHeadtracking") , m_ClippingRangeIsSet(false) , m_SensitivityXMIN (XMAX) , m_SensitivityXMAX (XMIN) , m_SensitivityYMIN (YMAX) , m_SensitivityYMAX (YMIN) , m_SensitivityX (0) , m_SensitivityY (0) , m_Calibrated (false) -, m_TransversalBR( NULL ) +, m_AxialBR( NULL ) , m_InitialScrollValue( 0 ) , m_UpdateFrequency( 0 ) , m_CurrentElevationAngle ( 0 ) , m_CurrentAzimuthAngle ( 0 ) { CONNECT_ACTION(mitk::AcONWIIMOTEINPUT, OnWiiMoteInput); CONNECT_ACTION(mitk::AcRESETVIEW, ResetView); CONNECT_ACTION(mitk::AC_INIT, InitCalibration); CONNECT_ACTION(mitk::AcCHECKPOINT, Calibration); CONNECT_ACTION(mitk::AcFINISH, FinishCalibration); } mitk::WiiMoteVtkCameraController::~WiiMoteVtkCameraController() { } bool mitk::WiiMoteVtkCameraController::OnWiiMoteInput(mitk::Action* a, const mitk::StateEvent* e) { //only if 3D rendering const mitk::BaseRenderer* br = mitk::GlobalInteraction::GetInstance()->GetFocus(); this->SetRenderer( br ); mitk::BaseRenderer::MapperSlotId id = ((mitk::BaseRenderer*)(br))->GetMapperID(); if (id != mitk::BaseRenderer::Standard3D) return true; //only if focused by the FocusManager if (this->GetRenderer() != mitk::GlobalInteraction::GetInstance()->GetFocus()) return true; //pre-checking for safety vtkRenderer* vtkRenderer = ((mitk::VtkPropRenderer*)this->GetRenderer())->GetVtkRenderer(); if (vtkRenderer == NULL) return false; vtkCamera* vtkCam = (vtkCamera*)vtkRenderer->GetActiveCamera(); //TODO check the range if(!m_ClippingRangeIsSet) vtkCam->SetClippingRange(0.1, 1000); const mitk::WiiMoteIREvent* wiiMoteIREvent; if(!(wiiMoteIREvent = dynamic_cast(e->GetEvent()))) { MITK_ERROR << "Not a WiiMote Event!"; return false; } // get data from the Wiimote mitk::Vector2D tempMovementVector(wiiMoteIREvent->GetMovementVector()); float inputCoordinates[3] = {tempMovementVector[0],tempMovementVector[1], 0}; mitk::Vector3D movementVector(inputCoordinates); //compute current sensitivity according to current BoundingBox of the whole scene! double sceneSensivity = 1.0; mitk::DataStorage* ds = m_Renderer->GetDataStorage(); mitk::BoundingBox::Pointer bb = ds->ComputeBoundingBox(); mitk::BoundingBox::AccumulateType length = bb->GetDiagonalLength2(); if (length > 0.00001)//if length not zero sceneSensivity *= 100.0 / (sqrt(length)) ; //sensivity to adapt to mitk speed movementVector *= sceneSensivity; if(!m_Calibrated) { movementVector[0] *= CALIBRATIONFACTORX; movementVector[1] *= CALIBRATIONFACTORY; } else { movementVector[0] *= m_SensitivityX; movementVector[1] *= m_SensitivityY; } // inverts y direction to simulate a 3D View // x direction is already inverted movementVector[1] *= -1; m_CurrentElevationAngle += movementVector[1]; MITK_INFO << "Elevation angle: " << m_CurrentElevationAngle; // avoids flipping of the surface // through the elevation function if(m_CurrentElevationAngle < 70 && m_CurrentElevationAngle > -70) { vtkCam->Elevation((double)movementVector[1]); } else if( m_CurrentElevationAngle > 70 ) { m_CurrentElevationAngle = 70; } else if( m_CurrentElevationAngle < -70 ) { m_CurrentElevationAngle = -70; } m_CurrentAzimuthAngle += movementVector[0]; // avoids spinning of the surface if(m_CurrentAzimuthAngle < 70 && m_CurrentAzimuthAngle > -70) { vtkCam->Azimuth((double)movementVector[0]); } else if( m_CurrentAzimuthAngle > 70 ) { m_CurrentAzimuthAngle = 70; } else if( m_CurrentAzimuthAngle < -70 ) { m_CurrentAzimuthAngle = -70; } ////compute the global space coordinates from the relative mouse coordinate ////first we need the position of the camera //mitk::Vector3D camPosition; //double camPositionTemp[3]; //vtkCam->GetPosition(camPositionTemp); //camPosition[0] = camPositionTemp[0]; camPosition[1] = camPositionTemp[1]; camPosition[2] = camPositionTemp[2]; ////then the upvector of the camera //mitk::Vector3D upCamVector; //double upCamTemp[3]; //vtkCam->GetViewUp(upCamTemp); //upCamVector[0] = upCamTemp[0]; upCamVector[1] = upCamTemp[1]; upCamVector[2] = upCamTemp[2]; //upCamVector.Normalize(); ////then the vector to which the camera is heading at (focalpoint) //mitk::Vector3D focalPoint; //double focalPointTemp[3]; //vtkCam->GetFocalPoint(focalPointTemp); //focalPoint[0] = focalPointTemp[0]; focalPoint[1] = focalPointTemp[1]; focalPoint[2] = focalPointTemp[2]; //mitk::Vector3D focalVector; //focalVector = focalPoint - camPosition; //focalVector.Normalize(); ////orthogonal vector to focalVector and upCamVector //mitk::Vector3D crossVector; //crossVector = CrossProduct(upCamVector, focalVector); //crossVector.Normalize(); ////now we have the current orientation so we can adapt it according to the current information, which we got from the Wiimote ////new position of the camera: ////left/right = camPosition + crossVector * movementVector[0]; //mitk::Vector3D vectorX = crossVector * -movementVector[0]; //changes the magnitude, not the direction //double nextCamPosition[3]; //nextCamPosition[0] = camPosition[0] + vectorX[0]; //nextCamPosition[1] = camPosition[1] + vectorX[1]; //nextCamPosition[2] = camPosition[2] + vectorX[2]; ////now the up/down movement //mitk::Vector3D vectorY = upCamVector * movementVector[1]; //changes the magnitude, not the direction //nextCamPosition[0] += vectorY[0]; //nextCamPosition[1] += vectorY[1]; //nextCamPosition[2] += vectorY[2]; ////forward/backward movement //mitk::Vector3D vectorZ = focalVector * -movementVector[2]; //changes the magnitude, not the direction //nextCamPosition[0] += vectorZ[0]; //nextCamPosition[1] += vectorZ[1]; //nextCamPosition[2] += vectorZ[2]; ////set the next position //double nextPosition[3]; //nextPosition[0] = nextCamPosition[0]; nextPosition[1] = nextCamPosition[1]; nextPosition[2] = nextCamPosition[2]; //vtkCam->SetPosition(nextPosition); ////adapt the focal point the same way //double currentFocalPoint[3], nextFocalPoint[3]; //vtkCam->GetFocalPoint(currentFocalPoint); //nextFocalPoint[0] = currentFocalPoint[0] + vectorX[0] + vectorY[0] + vectorZ[0]; //nextFocalPoint[1] = currentFocalPoint[1] + vectorX[1] + vectorY[1] + vectorZ[1]; ; //nextFocalPoint[2] = currentFocalPoint[2] + vectorX[2] + vectorY[2] + vectorZ[2]; //vtkCam->SetFocalPoint(nextFocalPoint); //Reset the camera clipping range based on the bounds of the visible actors. //This ensures that no props are cut off vtkRenderer->ResetCameraClippingRange(); - // ------------ transversal scrolling ----------------------- + // ------------ axial scrolling ----------------------- // get renderer const RenderingManager::RenderWindowVector& renderWindows = RenderingManager::GetInstance()->GetAllRegisteredRenderWindows(); for ( RenderingManager::RenderWindowVector::const_iterator iter = renderWindows.begin(); iter != renderWindows.end(); ++iter ) { if ( mitk::BaseRenderer::GetInstance((*iter))->GetMapperID() == BaseRenderer::Standard2D ) { if( mitk::BaseRenderer::GetInstance((*iter))->GetSliceNavigationController() - ->GetViewDirection() == mitk::SliceNavigationController::ViewDirection::Transversal ) + ->GetViewDirection() == mitk::SliceNavigationController::ViewDirection::Axial ) { - m_TransversalBR = mitk::BaseRenderer::GetInstance((*iter)); + m_AxialBR = mitk::BaseRenderer::GetInstance((*iter)); } } } SlicedGeometry3D* slicedWorldGeometry = dynamic_cast - (m_TransversalBR->GetSliceNavigationController()->GetCreatedWorldGeometry()->GetGeometry3D(m_TimeStep)); + (m_AxialBR->GetSliceNavigationController()->GetCreatedWorldGeometry()->GetGeometry3D(m_TimeStep)); int numberOfSlices = slicedWorldGeometry->GetSlices(); - const mitk::Geometry2D* currentGeo = m_TransversalBR->GetCurrentWorldGeometry2D(); + const mitk::Geometry2D* currentGeo = m_AxialBR->GetCurrentWorldGeometry2D(); mitk::Point3D origin = currentGeo->GetOrigin(); int sliceValue = wiiMoteIREvent->GetSliceNavigationValue(); if(sliceValue > 0) { if(m_InitialScrollValue == 0) { m_InitialScrollValue = sliceValue; } else if(std::abs(m_InitialScrollValue - sliceValue) > 10) { if(m_UpdateFrequency == UPDATEFREQUENCY /* 5 */) { int steppingValue; int currentPos = origin.GetElement(2); if(sliceValue < m_InitialScrollValue) { /* steppingValue = m_InitialScrollValue - sliceValue; */ steppingValue = currentGeo->GetSpacing()[2]; origin.SetElement(2, currentPos-steppingValue); } else if(sliceValue > m_InitialScrollValue) { /* steppingValue = sliceValue - m_InitialScrollValue;*/ steppingValue = currentGeo->GetSpacing()[2]; origin.SetElement(2, currentPos+steppingValue); } m_UpdateFrequency = 0; } else { m_UpdateFrequency++; } } } else { m_InitialScrollValue = 0; } - m_TransversalBR->GetSliceNavigationController()->SelectSliceByPoint(origin); + m_AxialBR->GetSliceNavigationController()->SelectSliceByPoint(origin); mitk::RenderingManager::GetInstance() ->RequestUpdateAll(); return true; } bool mitk::WiiMoteVtkCameraController::ResetView(mitk::Action *a, const mitk::StateEvent *e) { //reset the camera, so that the objects shown in the scene can be seen. const mitk::VtkPropRenderer* glRenderer = dynamic_cast(m_Renderer); if (glRenderer) { vtkRenderer* vtkRenderer = glRenderer->GetVtkRenderer(); mitk::DataStorage* ds = m_Renderer->GetDataStorage(); if (ds == NULL) return false; mitk::BoundingBox::Pointer bb = ds->ComputeBoundingBox(); mitk::Point3D middle = bb->GetCenter(); vtkRenderer->GetActiveCamera()->SetFocalPoint(middle[0],middle[1],middle[2]); vtkRenderer->ResetCamera(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); return true; } return false; } bool mitk::WiiMoteVtkCameraController::InitCalibration(mitk::Action *a, const mitk::StateEvent *e) { // to initialize the values with its counterpart // is essential. The reason is that through calibration // the values will increase or decrease depending on // semantics: // the max will try to reach the XMAX (from XMIN) // the min will try to reach the XMIN (from XMAX) // i.e. in the calibration process they move // into their opposite direction to create an // intervall that defines the boundaries m_SensitivityX = 0; m_SensitivityXMAX = XMIN; m_SensitivityXMIN = XMAX; m_SensitivityY = 0; m_SensitivityYMAX = YMIN; m_SensitivityYMIN = YMAX; this->m_Calibrated = false; MITK_INFO << "Starting calibration - other wiimote functionality deactivated."; return true; } bool mitk::WiiMoteVtkCameraController::Calibration(mitk::Action *a, const mitk::StateEvent *e) { const mitk::WiiMoteCalibrationEvent* WiiMoteCalibrationEvent; if(!(WiiMoteCalibrationEvent = dynamic_cast(e->GetEvent()))) { MITK_ERROR << "Not a WiiMote Event!"; return false; } double tempX(WiiMoteCalibrationEvent->GetXCoordinate()); double tempY(WiiMoteCalibrationEvent->GetYCoordinate()); MITK_INFO << "Raw X: " << tempX; MITK_INFO << "Raw Y: " << tempY; // checks first whether the incoming data is valid if(XMIN < tempX && tempX < XMAX) { if(tempX > m_SensitivityXMAX) { m_SensitivityXMAX = tempX; } else if(tempX < m_SensitivityXMIN) { m_SensitivityXMIN = tempX; } } if(YMIN < tempY && tempY < YMAX) { if(tempY > m_SensitivityYMAX) { m_SensitivityYMAX = tempY; } else if(tempY < m_SensitivityYMIN) { m_SensitivityYMIN = tempY; } } return true; } bool mitk::WiiMoteVtkCameraController::FinishCalibration(mitk::Action *a, const mitk::StateEvent *e) { // checks if one of the properties was not set at all during the calibration // should that happen, the computation will not be executed if( m_SensitivityXMAX != XMIN && m_SensitivityXMIN != XMAX && m_SensitivityYMAX != YMIN && m_SensitivityYMIN != YMAX ) { // computation of the sensitivity out of the calibration data m_SensitivityX = XMAX / (m_SensitivityXMAX - m_SensitivityXMIN); m_SensitivityX *= CALIBRATIONFACTORX; m_SensitivityY = YMAX / (m_SensitivityYMAX - m_SensitivityYMIN); m_SensitivityY *= CALIBRATIONFACTORY; this->m_Calibrated = true; } if(!m_Calibrated) { MITK_INFO << "Calibration was unsuccesful - " << "please repeat the process and move in all directions!"; } else { MITK_INFO << "Ending calibration - other wiimote functionality reactivated."; } return m_Calibrated; } diff --git a/Modules/InputDevices/WiiMote/mitkWiiMoteVtkCameraController.h b/Modules/InputDevices/WiiMote/mitkWiiMoteVtkCameraController.h index 38a132c555..4a42b2f6fd 100644 --- a/Modules/InputDevices/WiiMote/mitkWiiMoteVtkCameraController.h +++ b/Modules/InputDevices/WiiMote/mitkWiiMoteVtkCameraController.h @@ -1,76 +1,76 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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_WIIMOTEVTKCAMERACONTROLLER_H #define MITK_WIIMOTEVTKCAMERACONTROLLER_H // export #include "mitkWiiMoteExports.h" // mitk #include "mitkCameraController.h" #include "mitkAction.h" #include "mitkEvent.h" #include "mitkBaseRenderer.h" #include "mitkWiiMoteIREvent.h" #include "mitkWiiMoteCalibrationEvent.h" namespace mitk { class mitkWiiMote_EXPORT WiiMoteVtkCameraController : public CameraController { public: //SmartPointer Macros mitkClassMacro(WiiMoteVtkCameraController, CameraController); itkNewMacro(Self); protected: WiiMoteVtkCameraController(); ~WiiMoteVtkCameraController(); private: // head tracking bool OnWiiMoteInput(mitk::Action* a, const mitk::StateEvent* e); bool ResetView(mitk::Action* a, const mitk::StateEvent* e); bool m_ClippingRangeIsSet; double m_CurrentElevationAngle; double m_CurrentAzimuthAngle; // calibration bool m_Calibrated; double m_SensitivityXMAX; double m_SensitivityXMIN; double m_SensitivityYMAX; double m_SensitivityYMIN; double m_SensitivityX; double m_SensitivityY; bool InitCalibration(mitk::Action* a, const mitk::StateEvent* e); bool Calibration(mitk::Action* a, const mitk::StateEvent* e); bool FinishCalibration(mitk::Action* a, const mitk::StateEvent* e); // slice scrolling - mitk::BaseRenderer::Pointer m_TransversalBR; + mitk::BaseRenderer::Pointer m_AxialBR; double m_InitialScrollValue; int m_UpdateFrequency; }; // end class } // end namespace mitk #endif // MITK_WIIMOTEVTKCAMERACONTROLLER_H diff --git a/Modules/MitkExt/Algorithms/mitkPointSetToCurvedGeometryFilter.cpp b/Modules/MitkExt/Algorithms/mitkPointSetToCurvedGeometryFilter.cpp index fd550eab36..5a941f0a9c 100644 --- a/Modules/MitkExt/Algorithms/mitkPointSetToCurvedGeometryFilter.cpp +++ b/Modules/MitkExt/Algorithms/mitkPointSetToCurvedGeometryFilter.cpp @@ -1,186 +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 "mitkPointSetToCurvedGeometryFilter.h" #include "mitkThinPlateSplineCurvedGeometry.h" #include "mitkPlaneGeometry.h" #include "mitkImage.h" #include "mitkTimeSlicedGeometry.h" #include "mitkDataNode.h" #include "mitkGeometryData.h" #include "mitkGeometry2DData.h" #include "mitkProperties.h" #include "itkMesh.h" #include "itkPointSet.h" mitk::PointSetToCurvedGeometryFilter::PointSetToCurvedGeometryFilter() { m_ProjectionMode = YZPlane; m_PCAPlaneCalculator = mitk::PlaneFit::New(); m_ImageToBeMapped = NULL; m_Sigma = 1000; mitk::Geometry2DData::Pointer output = static_cast ( this->MakeOutput ( 0 ).GetPointer() ); output->Initialize(); Superclass::SetNumberOfRequiredOutputs ( 1 ); Superclass::SetNthOutput ( 0, output.GetPointer() ); } mitk::PointSetToCurvedGeometryFilter::~PointSetToCurvedGeometryFilter() {} void mitk::PointSetToCurvedGeometryFilter::GenerateOutputInformation() { mitk::PointSet::ConstPointer input = this->GetInput(); mitk::Geometry2DData::Pointer output = dynamic_cast ( this->GetOutput() ); if ( input.IsNull() ) itkGenericExceptionMacro ( "Input point set is NULL!" ); if ( input->GetTimeSlicedGeometry()->GetTimeSteps() != 1 ) itkWarningMacro ( "More than one time step is not yet supported!" ); if ( output.IsNull() ) itkGenericExceptionMacro ( "Output is NULL!" ); if ( m_ImageToBeMapped.IsNull() ) itkGenericExceptionMacro ( "Image to be mapped is NULL!" ); bool update = false; if ( output->GetGeometry() == NULL || output->GetGeometry2D() == NULL || output->GetTimeSlicedGeometry() == NULL ) update = true; if ( ( ! update ) && ( output->GetTimeSlicedGeometry()->GetTimeSteps() != input->GetTimeSlicedGeometry()->GetTimeSteps() ) ) update = true; if ( update ) { mitk::ThinPlateSplineCurvedGeometry::Pointer curvedGeometry = mitk::ThinPlateSplineCurvedGeometry::New(); output->SetGeometry(curvedGeometry); /* mitk::TimeSlicedGeometry::Pointer timeGeometry = mitk::TimeSlicedGeometry::New(); mitk::ThinPlateSplineCurvedGeometry::Pointer curvedGeometry = mitk::ThinPlateSplineCurvedGeometry::New(); timeGeometry->InitializeEvenlyTimed ( curvedGeometry, input->GetPointSetSeriesSize() ); for ( unsigned int t = 1; t < input->GetPointSetSeriesSize(); ++t ) { mitk::ThinPlateSplineCurvedGeometry::Pointer tmpCurvedGeometry = mitk::ThinPlateSplineCurvedGeometry::New(); timeGeometry->SetGeometry3D ( tmpCurvedGeometry.GetPointer(), t ); } output->SetGeometry ( timeGeometry ); output->SetGeometry2D ( curvedGeometry ); // @FIXME SetGeometry2D of mitk::Geometry2DData reinitializes the TimeSlicedGeometry to 1 time step */ } } void mitk::PointSetToCurvedGeometryFilter::GenerateData() { mitk::PointSet::ConstPointer input = this->GetInput(); mitk::GeometryData::Pointer output = this->GetOutput(); // // check preconditions // if ( input.IsNull() ) itkGenericExceptionMacro ( "Input point set is NULL!" ); if ( output.IsNull() ) itkGenericExceptionMacro ( "output geometry data is NULL!" ); if ( output->GetTimeSlicedGeometry() == NULL ) itkGenericExceptionMacro ( "Output time sliced geometry is NULL!" ); if ( output->GetTimeSlicedGeometry()->GetGeometry3D ( 0 ) == NULL ) itkGenericExceptionMacro ( "Output geometry3d is NULL!" ); mitk::ThinPlateSplineCurvedGeometry::Pointer curvedGeometry = dynamic_cast ( output->GetTimeSlicedGeometry()->GetGeometry3D ( 0 ) ); if ( curvedGeometry.IsNull() ) itkGenericExceptionMacro ( "Output geometry3d is not an instance of mitk::ThinPlateSPlineCurvedGeometry!" ); if ( m_ImageToBeMapped.IsNull() ) itkGenericExceptionMacro ( "Image to be mapped is NULL!" ); // // initialize members if needed // if ( m_XYPlane.IsNull() || m_XZPlane.IsNull() || m_YZPlane.IsNull() ) { m_ImageToBeMapped->UpdateOutputInformation(); const mitk::Geometry3D* imageGeometry = m_ImageToBeMapped->GetUpdatedGeometry(); imageGeometry = m_ImageToBeMapped->GetUpdatedGeometry(); m_XYPlane = mitk::PlaneGeometry::New(); m_XZPlane = mitk::PlaneGeometry::New(); m_YZPlane = mitk::PlaneGeometry::New(); - m_XYPlane->InitializeStandardPlane ( imageGeometry, mitk::PlaneGeometry::Transversal ); + m_XYPlane->InitializeStandardPlane ( imageGeometry, mitk::PlaneGeometry::Axial ); m_YZPlane->InitializeStandardPlane ( imageGeometry, mitk::PlaneGeometry::Sagittal ); m_XZPlane->InitializeStandardPlane ( imageGeometry, mitk::PlaneGeometry::Frontal ); } if ( m_PlaneLandmarkProjector.IsNull() ) { m_PlaneLandmarkProjector = mitk::PlaneLandmarkProjector::New(); m_SphereLandmarkProjector = mitk::SphereLandmarkProjector::New(); } // // set up geometry according to the current settings // if ( m_ProjectionMode == Sphere ) { curvedGeometry->SetLandmarkProjector ( m_SphereLandmarkProjector ); } else { if ( m_ProjectionMode == XYPlane ) m_PlaneLandmarkProjector->SetProjectionPlane ( m_XYPlane ); else if ( m_ProjectionMode == XZPlane ) m_PlaneLandmarkProjector->SetProjectionPlane ( m_XZPlane ); else if ( m_ProjectionMode == YZPlane ) m_PlaneLandmarkProjector->SetProjectionPlane ( m_YZPlane ); else if ( m_ProjectionMode == PCAPlane ) { itkExceptionMacro ( "PCAPlane not yet implemented!" ); m_PCAPlaneCalculator->SetInput ( input ); m_PCAPlaneCalculator->Update(); m_PlaneLandmarkProjector->SetProjectionPlane ( dynamic_cast ( m_PCAPlaneCalculator->GetOutput() ) ); } else itkExceptionMacro ( "Unknown projection mode" ); curvedGeometry->SetLandmarkProjector ( m_PlaneLandmarkProjector ); } //curvedGeometry->SetReferenceGeometry( m_ImageToBeMapped->GetGeometry() ); curvedGeometry->SetTargetLandmarks ( input->GetPointSet ( 0 )->GetPoints() ); curvedGeometry->SetSigma ( m_Sigma ); curvedGeometry->ComputeGeometry(); curvedGeometry->SetOversampling ( 1.0 ); } mitk::GeometryDataSource::DataObjectPointer mitk::PointSetToCurvedGeometryFilter::MakeOutput ( unsigned int ) { return static_cast ( mitk::Geometry2DData::New().GetPointer() ); } void mitk::PointSetToCurvedGeometryFilter::SetDefaultCurvedGeometryProperties ( mitk::DataNode* node ) { if ( node == NULL ) { itkGenericOutputMacro ( "Warning: node is NULL!" ); return; } node->SetIntProperty ( "xresolution", 50 ); node->SetIntProperty ( "yresolution", 50 ); node->SetProperty ( "name", mitk::StringProperty::New ( "Curved Plane" ) ); // exclude extent of this plane when calculating DataStorage bounding box node->SetProperty ( "includeInBoundingBox", mitk::BoolProperty::New ( false ) ); } diff --git a/Modules/MitkExt/Controllers/mitkToolManager.cpp b/Modules/MitkExt/Controllers/mitkToolManager.cpp index 70fccfbc7f..30854299e1 100644 --- a/Modules/MitkExt/Controllers/mitkToolManager.cpp +++ b/Modules/MitkExt/Controllers/mitkToolManager.cpp @@ -1,495 +1,528 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 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); + 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); } } } 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/Controllers/mitkToolManager.h b/Modules/MitkExt/Controllers/mitkToolManager.h index 922895efdc..106ca7bb2c 100644 --- a/Modules/MitkExt/Controllers/mitkToolManager.h +++ b/Modules/MitkExt/Controllers/mitkToolManager.h @@ -1,286 +1,290 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 mitkToolManager_h_Included #define mitkToolManager_h_Included #include "mitkTool.h" #include "MitkExtExports.h" #include "mitkDataNode.h" #include "mitkDataStorage.h" #include "mitkWeakPointer.h" #pragma GCC visibility push(default) #include #pragma GCC visibility pop #include #include namespace mitk { class Image; class PlaneGeometry; /** \brief Manages and coordinates instances of mitk::Tool. \sa QmitkToolSelectionBox \sa QmitkToolReferenceDataSelectionBox \sa QmitkToolWorkingDataSelectionBox \sa Tool \sa QmitkSegmentationView \ingroup Interaction \ingroup ToolManagerEtAl There is a separate page describing the general design of QmitkSegmentationView: \ref QmitkSegmentationTechnicalPage This class creates and manages several instances of mitk::Tool. \li ToolManager creates instances of mitk::Tool by asking the itk::ObjectFactory to list all known implementations of mitk::Tool. As a result, one has to implement both a subclass of mitk::Tool and a matching subclass of itk::ObjectFactoryBase that is registered to the top-level itk::ObjectFactory. For an example, see mitkContourToolFactory.h. (this limitiation of one-class-one-factory is due to the implementation of itk::ObjectFactory). In MITK, the right place to register the factories to itk::ObjectFactory is the mitk::QMCoreObjectFactory or mitk::SBCoreObjectFactory. \li One (and only one - or none at all) of the registered tools can be activated using ActivateTool. This tool is registered to mitk::GlobalInteraction as a listener and will receive all mouse clicks and keyboard strokes that get into the MITK event mechanism. Tools are automatically unregistered from GlobalInteraction when no clients are registered to ToolManager (see RegisterClient()). \li ToolManager knows a set of "reference" DataNodes and a set of "working" DataNodes. The first application are segmentation tools, where the reference is the original image and the working data the (kind of) binary segmentation. However, ToolManager is implemented more generally, so that there could be other tools that work, e.g., with surfaces. \li Any "user/client" of ToolManager, i.e. every functionality that wants to use a tool, should call RegisterClient when the tools should be active. ToolManager keeps track of how many clients want it to be used, and when this count reaches zero, it unregistes the active Tool from GlobalInteraction. In "normal" settings, the functionality does not need to care about that if it uses a QmitkToolSelectionBox, which does exactly that when it is enabled/disabled. \li There is a set of events that are sent by ToolManager. At the moment these are TODO update documentation: - mitk::ToolReferenceDataChangedEvent whenever somebody calls SetReferenceData. Most of the time this actually means that the data has changed, but there might be cases where the same data is passed to SetReferenceData a second time, so don't rely on the assumption that something actually changed. - mitk::ToolSelectedEvent is sent when a (truly) different tool was activated. In reaction to this event you can ask for the active Tool using GetActiveTool or GetActiveToolID (where NULL or -1 indicate that NO tool is active at the moment). Design descisions: \li Not a singleton, because there could be two functionalities using tools, each one with different reference/working data. $Author$ */ class MitkExt_EXPORT ToolManager : public itk::Object { public: typedef std::vector ToolVectorType; typedef std::vector ToolVectorTypeConst; typedef std::vector DataVectorType; // has to be observed for delete events! typedef std::map NodeTagMapType; Message<> NodePropertiesChanged; Message<> NewNodesGenerated; Message1 NewNodeObjectsGenerated; Message<> ActiveToolChanged; Message<> ReferenceDataChanged; Message<> WorkingDataChanged; Message<> RoiDataChanged; Message1 ToolErrorMessage; Message1 GeneralToolMessage; mitkClassMacro(ToolManager, itk::Object); mitkNewMacro1Param(ToolManager, DataStorage*); /** \brief Gives you a list of all tools. This is const on purpose. */ const ToolVectorTypeConst GetTools(); int GetToolID( const Tool* tool ); /* \param id The tool of interest. Counting starts with 0. */ Tool* GetToolById(int id); /** \param id The tool to activate. Provide -1 for disabling any tools. Counting starts with 0. + Registeres a listner for NodeRemoved event at DataStorage (see mitk::ToolManager::OnNodeRemoved). */ bool ActivateTool(int id); template int GetToolIdByToolType() { int id = 0; for ( ToolVectorType::iterator iter = m_Tools.begin(); iter != m_Tools.end(); ++iter, ++id ) { if ( dynamic_cast(iter->GetPointer()) ) { return id; } } return -1; } /** \return -1 for "No tool is active" */ int GetActiveToolID(); /** \return NULL for "No tool is active" */ Tool* GetActiveTool(); /* \brief Set a list of data/images as reference objects. */ void SetReferenceData(DataVectorType); /* \brief Set single data item/image as reference object. */ void SetReferenceData(DataNode*); /* \brief Set a list of data/images as working objects. */ void SetWorkingData(DataVectorType); /* \brief Set single data item/image as working object. */ void SetWorkingData(DataNode*); /* \brief Set a list of data/images as roi objects. */ void SetRoiData(DataVectorType); /* \brief Set a single data item/image as roi object. */ void SetRoiData(DataNode*); /* \brief Get the list of reference data. */ DataVectorType GetReferenceData(); /* \brief Get the current reference data. \warning If there is a list of items, this method will only return the first list item. */ DataNode* GetReferenceData(int); /* \brief Get the list of working data. */ DataVectorType GetWorkingData(); /* \brief Get the current working data. \warning If there is a list of items, this method will only return the first list item. */ DataNode* GetWorkingData(int); /* \brief Get the current roi data */ DataVectorType GetRoiData(); /* \brief Get the roi data at position idx */ DataNode* GetRoiData(int idx); DataStorage* GetDataStorage(); void SetDataStorage(DataStorage& storage); /* \brief Tell that someone is using tools. GUI elements should call this when they become active. This method increases an internal "client count". Tools are only registered to GlobalInteraction when this count is greater than 0. This is useful to automatically deactivate tools when you hide their GUI elements. */ void RegisterClient(); /* \brief Tell that someone is NOT using tools. GUI elements should call this when they become active. This method increases an internal "client count". Tools are only registered to GlobalInteraction when this count is greater than 0. This is useful to automatically deactivate tools when you hide their GUI elements. */ void UnregisterClient(); void OnOneOfTheReferenceDataDeletedConst(const itk::Object* caller, const itk::EventObject& e); void OnOneOfTheReferenceDataDeleted (itk::Object* caller, const itk::EventObject& e); void OnOneOfTheWorkingDataDeletedConst(const itk::Object* caller, const itk::EventObject& e); void OnOneOfTheWorkingDataDeleted (itk::Object* caller, const itk::EventObject& e); void OnOneOfTheRoiDataDeletedConst(const itk::Object* caller, const itk::EventObject& e); void OnOneOfTheRoiDataDeleted (itk::Object* caller, const itk::EventObject& e); /* \brief Connected to tool's messages This method just resends error messages coming from any of the tools. This way clients (GUIs) only have to observe one message. */ void OnToolErrorMessage(std::string s); void OnGeneralToolMessage(std::string s); protected: /** You may specify a list of tool "groups" that should be available for this ToolManager. Every Tool can report its group as a string. This constructor will try to find the tool's group inside the supplied string. If there is a match, the tool is accepted. Effectively, you can provide a human readable list like "default, lymphnodevolumetry, oldERISstuff". */ ToolManager(DataStorage* storage); // purposely hidden virtual ~ToolManager(); ToolVectorType m_Tools; Tool* m_ActiveTool; int m_ActiveToolID; DataVectorType m_ReferenceData; NodeTagMapType m_ReferenceDataObserverTags; DataVectorType m_WorkingData; NodeTagMapType m_WorkingDataObserverTags; DataVectorType m_RoiData; NodeTagMapType m_RoiDataObserverTags; int m_RegisteredClients; WeakPointer m_DataStorage; + + /// \brief Callback for NodeRemove events + void OnNodeRemoved(const mitk::DataNode* node); }; } // namespace #endif diff --git a/Modules/MitkExt/DataManagement/mitkApplyDiffImageOperation.h b/Modules/MitkExt/DataManagement/mitkApplyDiffImageOperation.h index f964a9fa73..5902e68766 100644 --- a/Modules/MitkExt/DataManagement/mitkApplyDiffImageOperation.h +++ b/Modules/MitkExt/DataManagement/mitkApplyDiffImageOperation.h @@ -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. ===================================================================*/ #ifndef mitkApplyDiffImageIIncluded #define mitkApplyDiffImageIIncluded #include "mitkOperation.h" #include "MitkExtExports.h" #include "mitkCompressedImageContainer.h" namespace mitk { /** @brief Operation, that holds information about some image difference This class stores undo information for DiffImageApplier. Instances of this class are created e.g. by OverwriteSliceImageFilter. This works only for images with 1 channel (gray scale images, no color images). ApplyDiffImageOperation of course refers to an image (a segmentation usually). The refered image is observed for itk::DeleteEvent, because there is no SmartPointer used to keep the image alive -- the purpose of this class is undo and the undo stack should not keep things alive forever. To save memory, zlib compression is used via CompressedImageContainer. @ingroup Undo @ingroup ToolManagerEtAl */ class MitkExt_EXPORT ApplyDiffImageOperation : public Operation { protected: void OnImageDeleted(); Image* m_Image; unsigned int m_SliceIndex; unsigned int m_SliceDimension; unsigned int m_TimeStep; double m_Factor; bool m_ImageStillValid; unsigned long m_DeleteTag; CompressedImageContainer::Pointer zlibContainer; public: /** Pass only 2D images here. \param sliceIndex brief Which slice to extract (first one has index 0). - \param sliceDimension Number of the dimension which is constant for all pixels of the desired slice (e.g. 0 for transversal) + \param sliceDimension Number of the dimension which is constant for all pixels of the desired slice (e.g. 0 for axial) */ ApplyDiffImageOperation(OperationType operationType, Image* image, Image* diffImage, unsigned int timeStep = 0, unsigned int sliceDimension = 2, unsigned int sliceIndex = 0); virtual ~ApplyDiffImageOperation(); // Unfortunately cannot use itkGet/SetMacros here, since Operation does not inherit itk::Object unsigned int GetSliceIndex() { return m_SliceIndex; } unsigned int GetSliceDimension() { return m_SliceDimension; } unsigned int GetTimeStep() { return m_TimeStep; } void SetFactor(double factor) { m_Factor = factor; } double GetFactor() { return m_Factor; } Image* GetImage() { return m_Image; } Image::ConstPointer GetDiffImage(); bool IsImageStillValid() { return m_ImageStillValid; } }; } // namespace mitk #endif diff --git a/Modules/OpenCVVideoSupport/mitkOpenCVVideoSource.cpp b/Modules/OpenCVVideoSupport/mitkOpenCVVideoSource.cpp index 62233c1c6f..65d4e62978 100644 --- a/Modules/OpenCVVideoSupport/mitkOpenCVVideoSource.cpp +++ b/Modules/OpenCVVideoSupport/mitkOpenCVVideoSource.cpp @@ -1,434 +1,426 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkOpenCVVideoSource.h" #include #include mitk::OpenCVVideoSource::OpenCVVideoSource() : m_VideoCapture(0), m_CurrentImage(0), m_CurrentVideoTexture(0), m_PauseImage(0), m_GrabbingDeviceNumber(-1), m_RepeatVideo(false), m_UseCVCAMLib(false), m_UndistortImage(false), - m_RotationAngle(0.0), - m_RotationEnabled(false) + m_FlipXAxisEnabled(false), + m_FlipYAxisEnabled(false) { } mitk::OpenCVVideoSource::~OpenCVVideoSource() { this->Reset(); } void mitk::OpenCVVideoSource::SetVideoFileInput(const char * filename, bool repeatVideo, bool /*useCVCAMLib*/) { this->Reset(); m_VideoFileName = filename; m_VideoCapture = cvCaptureFromFile(filename); if(!m_VideoCapture) MITK_WARN << "Error in initializing video file input!"; m_RepeatVideo = repeatVideo; //m_CurrentImage = cvCreateImage(cvSize(m_CaptureWidth,m_CaptureHeight),8,3); this->Modified(); } void mitk::OpenCVVideoSource::SetVideoCameraInput(int cameraindex, bool /*useCVCAMLib*/) { this->Reset(); m_GrabbingDeviceNumber = cameraindex; m_VideoCapture = cvCaptureFromCAM(m_GrabbingDeviceNumber); if(!m_VideoCapture) MITK_ERROR << "Error in initializing CVHighGUI video camera!"<< std::endl; this->Modified(); } double mitk::OpenCVVideoSource::GetVideoCaptureProperty(int property_id) { return cvGetCaptureProperty(m_VideoCapture, property_id); } int mitk::OpenCVVideoSource::SetVideoCaptureProperty(int property_id, double value) { return cvSetCaptureProperty(m_VideoCapture, property_id, value); } //method extended for "static video feature" if enabled unsigned char* mitk::OpenCVVideoSource::GetVideoTexture() { // Fetch Frame and return pointer to opengl texture FetchFrame(); - if (m_RotationEnabled) + if (m_FlipXAxisEnabled || m_FlipYAxisEnabled) { - //store pointer to release memory for the image after rotation - IplImage * tmpImage = m_CurrentImage; - //rotate the image to get a static video - m_CurrentImage = this->RotateImage(m_CurrentImage); + m_CurrentImage = this->FlipImage(m_CurrentImage); - // release memory - cvReleaseImage(&tmpImage); // } //transfer the image to a texture this->UpdateVideoTexture(); return this->m_CurrentVideoTexture; this->Modified(); } cv::Mat mitk::OpenCVVideoSource::GetImage() { if(m_CurrentImage) { cv::Mat copy( m_CurrentImage, false ); return copy.clone(); } return cv::Mat(); } const IplImage * mitk::OpenCVVideoSource::GetCurrentFrame() { return m_CurrentImage; } void mitk::OpenCVVideoSource::GetCurrentFrameAsOpenCVImage(IplImage * image) { // get last captured frame for processing the image data if(m_CurrentImage) { if(image) { image->origin = m_CurrentImage->origin; memcpy(image->imageData,m_CurrentImage->imageData,m_CurrentImage->width*m_CurrentImage->height*m_CurrentImage->nChannels); } } } void mitk::OpenCVVideoSource::FetchFrame() { // main procedure for updating video data if(m_CapturingInProcess) { if(m_VideoCapture) // we use highgui { if(!m_CapturePaused) { // release old image here m_CurrentImage = cvQueryFrame(m_VideoCapture); ++m_FrameCount; } if(m_CurrentImage == NULL) // do we need to repeat the video if it is from video file? { double framePos = this->GetVideoCaptureProperty(CV_CAP_PROP_POS_AVI_RATIO); MITK_DEBUG << "End of video file found. framePos: " << framePos; if(m_RepeatVideo && framePos >= 0.99) { MITK_DEBUG << "Restarting video file playback."; this->SetVideoCaptureProperty(CV_CAP_PROP_POS_AVI_RATIO, 0); m_FrameCount = 0; m_CurrentImage = cvQueryFrame(m_VideoCapture); } else { std::ostringstream s; s << "End of video file " << m_VideoFileName; std::logic_error err( s.str() ); throw err; } } else { // only undistort if not paused if(m_UndistortImage && m_UndistortCameraImage.IsNotNull()) m_UndistortCameraImage->UndistortImageFast(m_CurrentImage, 0); } if(m_CaptureWidth == 0 || m_CaptureHeight == 0) { MITK_DEBUG << "Trying to set m_CaptureWidth & m_CaptureHeight."; m_CaptureWidth = m_CurrentImage->width; m_CaptureHeight = m_CurrentImage->height; MITK_INFO << "frame width: " << m_CaptureWidth << ", height: " << m_CaptureHeight; m_CurrentImage->origin = 0; } } } } void mitk::OpenCVVideoSource::UpdateVideoTexture() { //write the grabbed frame into an opengl compatible array, that means flip it and swap channel order if(!m_CurrentImage) return; if(m_CurrentVideoTexture == NULL) m_CurrentVideoTexture = new unsigned char[m_CaptureWidth*m_CaptureHeight*3]; int width = m_CurrentImage->width; int height = m_CurrentImage->height; int widthStep = m_CurrentImage->widthStep; int nChannels = m_CurrentImage->nChannels; unsigned char* tex = m_CurrentVideoTexture; char* data = m_CurrentImage->imageData; char* currentData = m_CurrentImage->imageData; int hIndex=0; int wIndex=0; int iout,jout; for(int i=0;i= width) { wIndex=0; hIndex++; } // vertically flip the image iout = -hIndex+height-1; jout = wIndex; currentData = data + iout*widthStep; tex[i+2] = currentData[jout*nChannels + 0]; // B tex[i+1] = currentData[jout*nChannels + 1]; // G tex[i] = currentData[jout*nChannels + 2]; // R } } void mitk::OpenCVVideoSource::StartCapturing() { if(m_VideoCapture != NULL) m_CapturingInProcess = true; else m_CapturingInProcess = false; } void mitk::OpenCVVideoSource::StopCapturing() { m_CapturingInProcess = false; } bool mitk::OpenCVVideoSource::OnlineImageUndistortionEnabled() const { return m_UndistortCameraImage; } void mitk::OpenCVVideoSource::PauseCapturing() { m_CapturePaused = !m_CapturePaused; if(m_CapturePaused) { m_PauseImage = cvCloneImage(m_CurrentImage); // undistort this pause image if necessary if(m_UndistortImage) m_UndistortCameraImage->UndistortImageFast(m_PauseImage, 0); - m_CurrentImage = m_PauseImage; } else { cvReleaseImage( &m_PauseImage ); // release old pause image if necessary m_CurrentImage = 0; m_PauseImage = 0; } } void mitk::OpenCVVideoSource::EnableOnlineImageUndistortion(mitk::Point3D focal, mitk::Point3D principal, mitk::Point4D distortion) { // Initialize Undistortion m_UndistortImage = true; float kc[4]; kc[0] = distortion[0]; kc[1] = distortion[1]; kc[2] = distortion[2]; kc[3] = distortion[3]; if(m_CaptureWidth == 0 || m_CaptureHeight == 0) FetchFrame(); m_UndistortCameraImage = mitk::UndistortCameraImage::New(); m_UndistortCameraImage->SetUndistortImageFastInfo(focal[0], focal[1], principal[0], principal[1], kc, (float)m_CaptureWidth, (float)m_CaptureHeight); } void mitk::OpenCVVideoSource::DisableOnlineImageUndistortion() { m_UndistortImage = false; } // functions for compatibility with ITK segmentation only void mitk::OpenCVVideoSource::GetCurrentFrameAsItkHSVPixelImage(HSVPixelImageType::Pointer &Image) { FetchFrame(); // Prepare iteration HSVConstIteratorType itImage( Image, Image->GetLargestPossibleRegion()); itImage.Begin(); HSVPixelType pixel; int rowsize = 3 * m_CaptureWidth; char* bufferend; char* picture; picture = this->m_CurrentImage->imageData; bufferend = this->m_CurrentImage->imageData + 3*(m_CaptureHeight*m_CaptureWidth); float r,g,b,h,s,v; try { // we have to flip the image for(char* datapointer = bufferend - rowsize;datapointer >= picture; datapointer -= rowsize) { for(char* current = datapointer; current < datapointer + rowsize; current++) { - b = *current; current++; g = *current; current++; r = *current; RGBtoHSV(r,g,b,h,s,v); pixel[0] = h; pixel[1] = s; pixel[2] = v; itImage.Set(pixel); ++itImage; } } } catch( ... ) { std::cout << "Exception raised mitkOpenCVVideoSource: get hsv itk image conversion error." << std::endl; } } void mitk::OpenCVVideoSource::RGBtoHSV(float r, float g, float b, float &h, float &s, float &v) { if(r > 1.0) r = r/255; if(b > 1.0) b = b/255; if(g > 1.0) g = g/255; float mn=r,mx=r; int maxVal=0; if (g > mx){ mx=g;maxVal=1;} if (b > mx){ mx=b;maxVal=2;} if (g < mn) mn=g; if (b < mn) mn=b; float delta = mx - mn; v = mx; if( mx != 0 ) s = delta / mx; else { s = 0; h = 0; return; } if (s==0.0f) { h=-1; return; } else { switch (maxVal) { case 0:{h = ( g - b ) / delta;break;} // yel < h < mag case 1:{h = 2 + ( b - r ) / delta;break;} // cyan < h < yel case 2:{h = 4 + ( r - g ) / delta;break;} // mag < h < cyan } } h *= 60; if( h < 0 ) h += 360; } /* * Rotate input image according to rotation angle around the viewing direction. * Angle is supposed to be calculated in QmitkARRotationComponet in the update() method. */ -IplImage* mitk::OpenCVVideoSource::RotateImage(IplImage* input) +IplImage* mitk::OpenCVVideoSource::FlipImage(IplImage* input) { if(input == NULL) { //warn the user and quit std::cout<<"openCVVideoSource: Current video image is null! "<< std::endl; return input; } - IplImage* dst = cvCloneImage( input ); - double angle = this->GetRotationAngle(); //degree - CvPoint2D32f centre; - CvMat *translate = cvCreateMat(2, 3, CV_32FC1); - cvSetZero(translate); - centre.x = m_CaptureWidth/2; - centre.y = m_CaptureHeight/2; - cv2DRotationMatrix(centre, angle, 1.0, translate); - cvWarpAffine(input, dst, translate,CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS , cvScalarAll(0)); - cvReleaseMat(&translate); - - return dst; + + if(m_FlipXAxisEnabled && !m_FlipYAxisEnabled) + { + cvFlip(input,0,0); + } + if(!m_FlipXAxisEnabled && m_FlipYAxisEnabled) + { + cvFlip(input,0,1); + } + if(m_FlipXAxisEnabled && m_FlipYAxisEnabled) + { + cvFlip(input,0,-1); + } + + return input; } void mitk::OpenCVVideoSource::Reset() { // set capturing to false this->StopCapturing(); if(m_VideoCapture) cvReleaseCapture(&m_VideoCapture); m_VideoCapture = 0; m_CurrentImage = 0; m_CaptureWidth = 0; m_CaptureHeight = 0; delete m_CurrentVideoTexture; m_CurrentVideoTexture = 0; if(m_PauseImage) cvReleaseImage(&m_PauseImage); m_PauseImage = 0; m_CapturePaused = false; m_VideoFileName.clear(); m_GrabbingDeviceNumber = -1; // do not touch repeat video //m_RepeatVideo = false; m_UseCVCAMLib = false; // do not touch undistort settings // bool m_UndistortImage; } -void mitk::OpenCVVideoSource::EnableRotation(bool enable= true) +void mitk::OpenCVVideoSource::SetEnableXAxisFlip(bool enable) { - m_RotationEnabled = enable; - this->Modified(); + this->m_FlipXAxisEnabled = enable; + this->Modified(); } -void mitk::OpenCVVideoSource::SetRotationAngle(double rotationAngle) +void mitk::OpenCVVideoSource::SetEnableYAxisFlip(bool enable) { - m_RotationAngle = rotationAngle; - this->Modified(); + this->m_FlipXAxisEnabled = enable; + this->Modified(); } -double mitk::OpenCVVideoSource::GetRotationAngle() -{ - return m_RotationAngle; -} diff --git a/Modules/OpenCVVideoSupport/mitkOpenCVVideoSource.h b/Modules/OpenCVVideoSupport/mitkOpenCVVideoSource.h index a11061b977..9de76afe79 100644 --- a/Modules/OpenCVVideoSupport/mitkOpenCVVideoSource.h +++ b/Modules/OpenCVVideoSupport/mitkOpenCVVideoSource.h @@ -1,209 +1,200 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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_OpenCVVideo_Source_h_ #define _mitk_OpenCVVideo_Source_h_ #include "mitkConfig.h" #include "mitkVideoSource.h" #include "mitkUndistortCameraImage.h" // HighGui camera interface: a convenient way for grabbing from a video capture (on windows VfW is used) #include "highgui.h" // For Providing ITK Image Interface #include "itkRGBPixel.h" #include "itkImage.h" #include "itkImageRegionIterator.h" #include "mitkOpenCVImageSource.h" namespace mitk { /** * Interface for acquiring video data using Intel's OPENCV library. * Video data may either be provided from a file or a grabbing device. * At the moment, OPENCV includes two separated modules for this grabbing, but only HighGui is * used here. * Initialize via SetVideoFileInput() or SetVideoCameraInput(), start processing with StartCapturing(); */ class MITK_OPENCVVIDEOSUPPORT_EXPORT OpenCVVideoSource : virtual public VideoSource, virtual public OpenCVImageSource { public: typedef itk::RGBPixel< unsigned char > CharPixelType; typedef itk::FixedArray HSVPixelType; typedef itk::Image< CharPixelType , 2 > RGBPixelImageType; typedef itk::Image HSVPixelImageType; typedef itk::ImageRegionIterator< RGBPixelImageType > RGBConstIteratorType; typedef itk::ImageRegionIterator< HSVPixelImageType > HSVConstIteratorType; mitkClassMacro( OpenCVVideoSource, VideoSource ); itkNewMacro( Self ); ////##Documentation ////## @brief sets a video file as input device. One video frame is being processed by updating the renderwindow. ////## Notice: Which codecs and file formats are supported depends on the back end library. ////## Common Function that currently uses HighGui Lib for video playback virtual void SetVideoFileInput(const char * filename, bool repeatVideo, bool useCVCAMLib = false); ////##Documentation ////##@brief Initializes capturing video from camera. ////## Common Function for use either with HIGHGUI or with CVCAM library ////## On windows: if you use CVCAM Library, you can pass -1 as camera index for a selection menu virtual void SetVideoCameraInput(int cameraindex, bool useCVCAMLib = false); ////##Documentation ////## The function GetVideoCaptureProperty retrieves the specified property of camera or video file from HIGHGUI LIBRARY. ////## Video input has to be initialized before call, that means: at least one frame has to be grabbed already. ////## The property_id identifier can be the following: ////## CV_CAP_PROP_POS_MSEC film current position in milliseconds or video capture timestamp ////## CV_CAP_PROP_POS_FRAMES 0-based index of the frame to be decoded/captured next ////## CV_CAP_PROP_POS_AVI_RATIO relative position of video file (0 - start of the film, 1 - end of the film) ////## CV_CAP_PROP_FRAME_WIDTH width of frames in the video stream ////## CV_CAP_PROP_FRAME_HEIGHT height of frames in the video stream ////## CV_CAP_PROP_FPS frame rate ////## CV_CAP_PROP_FOURCC 4-character code of codec ////## CV_CAP_PROP_FRAME_COUNT number of frames in video file ////## See OpenCV Highgui documentation for more details ( http://opencvlibrary.sourceforge.net/HighGui ) virtual double GetVideoCaptureProperty(int property_id); ////##Documentation ////## @brief sets the specified property of video capturing from HIGHGUI LIBRARY. ////## Notice: Some properties only can be set using a video file as input devices, others using a camera. ////## See OpenCV Highgui documentation for more details ( http://opencvlibrary.sourceforge.net/HighGui ) virtual int SetVideoCaptureProperty(int property_id, double value); virtual void GetCurrentFrameAsOpenCVImage(IplImage * image); /// /// \return a copy of the image as opencv 2 Mat /// virtual cv::Mat GetImage(); virtual const IplImage * GetCurrentFrame(); ////##Documentation ////## @brief returns the current video data as an ITK image. virtual void GetCurrentFrameAsItkHSVPixelImage(HSVPixelImageType::Pointer &Image); ////##Documentation ////## @brief assigns the grabbing devices for acquiring the next frame. virtual void FetchFrame(); ////##Documentation ////## @brief returns a pointer to the image data array for opengl rendering. virtual unsigned char * GetVideoTexture(); ////##Documentation ////## @brief starts the video capturing. virtual void StartCapturing(); ////##Documentation ////## @brief stops the video capturing. virtual void StopCapturing(); ////##Documentation ////## @brief rotate image according to the set angle. - virtual IplImage* RotateImage(IplImage* input); + virtual IplImage* FlipImage(IplImage* input); ////##Documentation ////## @brief EnableOnlineImageUndistortion allows for an online image undistortion directly after capturing an image. ////## The function has to be called after setting up the video input; the result is made accessible via the normal ////## GetCurrentFrame... functions. virtual void EnableOnlineImageUndistortion(mitk::Point3D focal, mitk::Point3D principal, mitk::Point4D distortion); ////##Documentation ////## @brief DisableOnlineImageUndistortion is used to disable the automatic image undistortion. virtual void DisableOnlineImageUndistortion(); /// /// \return true if image undistorsion is enabled /// virtual bool OnlineImageUndistortionEnabled() const; virtual void PauseCapturing(); /// /// Returns the video file name (maybe empty if a grabbing device is used) /// itkGetConstMacro( VideoFileName, std::string ); + virtual void SetEnableXAxisFlip(bool enable); + virtual void SetEnableYAxisFlip(bool enable); + /// /// Returns the GrabbingDeviceNumber (maybe -1 if a video file is used) /// itkGetConstMacro( GrabbingDeviceNumber, short ); itkGetMacro( RepeatVideo, bool ); itkSetMacro( RepeatVideo, bool ); - /// - /// \return advices this class to enable online rotation (has to be - /// implemented in subclasses) - /// - virtual void EnableRotation(bool enable); - /// - /// \return sets the current rotation angle - /// - virtual void SetRotationAngle(double rotationAngle); - /// - /// \return the current rotation angle (might be 0) - /// - virtual double GetRotationAngle(); protected: OpenCVVideoSource(); virtual ~OpenCVVideoSource(); /// /// Resets the whole class for capturing from a new device /// void Reset(); ////##Documentation ////## @brief internally used for converting the current video frame to a texture for opengl rendering, ////## so that GetVideoTexture() can be used. void UpdateVideoTexture(); // Helper functions void sleep(unsigned int ms); void RGBtoHSV(float r, float g, float b, float &h, float &s, float &v); // HighGUI Library capture device CvCapture * m_VideoCapture; // current Video image IplImage * m_CurrentImage; unsigned char* m_CurrentVideoTexture; IplImage * m_PauseImage; /// /// saves the video file name (is empty if a grabbing device is used or if this is not initialized) std::string m_VideoFileName; /// /// saves the grabbing device number (is -1 if a videofilename is used or if this is not initialized) short m_GrabbingDeviceNumber; // Repeat a video file bool m_RepeatVideo; // Switch between CVCAM Lib and HighGui Lib bool m_UseCVCAMLib; // On-the-fly undistortion of the captured video image bool m_UndistortImage; mitk::UndistortCameraImage::Pointer m_UndistortCameraImage; + /** - * Angle for rotating the video image + * Flag to enable or disable video flipping by X Axis. **/ - double m_RotationAngle; + bool m_FlipXAxisEnabled; /** - * Flag to enable or disable video rotation used for performance enhancement. + * Flag to enable or disable video flipping by Y Axis. **/ - bool m_RotationEnabled; + bool m_FlipYAxisEnabled; }; } #endif // Header diff --git a/Modules/Qmitk/QmitkRenderWindowMenu.cpp b/Modules/Qmitk/QmitkRenderWindowMenu.cpp index ffd7f90284..568abcde6f 100644 --- a/Modules/Qmitk/QmitkRenderWindowMenu.cpp +++ b/Modules/Qmitk/QmitkRenderWindowMenu.cpp @@ -1,1016 +1,1016 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "QmitkRenderWindowMenu.h" #include "mitkResliceMethodProperty.h" #include "mitkProperties.h" #include #include #include #include #include #include #include #include #include #include #include #include "QmitkStdMultiWidget.h" //#include"iconClose.xpm" #include"iconFullScreen.xpm" #include"iconCrosshairMode.xpm" //#include"iconHoriSplit.xpm" #include"iconSettings.xpm" //#include"iconVertiSplit.xpm" #include"iconLeaveFullScreen.xpm" #include #ifdef QMITK_USE_EXTERNAL_RENDERWINDOW_MENU QmitkRenderWindowMenu::QmitkRenderWindowMenu(QWidget *parent, Qt::WindowFlags f, mitk::BaseRenderer *b, QmitkStdMultiWidget* mw ) :QWidget(parent, Qt::Tool | Qt::FramelessWindowHint ), #else QmitkRenderWindowMenu::QmitkRenderWindowMenu(QWidget *parent, Qt::WindowFlags f, mitk::BaseRenderer *b, QmitkStdMultiWidget* mw ) :QWidget(parent,f), #endif m_Settings(NULL), m_CrosshairMenu(NULL), m_Layout(0), m_LayoutDesign(0), m_OldLayoutDesign(0), m_FullScreenMode(false), m_Entered(false), m_Hidden(true), m_Renderer(b), m_MultiWidget(mw) { MITK_DEBUG << "creating renderwindow menu on baserenderer " << b; //Create Menu Widget this->CreateMenuWidget(); this->setMinimumWidth(61); //DIRTY.. If you add or remove a button, you need to change the size. this->setMaximumWidth(61); this->setAutoFillBackground( true ); //Workaround for fix for bug 3192 which fixed the render window menu issue on linux //but lead to focus issues on Mac OS X #ifdef Q_OS_MAC this->show(); this->setWindowOpacity(0.0f); #else this->setVisible(false); #endif //this->setAttribute( Qt::WA_NoSystemBackground ); //this->setBackgroundRole( QPalette::Dark ); //this->update(); //SetOpacity -- its just posible if the widget is a window. //Windows indicates that the widget is a window, usually with a window system frame and a title bar, //irrespective of whether the widget has a parent or not. /* this->setWindowFlags( Qt::Window | Qt::FramelessWindowHint); */ //this->setAttribute(Qt::WA_TranslucentBackground); //this->setWindowOpacity(0.75); currentCrosshairRotationMode = 0; // for autorotating m_AutoRotationTimer.setInterval( 75 ); connect( &m_AutoRotationTimer, SIGNAL(timeout()), this, SLOT(AutoRotateNextStep()) ); } QmitkRenderWindowMenu::~QmitkRenderWindowMenu() { if( m_AutoRotationTimer.isActive() ) m_AutoRotationTimer.stop(); } void QmitkRenderWindowMenu::CreateMenuWidget() { QHBoxLayout* layout = new QHBoxLayout(this); layout->setAlignment( Qt::AlignRight ); layout->setContentsMargins(1,1,1,1); QSize size( 13, 13 ); m_CrosshairMenu = new QMenu(this); connect( m_CrosshairMenu, SIGNAL( aboutToShow() ), this, SLOT(OnCrossHairMenuAboutToShow()) ); // button for changing rotation mode m_CrosshairModeButton = new QPushButton(this); m_CrosshairModeButton->setMaximumSize(15, 15); m_CrosshairModeButton->setIconSize(size); m_CrosshairModeButton->setFlat( true ); m_CrosshairModeButton->setMenu( m_CrosshairMenu ); m_CrosshairModeButton->setIcon( QIcon( iconCrosshairMode_xpm ) ); layout->addWidget( m_CrosshairModeButton ); //fullScreenButton m_FullScreenButton = new QPushButton(this); m_FullScreenButton->setMaximumSize(15, 15); m_FullScreenButton->setIconSize(size); m_FullScreenButton->setFlat( true ); m_FullScreenButton->setIcon( QIcon( iconFullScreen_xpm )); layout->addWidget( m_FullScreenButton ); //settingsButton m_SettingsButton = new QPushButton(this); m_SettingsButton->setMaximumSize(15, 15); m_SettingsButton->setIconSize(size); m_SettingsButton->setFlat( true ); m_SettingsButton->setIcon( QIcon( iconSettings_xpm )); layout->addWidget( m_SettingsButton ); //Create Connections -- coming soon? connect( m_FullScreenButton, SIGNAL( clicked(bool) ), this, SLOT(OnFullScreenButton(bool)) ); connect( m_SettingsButton, SIGNAL( clicked(bool) ), this, SLOT(OnSettingsButton(bool)) ); } void QmitkRenderWindowMenu::CreateSettingsWidget() { m_Settings = new QMenu(this); m_DefaultLayoutAction = new QAction( "standard layout", m_Settings ); m_DefaultLayoutAction->setDisabled( true ); m_2DImagesUpLayoutAction = new QAction( "2D images top, 3D bottom", m_Settings ); m_2DImagesUpLayoutAction->setDisabled( false ); m_2DImagesLeftLayoutAction = new QAction( "2D images left, 3D right", m_Settings ); m_2DImagesLeftLayoutAction->setDisabled( false ); m_Big3DLayoutAction = new QAction( "Big 3D", m_Settings ); m_Big3DLayoutAction->setDisabled( false ); - m_Widget1LayoutAction = new QAction( "Transversal plane", m_Settings ); + m_Widget1LayoutAction = new QAction( "Axial plane", m_Settings ); m_Widget1LayoutAction->setDisabled( false ); m_Widget2LayoutAction = new QAction( "Sagittal plane", m_Settings ); m_Widget2LayoutAction->setDisabled( false ); m_Widget3LayoutAction = new QAction( "Coronal plane", m_Settings ); m_Widget3LayoutAction->setDisabled( false ); m_RowWidget3And4LayoutAction = new QAction( "Coronal top, 3D bottom", m_Settings ); m_RowWidget3And4LayoutAction->setDisabled( false ); m_ColumnWidget3And4LayoutAction = new QAction( "Coronal left, 3D right", m_Settings ); m_ColumnWidget3And4LayoutAction->setDisabled( false ); m_SmallUpperWidget2Big3and4LayoutAction = new QAction( "Sagittal top, Coronal n 3D bottom", m_Settings ); m_SmallUpperWidget2Big3and4LayoutAction->setDisabled( false ); - m_2x2Dand3DWidgetLayoutAction = new QAction( "Transversal n Sagittal left, 3D right", m_Settings ); + m_2x2Dand3DWidgetLayoutAction = new QAction( "Axial n Sagittal left, 3D right", m_Settings ); m_2x2Dand3DWidgetLayoutAction->setDisabled( false ); - m_Left2Dand3DRight2DLayoutAction = new QAction( "Transversal n 3D left, Sagittal right", m_Settings ); + m_Left2Dand3DRight2DLayoutAction = new QAction( "Axial n 3D left, Sagittal right", m_Settings ); m_Left2Dand3DRight2DLayoutAction->setDisabled( false ); m_Settings->addAction(m_DefaultLayoutAction); m_Settings->addAction(m_2DImagesUpLayoutAction); m_Settings->addAction(m_2DImagesLeftLayoutAction); m_Settings->addAction(m_Big3DLayoutAction); m_Settings->addAction(m_Widget1LayoutAction); m_Settings->addAction(m_Widget2LayoutAction); m_Settings->addAction(m_Widget3LayoutAction); m_Settings->addAction(m_RowWidget3And4LayoutAction); m_Settings->addAction(m_ColumnWidget3And4LayoutAction); m_Settings->addAction(m_SmallUpperWidget2Big3and4LayoutAction); m_Settings->addAction(m_2x2Dand3DWidgetLayoutAction); m_Settings->addAction(m_Left2Dand3DRight2DLayoutAction); m_Settings->setVisible( false ); connect( m_DefaultLayoutAction, SIGNAL( triggered(bool) ), this, SLOT(OnChangeLayoutToDefault(bool)) ); connect( m_2DImagesUpLayoutAction, SIGNAL( triggered(bool) ), this, SLOT(OnChangeLayoutTo2DImagesUp(bool)) ); connect( m_2DImagesLeftLayoutAction, SIGNAL( triggered(bool) ), this, SLOT(OnChangeLayoutTo2DImagesLeft(bool)) ); connect( m_Big3DLayoutAction, SIGNAL( triggered(bool) ), this, SLOT(OnChangeLayoutToBig3D(bool)) ); connect( m_Widget1LayoutAction, SIGNAL( triggered(bool) ), this, SLOT(OnChangeLayoutToWidget1(bool)) ); connect( m_Widget2LayoutAction, SIGNAL( triggered(bool) ), this, SLOT(OnChangeLayoutToWidget2(bool)) ); connect( m_Widget3LayoutAction , SIGNAL( triggered(bool) ), this, SLOT(OnChangeLayoutToWidget3(bool)) ); connect( m_RowWidget3And4LayoutAction, SIGNAL( triggered(bool) ), this, SLOT(OnChangeLayoutToRowWidget3And4(bool)) ); connect( m_ColumnWidget3And4LayoutAction, SIGNAL( triggered(bool) ), this, SLOT(OnChangeLayoutToColumnWidget3And4(bool)) ); connect( m_SmallUpperWidget2Big3and4LayoutAction, SIGNAL( triggered(bool) ), this, SLOT(OnChangeLayoutToSmallUpperWidget2Big3and4(bool)) ); connect( m_2x2Dand3DWidgetLayoutAction, SIGNAL( triggered(bool) ), this, SLOT(OnChangeLayoutTo2x2Dand3DWidget(bool)) ); connect( m_Left2Dand3DRight2DLayoutAction, SIGNAL( triggered(bool) ), this, SLOT(OnChangeLayoutToLeft2Dand3DRight2D(bool)) ); } void QmitkRenderWindowMenu::paintEvent( QPaintEvent* /*e*/ ) { QPainter painter(this); QColor semiTransparentColor = Qt::black; semiTransparentColor.setAlpha(255); painter.fillRect(rect(), semiTransparentColor); } void QmitkRenderWindowMenu::SetLayoutIndex( unsigned int layoutIndex ) { m_Layout = layoutIndex; } void QmitkRenderWindowMenu::HideMenu( ) { MITK_DEBUG << "menu hideEvent"; m_Hidden = true; if( ! m_Entered ) { //Workaround for fix for bug 3192 which fixed the render window menu issue on linux //but lead to focus issues on Mac OS X #ifdef Q_OS_MAC this->setWindowOpacity(0.0f); #else this->setVisible(false); #endif } } void QmitkRenderWindowMenu::ShowMenu( ) { MITK_DEBUG << "menu showMenu"; m_Hidden = false; //Workaround for fix for bug 3192 which fixed the render window menu issue on linux //but lead to focus issues on Mac OS X #ifdef Q_OS_MAC this->setWindowOpacity(1.0f); #else this->setVisible(true); #endif } void QmitkRenderWindowMenu::enterEvent( QEvent * /*e*/ ) { MITK_DEBUG << "menu enterEvent"; m_Entered=true; m_Hidden=false; // setWindowOpacity(1.0f); } void QmitkRenderWindowMenu::DeferredHideMenu( ) { MITK_DEBUG << "menu deferredhidemenu"; if(m_Hidden) { #ifdef Q_OS_MAC this->setWindowOpacity(0.0f); #else this->setVisible(false); #endif } // setVisible(false); // setWindowOpacity(0.0f); ///hide(); } void QmitkRenderWindowMenu::leaveEvent( QEvent * /*e*/ ) { MITK_DEBUG << "menu leaveEvent"; smoothHide(); } /* This method is responsible for non fluttering of the renderWindowMenu when mouse cursor moves along the renderWindowMenu*/ void QmitkRenderWindowMenu::smoothHide() { MITK_DEBUG<< "menu leaveEvent"; m_Entered=false; m_Hidden = true; QTimer::singleShot(10,this,SLOT( DeferredHideMenu( ) ) ); } void QmitkRenderWindowMenu::ChangeFullScreenMode( bool state ) { this->OnFullScreenButton( state ); } /// \brief void QmitkRenderWindowMenu::OnFullScreenButton( bool /*checked*/ ) { if( !m_FullScreenMode ) { m_FullScreenMode = true; m_OldLayoutDesign = m_LayoutDesign; switch( m_Layout ) { - case TRANSVERSAL: + case AXIAL: { - emit SignalChangeLayoutDesign( LAYOUT_TRANSVERSAL ); + emit SignalChangeLayoutDesign( LAYOUT_AXIAL ); break; } case SAGITTAL: { emit SignalChangeLayoutDesign( LAYOUT_SAGITTAL ); break; } case CORONAL: { emit SignalChangeLayoutDesign( LAYOUT_CORONAL ); break; } case THREE_D: { emit SignalChangeLayoutDesign( LAYOUT_BIG3D ); break; } } //Move Widget and show again this->MoveWidgetToCorrectPos(1.0f); //change icon this->ChangeFullScreenIcon(); } else { m_FullScreenMode = false; emit SignalChangeLayoutDesign( m_OldLayoutDesign ); //Move Widget and show again this->MoveWidgetToCorrectPos(1.0f); //change icon this->ChangeFullScreenIcon(); } DeferredShowMenu( ); } /// \brief void QmitkRenderWindowMenu::OnSettingsButton( bool /*checked*/ ) { if( m_Settings == NULL ) this->CreateSettingsWidget(); QPoint point = this->mapToGlobal( m_SettingsButton->geometry().topLeft() ); m_Settings->setVisible( true ); m_Settings->exec( point ); } void QmitkRenderWindowMenu::OnChangeLayoutTo2DImagesUp(bool) { //set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); m_LayoutDesign = LAYOUT_2DIMAGEUP; emit SignalChangeLayoutDesign( LAYOUT_2DIMAGEUP ); DeferredShowMenu( ); } void QmitkRenderWindowMenu::OnChangeLayoutTo2DImagesLeft(bool) { //set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); m_LayoutDesign = LAYOUT_2DIMAGELEFT; emit SignalChangeLayoutDesign( LAYOUT_2DIMAGELEFT ); DeferredShowMenu( ); } void QmitkRenderWindowMenu::OnChangeLayoutToDefault(bool) { //set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); m_LayoutDesign = LAYOUT_DEFAULT; emit SignalChangeLayoutDesign( LAYOUT_DEFAULT ); DeferredShowMenu( ); } void QmitkRenderWindowMenu::DeferredShowMenu() { MITK_DEBUG << "deferred show menu"; //Workaround for fix for bug 3192 which fixed the render window menu issue on linux //but lead to focus issues on Mac OS X #ifdef Q_OS_MAC this->setWindowOpacity(1.0f); #else this->setVisible(true); #endif } void QmitkRenderWindowMenu::OnChangeLayoutToBig3D(bool) { MITK_DEBUG << "OnChangeLayoutToBig3D"; //set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); m_LayoutDesign = LAYOUT_BIG3D; emit SignalChangeLayoutDesign( LAYOUT_BIG3D ); DeferredShowMenu( ); } void QmitkRenderWindowMenu::OnChangeLayoutToWidget1(bool) { //set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); - m_LayoutDesign = LAYOUT_TRANSVERSAL; - emit SignalChangeLayoutDesign( LAYOUT_TRANSVERSAL ); + m_LayoutDesign = LAYOUT_AXIAL; + emit SignalChangeLayoutDesign( LAYOUT_AXIAL ); DeferredShowMenu( ); } void QmitkRenderWindowMenu::OnChangeLayoutToWidget2(bool) { //set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); m_LayoutDesign = LAYOUT_SAGITTAL; emit SignalChangeLayoutDesign( LAYOUT_SAGITTAL ); DeferredShowMenu( ); } void QmitkRenderWindowMenu::OnChangeLayoutToWidget3(bool) { //set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); m_LayoutDesign = LAYOUT_CORONAL; emit SignalChangeLayoutDesign( LAYOUT_CORONAL ); DeferredShowMenu( ); } void QmitkRenderWindowMenu::OnChangeLayoutToRowWidget3And4(bool) { //set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); m_LayoutDesign = LAYOUT_ROWWIDGET3AND4; emit SignalChangeLayoutDesign( LAYOUT_ROWWIDGET3AND4 ); DeferredShowMenu( ); } void QmitkRenderWindowMenu::OnChangeLayoutToColumnWidget3And4(bool) { //set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); m_LayoutDesign = LAYOUT_COLUMNWIDGET3AND4; emit SignalChangeLayoutDesign( LAYOUT_COLUMNWIDGET3AND4 ); DeferredShowMenu( ); } void QmitkRenderWindowMenu::OnChangeLayoutToSmallUpperWidget2Big3and4(bool) { //set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); m_LayoutDesign = LAYOUT_SMALLUPPERWIDGET2BIGAND4; emit SignalChangeLayoutDesign( LAYOUT_SMALLUPPERWIDGET2BIGAND4 ); DeferredShowMenu( ); } void QmitkRenderWindowMenu::OnChangeLayoutTo2x2Dand3DWidget(bool) { //set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); m_LayoutDesign = LAYOUT_2X2DAND3DWIDGET; emit SignalChangeLayoutDesign( LAYOUT_2X2DAND3DWIDGET ); DeferredShowMenu( ); } void QmitkRenderWindowMenu::OnChangeLayoutToLeft2Dand3DRight2D(bool) { //set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); m_LayoutDesign = LAYOUT_LEFT2DAND3DRIGHT2D; emit SignalChangeLayoutDesign( LAYOUT_LEFT2DAND3DRIGHT2D ); DeferredShowMenu( ); } void QmitkRenderWindowMenu::UpdateLayoutDesignList( int layoutDesignIndex ) { m_LayoutDesign = layoutDesignIndex; if( m_Settings == NULL ) this->CreateSettingsWidget(); switch( m_LayoutDesign ) { case LAYOUT_DEFAULT: { m_DefaultLayoutAction->setEnabled(false); m_2DImagesUpLayoutAction->setEnabled(true); m_2DImagesLeftLayoutAction->setEnabled(true); m_Big3DLayoutAction->setEnabled(true); m_Widget1LayoutAction->setEnabled(true); m_Widget2LayoutAction->setEnabled(true); m_Widget3LayoutAction->setEnabled(true); m_RowWidget3And4LayoutAction->setEnabled(true); m_ColumnWidget3And4LayoutAction->setEnabled(true); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); m_2x2Dand3DWidgetLayoutAction->setEnabled(true); m_Left2Dand3DRight2DLayoutAction->setEnabled(true); break; } case LAYOUT_2DIMAGEUP: { m_DefaultLayoutAction->setEnabled(true); m_2DImagesUpLayoutAction->setEnabled(false); m_2DImagesLeftLayoutAction->setEnabled(true); m_Big3DLayoutAction->setEnabled(true); m_Widget1LayoutAction->setEnabled(true); m_Widget2LayoutAction->setEnabled(true); m_Widget3LayoutAction->setEnabled(true); m_RowWidget3And4LayoutAction->setEnabled(true); m_ColumnWidget3And4LayoutAction->setEnabled(true); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); m_2x2Dand3DWidgetLayoutAction->setEnabled(true); m_Left2Dand3DRight2DLayoutAction->setEnabled(true); break; } case LAYOUT_2DIMAGELEFT: { m_DefaultLayoutAction->setEnabled(true); m_2DImagesUpLayoutAction->setEnabled(true); m_2DImagesLeftLayoutAction->setEnabled(false); m_Big3DLayoutAction->setEnabled(true); m_Widget1LayoutAction->setEnabled(true); m_Widget2LayoutAction->setEnabled(true); m_Widget3LayoutAction->setEnabled(true); m_RowWidget3And4LayoutAction->setEnabled(true); m_ColumnWidget3And4LayoutAction->setEnabled(true); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); m_2x2Dand3DWidgetLayoutAction->setEnabled(true); m_Left2Dand3DRight2DLayoutAction->setEnabled(true); break; } case LAYOUT_BIG3D: { m_DefaultLayoutAction->setEnabled(true); m_2DImagesUpLayoutAction->setEnabled(true); m_2DImagesLeftLayoutAction->setEnabled(true); m_Big3DLayoutAction->setEnabled(false); m_Widget1LayoutAction->setEnabled(true); m_Widget2LayoutAction->setEnabled(true); m_Widget3LayoutAction->setEnabled(true); m_RowWidget3And4LayoutAction->setEnabled(true); m_ColumnWidget3And4LayoutAction->setEnabled(true); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); m_2x2Dand3DWidgetLayoutAction->setEnabled(true); m_Left2Dand3DRight2DLayoutAction->setEnabled(true); break; } - case LAYOUT_TRANSVERSAL: + case LAYOUT_AXIAL: { m_DefaultLayoutAction->setEnabled(true); m_2DImagesUpLayoutAction->setEnabled(true); m_2DImagesLeftLayoutAction->setEnabled(true); m_Big3DLayoutAction->setEnabled(true); m_Widget1LayoutAction->setEnabled(false); m_Widget2LayoutAction->setEnabled(true); m_Widget3LayoutAction->setEnabled(true); m_RowWidget3And4LayoutAction->setEnabled(true); m_ColumnWidget3And4LayoutAction->setEnabled(true); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); m_2x2Dand3DWidgetLayoutAction->setEnabled(true); m_Left2Dand3DRight2DLayoutAction->setEnabled(true); break; } case LAYOUT_SAGITTAL: { m_DefaultLayoutAction->setEnabled(true); m_2DImagesUpLayoutAction->setEnabled(true); m_2DImagesLeftLayoutAction->setEnabled(true); m_Big3DLayoutAction->setEnabled(true); m_Widget1LayoutAction->setEnabled(true); m_Widget2LayoutAction->setEnabled(false); m_Widget3LayoutAction->setEnabled(true); m_RowWidget3And4LayoutAction->setEnabled(true); m_ColumnWidget3And4LayoutAction->setEnabled(true); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); m_2x2Dand3DWidgetLayoutAction->setEnabled(true); m_Left2Dand3DRight2DLayoutAction->setEnabled(true); break; } case LAYOUT_CORONAL: { m_DefaultLayoutAction->setEnabled(true); m_2DImagesUpLayoutAction->setEnabled(true); m_2DImagesLeftLayoutAction->setEnabled(true); m_Big3DLayoutAction->setEnabled(true); m_Widget1LayoutAction->setEnabled(true); m_Widget2LayoutAction->setEnabled(true); m_Widget3LayoutAction->setEnabled(false); m_RowWidget3And4LayoutAction->setEnabled(true); m_ColumnWidget3And4LayoutAction->setEnabled(true); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); m_2x2Dand3DWidgetLayoutAction->setEnabled(true); m_Left2Dand3DRight2DLayoutAction->setEnabled(true); break; } case LAYOUT_2X2DAND3DWIDGET: { m_DefaultLayoutAction->setEnabled(true); m_2DImagesUpLayoutAction->setEnabled(true); m_2DImagesLeftLayoutAction->setEnabled(true); m_Big3DLayoutAction->setEnabled(true); m_Widget1LayoutAction->setEnabled(true); m_Widget2LayoutAction->setEnabled(true); m_Widget3LayoutAction->setEnabled(true); m_RowWidget3And4LayoutAction->setEnabled(true); m_ColumnWidget3And4LayoutAction->setEnabled(true); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); m_2x2Dand3DWidgetLayoutAction->setEnabled(false); m_Left2Dand3DRight2DLayoutAction->setEnabled(true); break; } case LAYOUT_ROWWIDGET3AND4: { m_DefaultLayoutAction->setEnabled(true); m_2DImagesUpLayoutAction->setEnabled(true); m_2DImagesLeftLayoutAction->setEnabled(true); m_Big3DLayoutAction->setEnabled(true); m_Widget1LayoutAction->setEnabled(true); m_Widget2LayoutAction->setEnabled(true); m_Widget3LayoutAction->setEnabled(true); m_RowWidget3And4LayoutAction->setEnabled(false); m_ColumnWidget3And4LayoutAction->setEnabled(true); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); m_2x2Dand3DWidgetLayoutAction->setEnabled(true); m_Left2Dand3DRight2DLayoutAction->setEnabled(true); break; } case LAYOUT_COLUMNWIDGET3AND4: { m_DefaultLayoutAction->setEnabled(true); m_2DImagesUpLayoutAction->setEnabled(true); m_2DImagesLeftLayoutAction->setEnabled(true); m_Big3DLayoutAction->setEnabled(true); m_Widget1LayoutAction->setEnabled(true); m_Widget2LayoutAction->setEnabled(true); m_Widget3LayoutAction->setEnabled(true); m_RowWidget3And4LayoutAction->setEnabled(true); m_ColumnWidget3And4LayoutAction->setEnabled(false); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); m_2x2Dand3DWidgetLayoutAction->setEnabled(true); m_Left2Dand3DRight2DLayoutAction->setEnabled(true); break; } case LAYOUT_SMALLUPPERWIDGET2BIGAND4: { m_DefaultLayoutAction->setEnabled(true); m_2DImagesUpLayoutAction->setEnabled(true); m_2DImagesLeftLayoutAction->setEnabled(true); m_Big3DLayoutAction->setEnabled(true); m_Widget1LayoutAction->setEnabled(true); m_Widget2LayoutAction->setEnabled(true); m_Widget3LayoutAction->setEnabled(true); m_RowWidget3And4LayoutAction->setEnabled(true); m_ColumnWidget3And4LayoutAction->setEnabled(true); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(false); m_2x2Dand3DWidgetLayoutAction->setEnabled(true); m_Left2Dand3DRight2DLayoutAction->setEnabled(true); break; } case LAYOUT_LEFT2DAND3DRIGHT2D: { m_DefaultLayoutAction->setEnabled(true); m_2DImagesUpLayoutAction->setEnabled(true); m_2DImagesLeftLayoutAction->setEnabled(true); m_Big3DLayoutAction->setEnabled(true); m_Widget1LayoutAction->setEnabled(true); m_Widget2LayoutAction->setEnabled(true); m_Widget3LayoutAction->setEnabled(true); m_RowWidget3And4LayoutAction->setEnabled(true); m_ColumnWidget3And4LayoutAction->setEnabled(true); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); m_2x2Dand3DWidgetLayoutAction->setEnabled(true); m_Left2Dand3DRight2DLayoutAction->setEnabled(false); break; } } } #ifdef QMITK_USE_EXTERNAL_RENDERWINDOW_MENU void QmitkRenderWindowMenu::MoveWidgetToCorrectPos(float opacity) #else void QmitkRenderWindowMenu::MoveWidgetToCorrectPos(float /*opacity*/) #endif { #ifdef QMITK_USE_EXTERNAL_RENDERWINDOW_MENU int X=floor( double(this->parentWidget()->width() - this->width() - 8.0) ); int Y=7; QPoint pos = this->parentWidget()->mapToGlobal( QPoint(0,0) ); this->move( X+pos.x(), Y+pos.y() ); if(opacity<0) opacity=0; else if(opacity>1) opacity=1; this->setWindowOpacity(opacity); #else int moveX= floor( double(this->parentWidget()->width() - this->width() - 4.0) ); this->move( moveX, 3 ); this->show(); #endif } void QmitkRenderWindowMenu::ChangeFullScreenIcon() { if( m_FullScreenMode ) { const QIcon icon( iconLeaveFullScreen_xpm ); m_FullScreenButton->setIcon(icon); } else { const QIcon icon( iconFullScreen_xpm ); m_FullScreenButton->setIcon(icon); } } void QmitkRenderWindowMenu::OnCrosshairRotationModeSelected(QAction* action) { MITK_DEBUG << "selected crosshair mode " << action->data().toInt() ; emit ChangeCrosshairRotationMode( action->data().toInt() ); } void QmitkRenderWindowMenu::SetCrossHairVisibility( bool state ) { if(m_Renderer.IsNotNull()) { mitk::DataNode *n; if(this->m_MultiWidget) { n = this->m_MultiWidget->GetWidgetPlane1(); if(n) n->SetVisibility(state); n = this->m_MultiWidget->GetWidgetPlane2(); if(n) n->SetVisibility(state); n = this->m_MultiWidget->GetWidgetPlane3(); if(n) n->SetVisibility(state); m_Renderer->GetRenderingManager()->RequestUpdateAll(); } } } void QmitkRenderWindowMenu::OnTSNumChanged(int num) { MITK_DEBUG << "Thickslices num: " << num << " on renderer " << m_Renderer.GetPointer(); if(m_Renderer.IsNotNull()) { if(num==0) { m_Renderer->GetCurrentWorldGeometry2DNode()->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( 0 ) ); m_Renderer->GetCurrentWorldGeometry2DNode()->SetProperty( "reslice.thickslices.showarea", mitk::BoolProperty::New( false ) ); } else { m_Renderer->GetCurrentWorldGeometry2DNode()->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( 1 ) ); m_Renderer->GetCurrentWorldGeometry2DNode()->SetProperty( "reslice.thickslices.num", mitk::IntProperty::New( num ) ); m_Renderer->GetCurrentWorldGeometry2DNode()->SetProperty( "reslice.thickslices.showarea", mitk::BoolProperty::New( num > 1 ) ); } m_TSLabel->setText(QString::number(num*2+1)); m_Renderer->SendUpdateSlice(); m_Renderer->GetRenderingManager()->RequestUpdateAll(); } } void QmitkRenderWindowMenu::OnCrossHairMenuAboutToShow() { QMenu *crosshairModesMenu = m_CrosshairMenu; crosshairModesMenu->clear(); QAction* resetViewAction = new QAction(crosshairModesMenu); resetViewAction->setText("Reset view"); crosshairModesMenu->addAction( resetViewAction ); connect( resetViewAction, SIGNAL(triggered()), this, SIGNAL(ResetView())); // Show hide crosshairs { bool currentState = true; if(m_Renderer.IsNotNull()) { mitk::DataStorage *ds=m_Renderer->GetDataStorage(); mitk::DataNode *n; if(ds) { n = this->m_MultiWidget->GetWidgetPlane1(); if(n) { bool v; if(n->GetVisibility(v,0)) currentState&=v; } n = this->m_MultiWidget->GetWidgetPlane2(); if(n) { bool v; if(n->GetVisibility(v,0)) currentState&=v; } n = this->m_MultiWidget->GetWidgetPlane3(); if(n) { bool v; if(n->GetVisibility(v,0)) currentState&=v; } } } QAction* showHideCrosshairVisibilityAction = new QAction(crosshairModesMenu); showHideCrosshairVisibilityAction->setText("Show crosshair"); showHideCrosshairVisibilityAction->setCheckable(true); showHideCrosshairVisibilityAction->setChecked(currentState); crosshairModesMenu->addAction( showHideCrosshairVisibilityAction ); connect( showHideCrosshairVisibilityAction, SIGNAL(toggled(bool)), this, SLOT(SetCrossHairVisibility(bool))); } // Rotation mode { QAction* rotationGroupSeparator = new QAction(crosshairModesMenu); rotationGroupSeparator->setSeparator(true); rotationGroupSeparator->setText("Rotation mode"); crosshairModesMenu->addAction( rotationGroupSeparator ); QActionGroup* rotationModeActionGroup = new QActionGroup(crosshairModesMenu); rotationModeActionGroup->setExclusive(true); QAction* noCrosshairRotation = new QAction(crosshairModesMenu); noCrosshairRotation->setActionGroup(rotationModeActionGroup); noCrosshairRotation->setText("No crosshair rotation"); noCrosshairRotation->setCheckable(true); noCrosshairRotation->setChecked(currentCrosshairRotationMode==0); noCrosshairRotation->setData( 0 ); crosshairModesMenu->addAction( noCrosshairRotation ); QAction* singleCrosshairRotation = new QAction(crosshairModesMenu); singleCrosshairRotation->setActionGroup(rotationModeActionGroup); singleCrosshairRotation->setText("Crosshair rotation"); singleCrosshairRotation->setCheckable(true); singleCrosshairRotation->setChecked(currentCrosshairRotationMode==1); singleCrosshairRotation->setData( 1 ); crosshairModesMenu->addAction( singleCrosshairRotation ); QAction* coupledCrosshairRotation = new QAction(crosshairModesMenu); coupledCrosshairRotation->setActionGroup(rotationModeActionGroup); coupledCrosshairRotation->setText("Coupled crosshair rotation"); coupledCrosshairRotation->setCheckable(true); coupledCrosshairRotation->setChecked(currentCrosshairRotationMode==2); coupledCrosshairRotation->setData( 2 ); crosshairModesMenu->addAction( coupledCrosshairRotation ); QAction* swivelMode = new QAction(crosshairModesMenu); swivelMode->setActionGroup(rotationModeActionGroup); swivelMode->setText("Swivel mode"); swivelMode->setCheckable(true); swivelMode->setChecked(currentCrosshairRotationMode==3); swivelMode->setData( 3 ); crosshairModesMenu->addAction( swivelMode ); connect( rotationModeActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(OnCrosshairRotationModeSelected(QAction*)) ); } // auto rotation support if( m_Renderer.IsNotNull() && m_Renderer->GetMapperID() == mitk::BaseRenderer::Standard3D ) { QAction* autoRotationGroupSeparator = new QAction(crosshairModesMenu); autoRotationGroupSeparator->setSeparator(true); crosshairModesMenu->addAction( autoRotationGroupSeparator ); QAction* autoRotationAction = crosshairModesMenu->addAction( "Auto Rotation" ); autoRotationAction->setCheckable(true); autoRotationAction->setChecked( m_AutoRotationTimer.isActive() ); connect( autoRotationAction, SIGNAL(triggered()), this, SLOT(OnAutoRotationActionTriggered()) ); } // Thickslices support if( m_Renderer.IsNotNull() && m_Renderer->GetMapperID() == mitk::BaseRenderer::Standard2D ) { QAction* thickSlicesGroupSeparator = new QAction(crosshairModesMenu); thickSlicesGroupSeparator->setSeparator(true); thickSlicesGroupSeparator->setText("ThickSlices mode"); crosshairModesMenu->addAction( thickSlicesGroupSeparator ); QActionGroup* thickSlicesActionGroup = new QActionGroup(crosshairModesMenu); thickSlicesActionGroup->setExclusive(true); int currentMode = 0; { mitk::ResliceMethodProperty::Pointer m = dynamic_cast(m_Renderer->GetCurrentWorldGeometry2DNode()->GetProperty( "reslice.thickslices" )); if( m.IsNotNull() ) currentMode = m->GetValueAsId(); } int currentNum = 1; { mitk::IntProperty::Pointer m = dynamic_cast(m_Renderer->GetCurrentWorldGeometry2DNode()->GetProperty( "reslice.thickslices.num" )); if( m.IsNotNull() ) { currentNum = m->GetValue(); if(currentNum < 1) currentNum = 1; if(currentNum > 10) currentNum = 10; } } if(currentMode==0) currentNum=0; QSlider *m_TSSlider = new QSlider(crosshairModesMenu); m_TSSlider->setMinimum(0); m_TSSlider->setMaximum(9); m_TSSlider->setValue(currentNum); m_TSSlider->setOrientation(Qt::Horizontal); connect( m_TSSlider, SIGNAL( valueChanged(int) ), this, SLOT( OnTSNumChanged(int) ) ); QHBoxLayout* _TSLayout = new QHBoxLayout; _TSLayout->setContentsMargins(4,4,4,4); _TSLayout->addWidget(new QLabel("TS: ")); _TSLayout->addWidget(m_TSSlider); _TSLayout->addWidget(m_TSLabel=new QLabel(QString::number(currentNum*2+1),this)); QWidget* _TSWidget = new QWidget; _TSWidget->setLayout(_TSLayout); QWidgetAction *m_TSSliderAction = new QWidgetAction(crosshairModesMenu); m_TSSliderAction->setDefaultWidget(_TSWidget); crosshairModesMenu->addAction(m_TSSliderAction); } } void QmitkRenderWindowMenu::NotifyNewWidgetPlanesMode( int mode ) { currentCrosshairRotationMode = mode; } void QmitkRenderWindowMenu::OnAutoRotationActionTriggered() { if(m_AutoRotationTimer.isActive()) { m_AutoRotationTimer.stop(); m_Renderer->GetCameraRotationController()->GetSlice()->PingPongOff(); } else { m_Renderer->GetCameraRotationController()->GetSlice()->PingPongOn(); m_AutoRotationTimer.start(); } } void QmitkRenderWindowMenu::AutoRotateNextStep() { if(m_Renderer->GetCameraRotationController()) m_Renderer->GetCameraRotationController()->GetSlice()->Next(); } diff --git a/Modules/Qmitk/QmitkRenderWindowMenu.h b/Modules/Qmitk/QmitkRenderWindowMenu.h index 4f51c75deb..503eb97cb1 100644 --- a/Modules/Qmitk/QmitkRenderWindowMenu.h +++ b/Modules/Qmitk/QmitkRenderWindowMenu.h @@ -1,324 +1,339 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 QmitkRenderWindowMenu_h #define QmitkRenderWindowMenu_h #if defined(_WIN32) || defined(__APPLE__) #define QMITK_USE_EXTERNAL_RENDERWINDOW_MENU #endif #include #include "mitkBaseRenderer.h" #include #include #include #include #include #include #include class QmitkStdMultiWidget; /** * \brief The QmitkRenderWindowMenu is a popup Widget which shows up when the mouse curser enter a QmitkRenderWindow. * The Menu Widget is located in the right top corner of each RenderWindow. It includes different settings. For example * the layout design can be changed with the setting button. Switching between full-screen mode and layout design can be done * with the full-screen button. Splitting the Widget horizontal or vertical as well closing the Widget is not implemented yet. * The popup Widget can be deactivated with ActivateMenuWidget(false) in QmitkRenderWindow. * * \ingroup Renderer * * \sa QmitkRenderWindow * \sa QmitkStdMultiWidget * */ class QMITK_EXPORT QmitkRenderWindowMenu : public QWidget { Q_OBJECT public: QmitkRenderWindowMenu( QWidget* parent = 0, Qt::WFlags f = 0, mitk::BaseRenderer * b = 0, QmitkStdMultiWidget* mw = 0 ); virtual ~QmitkRenderWindowMenu(); /*! Return visibility of settings menu. The menu is connected with m_SettingsButton and includes - layout direction (transversal, coronal .. ) and layout design (standard layout, 2D images top, + layout direction (axial, coronal .. ) and layout design (standard layout, 2D images top, 3D bottom ... ). */ bool GetSettingsMenuVisibilty() { if( m_Settings == NULL) return false; else return m_Settings->isVisible(); } - /*! Set layout index. Defines layout direction (transversal, coronal, sagital or threeD) of the parent. */ + /*! Set layout index. Defines layout direction (axial, coronal, sagital or threeD) of the parent. */ void SetLayoutIndex( unsigned int layoutIndex ); - /*! Return layout direction of parent (transversal, coronal, sagital or threeD) */ + /*! Return layout direction of parent (axial, coronal, sagital or threeD) */ unsigned int GetLayoutIndex() { return m_Layout; } /*! Update list of layout design (standard layout, 2D images top, 3D bottom ..). Set action of current layout design to disable and all other to enable. */ void UpdateLayoutDesignList( int layoutDesignIndex ); /*! Move menu widget to correct position (right upper corner). E.g. it is necessary when the full-screen mode is activated.*/ #ifdef QMITK_USE_EXTERNAL_RENDERWINDOW_MENU void MoveWidgetToCorrectPos(float opacity); #else void MoveWidgetToCorrectPos(float /*opacity*/); #endif void ChangeFullScreenMode( bool state ); void NotifyNewWidgetPlanesMode( int mode ); protected: /*! Create menu widget. The menu contains five QPushButtons (hori-split, verti-split, full-screen, settings and close button) and their signal/slot connection for handling. */ void CreateMenuWidget(); /*! Create settings menu which contains layout direction and the different layout designs. */ void CreateSettingsWidget(); /*! Reimplemented from QWidget. The paint event is a request to repaint all or part of a widget.*/ void paintEvent(QPaintEvent *event); - /*! Update list of layout direction (transversal, coronal, sagital or threeD). Set action of currect layout direction + /*! Update list of layout direction (axial, coronal, sagital or threeD). Set action of currect layout direction to disable and all other to enable. Normaly the user can switch here between the different layout direction, but this is not supported yet. */ void UpdateLayoutList(); /*! Change Icon of full-screen button depending on full-screen mode. */ void ChangeFullScreenIcon(); int currentCrosshairRotationMode; public slots: void SetCrossHairVisibility( bool state ) ; signals: void ResetView(); // == "global reinit" // \brief int parameters are enum from QmitkStdMultiWidget void ChangeCrosshairRotationMode(int); /*! emit signal, when layout design changed by the setting menu.*/ void SignalChangeLayoutDesign( int layoutDesign ); public slots: void DeferredHideMenu( ); void DeferredShowMenu( ); void smoothHide( ); protected slots: /// /// this function is continously called by a timer /// to do the auto rotation /// void AutoRotateNextStep(); /// /// this function is invoked when the auto-rotate action /// is clicked /// void OnAutoRotationActionTriggered(); void enterEvent( QEvent* /*e*/ ); void leaveEvent( QEvent* /*e*/ ); void OnTSNumChanged(int); void OnCrosshairRotationModeSelected(QAction*); /*! slot for activating/deactivating the full-screen mode. The slot is connected to the clicked() event of m_FullScreenButton. Activating the full-screen maximize the current widget, deactivating restore If layout design changed by the settings menu, the full-Screen mode is automatically switch to false. */ void OnFullScreenButton( bool checked ); /*! Slot for opening setting menu. The slot is connected to the clicked() event of m_SettingsButton. - The settings menu includes differen layout directions (transversal, coronal, saggital and 3D) as well all layout design + The settings menu includes differen layout directions (axial, coronal, saggital and 3D) as well all layout design (standard layout, 2D images top, 3D bottom ..)*/ void OnSettingsButton( bool checked ); /*! Slot for changing layout design to standard layout. The slot is connected to the triggered() signal of m_DefaultLayoutAction. */ void OnChangeLayoutToDefault(bool); /*! Slot for changing layout design to 2D images top, 3D bottom layout. The slot is connected to the triggered() signal of m_2DImagesUpLayoutAction. */ void OnChangeLayoutTo2DImagesUp(bool); /*! Slot for changing layout design to 2D images left, 3D right layout. The slot is connected to the triggered() signal of m_2DImagesLeftLayoutAction. */ void OnChangeLayoutTo2DImagesLeft(bool); /*! Slot for changing layout to Big 3D layout. The slot is connected to the triggered() signal of m_Big3DLayoutAction. */ void OnChangeLayoutToBig3D(bool); - /*! Slot for changing layout design to Transversal plane layout. The slot is connected to the triggered() signal of m_Widget1LayoutAction. */ + /*! Slot for changing layout design to Axial plane layout. The slot is connected to the triggered() signal of m_Widget1LayoutAction. */ void OnChangeLayoutToWidget1(bool); /*! Slot for changing layout design to Sagittal plane layout. The slot is connected to the triggered() signal of m_Widget2LayoutAction. */ void OnChangeLayoutToWidget2(bool); /*! Slot for changing layout design to Coronal plane layout. The slot is connected to the triggered() signal of m_Widget3LayoutAction. */ void OnChangeLayoutToWidget3(bool); /*! Slot for changing layout design to Coronal top, 3D bottom layout. The slot is connected to the triggered() signal of m_RowWidget3And4LayoutAction. */ void OnChangeLayoutToRowWidget3And4(bool); /*! Slot for changing layout design to Coronal left, 3D right layout. The slot is connected to the triggered() signal of m_ColumnWidget3And4LayoutAction. */ void OnChangeLayoutToColumnWidget3And4(bool); /*! Slot for changing layout design to Sagittal top, Coronal n 3D bottom layout. The slot is connected to the triggered() signal of m_SmallUpperWidget2Big3and4LayoutAction. */ void OnChangeLayoutToSmallUpperWidget2Big3and4(bool); - /*! Slot for changing layout design to Transversal n Sagittal left, 3D right layout. The slot is connected to the triggered() signal of m_2x2Dand3DWidgetLayoutAction. */ + /*! Slot for changing layout design to Axial n Sagittal left, 3D right layout. The slot is connected to the triggered() signal of m_2x2Dand3DWidgetLayoutAction. */ void OnChangeLayoutTo2x2Dand3DWidget(bool); - /*! Slot for changing layout design to Transversal n 3D left, Sagittal right layout. The slot is connected to the triggered() signal of m_Left2Dand3DRight2DLayoutAction. */ + /*! Slot for changing layout design to Axial n 3D left, Sagittal right layout. The slot is connected to the triggered() signal of m_Left2Dand3DRight2DLayoutAction. */ void OnChangeLayoutToLeft2Dand3DRight2D(bool); void OnCrossHairMenuAboutToShow(); public: /*! enum for layout direction*/ - enum { - TRANSVERSAL, + enum + { +#ifdef _MSC_VER + TRANSVERSAL, // deprecated +#endif + AXIAL = 0, SAGITTAL, CORONAL, THREE_D }; +#ifdef __GNUC__ + __attribute__ ((deprecated)) static const int TRANSVERSAL = AXIAL; +#endif /*! enum for layout design */ - enum { + enum + { LAYOUT_DEFAULT, LAYOUT_2DIMAGEUP, LAYOUT_2DIMAGELEFT, LAYOUT_BIG3D, - LAYOUT_TRANSVERSAL, +#ifdef _MSC_VER + LAYOUT_TRANSVERSAL, // deprecated +#endif + LAYOUT_AXIAL = LAYOUT_BIG3D + 1, LAYOUT_SAGITTAL, LAYOUT_CORONAL, LAYOUT_2X2DAND3DWIDGET, LAYOUT_ROWWIDGET3AND4, LAYOUT_COLUMNWIDGET3AND4, LAYOUT_ROWWIDGETSMALL3ANDBIG4, //not in use in this class, but we need it here to synchronize with the SdtMultiWidget. LAYOUT_SMALLUPPERWIDGET2BIGAND4, LAYOUT_LEFT2DAND3DRIGHT2D }; +#ifdef __GNUC__ + __attribute__ ((deprecated)) static const int LAYOUT_TRANSVERSAL = LAYOUT_AXIAL; +#endif + void ShowMenu(); void HideMenu(); protected: QPushButton* m_CrosshairModeButton; //QAction* m_ShowHideCrosshairVisibilityAction; /*! QPushButton for activating/deactivating full-screen mode*/ QPushButton* m_FullScreenButton; /*! QPushButton for open the settings menu*/ QPushButton* m_SettingsButton; /*! QAction for Default layout design */ QAction* m_DefaultLayoutAction; /*! QAction for 2D images up layout design */ QAction* m_2DImagesUpLayoutAction; /*! QAction for 2D images left layout design */ QAction* m_2DImagesLeftLayoutAction; /*! QAction for big 3D layout design */ QAction* m_Big3DLayoutAction; - /*! QAction for big transversal layout design */ + /*! QAction for big axial layout design */ QAction* m_Widget1LayoutAction; /*! QAction for big saggital layout design */ QAction* m_Widget2LayoutAction; /*! QAction for big coronal layout design */ QAction* m_Widget3LayoutAction; /*! QAction for coronal top, 3D bottom layout design */ QAction* m_RowWidget3And4LayoutAction; /*! QAction for coronal left, 3D right layout design */ QAction* m_ColumnWidget3And4LayoutAction; /*! QAction for sagittal top, coronal n 3D bottom layout design */ QAction* m_SmallUpperWidget2Big3and4LayoutAction; - /*! QAction for transversal n sagittal left, 3D right layout design */ + /*! QAction for axial n sagittal left, 3D right layout design */ QAction* m_2x2Dand3DWidgetLayoutAction; - /*! QAction for transversal n 3D left, sagittal right layout design*/ + /*! QAction for axial n 3D left, sagittal right layout design*/ QAction* m_Left2Dand3DRight2DLayoutAction; QLabel *m_TSLabel; /*! QMenu containg all layout direction and layout design settings.*/ QMenu* m_Settings; QMenu* m_CrosshairMenu; - /*! Index of layout direction. 0: transversal; 1: saggital; 2: coronal; 3: threeD */ + /*! Index of layout direction. 0: axial; 1: saggital; 2: coronal; 3: threeD */ unsigned int m_Layout; /*! Index of layout design. 0: LAYOUT_DEFAULT; 1: LAYOUT_2DIMAGEUP; 2: LAYOUT_2DIMAGELEFT; 3: LAYOUT_BIG3D - 4: LAYOUT_TRANSVERSAL; 5: LAYOUT_SAGITTAL; 6: LAYOUT_CORONAL; 7: LAYOUT_2X2DAND3DWIDGET; 8: LAYOUT_ROWWIDGET3AND4; + 4: LAYOUT_AXIAL; 5: LAYOUT_SAGITTAL; 6: LAYOUT_CORONAL; 7: LAYOUT_2X2DAND3DWIDGET; 8: LAYOUT_ROWWIDGET3AND4; 9: LAYOUT_COLUMNWIDGET3AND4; 10: LAYOUT_ROWWIDGETSMALL3ANDBIG4; 11: LAYOUT_SMALLUPPERWIDGET2BIGAND4; 12: LAYOUT_LEFT2DAND3DRIGHT2D */ unsigned int m_LayoutDesign; /*! Store index of old layout design. It is used e.g. for the full-screen mode, when deactivating the mode the former layout design will restore.*/ unsigned int m_OldLayoutDesign; /*! Flag if full-screen mode is activated or deactivated. */ bool m_FullScreenMode; bool m_Entered; bool m_Hidden; private: mitk::BaseRenderer::Pointer m_Renderer; QmitkStdMultiWidget* m_MultiWidget; /// /// a timer for the auto rotate action /// QTimer m_AutoRotationTimer; }; #endif // QmitkRenderWindowMenu_H diff --git a/Modules/Qmitk/QmitkServiceListWidget.cpp b/Modules/Qmitk/QmitkServiceListWidget.cpp index a7f0ebc74f..22948357df 100644 --- a/Modules/Qmitk/QmitkServiceListWidget.cpp +++ b/Modules/Qmitk/QmitkServiceListWidget.cpp @@ -1,186 +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. ===================================================================*/ //#define _USE_MATH_DEFINES #include -// STL HEaders +// STL Headers #include -//QT headers -#include - //microservices #include -#include "mitkModuleContext.h" +#include #include +#include + const std::string QmitkServiceListWidget::VIEW_ID = "org.mitk.views.QmitkServiceListWidget"; QmitkServiceListWidget::QmitkServiceListWidget(QWidget* parent, Qt::WindowFlags f): QWidget(parent, f) { m_Controls = NULL; CreateQtPartControl(this); } QmitkServiceListWidget::~QmitkServiceListWidget() { m_Context->RemoveServiceListener(this, &QmitkServiceListWidget::OnServiceEvent); } //////////////////// INITIALIZATION ///////////////////// void QmitkServiceListWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkServiceListWidgetControls; m_Controls->setupUi(parent); this->CreateConnections(); } m_Context = mitk::GetModuleContext(); } void QmitkServiceListWidget::CreateConnections() { if ( m_Controls ) { connect( m_Controls->m_ServiceList, SIGNAL(currentItemChanged( QListWidgetItem *, QListWidgetItem *)), this, SLOT(OnServiceSelectionChanged()) ); } } void QmitkServiceListWidget::InitPrivate(const std::string& namingProperty, const std::string& filter) { if (filter.empty()) m_Filter = "(" + mitk::ServiceConstants::OBJECTCLASS() + "=" + m_Interface + ")"; else m_Filter = filter; m_NamingProperty = namingProperty; m_Context->RemoveServiceListener(this, &QmitkServiceListWidget::OnServiceEvent); m_Context->AddServiceListener(this, &QmitkServiceListWidget::OnServiceEvent, m_Filter); // Empty ListWidget this->m_ListContent.clear(); m_Controls->m_ServiceList->clear(); // get Services std::list services = this->GetAllRegisteredServices(); // Transfer them to the List for(std::list::iterator it = services.begin(); it != services.end(); ++it) AddServiceToList(*it); } ///////////// Methods & Slots Handling Direct Interaction ///////////////// bool QmitkServiceListWidget::GetIsServiceSelected(){ return (this->m_Controls->m_ServiceList->currentItem() != 0); } void QmitkServiceListWidget::OnServiceSelectionChanged(){ mitk::ServiceReference ref = this->GetServiceForListItem(this->m_Controls->m_ServiceList->currentItem()); if (! ref){ emit (ServiceSelectionChanged(mitk::ServiceReference())); return; } emit (ServiceSelectionChanged(ref)); } -mitk::ServiceReference QmitkServiceListWidget::GetSelectedService(){ +mitk::ServiceReference QmitkServiceListWidget::GetSelectedServiceReference(){ return this->GetServiceForListItem(this->m_Controls->m_ServiceList->currentItem()); } ///////////////// Methods & Slots Handling Logic ////////////////////////// void QmitkServiceListWidget::OnServiceEvent(const mitk::ServiceEvent event){ + //MITK_INFO << "ServiceEvent" << event.GetType(); switch (event.GetType()) { case mitk::ServiceEvent::MODIFIED: emit(ServiceModified(event.GetServiceReference())); RemoveServiceFromList(event.GetServiceReference()); AddServiceToList(event.GetServiceReference()); break; case mitk::ServiceEvent::REGISTERED: emit(ServiceRegistered(event.GetServiceReference())); AddServiceToList(event.GetServiceReference()); break; case mitk::ServiceEvent::UNREGISTERING: emit(ServiceUnregistering(event.GetServiceReference())); RemoveServiceFromList(event.GetServiceReference()); break; case mitk::ServiceEvent::MODIFIED_ENDMATCH: emit(ServiceModifiedEndMatch(event.GetServiceReference())); RemoveServiceFromList(event.GetServiceReference()); break; } } /////////////////////// HOUSEHOLDING CODE ///////////////////////////////// QListWidgetItem* QmitkServiceListWidget::AddServiceToList(mitk::ServiceReference serviceRef){ QListWidgetItem *newItem = new QListWidgetItem; std::string caption; //TODO allow more complex formatting if (m_NamingProperty.empty()) caption = m_Interface; - else - caption = serviceRef.GetProperty(m_NamingProperty).ToString(); + else + { + mitk::Any prop = serviceRef.GetProperty(m_NamingProperty); + if (prop.Empty()) + { + MITK_WARN << "QmitkServiceListWidget tried to resolve property '" + m_NamingProperty + "' but failed. Resorting to interface name for display."; + caption = m_Interface; + } + else + caption = prop.ToString(); + } newItem->setText(caption.c_str()); - //Add new item to QListWidget + // Add new item to QListWidget m_Controls->m_ServiceList->addItem(newItem); + m_Controls->m_ServiceList->sortItems(); // Construct link and add to internal List for reference QmitkServiceListWidget::ServiceListLink link; link.service = serviceRef; link.item = newItem; m_ListContent.push_back(link); return newItem; } bool QmitkServiceListWidget::RemoveServiceFromList(mitk::ServiceReference serviceRef){ for(std::vector::iterator it = m_ListContent.begin(); it != m_ListContent.end(); ++it){ if ( serviceRef == it->service ) { int row = m_Controls->m_ServiceList->row(it->item); QListWidgetItem* oldItem = m_Controls->m_ServiceList->takeItem(row); delete oldItem; this->m_ListContent.erase(it); return true; } } return false; } mitk::ServiceReference QmitkServiceListWidget::GetServiceForListItem(QListWidgetItem* item) { for(std::vector::iterator it = m_ListContent.begin(); it != m_ListContent.end(); ++it) if (item == it->item) return it->service; // Return invalid ServiceReference (will evaluate to false in bool expressions) return mitk::ServiceReference(); } std::list QmitkServiceListWidget::GetAllRegisteredServices(){ //Get Service References return m_Context->GetServiceReferences(m_Interface, m_Filter); } \ No newline at end of file diff --git a/Modules/Qmitk/QmitkServiceListWidget.h b/Modules/Qmitk/QmitkServiceListWidget.h index a9b9db5a13..0c5e5d037b 100644 --- a/Modules/Qmitk/QmitkServiceListWidget.h +++ b/Modules/Qmitk/QmitkServiceListWidget.h @@ -1,239 +1,239 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #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" /** * @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 +* 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() * * @ingroup QMITK */ 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 GetSelectedService(); + 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 = GetSelectedServiceAsClass(); \endverbatim + * \verbatim mitk::USDevice::Pointer device = GetSelectedService(); \endverbatim */ template - T* GetSelectedServiceAsClass() + T* GetSelectedService() { mitk::ServiceReference ref = GetServiceForListItem( this->m_Controls->m_ServiceList->currentItem() ); - return dynamic_cast ( m_Context->GetService(ref) ); + 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. - * This. Pass class T to tell the widget which class it should filter for - only services of this class will be listed. + * 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); + 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, std::string& filter) + 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 c4ddc41e34..92b48792e6 100644 --- a/Modules/Qmitk/QmitkStdMultiWidget.cpp +++ b/Modules/Qmitk/QmitkStdMultiWidget.cpp @@ -1,2214 +1,2216 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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" 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 is none was specified + * 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( TRANSVERSAL ); + 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::Transversal ); + 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::Transversal ) - // layoutName = "Transversal"; + //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 == transversal + //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() ); - //initialize m_TimeNavigationController: send time via sliceNavigationControllers - m_TimeNavigationController = mitk::SliceNavigationController::New("dummy"); + //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())); - // Set TimeNavigationController to RenderingManager - // (which uses it internally for views initialization!) - m_RenderingManager->SetTimeNavigationController( m_TimeNavigationController ); - //reverse connection between sliceNavigationControllers and m_TimeNavigationController mitkWidget1->GetSliceNavigationController() - ->ConnectGeometryTimeEvent(m_TimeNavigationController.GetPointer(), false); + ->ConnectGeometryTimeEvent(m_TimeNavigationController, false); mitkWidget2->GetSliceNavigationController() - ->ConnectGeometryTimeEvent(m_TimeNavigationController.GetPointer(), false); + ->ConnectGeometryTimeEvent(m_TimeNavigationController, false); mitkWidget3->GetSliceNavigationController() - ->ConnectGeometryTimeEvent(m_TimeNavigationController.GetPointer(), false); + ->ConnectGeometryTimeEvent(m_TimeNavigationController, false); mitkWidget4->GetSliceNavigationController() - ->ConnectGeometryTimeEvent(m_TimeNavigationController.GetPointer(), false); + ->ConnectGeometryTimeEvent(m_TimeNavigationController, false); m_MouseModeSwitcher = mitk::MouseModeSwitcher::New( mitk::GlobalInteraction::GetInstance() ); 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.GetPointer(); + 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 image3D; 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 ) ) { image3D = dynamic_cast(nodes->at(x)->GetData()); maxlayer = layer; } } } } std::stringstream stream; mitk::Index3D p; if(image3D.IsNotNull()) { image3D->GetGeometry()->WorldToIndex(crosshairPos, p); stream.precision(2); stream<<"Position: <" << std::fixed < mm"; stream<<"; Index: <"< "; mitk::ScalarType pixelValue = image3D->GetPixelValueByIndex(p, baseRenderer->GetTimeStep()); if (fabs(pixelValue)>1000000) { stream<<"; Time: " << baseRenderer->GetTime() << " ms; Pixelvalue: "<GetPixelValueByIndex(p, baseRenderer->GetTimeStep())<<" "; } else { stream<<"; Time: " << baseRenderer->GetTime() << " ms; Pixelvalue: "<GetPixelValueByIndex(p, baseRenderer->GetTimeStep())<<" "; } } 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/Qmitk/QmitkStdMultiWidget.h b/Modules/Qmitk/QmitkStdMultiWidget.h index 6bf69c2e9e..47e915a447 100644 --- a/Modules/Qmitk/QmitkStdMultiWidget.h +++ b/Modules/Qmitk/QmitkStdMultiWidget.h @@ -1,358 +1,359 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 QMITKSTDMULTIWIDGET_H_ #define QMITKSTDMULTIWIDGET_H_ #include #include "mitkPositionTracker.h" #include "mitkSlicesRotator.h" #include "mitkSlicesSwiveller.h" #include "mitkRenderWindowFrame.h" #include "mitkManufacturerLogo.h" #include "mitkGradientBackground.h" #include "mitkCoordinateSupplier.h" #include "mitkDataStorage.h" #include "mitkMouseModeSwitcher.h" #include #include #include #include #include #include "vtkTextProperty.h" #include "vtkCornerAnnotation.h" class QHBoxLayout; class QVBoxLayout; class QGridLayout; class QSpacerItem; class QmitkLevelWindowWidget; class QmitkRenderWindow; namespace mitk { class RenderingManager; } class QMITK_EXPORT QmitkStdMultiWidget : public QWidget { Q_OBJECT public: QmitkStdMultiWidget(QWidget* parent = 0, Qt::WindowFlags f = 0, mitk::RenderingManager* renderingManager = 0); virtual ~QmitkStdMultiWidget(); mitk::SliceNavigationController* GetTimeNavigationController(); void RequestUpdate(); void ForceImmediateUpdate(); mitk::MouseModeSwitcher* GetMouseModeSwitcher(); QmitkRenderWindow* GetRenderWindow1() const; QmitkRenderWindow* GetRenderWindow2() const; QmitkRenderWindow* GetRenderWindow3() const; QmitkRenderWindow* GetRenderWindow4() const; const mitk::Point3D & GetLastLeftClickPosition() const; const mitk::Point3D GetCrossPosition() const; void EnablePositionTracking(); void DisablePositionTracking(); int GetLayout() const; mitk::SlicesRotator * GetSlicesRotator() const; mitk::SlicesSwiveller * GetSlicesSwiveller() const; bool GetGradientBackgroundFlag() const; /*! \brief Access node of widget plane 1 \return DataNode holding widget plane 1 */ mitk::DataNode::Pointer GetWidgetPlane1(); /*! \brief Access node of widget plane 2 \return DataNode holding widget plane 2 */ mitk::DataNode::Pointer GetWidgetPlane2(); /*! \brief Access node of widget plane 3 \return DataNode holding widget plane 3 */ mitk::DataNode::Pointer GetWidgetPlane3(); /*! \brief Convenience method to access node of widget planes \param id number of widget plane to be returned \return DataNode holding widget plane 3 */ mitk::DataNode::Pointer GetWidgetPlane(int id); bool IsColoredRectanglesEnabled() const; bool IsDepartmentLogoEnabled() const; bool IsCrosshairNavigationEnabled() const; void InitializeWidget(); /// called when the StdMultiWidget is closed to remove the 3 widget planes and the helper node from the DataStorage void RemovePlanesFromDataStorage(); void AddPlanesToDataStorage(); void SetDataStorage( mitk::DataStorage* ds ); /** \brief Listener to the CrosshairPositionEvent Ensures the CrosshairPositionEvent is handled only once and at the end of the Qt-Event loop */ void HandleCrosshairPositionEvent(); /// activate Menu Widget. true: activated, false: deactivated void ActivateMenuWidget( bool state ); bool IsMenuWidgetEnabled() const; protected: void UpdateAllWidgets(); void HideAllWidgetToolbars(); public slots: /// Receives the signal from HandleCrosshairPositionEvent, executes the StatusBar update void HandleCrosshairPositionEventDelayed(); void changeLayoutTo2DImagesUp(); void changeLayoutTo2DImagesLeft(); void changeLayoutToDefault(); void changeLayoutToBig3D(); void changeLayoutToWidget1(); void changeLayoutToWidget2(); void changeLayoutToWidget3(); void changeLayoutToRowWidget3And4(); void changeLayoutToColumnWidget3And4(); void changeLayoutToRowWidgetSmall3andBig4(); void changeLayoutToSmallUpperWidget2Big3and4(); void changeLayoutTo2x2Dand3DWidget(); void changeLayoutToLeft2Dand3DRight2D(); void changeLayoutTo2DUpAnd3DDown(); void Fit(); void InitPositionTracking(); void AddDisplayPlaneSubTree(); void EnableStandardLevelWindow(); void DisableStandardLevelWindow(); bool InitializeStandardViews( const mitk::Geometry3D * geometry ); void wheelEvent( QWheelEvent * e ); void mousePressEvent(QMouseEvent * e); void moveEvent( QMoveEvent* e ); void leaveEvent ( QEvent * e ); void EnsureDisplayContainsPoint( mitk::DisplayGeometry* displayGeometry, const mitk::Point3D& p); void MoveCrossToPosition(const mitk::Point3D& newPosition); void EnableNavigationControllerEventListening(); void DisableNavigationControllerEventListening(); void EnableGradientBackground(); void DisableGradientBackground(); void EnableDepartmentLogo(); void DisableDepartmentLogo(); void EnableColoredRectangles(); void DisableColoredRectangles(); void SetWidgetPlaneVisibility(const char* widgetName, bool visible, mitk::BaseRenderer *renderer=NULL); void SetWidgetPlanesVisibility(bool visible, mitk::BaseRenderer *renderer=NULL); void SetWidgetPlanesLocked(bool locked); void SetWidgetPlanesRotationLocked(bool locked); void SetWidgetPlanesRotationLinked( bool link ); void SetWidgetPlaneMode( int mode ); void SetGradientBackgroundColors( const mitk::Color & upper, const mitk::Color & lower ); void SetDepartmentLogoPath( const char * path ); void SetWidgetPlaneModeToSlicing( bool activate ); void SetWidgetPlaneModeToRotation( bool activate ); void SetWidgetPlaneModeToSwivel( bool activate ); void OnLayoutDesignChanged( int layoutDesignIndex ); void ResetCrosshair(); void MouseModeSelected( mitk::MouseModeSwitcher::MouseMode mouseMode ); signals: void LeftMouseClicked(mitk::Point3D pointValue); void WheelMoved(QWheelEvent*); void WidgetPlanesRotationLinked(bool); void WidgetPlanesRotationEnabled(bool); void ViewsInitialized(); void WidgetPlaneModeSlicing(bool); void WidgetPlaneModeRotation(bool); void WidgetPlaneModeSwivel(bool); void WidgetPlaneModeChange(int); void WidgetNotifyNewCrossHairMode(int); void Moved(); public: /** Define RenderWindow (public)*/ QmitkRenderWindow* mitkWidget1; QmitkRenderWindow* mitkWidget2; QmitkRenderWindow* mitkWidget3; QmitkRenderWindow* mitkWidget4; QmitkLevelWindowWidget* levelWindowWidget; /********************************/ enum { PLANE_MODE_SLICING = 0, PLANE_MODE_ROTATION, PLANE_MODE_SWIVEL }; enum { LAYOUT_DEFAULT = 0, LAYOUT_2D_IMAGES_UP, LAYOUT_2D_IMAGES_LEFT, LAYOUT_BIG_3D, LAYOUT_WIDGET1, LAYOUT_WIDGET2, LAYOUT_WIDGET3, LAYOUT_2X_2D_AND_3D_WIDGET, LAYOUT_ROW_WIDGET_3_AND_4, LAYOUT_COLUMN_WIDGET_3_AND_4, LAYOUT_ROW_WIDGET_SMALL3_AND_BIG4 , LAYOUT_SMALL_UPPER_WIDGET2_BIG3_AND4,LAYOUT_2D_AND_3D_LEFT_2D_RIGHT_WIDGET, LAYOUT_2D_UP_AND_3D_DOWN}; enum { TRANSVERSAL, + AXIAL = TRANSVERSAL, SAGITTAL, CORONAL, THREE_D }; protected: QHBoxLayout* QmitkStdMultiWidgetLayout; int m_Layout; int m_PlaneMode; mitk::RenderingManager* m_RenderingManager; mitk::RenderWindowFrame::Pointer m_RectangleRendering3; mitk::RenderWindowFrame::Pointer m_RectangleRendering2; mitk::RenderWindowFrame::Pointer m_RectangleRendering1; mitk::RenderWindowFrame::Pointer m_RectangleRendering4; mitk::ManufacturerLogo::Pointer m_LogoRendering1; mitk::ManufacturerLogo::Pointer m_LogoRendering2; mitk::ManufacturerLogo::Pointer m_LogoRendering3; mitk::ManufacturerLogo::Pointer m_LogoRendering4; mitk::GradientBackground::Pointer m_GradientBackground1; mitk::GradientBackground::Pointer m_GradientBackground2; mitk::GradientBackground::Pointer m_GradientBackground4; mitk::GradientBackground::Pointer m_GradientBackground3; bool m_GradientBackgroundFlag; mitk::MouseModeSwitcher::Pointer m_MouseModeSwitcher; mitk::CoordinateSupplier::Pointer m_LastLeftClickPositionSupplier; mitk::PositionTracker::Pointer m_PositionTracker; - mitk::SliceNavigationController::Pointer m_TimeNavigationController; + mitk::SliceNavigationController* m_TimeNavigationController; mitk::SlicesRotator::Pointer m_SlicesRotator; mitk::SlicesSwiveller::Pointer m_SlicesSwiveller; mitk::DataNode::Pointer m_PositionTrackerNode; mitk::DataStorage::Pointer m_DataStorage; mitk::DataNode::Pointer m_PlaneNode1; mitk::DataNode::Pointer m_PlaneNode2; mitk::DataNode::Pointer m_PlaneNode3; mitk::DataNode::Pointer m_Node; QSplitter *m_MainSplit; QSplitter *m_LayoutSplit; QSplitter *m_SubSplit1; QSplitter *m_SubSplit2; QWidget *mitkWidget1Container; QWidget *mitkWidget2Container; QWidget *mitkWidget3Container; QWidget *mitkWidget4Container; struct { vtkCornerAnnotation *cornerText; vtkTextProperty *textProp; vtkRenderer *ren; } m_CornerAnnotaions[3]; bool m_PendingCrosshairPositionEvent; bool m_CrosshairNavigationEnabled; }; #endif /*QMITKSTDMULTIWIDGET_H_*/ diff --git a/Modules/QmitkExt/QmitkAboutDialog/QmitkAboutDialog.cpp b/Modules/QmitkExt/QmitkAboutDialog/QmitkAboutDialog.cpp index be1d4dfb8d..52578f7ca2 100644 --- a/Modules/QmitkExt/QmitkAboutDialog/QmitkAboutDialog.cpp +++ b/Modules/QmitkExt/QmitkAboutDialog/QmitkAboutDialog.cpp @@ -1,78 +1,76 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "QmitkAboutDialog.h" #include "QmitkModulesDialog.h" #include #include QmitkAboutDialog::QmitkAboutDialog(QWidget* parent, Qt::WindowFlags f) : QDialog(parent, f) { m_GUI.setupUi(this); QString mitkRevision(MITK_REVISION); m_GUI.m_RevisionLabel->setText(m_GUI.m_RevisionLabel->text().arg(mitkRevision)); QPushButton* btnModules = new QPushButton(QIcon(":/qmitk/ModuleView.png"), "Modules"); m_GUI.m_ButtonBox->addButton(btnModules, QDialogButtonBox::ActionRole); connect(btnModules, SIGNAL(clicked()), this, SLOT(ShowModules())); connect(m_GUI.m_ButtonBox, SIGNAL(rejected()), this, SLOT(reject())); } QmitkAboutDialog::~QmitkAboutDialog() { } void QmitkAboutDialog::ShowModules() { QmitkModulesDialog dialog(this); dialog.exec(); - - SetCaptionText("MITK Diffusion"); } QString QmitkAboutDialog::GetAboutText() const { return m_GUI.m_AboutLabel->text(); } QString QmitkAboutDialog::GetCaptionText() const { return m_GUI.m_CaptionLabel->text(); } QString QmitkAboutDialog::GetRevisionText() const { return m_GUI.m_RevisionLabel->text(); } void QmitkAboutDialog::SetAboutText(const QString &text) { m_GUI.m_AboutLabel->setText(text); } void QmitkAboutDialog::SetCaptionText(const QString &text) { m_GUI.m_CaptionLabel->setText(text); } void QmitkAboutDialog::SetRevisionText(const QString &text) { m_GUI.m_RevisionLabel->setText(text); } diff --git a/Modules/QmitkExt/QmitkPointListWidget.cpp b/Modules/QmitkExt/QmitkPointListWidget.cpp index 5013135464..4463936991 100644 --- a/Modules/QmitkExt/QmitkPointListWidget.cpp +++ b/Modules/QmitkExt/QmitkPointListWidget.cpp @@ -1,466 +1,471 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "QmitkPointListWidget.h" #include #include #include #include #include #include #include #include #include "btnLoad.xpm" #include "btnSave.xpm" #include "btnClear.xpm" #include "btnSetPoints.xpm" #include "btnSetPointsManually.xpm" #include "btnUp.xpm" #include "btnDown.xpm" QmitkPointListWidget::QmitkPointListWidget(QWidget *parent, int orientation): QWidget(parent), m_PointListView(NULL), m_MultiWidget(NULL), m_PointSetNode(NULL), m_Orientation(0), m_MovePointUpBtn(NULL), m_MovePointDownBtn(NULL), m_RemovePointBtn(NULL), m_SavePointsBtn(NULL), m_LoadPointsBtn(NULL), m_ToggleAddPoint(NULL), m_AddPoint(NULL), m_Interactor(NULL), m_TimeStep(0), m_EditAllowed(true), m_NodeObserverTag(0), m_Snc1(NULL), m_Snc2(NULL), m_Snc3(NULL) { m_PointListView = new QmitkPointListView(); if(orientation != 0) m_Orientation = orientation; SetupUi(); SetupConnections(); ObserveNewNode(NULL); } QmitkPointListWidget::~QmitkPointListWidget() { if (m_Interactor) mitk::GlobalInteraction::GetInstance()->RemoveInteractor( m_Interactor ); m_Interactor = NULL; if(m_PointSetNode && m_NodeObserverTag) { m_PointSetNode->RemoveObserver(m_NodeObserverTag); m_NodeObserverTag = 0; } m_MultiWidget = NULL; delete m_PointListView; } void QmitkPointListWidget::SetupConnections() { //m_PointListView->setModel(m_PointListModel); connect(this->m_LoadPointsBtn, SIGNAL(clicked()), this, SLOT(OnBtnLoadPoints())); connect(this->m_SavePointsBtn, SIGNAL(clicked()), this, SLOT(OnBtnSavePoints())); connect(this->m_MovePointUpBtn, SIGNAL(clicked()), this, SLOT(MoveSelectedPointUp())); connect(this->m_MovePointDownBtn, SIGNAL(clicked()), this, SLOT(MoveSelectedPointDown())); connect(this->m_RemovePointBtn, SIGNAL(clicked()), this, SLOT(RemoveSelectedPoint())); connect(this->m_ToggleAddPoint, SIGNAL(toggled(bool)), this, SLOT(OnBtnAddPoint(bool))); connect(this->m_AddPoint, SIGNAL(clicked()), this, SLOT(OnBtnAddPointManually())); connect(this->m_PointListView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(OnListDoubleClick())); connect(this->m_PointListView, SIGNAL(SignalPointSelectionChanged()), this, SLOT(OnPointSelectionChanged())); } void QmitkPointListWidget::SetupUi() { //Setup the buttons m_ToggleAddPoint = new QPushButton();//iconSetPoints, "", this); m_ToggleAddPoint->setMaximumSize(25,25); m_ToggleAddPoint->setCheckable(true); m_ToggleAddPoint->setToolTip("Toggle point editing (use SHIFT + Left Mouse Button to add Points)"); QIcon iconAdd(btnSetPoints_xpm); m_ToggleAddPoint->setIcon(iconAdd); m_AddPoint = new QPushButton();//iconSetPoints, "", this); m_AddPoint->setMaximumSize(25,25); m_AddPoint->setToolTip("Manually add point"); QIcon iconAddManually(btnSetPointsManually_xpm); m_AddPoint->setIcon(iconAddManually); m_RemovePointBtn = new QPushButton(); m_RemovePointBtn->setMaximumSize(25, 25); const QIcon iconDel(btnClear_xpm); m_RemovePointBtn->setIcon(iconDel); m_RemovePointBtn->setToolTip("Erase one point from list (Hotkey: DEL)"); m_MovePointUpBtn = new QPushButton(); m_MovePointUpBtn->setMaximumSize(25, 25); const QIcon iconUp(btnUp_xpm); m_MovePointUpBtn->setIcon(iconUp); m_MovePointUpBtn->setToolTip("Swap selected point upwards (Hotkey: F2)"); m_MovePointDownBtn = new QPushButton(); m_MovePointDownBtn->setMaximumSize(25, 25); const QIcon iconDown(btnDown_xpm); m_MovePointDownBtn->setIcon(iconDown); m_MovePointDownBtn->setToolTip("Swap selected point downwards (Hotkey: F3)"); m_SavePointsBtn = new QPushButton(); m_SavePointsBtn->setMaximumSize(25, 25); QIcon iconSave(btnSave_xpm); m_SavePointsBtn->setIcon(iconSave); m_SavePointsBtn->setToolTip("Save points to file"); m_LoadPointsBtn = new QPushButton(); m_LoadPointsBtn->setMaximumSize(25, 25); QIcon iconLoad(btnLoad_xpm); m_LoadPointsBtn->setIcon(iconLoad); m_LoadPointsBtn->setToolTip("Load list of points from file (REPLACES current content)"); int i; QBoxLayout* lay1; QBoxLayout* lay2; switch (m_Orientation) { case 0: lay1 = new QVBoxLayout(this); lay2 = new QHBoxLayout(); i = 0; break; case 1: lay1 = new QHBoxLayout(this); lay2 = new QVBoxLayout(); i=-1; break; case 2: lay1 = new QHBoxLayout(this); lay2 = new QVBoxLayout(); i=0; break; default: lay1 = new QVBoxLayout(this); lay2 = new QHBoxLayout(); i=-1; break; } //setup Layouts this->setLayout(lay1); lay1->addLayout(lay2); lay2->stretch(true); lay2->addWidget(m_ToggleAddPoint); lay2->addWidget(m_AddPoint); lay2->addWidget(m_RemovePointBtn); lay2->addWidget(m_MovePointUpBtn); lay2->addWidget(m_MovePointDownBtn); lay2->addWidget(m_SavePointsBtn); lay2->addWidget(m_LoadPointsBtn); //lay2->addSpacing();; lay1->insertWidget(i,m_PointListView); this->setLayout(lay1); } void QmitkPointListWidget::SetPointSet(mitk::PointSet* newPs) { if(newPs == NULL) return; this->m_PointSetNode->SetData(newPs); dynamic_cast(this->m_PointListView->model())->SetPointSetNode(m_PointSetNode); ObserveNewNode(m_PointSetNode); } void QmitkPointListWidget::SetPointSetNode(mitk::DataNode *newNode) { ObserveNewNode(newNode); dynamic_cast(this->m_PointListView->model())->SetPointSetNode(newNode); } void QmitkPointListWidget::OnBtnSavePoints() { if ((dynamic_cast(m_PointSetNode->GetData())) == NULL) return; // don't write empty point sets. If application logic requires something else then do something else. if ((dynamic_cast(m_PointSetNode->GetData()))->GetSize() == 0) return; // let the user choose a file std::string name(""); QString fileNameProposal = QString("/PointSet.mps");//.arg(m_PointSetNode->GetName().c_str()); //"PointSet.mps"; QString aFilename = QFileDialog::getSaveFileName( NULL, "Save point set", QDir::currentPath() + fileNameProposal, "MITK Pointset (*.mps)" ); if ( aFilename.isEmpty() ) return; try { // instantiate the writer and add the point-sets to write mitk::PointSetWriter::Pointer writer = mitk::PointSetWriter::New(); writer->SetInput( dynamic_cast(m_PointSetNode->GetData()) ); writer->SetFileName( aFilename.toLatin1() ); writer->Update(); } catch(...) { QMessageBox::warning( this, "Save point set", QString("File writer reported problems writing %1\n\n" "PLEASE CHECK output file!").arg(aFilename) ); } } void QmitkPointListWidget::OnBtnLoadPoints() { // get the name of the file to load QString filename = QFileDialog::getOpenFileName( NULL, "Open MITK Pointset", "", "MITK Point Sets (*.mps)"); if ( filename.isEmpty() ) return; // attempt to load file try { mitk::PointSetReader::Pointer reader = mitk::PointSetReader::New(); reader->SetFileName( filename.toLatin1() ); reader->Update(); mitk::PointSet::Pointer pointSet = reader->GetOutput(); if ( pointSet.IsNull() ) { QMessageBox::warning( this, "Load point set", QString("File reader could not read %1").arg(filename) ); return; } // loading successful // bool interactionOn( m_Interactor.IsNotNull() ); // if (interactionOn) // { // OnEditPointSetButtonToggled(false); // } // this->SetPointSet(pointSet); // if (interactionOn) // { // OnEditPointSetButtonToggled(true); // } } catch(...) { QMessageBox::warning( this, "Load point set", QString("File reader collapsed while reading %1").arg(filename) ); } emit PointListChanged(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } mitk::PointSet* QmitkPointListWidget::GetPointSet() { return dynamic_cast(m_PointSetNode->GetData()); } mitk::DataNode* QmitkPointListWidget::GetPointSetNode() { return m_PointSetNode; } void QmitkPointListWidget::SetMultiWidget(QmitkStdMultiWidget *multiWidget) { this->m_MultiWidget = multiWidget; m_PointListView->SetMultiWidget(multiWidget); } void QmitkPointListWidget::RemoveSelectedPoint() { if (!m_PointSetNode) return; mitk::PointSet* pointSet = dynamic_cast( m_PointSetNode->GetData() ); if (!pointSet) return; if (pointSet->GetSize() == 0) return; QmitkPointListModel* pointListModel = dynamic_cast( m_PointListView->model() ); pointListModel->RemoveSelectedPoint(); emit PointListChanged(); } void QmitkPointListWidget::MoveSelectedPointDown() { if (!m_PointSetNode) return; mitk::PointSet* pointSet = dynamic_cast( m_PointSetNode->GetData() ); if (!pointSet) return; if (pointSet->GetSize() == 0) return; QmitkPointListModel* pointListModel = dynamic_cast( m_PointListView->model() ); pointListModel->MoveSelectedPointDown(); emit PointListChanged(); } void QmitkPointListWidget::MoveSelectedPointUp() { if (!m_PointSetNode) return; mitk::PointSet* pointSet = dynamic_cast( m_PointSetNode->GetData() ); if (!pointSet) return; if (pointSet->GetSize() == 0) return; QmitkPointListModel* pointListModel = dynamic_cast( m_PointListView->model() ); pointListModel->MoveSelectedPointUp(); emit PointListChanged(); } void QmitkPointListWidget::OnBtnAddPoint(bool checked) { if (m_PointSetNode) { if (checked) { m_Interactor = dynamic_cast(m_PointSetNode->GetInteractor()); if (m_Interactor.IsNull())//if not present, instanciate one m_Interactor = mitk::PointSetInteractor::New("pointsetinteractor", m_PointSetNode); //add it to global interaction to activate it mitk::GlobalInteraction::GetInstance()->AddInteractor( m_Interactor ); } else if ( m_Interactor ) { mitk::GlobalInteraction::GetInstance()->RemoveInteractor( m_Interactor ); m_Interactor = NULL; } emit EditPointSets(checked); } } void QmitkPointListWidget::OnBtnAddPointManually() { mitk::PointSet* pointSet = this->GetPointSet(); int currentPosition = pointSet->GetSize(); QmitkEditPointDialog editPointDialog(this); editPointDialog.SetPoint(pointSet, currentPosition, m_TimeStep); editPointDialog.exec(); } void QmitkPointListWidget::OnListDoubleClick() { ; } void QmitkPointListWidget::OnPointSelectionChanged() { emit this->PointSelectionChanged(); } void QmitkPointListWidget::DeactivateInteractor(bool /*deactivate*/) { ; } void QmitkPointListWidget::EnableEditButton( bool enabled ) { m_EditAllowed = enabled; if (enabled == false) m_ToggleAddPoint->setEnabled(false); else m_ToggleAddPoint->setEnabled(true); OnBtnAddPoint(enabled); } void QmitkPointListWidget::ObserveNewNode( mitk::DataNode* node ) { // remove old observer if ( m_PointSetNode ) { if (m_Interactor) { mitk::GlobalInteraction::GetInstance()->RemoveInteractor( m_Interactor ); m_Interactor = NULL; m_ToggleAddPoint->setChecked( false ); } m_PointSetNode->RemoveObserver( m_NodeObserverTag ); m_NodeObserverTag = 0; } m_PointSetNode = node; // add new observer if necessary if ( m_PointSetNode ) { itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction( this, &QmitkPointListWidget::OnNodeDeleted ); m_NodeObserverTag = m_PointSetNode->AddObserver( itk::DeleteEvent(), command ); } else { m_NodeObserverTag = 0; } if (m_EditAllowed == true) m_ToggleAddPoint->setEnabled( m_PointSetNode ); else m_ToggleAddPoint->setEnabled( false ); m_RemovePointBtn->setEnabled( m_PointSetNode ); m_LoadPointsBtn->setEnabled( m_PointSetNode ); m_SavePointsBtn->setEnabled(m_PointSetNode); m_AddPoint->setEnabled(m_PointSetNode); } void QmitkPointListWidget::OnNodeDeleted( const itk::EventObject & /*e*/ ) { if(m_PointSetNode.IsNotNull() && ! m_NodeObserverTag) m_PointSetNode->RemoveObserver( m_NodeObserverTag ); m_NodeObserverTag = 0; m_PointSetNode = NULL; m_PointListView->SetPointSetNode(NULL); m_ToggleAddPoint->setEnabled(false); m_RemovePointBtn->setEnabled( false ); m_LoadPointsBtn->setEnabled( false ); m_SavePointsBtn->setEnabled(false); m_AddPoint->setEnabled(false); } void QmitkPointListWidget::SetSnc1(mitk::SliceNavigationController* snc) { m_Snc1 = snc; m_PointListView->SetSnc1(snc); } void QmitkPointListWidget::SetSnc2(mitk::SliceNavigationController* snc) { m_Snc2 = snc; m_PointListView->SetSnc2(snc); } void QmitkPointListWidget::SetSnc3(mitk::SliceNavigationController* snc) { m_Snc3 = snc; m_PointListView->SetSnc3(snc); } + +void QmitkPointListWidget::UnselectEditButton() +{ + m_ToggleAddPoint->setChecked(false); +} \ No newline at end of file diff --git a/Modules/QmitkExt/QmitkPointListWidget.h b/Modules/QmitkExt/QmitkPointListWidget.h index e789f89e20..6ce96d8d9d 100644 --- a/Modules/QmitkExt/QmitkPointListWidget.h +++ b/Modules/QmitkExt/QmitkPointListWidget.h @@ -1,150 +1,153 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 QmitkPointListWidget_H #define QmitkPointListWidget_H #include #include #include "QmitkExtExports.h" #include #include #include #include #include #include /*! * \brief Widget for regular operations on point sets * * Displays a list of point coordinates and a couple of * buttons which * * \li enable point set interaction * \li clear all points from a set * \li load points from file * \li save points to file * * The user/application module of this widget needs to * assign a mitk::PointSet object to this widget. The user * also has to decide whether it wants to put the point set * into (a) DataStorage. This widget will not add/remove * point sets to DataStorage. * * If the render window crosshair should be moved to the * currently selected point, the widget user has to provide * a QmitkStdMultiWidget object. */ class QmitkExt_EXPORT QmitkPointListWidget : public QWidget { Q_OBJECT public: QmitkPointListWidget(QWidget *parent = 0, int orientation = 0); ~QmitkPointListWidget(); void SetupConnections(); ///@{ /** * \brief Sets the SliceNavigationController of the three 2D Renderwindows. * If they are defined, they can be used to automatically set the crosshair to the selected point */ void SetSnc1(mitk::SliceNavigationController* snc); void SetSnc2(mitk::SliceNavigationController* snc); void SetSnc3(mitk::SliceNavigationController* snc); ///@} - /// assign a point set (contained in a node of DataStorage) for observation + /** @brief assign a point set (contained in a node of DataStorage) for observation */ void SetPointSet(mitk::PointSet* newPs); mitk::PointSet* GetPointSet(); - /// assign a point set (contained in a node of DataStorage) for observation + /** @brief assign a point set (contained in a node of DataStorage) for observation */ void SetPointSetNode(mitk::DataNode* newNode); mitk::DataNode* GetPointSetNode(); - /// assign a QmitkStdMultiWidget for updating render window crosshair + /** @brief assign a QmitkStdMultiWidget for updating render window crosshair */ void SetMultiWidget(QmitkStdMultiWidget* multiWidget); - /// itk observer for node "delete" events + /** @brief itk observer for node "delete" events */ void OnNodeDeleted( const itk::EventObject & e ); + /** @brief Unselects the edit button if it is selected. */ + void UnselectEditButton(); + public slots: void DeactivateInteractor(bool deactivate); - void EnableEditButton(bool enabled); + void EnableEditButton(bool enabled); signals: - /// signal to inform about the state of the EditPointSetButton, whether an interactor for setting points is active or not + /** @brief signal to inform about the state of the EditPointSetButton, whether an interactor for setting points is active or not */ void EditPointSets(bool active); /// signal to inform that the selection of a point in the pointset has changed void PointSelectionChanged(); /// signal to inform about cleared or loaded point sets void PointListChanged(); protected slots: void OnBtnSavePoints(); void OnBtnLoadPoints(); void RemoveSelectedPoint(); void MoveSelectedPointDown(); void MoveSelectedPointUp(); void OnBtnAddPoint(bool checked); void OnBtnAddPointManually(); //void OnBtnSetPointsMode(bool checked); /*! \brief pass through signal from PointListView that point selection has changed */ void OnPointSelectionChanged(); void OnListDoubleClick(); protected: void SetupUi(); void ObserveNewNode(mitk::DataNode* node); QmitkPointListView* m_PointListView; QmitkStdMultiWidget* m_MultiWidget; mitk::DataNode::Pointer m_PointSetNode; int m_Orientation; QPushButton* m_MovePointUpBtn; QPushButton* m_MovePointDownBtn; QPushButton* m_RemovePointBtn; QPushButton* m_SavePointsBtn; QPushButton* m_LoadPointsBtn; QPushButton* m_ToggleAddPoint; QPushButton* m_AddPoint; mitk::SliceNavigationController* m_Snc1; mitk::SliceNavigationController* m_Snc2; mitk::SliceNavigationController* m_Snc3; mitk::PointSetInteractor::Pointer m_Interactor; int m_TimeStep; bool m_EditAllowed; unsigned long m_NodeObserverTag; }; #endif diff --git a/Modules/QmitkExt/QmitkSliceWidget.cpp b/Modules/QmitkExt/QmitkSliceWidget.cpp index 28d83697aa..c8da366816 100644 --- a/Modules/QmitkExt/QmitkSliceWidget.cpp +++ b/Modules/QmitkExt/QmitkSliceWidget.cpp @@ -1,370 +1,370 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "QmitkSliceWidget.h" #include "QmitkStepperAdapter.h" #include "mitkNodePredicateDataType.h" //#include "QmitkRenderWindow.h" // //#include "mitkSliceNavigationController.h" //#include "QmitkLevelWindowWidget.h" // //#include //#include "mitkRenderingManager.h" #include #include QmitkSliceWidget::QmitkSliceWidget(QWidget* parent, const char* name, - Qt::WindowFlags f) : - QWidget(parent, f) + Qt::WindowFlags f) : + QWidget(parent, f) { - this->setupUi(this); + this->setupUi(this); - if (name != 0) - this->setObjectName(name); + if (name != 0) + this->setObjectName(name); - popUp = new QMenu(this); - popUp->addAction("Transversal"); - popUp->addAction("Frontal"); - popUp->addAction("Sagittal"); + popUp = new QMenu(this); + popUp->addAction("Axial"); + popUp->addAction("Frontal"); + popUp->addAction("Sagittal"); - QObject::connect(popUp, SIGNAL(triggered(QAction*)), this, SLOT(ChangeView(QAction*)) ); - setPopUpEnabled(false); + QObject::connect(popUp, SIGNAL(triggered(QAction*)), this, SLOT(ChangeView(QAction*)) ); + setPopUpEnabled(false); - m_SlicedGeometry = 0; - m_View = mitk::SliceNavigationController::Transversal; + m_SlicedGeometry = 0; + m_View = mitk::SliceNavigationController::Axial; - QHBoxLayout *hlayout = new QHBoxLayout(container); - hlayout->setMargin(0); + QHBoxLayout *hlayout = new QHBoxLayout(container); + hlayout->setMargin(0); - // create widget - QString composedName("QmitkSliceWidget::"); - if (!this->objectName().isEmpty()) - composedName += this->objectName(); - else - composedName += "QmitkGLWidget"; - m_RenderWindow = new QmitkRenderWindow(container, composedName); - m_Renderer = m_RenderWindow->GetRenderer(); - hlayout->addWidget(m_RenderWindow); + // create widget + QString composedName("QmitkSliceWidget::"); + if (!this->objectName().isEmpty()) + composedName += this->objectName(); + else + composedName += "QmitkGLWidget"; + m_RenderWindow = new QmitkRenderWindow(container, composedName); + m_Renderer = m_RenderWindow->GetRenderer(); + hlayout->addWidget(m_RenderWindow); - new QmitkStepperAdapter(m_NavigatorWidget, - m_RenderWindow->GetSliceNavigationController()->GetSlice(), - "navigation"); + new QmitkStepperAdapter(m_NavigatorWidget, + m_RenderWindow->GetSliceNavigationController()->GetSlice(), + "navigation"); - SetLevelWindowEnabled(true); + SetLevelWindowEnabled(true); } mitk::VtkPropRenderer* QmitkSliceWidget::GetRenderer() { - return m_Renderer; + return m_Renderer; } QFrame* QmitkSliceWidget::GetSelectionFrame() { - return SelectionFrame; + return SelectionFrame; } void QmitkSliceWidget::SetDataStorage( - mitk::StandaloneDataStorage::Pointer storage) + mitk::StandaloneDataStorage::Pointer storage) { - m_DataStorage = storage; - m_Renderer->SetDataStorage(m_DataStorage); + m_DataStorage = storage; + m_Renderer->SetDataStorage(m_DataStorage); } mitk::StandaloneDataStorage* QmitkSliceWidget::GetDataStorage() { - if (m_DataStorage.IsNotNull()) - { - return m_DataStorage; - } - else - { - return NULL; - } + if (m_DataStorage.IsNotNull()) + { + return m_DataStorage; + } + else + { + return NULL; + } } void QmitkSliceWidget::SetData( - mitk::DataStorage::SetOfObjects::ConstIterator it) + mitk::DataStorage::SetOfObjects::ConstIterator it) { - SetData(it->Value(), m_View); + SetData(it->Value(), m_View); } void QmitkSliceWidget::SetData( - mitk::DataStorage::SetOfObjects::ConstIterator it, - mitk::SliceNavigationController::ViewDirection view) + mitk::DataStorage::SetOfObjects::ConstIterator it, + mitk::SliceNavigationController::ViewDirection view) { - SetData(it->Value(), view); + SetData(it->Value(), view); } void QmitkSliceWidget::SetData(mitk::DataNode::Pointer node) { - try - { - if (m_DataStorage.IsNotNull()) - { - m_DataStorage->Add(node); - } - } catch (...) - { - } - SetData(node, m_View); + try + { + if (m_DataStorage.IsNotNull()) + { + m_DataStorage->Add(node); + } + } catch (...) + { + } + SetData(node, m_View); } //void QmitkSliceWidget::AddData( mitk::DataNode::Pointer node) //{ // if ( m_DataTree.IsNull() ) // { // m_DataTree = mitk::DataTree::New(); // } // mitk::DataTreePreOrderIterator it(m_DataTree); // it.Add( node ); // SetData(&it, m_View); //} void QmitkSliceWidget::SetData(mitk::DataNode::Pointer /*treeNode*/, - mitk::SliceNavigationController::ViewDirection view) + mitk::SliceNavigationController::ViewDirection view) { - try - { - if (m_DataStorage.IsNotNull()) - { - levelWindow->SetDataStorage(m_DataStorage); - mitk::DataStorage::SetOfObjects::ConstPointer rs = - m_DataStorage->GetSubset(mitk::NodePredicateDataType::New( - "Image")); - mitk::DataStorage::SetOfObjects::ConstIterator it; - bool noVisibleImage = true; - for (it = rs->Begin(); it != rs->End(); ++it) - { - mitk::DataNode::Pointer node = it.Value(); - node->SetName("currentImage"); - mitk::Image::Pointer image = m_DataStorage->GetNamedObject< - mitk::Image> ("currentImage"); - - if (image.IsNotNull() && node->IsVisible(GetRenderer())) - { - m_SlicedGeometry = image->GetSlicedGeometry(); - mitk::LevelWindow picLevelWindow; - node->GetLevelWindow(picLevelWindow, NULL); - noVisibleImage = false; - break; - } - } - - if (noVisibleImage) - MITK_INFO << " No image visible!"; - - GetRenderer()->SetDataStorage(m_DataStorage); - } - InitWidget(view); - } catch (...) - { - } + try + { + if (m_DataStorage.IsNotNull()) + { + levelWindow->SetDataStorage(m_DataStorage); + mitk::DataStorage::SetOfObjects::ConstPointer rs = + m_DataStorage->GetSubset(mitk::NodePredicateDataType::New( + "Image")); + mitk::DataStorage::SetOfObjects::ConstIterator it; + bool noVisibleImage = true; + for (it = rs->Begin(); it != rs->End(); ++it) + { + mitk::DataNode::Pointer node = it.Value(); + node->SetName("currentImage"); + mitk::Image::Pointer image = m_DataStorage->GetNamedObject< + mitk::Image> ("currentImage"); + + if (image.IsNotNull() && node->IsVisible(GetRenderer())) + { + m_SlicedGeometry = image->GetSlicedGeometry(); + mitk::LevelWindow picLevelWindow; + node->GetLevelWindow(picLevelWindow, NULL); + noVisibleImage = false; + break; + } + } + + if (noVisibleImage) + MITK_INFO << " No image visible!"; + + GetRenderer()->SetDataStorage(m_DataStorage); + } + InitWidget(view); + } catch (...) + { + } } void QmitkSliceWidget::InitWidget( - mitk::SliceNavigationController::ViewDirection viewDirection) + mitk::SliceNavigationController::ViewDirection viewDirection) { - m_View = viewDirection; - - mitk::SliceNavigationController* controller = - m_RenderWindow->GetSliceNavigationController(); - - if (viewDirection == mitk::SliceNavigationController::Transversal) - { - controller->SetViewDirection( - mitk::SliceNavigationController::Transversal); - } - else if (viewDirection == mitk::SliceNavigationController::Frontal) - { - controller->SetViewDirection(mitk::SliceNavigationController::Frontal); - } - // init sagittal view - else - { - controller->SetViewDirection(mitk::SliceNavigationController::Sagittal); - } - - int currentPos = 0; - if (m_RenderWindow->GetSliceNavigationController()) - { - currentPos = controller->GetSlice()->GetPos(); - } - - if (m_SlicedGeometry.IsNull()) - { - return; - } - - // compute bounding box with respect to first images geometry - const mitk::BoundingBox::BoundsArrayType imageBounds = - m_SlicedGeometry->GetBoundingBox()->GetBounds(); - - // mitk::SlicedGeometry3D::Pointer correctGeometry = m_SlicedGeometry.GetPointer(); - mitk::Geometry3D::Pointer - geometry = - static_cast (m_SlicedGeometry->Clone().GetPointer()); - - const mitk::BoundingBox::Pointer boundingbox = - m_DataStorage->ComputeVisibleBoundingBox(GetRenderer(), NULL); - if (boundingbox->GetPoints()->Size() > 0) - { - ////geometry = mitk::Geometry3D::New(); - ////geometry->Initialize(); - //geometry->SetBounds(boundingbox->GetBounds()); - //geometry->SetSpacing(correctGeometry->GetSpacing()); - - //let's see if we have data with a limited live-span ... - mitk::TimeBounds timebounds = m_DataStorage->ComputeTimeBounds( - GetRenderer(), NULL); - - if (timebounds[1] < mitk::ScalarTypeNumericTraits::max()) - { - mitk::ScalarType duration = timebounds[1] - timebounds[0]; - - mitk::TimeSlicedGeometry::Pointer timegeometry = - mitk::TimeSlicedGeometry::New(); - - timegeometry->InitializeEvenlyTimed(geometry.GetPointer(), - (unsigned int) duration); - - timegeometry->SetTimeBounds(timebounds); //@bug really required? FIXME - - timebounds[1] = timebounds[0] + 1.0f; - geometry->SetTimeBounds(timebounds); - - geometry = timegeometry; - } - - if (const_cast (geometry->GetBoundingBox())->GetDiagonalLength2() - >= mitk::eps) - { - controller->SetInputWorldGeometry(geometry); - controller->Update(); - } - } - - GetRenderer()->GetDisplayGeometry()->Fit(); - mitk::RenderingManager::GetInstance()->RequestUpdate( - GetRenderer()->GetRenderWindow()); - //int w=vtkObject::GetGlobalWarningDisplay(); - //vtkObject::GlobalWarningDisplayOff(); - //vtkRenderer * vtkrenderer = ((mitk::OpenGLRenderer*)(GetRenderer()))->GetVtkRenderer(); - //if(vtkrenderer!=NULL) vtkrenderer->ResetCamera(); - //vtkObject::SetGlobalWarningDisplay(w); + m_View = viewDirection; + + mitk::SliceNavigationController* controller = + m_RenderWindow->GetSliceNavigationController(); + + if (viewDirection == mitk::SliceNavigationController::Axial) + { + controller->SetViewDirection( + mitk::SliceNavigationController::Axial); + } + else if (viewDirection == mitk::SliceNavigationController::Frontal) + { + controller->SetViewDirection(mitk::SliceNavigationController::Frontal); + } + // init sagittal view + else + { + controller->SetViewDirection(mitk::SliceNavigationController::Sagittal); + } + + int currentPos = 0; + if (m_RenderWindow->GetSliceNavigationController()) + { + currentPos = controller->GetSlice()->GetPos(); + } + + if (m_SlicedGeometry.IsNull()) + { + return; + } + + // compute bounding box with respect to first images geometry + const mitk::BoundingBox::BoundsArrayType imageBounds = + m_SlicedGeometry->GetBoundingBox()->GetBounds(); + + // mitk::SlicedGeometry3D::Pointer correctGeometry = m_SlicedGeometry.GetPointer(); + mitk::Geometry3D::Pointer + geometry = + static_cast (m_SlicedGeometry->Clone().GetPointer()); + + const mitk::BoundingBox::Pointer boundingbox = + m_DataStorage->ComputeVisibleBoundingBox(GetRenderer(), NULL); + if (boundingbox->GetPoints()->Size() > 0) + { + ////geometry = mitk::Geometry3D::New(); + ////geometry->Initialize(); + //geometry->SetBounds(boundingbox->GetBounds()); + //geometry->SetSpacing(correctGeometry->GetSpacing()); + + //let's see if we have data with a limited live-span ... + mitk::TimeBounds timebounds = m_DataStorage->ComputeTimeBounds( + GetRenderer(), NULL); + + if (timebounds[1] < mitk::ScalarTypeNumericTraits::max()) + { + mitk::ScalarType duration = timebounds[1] - timebounds[0]; + + mitk::TimeSlicedGeometry::Pointer timegeometry = + mitk::TimeSlicedGeometry::New(); + + timegeometry->InitializeEvenlyTimed(geometry.GetPointer(), + (unsigned int) duration); + + timegeometry->SetTimeBounds(timebounds); //@bug really required? FIXME + + timebounds[1] = timebounds[0] + 1.0f; + geometry->SetTimeBounds(timebounds); + + geometry = timegeometry; + } + + if (const_cast (geometry->GetBoundingBox())->GetDiagonalLength2() + >= mitk::eps) + { + controller->SetInputWorldGeometry(geometry); + controller->Update(); + } + } + + GetRenderer()->GetDisplayGeometry()->Fit(); + mitk::RenderingManager::GetInstance()->RequestUpdate( + GetRenderer()->GetRenderWindow()); + //int w=vtkObject::GetGlobalWarningDisplay(); + //vtkObject::GlobalWarningDisplayOff(); + //vtkRenderer * vtkrenderer = ((mitk::OpenGLRenderer*)(GetRenderer()))->GetVtkRenderer(); + //if(vtkrenderer!=NULL) vtkrenderer->ResetCamera(); + //vtkObject::SetGlobalWarningDisplay(w); } void QmitkSliceWidget::UpdateGL() { - GetRenderer()->GetDisplayGeometry()->Fit(); - mitk::RenderingManager::GetInstance()->RequestUpdate( - GetRenderer()->GetRenderWindow()); + GetRenderer()->GetDisplayGeometry()->Fit(); + mitk::RenderingManager::GetInstance()->RequestUpdate( + GetRenderer()->GetRenderWindow()); } void QmitkSliceWidget::mousePressEvent(QMouseEvent * e) { - if (e->button() == Qt::RightButton && popUpEnabled) - { - popUp->popup(QCursor::pos()); - } + if (e->button() == Qt::RightButton && popUpEnabled) + { + popUp->popup(QCursor::pos()); + } } void QmitkSliceWidget::wheelEvent(QWheelEvent * e) { - int val = m_NavigatorWidget->GetPos(); - - if (e->orientation() * e->delta() > 0) - { - m_NavigatorWidget->SetPos(val + 1); - } - else - { - if (val > 0) - m_NavigatorWidget->SetPos(val - 1); - } + int val = m_NavigatorWidget->GetPos(); + + if (e->orientation() * e->delta() > 0) + { + m_NavigatorWidget->SetPos(val + 1); + } + else + { + if (val > 0) + m_NavigatorWidget->SetPos(val - 1); + } } void QmitkSliceWidget::ChangeView(QAction* val) { - if (val->text() == "Transversal") - { - InitWidget(mitk::SliceNavigationController::Transversal); - } - else if (val->text() == "Frontal") - { - InitWidget(mitk::SliceNavigationController::Frontal); - } - else if (val->text() == "Sagittal") - { - InitWidget(mitk::SliceNavigationController::Sagittal); - } + if (val->text() == "Axial") + { + InitWidget(mitk::SliceNavigationController::Axial); + } + else if (val->text() == "Frontal") + { + InitWidget(mitk::SliceNavigationController::Frontal); + } + else if (val->text() == "Sagittal") + { + InitWidget(mitk::SliceNavigationController::Sagittal); + } } void QmitkSliceWidget::setPopUpEnabled(bool b) { - popUpEnabled = b; + popUpEnabled = b; } QmitkSliderNavigatorWidget* QmitkSliceWidget::GetNavigatorWidget() { - return m_NavigatorWidget; + return m_NavigatorWidget; } void QmitkSliceWidget::SetLevelWindowEnabled(bool enable) { - levelWindow->setEnabled(enable); - if (!enable) - { - levelWindow->setMinimumWidth(0); - levelWindow->setMaximumWidth(0); - } - else - { - levelWindow->setMinimumWidth(28); - levelWindow->setMaximumWidth(28); - } + levelWindow->setEnabled(enable); + if (!enable) + { + levelWindow->setMinimumWidth(0); + levelWindow->setMaximumWidth(0); + } + else + { + levelWindow->setMinimumWidth(28); + levelWindow->setMaximumWidth(28); + } } bool QmitkSliceWidget::IsLevelWindowEnabled() { - return levelWindow->isEnabled(); + return levelWindow->isEnabled(); } QmitkRenderWindow* QmitkSliceWidget::GetRenderWindow() { - return m_RenderWindow; + return m_RenderWindow; } mitk::SliceNavigationController* QmitkSliceWidget::GetSliceNavigationController() const { - return m_RenderWindow->GetSliceNavigationController(); + return m_RenderWindow->GetSliceNavigationController(); } mitk::CameraRotationController* QmitkSliceWidget::GetCameraRotationController() const { - return m_RenderWindow->GetCameraRotationController(); + return m_RenderWindow->GetCameraRotationController(); } mitk::BaseController* QmitkSliceWidget::GetController() const { - return m_RenderWindow->GetController(); + return m_RenderWindow->GetController(); } diff --git a/Modules/QmitkExt/QmitkSlicesInterpolator.cpp b/Modules/QmitkExt/QmitkSlicesInterpolator.cpp index e40401d4ac..0833932c65 100644 --- a/Modules/QmitkExt/QmitkSlicesInterpolator.cpp +++ b/Modules/QmitkExt/QmitkSlicesInterpolator.cpp @@ -1,1053 +1,1066 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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("Transversal (red window)", 0)] = 2; + 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); 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(true); 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))); 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))); 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(SurfaceInterpolationFinished())); 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::OnTransversalTimeChanged ); + 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::OnTransversalSliceChanged ); + 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); } 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); } } void QmitkSlicesInterpolator::OnToolManagerReferenceDataModified() { if (m_2DInterpolationEnabled) { OnInterpolationActivated( true ); // re-initialize if needed } if (m_3DInterpolationEnabled) { this->Show3DInterpolationResult(false); } } - -void QmitkSlicesInterpolator::OnTransversalTimeChanged(itk::Object* sender, const itk::EventObject& e) +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::OnTransversalSliceChanged(const itk::EventObject& e) +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::SurfaceInterpolationFinished() { 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())); 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); } } } 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: transversal window = renderWindow1 + // 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 ((workingNode->IsSelected() && workingNode->IsVisible(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3")))) && !isInterpolationResult) { QWidget::setEnabled( true ); if (workingNode->GetIntProperty("3DInterpolationListID", listID)) { m_SurfaceInterpolator->SetCurrentListID(listID); } else { listID = m_SurfaceInterpolator->CreateNewContourList(); workingNode->SetIntProperty("3DInterpolationListID", listID); this->Show3DInterpolationResult(false); m_BtnAccept3DInterpolation->setEnabled(false); } 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->SetWorkingImage(dynamic_cast(workingNode->GetData())); m_SurfaceInterpolator->SetMaxSpacing(maxSpacing); m_SurfaceInterpolator->SetMinSpacing(minSpacing); m_SurfaceInterpolator->SetDistanceImageVolume(50000); } } } } void QmitkSlicesInterpolator::Show3DInterpolationResult(bool status) { m_InterpolatedSurfaceNode->SetVisibility(status); m_3DContourNode->SetVisibility(status, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); } diff --git a/Modules/QmitkExt/QmitkSlicesInterpolator.h b/Modules/QmitkExt/QmitkSlicesInterpolator.h index b062a95514..2e79ce7d63 100644 --- a/Modules/QmitkExt/QmitkSlicesInterpolator.h +++ b/Modules/QmitkExt/QmitkSlicesInterpolator.h @@ -1,303 +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 QmitkSlicesInterpolator_h_Included #define QmitkSlicesInterpolator_h_Included #include "mitkSliceNavigationController.h" #include "QmitkExtExports.h" #include "mitkSegmentationInterpolationController.h" #include "mitkDataNode.h" #include "mitkDataStorage.h" #include "mitkWeakPointer.h" #include "mitkSurfaceInterpolationController.h" #include #include #include #include #include #include "mitkVtkRepresentationProperty.h" #include "vtkProperty.h" //For running 3D interpolation in background #include #include #include #include namespace mitk { class ToolManager; class PlaneGeometry; } class QmitkStdMultiWidget; class QPushButton; //Enhancement for 3D Interpolation //class QRadioButton; //class QGroupBox; //class QCheckBox; /** \brief GUI for slices interpolation. \ingroup ToolManagerEtAl \ingroup Widgets \sa QmitkInteractiveSegmentation \sa mitk::SegmentationInterpolation There is a separate page describing the general design of QmitkInteractiveSegmentation: \ref QmitkInteractiveSegmentationTechnicalPage While mitk::SegmentationInterpolation does the bookkeeping of interpolation (keeping track of which slices contain how much segmentation) and the algorithmic work, QmitkSlicesInterpolator is responsible to watch the GUI, to notice, which slice is currently visible. It triggers generation of interpolation suggestions and also triggers acception of suggestions. \todo show/hide feedback on demand Last contributor: $Author: maleike $ */ class QmitkExt_EXPORT QmitkSlicesInterpolator : public QWidget { Q_OBJECT public: QmitkSlicesInterpolator(QWidget* parent = 0, const char* name = 0); /** To be called once before real use. */ void Initialize(mitk::ToolManager* toolManager, QmitkStdMultiWidget* multiWidget); virtual ~QmitkSlicesInterpolator(); void SetDataStorage( mitk::DataStorage& storage ); mitk::DataStorage* GetDataStorage(); /** Just public because it is called by itk::Commands. You should not need to call this. */ void OnToolManagerWorkingDataModified(); /** Just public because it is called by itk::Commands. You should not need to call this. */ void OnToolManagerReferenceDataModified(); /** Just public because it is called by itk::Commands. You should not need to call this. */ - void OnTransversalTimeChanged(itk::Object* sender, const itk::EventObject&); + void OnAxialTimeChanged(itk::Object* sender, const itk::EventObject&); + + /** + Just public because it is called by itk::Commands. You should not need to call this. + */ + DEPRECATED(void OnTransversalTimeChanged(itk::Object* sender, const itk::EventObject&)); /** Just public because it is called by itk::Commands. You should not need to call this. */ void OnSagittalTimeChanged(itk::Object* sender, const itk::EventObject&); /** Just public because it is called by itk::Commands. You should not need to call this. */ void OnFrontalTimeChanged(itk::Object* sender, const itk::EventObject&); + + /** + Just public because it is called by itk::Commands. You should not need to call this. + */ + void OnAxialSliceChanged(const itk::EventObject&); /** Just public because it is called by itk::Commands. You should not need to call this. */ - void OnTransversalSliceChanged(const itk::EventObject&); + DEPRECATED(void OnTransversalSliceChanged(const itk::EventObject&)); /** Just public because it is called by itk::Commands. You should not need to call this. */ void OnSagittalSliceChanged(const itk::EventObject&); /** Just public because it is called by itk::Commands. You should not need to call this. */ void OnFrontalSliceChanged(const itk::EventObject&); /** Just public because it is called by itk::Commands. You should not need to call this. */ void OnInterpolationInfoChanged(const itk::EventObject&); /** Just public because it is called by itk::Commands. You should not need to call this. */ void OnSurfaceInterpolationInfoChanged(const itk::EventObject&); signals: void SignalRememberContourPositions(bool); void SignalShowMarkerNodes(bool); public slots: /** Call this from the outside to enable/disable interpolation */ void EnableInterpolation(bool); void Enable3DInterpolation(bool); /** Call this from the outside to accept all interpolations */ void FinishInterpolation(int windowID = -1); protected slots: /** Reaction to button clicks. */ void OnAcceptInterpolationClicked(); /* Opens popup to ask about which orientation should be interpolated */ void OnAcceptAllInterpolationsClicked(); /* Reaction to button clicks */ void OnAccept3DInterpolationClicked(); /* * Will trigger interpolation for all slices in given orientation (called from popup menu of OnAcceptAllInterpolationsClicked) */ void OnAcceptAllPopupActivated(QAction* action); /** Called on activation/deactivation */ void OnInterpolationActivated(bool); void On3DInterpolationActivated(bool); void OnMultiWidgetDeleted(QObject*); //Enhancement for 3D interpolation void On2DInterpolationEnabled(bool); void On3DInterpolationEnabled(bool); void OnInterpolationDisabled(bool); void OnShowMarkers(bool); void Run3DInterpolation(); void SurfaceInterpolationFinished(); void StartUpdateInterpolationTimer(); void StopUpdateInterpolationTimer(); void ChangeSurfaceColor(); protected: const std::map createActionToSliceDimension(); const std::map ACTION_TO_SLICEDIMENSION; void AcceptAllInterpolations(unsigned int windowID); /** Retrieves the currently selected PlaneGeometry from a SlicedGeometry3D that is generated by a SliceNavigationController and calls Interpolate to further process this PlaneGeometry into an interpolation. \param e is a actually a mitk::SliceNavigationController::GeometrySliceEvent, sent by a SliceNavigationController - \param windowID is 2 for transversal, 1 for frontal, 0 for sagittal (similar to sliceDimension in other methods) + \param windowID is 2 for axial, 1 for frontal, 0 for sagittal (similar to sliceDimension in other methods) */ bool TranslateAndInterpolateChangedSlice(const itk::EventObject& e, unsigned int windowID); /** Given a PlaneGeometry, this method figures out which slice of the first working image (of the associated ToolManager) should be interpolated. The actual work is then done by our SegmentationInterpolation object. */ void Interpolate( mitk::PlaneGeometry* plane, unsigned int timeStep ); //void InterpolateSurface(); /** Called internally to update the interpolation suggestion. Finds out about the focused render window and requests an interpolation. */ void UpdateVisibleSuggestion(); /** * Tries to figure out the slice position and orientation for a given render window. - * \param windowID is 2 for transversal, 1 for frontal, 0 for sagittal (similar to sliceDimension in other methods) + * \param windowID is 2 for axial, 1 for frontal, 0 for sagittal (similar to sliceDimension in other methods) * \return false if orientation could not be determined */ bool GetSliceForWindowsID(unsigned windowID, int& sliceDimension, int& sliceIndex); void SetCurrentContourListID(); void Show3DInterpolationResult(bool); mitk::SegmentationInterpolationController::Pointer m_Interpolator; mitk::SurfaceInterpolationController::Pointer m_SurfaceInterpolator; QmitkStdMultiWidget* m_MultiWidget; mitk::ToolManager* m_ToolManager; bool m_Initialized; unsigned int TSliceObserverTag; unsigned int SSliceObserverTag; unsigned int FSliceObserverTag; unsigned int TTimeObserverTag; unsigned int STimeObserverTag; unsigned int FTimeObserverTag; unsigned int InterpolationInfoChangedObserverTag; unsigned int SurfaceInterpolationInfoChangedObserverTag; QPushButton* m_BtnAcceptInterpolation; QPushButton* m_BtnAcceptAllInterpolations; //Enhancement for 3D Surface Interpolation QRadioButton* m_RBtnEnable2DInterpolation; QRadioButton* m_RBtnEnable3DInterpolation; QRadioButton* m_RBtnDisableInterpolation; QGroupBox* m_GroupBoxEnableExclusiveInterpolationMode; QPushButton* m_BtnAccept3DInterpolation; QCheckBox* m_CbShowMarkers; mitk::DataNode::Pointer m_FeedbackNode; mitk::DataNode::Pointer m_InterpolatedSurfaceNode; mitk::DataNode::Pointer m_3DContourNode; mitk::Image* m_Segmentation; unsigned int m_LastSliceDimension; unsigned int m_LastSliceIndex; std::vector m_TimeStep; // current time step of the render windows bool m_2DInterpolationEnabled; bool m_3DInterpolationEnabled; //unsigned int m_CurrentListID; mitk::WeakPointer m_DataStorage; QFuture m_Future; QFutureWatcher m_Watcher; QTimer* m_Timer; }; #endif diff --git a/Modules/Segmentation/Algorithms/mitkOverwriteDirectedPlaneImageFilter.h b/Modules/Segmentation/Algorithms/mitkOverwriteDirectedPlaneImageFilter.h index 5e8aaeefaf..e5d61b4848 100644 --- a/Modules/Segmentation/Algorithms/mitkOverwriteDirectedPlaneImageFilter.h +++ b/Modules/Segmentation/Algorithms/mitkOverwriteDirectedPlaneImageFilter.h @@ -1,121 +1,121 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkOverwriteDirectedPlaneImageFilter_h_Included #define mitkOverwriteDirectedPlaneImageFilter_h_Included #include "mitkCommon.h" #include "SegmentationExports.h" #include "mitkImageToImageFilter.h" #include namespace mitk { /** \deprecated This class is deprecated. Use mitkVtkImageOverwrite instead. \sa mitkVtkImageOverwrite \brief Writes a 2D slice into a 3D image. \sa SegTool2D \sa ContourTool \sa ExtractImageFilter \ingroup Process \ingroup Reliver There is a separate page describing the general design of QmitkInteractiveSegmentation: \ref QmitkInteractiveSegmentationTechnicalPage This class takes a 3D mitk::Image as input and tries to replace one slice in it with the second input image, which is specified by calling SetSliceImage with a 2D mitk::Image. - Two parameters determine which slice is replaced: the "slice dimension" is that one, which is constant for all points in the plane, e.g. transversal would mean 2. + Two parameters determine which slice is replaced: the "slice dimension" is that one, which is constant for all points in the plane, e.g. axial would mean 2. The "slice index" is the slice index in the image direction you specified with "affected dimension". Indices count from zero. This class works with all kind of image types, the only restrictions being that the input is 3D, and the slice image is 2D. If requested by SetCreateUndoInformation(true), this class will create instances of ApplyDiffImageOperation for the undo stack. These operations will (on user request) be executed by DiffImageApplier to perform undo. Last contributor: $Author: maleike $ */ class Segmentation_EXPORT OverwriteDirectedPlaneImageFilter : public ImageToImageFilter { public: mitkClassMacro(OverwriteDirectedPlaneImageFilter, ImageToImageFilter); itkNewMacro(OverwriteDirectedPlaneImageFilter); /** \brief Which plane to overwrite */ const Geometry3D* GetPlaneGeometry3D() const { return m_PlaneGeometry; } void SetPlaneGeometry3D( const Geometry3D *geometry ) { m_PlaneGeometry = geometry; } /** \brief Time step of the slice to overwrite */ itkSetMacro(TimeStep, unsigned int); itkGetConstMacro(TimeStep, unsigned int); /** \brief Whether to create undo operation in the MITK undo stack */ itkSetMacro(CreateUndoInformation, bool); itkGetConstMacro(CreateUndoInformation, bool); itkSetObjectMacro(SliceImage, Image); const Image* GetSliceImage() { return m_SliceImage.GetPointer(); } const Image* GetLastDifferenceImage() { return m_SliceDifferenceImage.GetPointer(); } protected: OverwriteDirectedPlaneImageFilter(); // purposely hidden virtual ~OverwriteDirectedPlaneImageFilter(); virtual void GenerateData(); template void ItkSliceOverwriting (itk::Image* input3D); template void ItkImageSwitch( itk::Image* image ); template void ItkImageProcessing( itk::Image* itkImage1, itk::Image* itkImage2 ); //std::string EventDescription( unsigned int sliceDimension, unsigned int sliceIndex, unsigned int timeStep ); Image::ConstPointer m_SliceImage; Image::Pointer m_SliceDifferenceImage; const Geometry3D *m_PlaneGeometry; const Geometry3D *m_ImageGeometry3D; unsigned int m_TimeStep; unsigned int m_Dimension0; unsigned int m_Dimension1; bool m_CreateUndoInformation; }; } // namespace #endif diff --git a/Modules/Segmentation/Algorithms/mitkOverwriteSliceImageFilter.h b/Modules/Segmentation/Algorithms/mitkOverwriteSliceImageFilter.h index 1c0e2d9624..99558b6cf2 100644 --- a/Modules/Segmentation/Algorithms/mitkOverwriteSliceImageFilter.h +++ b/Modules/Segmentation/Algorithms/mitkOverwriteSliceImageFilter.h @@ -1,126 +1,126 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkOverwriteSliceImageFilter_h_Included #define mitkOverwriteSliceImageFilter_h_Included #include "mitkCommon.h" #include "SegmentationExports.h" #include "mitkImageToImageFilter.h" #include namespace mitk { /** \deprecated This class is deprecated. Use mitkVtkImageOverwrite instead. \sa mitkVtkImageOverwrite \brief Writes a 2D slice into a 3D image. \sa SegTool2D \sa ContourTool \sa ExtractImageFilter \ingroup Process \ingroup ToolManagerEtAl There is a separate page describing the general design of QmitkInteractiveSegmentation: \ref QmitkInteractiveSegmentationTechnicalPage This class takes a 3D mitk::Image as input and tries to replace one slice in it with the second input image, which is specified by calling SetSliceImage with a 2D mitk::Image. - Two parameters determine which slice is replaced: the "slice dimension" is that one, which is constant for all points in the plane, e.g. transversal would mean 2. + Two parameters determine which slice is replaced: the "slice dimension" is that one, which is constant for all points in the plane, e.g. axial would mean 2. The "slice index" is the slice index in the image direction you specified with "affected dimension". Indices count from zero. This class works with all kind of image types, the only restrictions being that the input is 3D, and the slice image is 2D. If requested by SetCreateUndoInformation(true), this class will create instances of ApplyDiffImageOperation for the undo stack. These operations will (on user request) be executed by DiffImageApplier to perform undo. Last contributor: $Author$ */ class Segmentation_EXPORT OverwriteSliceImageFilter : public ImageToImageFilter { public: mitkClassMacro(OverwriteSliceImageFilter, ImageToImageFilter); itkNewMacro(OverwriteSliceImageFilter); /** \brief Which slice to overwrite (first one has index 0). */ itkSetMacro(SliceIndex, unsigned int); itkGetConstMacro(SliceIndex, unsigned int); /** \brief The orientation of the slice to overwrite. - \a Parameter \a SliceDimension Number of the dimension which is constant for all pixels of the desired slices (e.g. 0 for transversal) + \a Parameter \a SliceDimension Number of the dimension which is constant for all pixels of the desired slices (e.g. 0 for axial) */ itkSetMacro(SliceDimension, unsigned int); itkGetConstMacro(SliceDimension, unsigned int); /** \brief Time step of the slice to overwrite */ itkSetMacro(TimeStep, unsigned int); itkGetConstMacro(TimeStep, unsigned int); /** \brief Whether to create undo operation in the MITK undo stack */ itkSetMacro(CreateUndoInformation, bool); itkGetConstMacro(CreateUndoInformation, bool); itkSetObjectMacro(SliceImage, Image); const Image* GetSliceImage() { return m_SliceImage.GetPointer(); } const Image* GetLastDifferenceImage() { return m_SliceDifferenceImage.GetPointer(); } protected: OverwriteSliceImageFilter(); // purposely hidden virtual ~OverwriteSliceImageFilter(); virtual void GenerateData(); template void ItkImageSwitch( itk::Image* image ); template void ItkImageProcessing( itk::Image* itkImage1, itk::Image* itkImage2 ); std::string EventDescription( unsigned int sliceDimension, unsigned int sliceIndex, unsigned int timeStep ); Image::ConstPointer m_SliceImage; Image::Pointer m_SliceDifferenceImage; unsigned int m_SliceIndex; unsigned int m_SliceDimension; unsigned int m_TimeStep; unsigned int m_Dimension0; unsigned int m_Dimension1; bool m_CreateUndoInformation; }; } // namespace #endif diff --git a/Modules/Segmentation/Algorithms/mitkSegmentationInterpolationAlgorithm.h b/Modules/Segmentation/Algorithms/mitkSegmentationInterpolationAlgorithm.h index 8478ab0017..1d8f456427 100644 --- a/Modules/Segmentation/Algorithms/mitkSegmentationInterpolationAlgorithm.h +++ b/Modules/Segmentation/Algorithms/mitkSegmentationInterpolationAlgorithm.h @@ -1,70 +1,70 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 mitkSegmentationInterpolationAlgorithm_h_Included #define mitkSegmentationInterpolationAlgorithm_h_Included #include "mitkCommon.h" #include "SegmentationExports.h" #include "mitkImage.h" #include namespace mitk { /** * \brief Interface class for interpolation algorithms * * Interpolation algorithms estimate a binary image (segmentation) given * manual segmentations of neighboring slices. They get the following inputs: * - * - slice orientation of given and requested slices (dimension which is constant for all pixels of the meant orientation, e.g. 2 for transversal). + * - slice orientation of given and requested slices (dimension which is constant for all pixels of the meant orientation, e.g. 2 for axial). * - slice indices of the neighboring slices (for upper and lower slice) * - slice data of the neighboring slices (for upper and lower slice) * - slice index of the requested slice (guaranteed to be between upper and lower index) * - image data of the original patient image that is being segmented (optional, may not be present) * - time step of the requested slice (needed to read out original image data) * * Concrete algorithms can use e.g. itk::ImageSliceConstIteratorWithIndex to * inspect the original patient image at appropriate positions - if they * want to take image data into account. * * All processing is triggered by calling Interpolate(). * * Last contributor: * $Author:$ */ class Segmentation_EXPORT SegmentationInterpolationAlgorithm : public itk::Object { public: mitkClassMacro(SegmentationInterpolationAlgorithm, itk::Object); virtual Image::Pointer Interpolate(Image::ConstPointer lowerSlice, unsigned int lowerSliceIndex, Image::ConstPointer upperSlice, unsigned int upperSliceIndex, unsigned int requestedIndex, unsigned int sliceDimension, Image::Pointer resultImage, unsigned int timeStep = 0, Image::ConstPointer referenceImage = NULL) = 0; }; } // namespace #endif diff --git a/Modules/Segmentation/Controllers/mitkSegmentationInterpolationController.h b/Modules/Segmentation/Controllers/mitkSegmentationInterpolationController.h index 42eda6da0f..8f9913bd3e 100644 --- a/Modules/Segmentation/Controllers/mitkSegmentationInterpolationController.h +++ b/Modules/Segmentation/Controllers/mitkSegmentationInterpolationController.h @@ -1,202 +1,202 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 mitkSegmentationInterpolationController_h_Included #define mitkSegmentationInterpolationController_h_Included #include "mitkCommon.h" #include "SegmentationExports.h" #include "mitkImage.h" #include #include #include #include namespace mitk { class Image; /** \brief Generates interpolations of 2D slices. \sa QmitkSlicesInterpolator \sa QmitkInteractiveSegmentation \ingroup ToolManagerEtAl There is a separate page describing the general design of QmitkInteractiveSegmentation: \ref QmitkInteractiveSegmentationTechnicalPage This class keeps track of the contents of a 3D segmentation image. \attention mitk::SegmentationInterpolationController assumes that the image contains pixel values of 0 and 1. After you set the segmentation image using SetSegmentationVolume(), the whole image is scanned for pixels other than 0. SegmentationInterpolationController registers as an observer to the segmentation image, and repeats the scan whenvever the image is modified. You can prevent this (time consuming) scan if you do the changes slice-wise and send difference images to SegmentationInterpolationController. For this purpose SetChangedSlice() should be used. mitk::OverwriteImageFilter already does this every time it changes a slice of an image. There is a static method InterpolatorForImage(), which can be used to find out if there already is an interpolator instance for a specified image. OverwriteImageFilter uses this to get to know its interpolator. SegmentationInterpolationController needs to maintain some information about the image slices (in every dimension). This information is stored internally in m_SegmentationCountInSlice, which is basically three std::vectors (one for each dimension). Each item describes one image dimension, each vector item holds the count of pixels in "its" slice. This is perhaps better to understand from the following picture (where red items just mean to symbolize "there is some segmentation" - in reality there is an integer count). \image html slice_based_segmentation_interpolator.png $Author$ */ class Segmentation_EXPORT SegmentationInterpolationController : public itk::Object { public: mitkClassMacro(SegmentationInterpolationController, itk::Object); itkNewMacro(SegmentationInterpolationController); /// specify the segmentation image that should be interpolated /** \brief Find interpolator for a given image. \return NULL if there is no interpolator yet. This method is useful if several "clients" modify the same image and want to access the interpolations. Then they can share the same object. */ static SegmentationInterpolationController* InterpolatorForImage(const Image*); /** \brief Block reaction to an images Modified() events. Blocking the scan of the whole image is especially useful when you are about to change a single slice of the image. Then you would send a difference image of this single slice to SegmentationInterpolationController but call image->Modified() anyway. Before calling image->Modified() you should block SegmentationInterpolationController's reactions to this modified by using this method. */ void BlockModified(bool); /** \brief Initialize with a whole volume. Will scan the volume for segmentation pixels (values other than 0) and fill some internal data structures. You don't have to call this method every time something changes, but only when several slices at once change. When you change a single slice, call SetChangedSlice() instead. */ void SetSegmentationVolume( const Image* segmentation ); /** \brief Set a reference image (original patient image) - optional. If this volume is set (must exactly match the dimensions of the segmentation), the interpolation algorithm may consider image content to improve the interpolated (estimated) segmentation. */ void SetReferenceVolume( const Image* segmentation ); /** \brief Update after changing a single slice. \param sliceDiff is a 2D image with the difference image of the slice determined by sliceDimension and sliceIndex. The difference is (pixel value in the new slice minus pixel value in the old slice). \param sliceDimension Number of the dimension which is constant for all pixels of the meant slice. \param sliceIndex Which slice to take, in the direction specified by sliceDimension. Count starts from 0. \param timeStep Which time step is changed */ void SetChangedSlice( const Image* sliceDiff, unsigned int sliceDimension, unsigned int sliceIndex, unsigned int timeStep ); void SetChangedVolume( const Image* sliceDiff, unsigned int timeStep ); /** \brief Generates an interpolated image for the given slice. \param sliceDimension Number of the dimension which is constant for all pixels of the meant slice. \param sliceIndex Which slice to take, in the direction specified by sliceDimension. Count starts from 0. \param timeStep Which time step to use */ Image::Pointer Interpolate( unsigned int sliceDimension, unsigned int sliceIndex, unsigned int timeStep ); void OnImageModified(const itk::EventObject&); protected: /** \brief Protected class of mitk::SegmentationInterpolationController. Don't use (you shouldn't be able to do so)! */ class Segmentation_EXPORT SetChangedSliceOptions { public: SetChangedSliceOptions( unsigned int sd, unsigned int si, unsigned int d0, unsigned int d1, unsigned int t, void* pixels ) : sliceDimension(sd), sliceIndex(si), dim0(d0), dim1(d1), timeStep(t), pixelData(pixels) { } unsigned int sliceDimension; unsigned int sliceIndex; unsigned int dim0; unsigned int dim1; unsigned int timeStep; void* pixelData; }; typedef std::vector DirtyVectorType; //typedef std::vector< DirtyVectorType[3] > TimeResolvedDirtyVectorType; // cannot work with C++, so next line is used for implementation typedef std::vector< std::vector > TimeResolvedDirtyVectorType; typedef std::map< const Image*, SegmentationInterpolationController* > InterpolatorMapType; SegmentationInterpolationController();// purposely hidden virtual ~SegmentationInterpolationController(); /// internal scan of a single slice template < typename DATATYPE > void ScanChangedSlice( itk::Image*, const SetChangedSliceOptions& options ); template < typename TPixel, unsigned int VImageDimension > void ScanChangedVolume( itk::Image*, unsigned int timeStep ); template < typename DATATYPE > void ScanWholeVolume( itk::Image*, const Image* volume, unsigned int timeStep ); void PrintStatus(); /** An array of flags. One for each dimension of the image. A flag is set, when a slice in a certain dimension has at least one pixel that is not 0 (which would mean that it has to be considered by the interpolation algorithm). - E.g. flags for transversal slices are stored in m_SegmentationCountInSlice[0][index]. + E.g. flags for axial slices are stored in m_SegmentationCountInSlice[0][index]. Enhanced with time steps it is now m_SegmentationCountInSlice[timeStep][0][index] */ TimeResolvedDirtyVectorType m_SegmentationCountInSlice; static InterpolatorMapType s_InterpolatorForImage; Image::ConstPointer m_Segmentation; Image::ConstPointer m_ReferenceImage; bool m_BlockModified; }; } // namespace #endif diff --git a/Modules/Segmentation/Interactions/mitkBinaryThresholdTool.cpp b/Modules/Segmentation/Interactions/mitkBinaryThresholdTool.cpp index c891fe9765..b4b9ecd1b6 100644 --- a/Modules/Segmentation/Interactions/mitkBinaryThresholdTool.cpp +++ b/Modules/Segmentation/Interactions/mitkBinaryThresholdTool.cpp @@ -1,320 +1,321 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkBinaryThresholdTool.h" #include "mitkBinaryThresholdTool.xpm" #include "mitkToolManager.h" #include "mitkBoundingObjectToSegmentationFilter.h" #include #include "mitkLevelWindowProperty.h" #include "mitkColorProperty.h" #include "mitkProperties.h" #include "mitkOrganTypeProperty.h" #include "mitkVtkResliceInterpolationProperty.h" #include "mitkDataStorage.h" #include "mitkRenderingManager.h" #include "mitkImageCast.h" #include "mitkImageAccessByItk.h" #include "mitkImageTimeSelector.h" #include #include #include "mitkPadImageFilter.h" #include "mitkMaskAndCutRoiImageFilter.h" namespace mitk { MITK_TOOL_MACRO(Segmentation_EXPORT, BinaryThresholdTool, "Thresholding tool"); } mitk::BinaryThresholdTool::BinaryThresholdTool() :m_SensibleMinimumThresholdValue(-100), m_SensibleMaximumThresholdValue(+100), m_CurrentThresholdValue(0.0), m_IsFloatImage(false) { this->SupportRoiOn(); m_ThresholdFeedbackNode = DataNode::New(); mitk::CoreObjectFactory::GetInstance()->SetDefaultProperties( m_ThresholdFeedbackNode ); m_ThresholdFeedbackNode->SetProperty( "color", ColorProperty::New(1.0, 0.0, 0.0) ); m_ThresholdFeedbackNode->SetProperty( "texture interpolation", BoolProperty::New(false) ); m_ThresholdFeedbackNode->SetProperty( "layer", IntProperty::New( 100 ) ); m_ThresholdFeedbackNode->SetProperty( "levelwindow", LevelWindowProperty::New( LevelWindow(100, 1) ) ); m_ThresholdFeedbackNode->SetProperty( "name", StringProperty::New("Thresholding feedback") ); m_ThresholdFeedbackNode->SetProperty( "opacity", FloatProperty::New(0.3) ); m_ThresholdFeedbackNode->SetProperty( "helper object", BoolProperty::New(true) ); } mitk::BinaryThresholdTool::~BinaryThresholdTool() { } const char** mitk::BinaryThresholdTool::GetXPM() const { return mitkBinaryThresholdTool_xpm; } const char* mitk::BinaryThresholdTool::GetName() const { return "Thresholding"; } void mitk::BinaryThresholdTool::Activated() { m_ToolManager->RoiDataChanged += mitk::MessageDelegate(this, &mitk::BinaryThresholdTool::OnRoiDataChanged); m_OriginalImageNode = m_ToolManager->GetReferenceData(0); m_NodeForThresholding = m_OriginalImageNode; if ( m_NodeForThresholding.IsNotNull() ) { SetupPreviewNodeFor( m_NodeForThresholding ); } else { m_ToolManager->ActivateTool(-1); } } void mitk::BinaryThresholdTool::Deactivated() { m_ToolManager->RoiDataChanged -= mitk::MessageDelegate(this, &mitk::BinaryThresholdTool::OnRoiDataChanged); m_NodeForThresholding = NULL; m_OriginalImageNode = NULL; try { if (DataStorage* storage = m_ToolManager->GetDataStorage()) { storage->Remove( m_ThresholdFeedbackNode ); RenderingManager::GetInstance()->RequestUpdateAll(); } } catch(...) { // don't care } m_ThresholdFeedbackNode->SetData(NULL); } void mitk::BinaryThresholdTool::SetThresholdValue(double value) { if (m_ThresholdFeedbackNode.IsNotNull()) { m_CurrentThresholdValue = value; m_ThresholdFeedbackNode->SetProperty( "levelwindow", LevelWindowProperty::New( LevelWindow(m_CurrentThresholdValue, 0.001) ) ); RenderingManager::GetInstance()->RequestUpdateAll(); } } void mitk::BinaryThresholdTool::AcceptCurrentThresholdValue(const std::string& organName, const Color& color) { CreateNewSegmentationFromThreshold(m_NodeForThresholding, organName, color ); RenderingManager::GetInstance()->RequestUpdateAll(); m_ToolManager->ActivateTool(-1); } void mitk::BinaryThresholdTool::CancelThresholding() { m_ToolManager->ActivateTool(-1); } void mitk::BinaryThresholdTool::SetupPreviewNodeFor( DataNode* nodeForThresholding ) { if (nodeForThresholding) { Image::Pointer image = dynamic_cast( nodeForThresholding->GetData() ); Image::Pointer originalImage = dynamic_cast (m_OriginalImageNode->GetData()); if (image.IsNotNull()) { // initialize and a new node with the same image as our reference image // use the level window property of this image copy to display the result of a thresholding operation m_ThresholdFeedbackNode->SetData( image ); int layer(50); nodeForThresholding->GetIntProperty("layer", layer); m_ThresholdFeedbackNode->SetIntProperty("layer", layer+1); if (DataStorage* storage = m_ToolManager->GetDataStorage()) { if (storage->Exists(m_ThresholdFeedbackNode)) storage->Remove(m_ThresholdFeedbackNode); storage->Add( m_ThresholdFeedbackNode, m_OriginalImageNode ); } if (image.GetPointer() == originalImage.GetPointer()) { - if (originalImage->GetPixelType().GetPixelTypeId() == typeid(float)) + if ((originalImage->GetPixelType().GetPixelTypeId() == itk::ImageIOBase::SCALAR) + &&(originalImage->GetPixelType().GetTypeId() == typeid(float))) m_IsFloatImage = true; else m_IsFloatImage = false; m_SensibleMinimumThresholdValue = static_cast( originalImage->GetScalarValueMin() ); m_SensibleMaximumThresholdValue = static_cast( originalImage->GetScalarValueMax() ); } LevelWindowProperty::Pointer lwp = dynamic_cast( m_ThresholdFeedbackNode->GetProperty( "levelwindow" )); if (lwp && !m_IsFloatImage ) { m_CurrentThresholdValue = static_cast( lwp->GetLevelWindow().GetLevel() ); } else { m_CurrentThresholdValue = (m_SensibleMaximumThresholdValue + m_SensibleMinimumThresholdValue)/2; } IntervalBordersChanged.Send(m_SensibleMinimumThresholdValue, m_SensibleMaximumThresholdValue, m_IsFloatImage); ThresholdingValueChanged.Send(m_CurrentThresholdValue); } } } void mitk::BinaryThresholdTool::CreateNewSegmentationFromThreshold(DataNode* node, const std::string& organName, const Color& color) { if (node) { Image::Pointer image = dynamic_cast( m_NodeForThresholding->GetData() ); if (image.IsNotNull()) { // create a new image of the same dimensions and smallest possible pixel type DataNode::Pointer emptySegmentation = Tool::CreateEmptySegmentationNode( image, organName, color ); if (emptySegmentation) { // actually perform a thresholding and ask for an organ type for (unsigned int timeStep = 0; timeStep < image->GetTimeSteps(); ++timeStep) { try { ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New(); timeSelector->SetInput( image ); timeSelector->SetTimeNr( timeStep ); timeSelector->UpdateLargestPossibleRegion(); Image::Pointer image3D = timeSelector->GetOutput(); if (image3D->GetDimension() == 2) { AccessFixedDimensionByItk_2( image3D, ITKThresholding, 2, dynamic_cast(emptySegmentation->GetData()), timeStep ); } else { AccessFixedDimensionByItk_2( image3D, ITKThresholding, 3, dynamic_cast(emptySegmentation->GetData()), timeStep ); } } catch(...) { Tool::ErrorMessage("Error accessing single time steps of the original image. Cannot create segmentation."); } } if (m_OriginalImageNode.GetPointer() != m_NodeForThresholding.GetPointer()) { mitk::PadImageFilter::Pointer padFilter = mitk::PadImageFilter::New(); padFilter->SetInput(0, dynamic_cast (emptySegmentation->GetData())); padFilter->SetInput(1, dynamic_cast (m_OriginalImageNode->GetData())); padFilter->SetBinaryFilter(true); padFilter->SetUpperThreshold(1); padFilter->SetLowerThreshold(1); padFilter->Update(); emptySegmentation->SetData(padFilter->GetOutput()); } if (DataStorage::Pointer storage = m_ToolManager->GetDataStorage()) { storage->Add( emptySegmentation, m_OriginalImageNode ); // add as a child, because the segmentation "derives" from the original } m_ToolManager->SetWorkingData( emptySegmentation ); } } } } template void mitk::BinaryThresholdTool::ITKThresholding( itk::Image* originalImage, Image* segmentation, unsigned int timeStep ) { ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New(); timeSelector->SetInput( segmentation ); timeSelector->SetTimeNr( timeStep ); timeSelector->UpdateLargestPossibleRegion(); Image::Pointer segmentation3D = timeSelector->GetOutput(); typedef itk::Image< Tool::DefaultSegmentationDataType, 3> SegmentationType; // this is sure for new segmentations SegmentationType::Pointer itkSegmentation; CastToItkImage( segmentation3D, itkSegmentation ); // iterate over original and segmentation typedef itk::ImageRegionConstIterator< itk::Image > InputIteratorType; typedef itk::ImageRegionIterator< SegmentationType > SegmentationIteratorType; InputIteratorType inputIterator( originalImage, originalImage->GetLargestPossibleRegion() ); SegmentationIteratorType outputIterator( itkSegmentation, itkSegmentation->GetLargestPossibleRegion() ); inputIterator.GoToBegin(); outputIterator.GoToBegin(); while (!outputIterator.IsAtEnd()) { if ( inputIterator.Get() >= m_CurrentThresholdValue ) outputIterator.Set( 1 ); else outputIterator.Set( 0 ); ++inputIterator; ++outputIterator; } } void mitk::BinaryThresholdTool::OnRoiDataChanged() { mitk::DataNode::Pointer node = m_ToolManager->GetRoiData(0); if (node.IsNotNull()) { mitk::Image::Pointer image = dynamic_cast (m_NodeForThresholding->GetData()); if (image.IsNull()) return; mitk::MaskAndCutRoiImageFilter::Pointer roiFilter = mitk::MaskAndCutRoiImageFilter::New(); roiFilter->SetInput(image); roiFilter->SetRegionOfInterest(node->GetData()); roiFilter->Update(); mitk::DataNode::Pointer tmpNode = mitk::DataNode::New(); mitk::Image::Pointer tmpImage = roiFilter->GetOutput(); tmpNode->SetData(tmpImage); m_SensibleMaximumThresholdValue = static_cast (roiFilter->GetMaxValue()); m_SensibleMinimumThresholdValue = static_cast (roiFilter->GetMinValue()); SetupPreviewNodeFor( tmpNode ); m_NodeForThresholding = tmpNode; return; } else { this->SetupPreviewNodeFor(m_OriginalImageNode); m_NodeForThresholding = m_OriginalImageNode; return; } } diff --git a/Modules/Segmentation/Interactions/mitkSegTool2D.cpp b/Modules/Segmentation/Interactions/mitkSegTool2D.cpp index edb58fe711..c410f95907 100644 --- a/Modules/Segmentation/Interactions/mitkSegTool2D.cpp +++ b/Modules/Segmentation/Interactions/mitkSegTool2D.cpp @@ -1,347 +1,355 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 (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 - if( m_LastEventSender != positionEvent->GetSender()) return 0.0; - if( m_LastEventSlice != positionEvent->GetSender()->GetSlice() ) return 0.0; - - return 1.0; + //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 ); - // transversal + // 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(); /*============= 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 (contour->GetVtkPolyData()->GetNumberOfPoints() > 0 ) { 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; } 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(); 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)); 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/Segmentation/Interactions/mitkSegTool2D.h b/Modules/Segmentation/Interactions/mitkSegTool2D.h index 63f3f81881..866e818a55 100644 --- a/Modules/Segmentation/Interactions/mitkSegTool2D.h +++ b/Modules/Segmentation/Interactions/mitkSegTool2D.h @@ -1,140 +1,140 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 mitkSegTool2D_h_Included #define mitkSegTool2D_h_Included #include "mitkCommon.h" #include "SegmentationExports.h" #include "mitkTool.h" #include "mitkImage.h" #include "mitkStateEvent.h" #include "mitkPositionEvent.h" #include "mitkPlanePositionManager.h" #include "mitkRestorePlanePositionOperation.h" #include "mitkInteractionConst.h" #include namespace mitk { class BaseRenderer; /** \brief Abstract base class for segmentation tools. \sa Tool \ingroup Interaction \ingroup ToolManagerEtAl Implements 2D segmentation specific helper methods, that might be of use to all kind of 2D segmentation tools. At the moment these are: - Determination of the slice where the user paints upon (DetermineAffectedImageSlice) - Projection of a 3D contour onto a 2D plane/slice SegTool2D tries to structure the interaction a bit. If you pass "PressMoveRelease" as the interaction type of your derived tool, you might implement the methods OnMousePressed, OnMouseMoved, and OnMouseReleased. Yes, your guess about when they are called is correct. \warning Only to be instantiated by mitk::ToolManager. $Author$ */ class Segmentation_EXPORT SegTool2D : public Tool { public: mitkClassMacro(SegTool2D, Tool); /** \brief Calculates for a given Image and PlaneGeometry, which slice of the image (in index corrdinates) is meant by the plane. \return false, if no slice direction seems right (e.g. rotated planes) - \param affectedDimension The image dimension, which is constant for all points in the plane, e.g. Transversal --> 2 + \param affectedDimension The image dimension, which is constant for all points in the plane, e.g. Axial --> 2 \param affectedSlice The index of the image slice */ static bool DetermineAffectedImageSlice( const Image* image, const PlaneGeometry* plane, int& affectedDimension, int& affectedSlice ); void SetShowMarkerNodes(bool); protected: SegTool2D(); // purposely hidden SegTool2D(const char*); // purposely hidden virtual ~SegTool2D(); /** * \brief Calculates how good the data, this statemachine handles, is hit by the event. * */ virtual float CanHandleEvent( StateEvent const *stateEvent) const; /** \brief Extract the slice of an image that the user just scribbles on. \return NULL if SegTool2D is either unable to determine which slice was affected, or if there was some problem getting the image data at that position. */ Image::Pointer GetAffectedImageSliceAs2DImage(const PositionEvent*, const Image* image); /** \brief Extract the slice of the currently selected working image that the user just scribbles on. \return NULL if SegTool2D is either unable to determine which slice was affected, or if there was some problem getting the image data at that position, or just no working image is selected. */ Image::Pointer GetAffectedWorkingSlice(const PositionEvent*); /** \brief Extract the slice of the currently selected reference image that the user just scribbles on. \return NULL if SegTool2D is either unable to determine which slice was affected, or if there was some problem getting the image data at that position, or just no reference image is selected. */ Image::Pointer GetAffectedReferenceSlice(const PositionEvent*); void WriteBackSegmentationResult (const PositionEvent*, Image*); /** \brief Adds a new node called Contourmarker to the datastorage which holds a mitk::PlanarFigure. By selecting this node the slicestack will be reoriented according to the PlanarFigure's Geometry */ unsigned int AddContourmarker ( const PositionEvent* ); void InteractiveSegmentationBugMessage( const std::string& message ); BaseRenderer* m_LastEventSender; unsigned int m_LastEventSlice; private: //The prefix of the contourmarkername. Suffix is a consecutive number const std::string m_Contourmarkername; bool m_ShowMarkerNodes; bool m_3DInterpolationEnabled; DiffSliceOperation* m_doOperation; DiffSliceOperation* m_undoOperation; }; } // namespace #endif diff --git a/Modules/Segmentation/Testing/mitkOverwriteSliceFilterObliquePlaneTest.cpp b/Modules/Segmentation/Testing/mitkOverwriteSliceFilterObliquePlaneTest.cpp index 1749c6dc71..6a1eea2a19 100644 --- a/Modules/Segmentation/Testing/mitkOverwriteSliceFilterObliquePlaneTest.cpp +++ b/Modules/Segmentation/Testing/mitkOverwriteSliceFilterObliquePlaneTest.cpp @@ -1,277 +1,277 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 int VolumeSize = 128; static void OverwriteObliquePlaneTest(mitk::Image* workingImage, mitk::Image* refImg) { /*==============TEST WITHOUT MITK CONVERTION=============================*/ /* ============= setup plane ============*/ int sliceindex = (int)(VolumeSize/2);//rand() % 32; bool isFrontside = true; bool isRotated = false; mitk::PlaneGeometry::Pointer obliquePlane = mitk::PlaneGeometry::New(); - obliquePlane->InitializeStandardPlane(workingImage->GetGeometry(), mitk::PlaneGeometry::Transversal, sliceindex, isFrontside, isRotated); + obliquePlane->InitializeStandardPlane(workingImage->GetGeometry(), mitk::PlaneGeometry::Axial, sliceindex, isFrontside, isRotated); mitk::Point3D origin = obliquePlane->GetOrigin(); mitk::Vector3D normal; 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 = obliquePlane->GetAxisVector(0); rotationVector.Normalize(); float degree = 45.0; mitk::RotationOperation* op = new mitk::RotationOperation(mitk::OpROTATE, obliquePlane->GetCenter(), rotationVector, degree); obliquePlane->ExecuteOperation(op); delete op; /* ============= extract slice ============*/ mitk::ExtractSliceFilter::Pointer slicer = mitk::ExtractSliceFilter::New(); slicer->SetInput(workingImage); slicer->SetWorldGeometry(obliquePlane); slicer->SetVtkOutputRequest(true); slicer->Modified(); slicer->Update(); vtkSmartPointer slice = vtkSmartPointer::New(); slice = slicer->GetVtkOutput(); /* ============= overwrite slice ============*/ vtkSmartPointer resliceIdx = vtkSmartPointer::New(); mitk::ExtractSliceFilter::Pointer overwriter = mitk::ExtractSliceFilter::New(resliceIdx); resliceIdx->SetOverwriteMode(true); resliceIdx->SetInputSlice(slice); resliceIdx->Modified(); overwriter->SetInput(workingImage); overwriter->SetWorldGeometry(obliquePlane); overwriter->SetVtkOutputRequest(true); overwriter->Modified(); overwriter->Update(); /* ============= check ref == working ============*/ bool areSame = true; mitk::Index3D id; id[0] = id[1] = id[2] = 0; for (int x = 0; x < VolumeSize; ++x){ id[0] = x; for (int y = 0; y < VolumeSize; ++y){ id[1] = y; for (int z = 0; z < VolumeSize; ++z){ id[2] = z; areSame = refImg->GetPixelValueByIndex(id) == workingImage->GetPixelValueByIndex(id); if(!areSame) goto stop; } } } stop: MITK_TEST_CONDITION(areSame,"comparing images (no mitk convertion) [oblique]"); /*==============TEST WITH MITK CONVERTION=============================*/ /* ============= extract slice ============*/ mitk::ExtractSliceFilter::Pointer slicer2 = mitk::ExtractSliceFilter::New(); slicer2->SetInput(workingImage); slicer2->SetWorldGeometry(obliquePlane); slicer2->Modified(); slicer2->Update(); mitk::Image::Pointer sliceInMitk = slicer2->GetOutput(); vtkSmartPointer slice2 = vtkSmartPointer::New(); slice2 = sliceInMitk->GetVtkImageData(); /* ============= overwrite slice ============*/ vtkSmartPointer resliceIdx2 = vtkSmartPointer::New(); mitk::ExtractSliceFilter::Pointer overwriter2 = mitk::ExtractSliceFilter::New(resliceIdx2); resliceIdx2->SetOverwriteMode(true); resliceIdx2->SetInputSlice(slice2); resliceIdx2->Modified(); overwriter2->SetInput(workingImage); overwriter2->SetWorldGeometry(obliquePlane); overwriter2->SetVtkOutputRequest(true); overwriter2->Modified(); overwriter2->Update(); /* ============= check ref == working ============*/ areSame = true; id[0] = id[1] = id[2] = 0; for (int x = 0; x < VolumeSize; ++x){ id[0] = x; for (int y = 0; y < VolumeSize; ++y){ id[1] = y; for (int z = 0; z < VolumeSize; ++z){ id[2] = z; areSame = refImg->GetPixelValueByIndex(id) == workingImage->GetPixelValueByIndex(id); if(!areSame) goto stop2; } } } stop2: MITK_TEST_CONDITION(areSame,"comparing images (with mitk convertion) [oblique]"); /*==============TEST EDIT WITHOUT MITK CONVERTION=============================*/ /* ============= edit slice ============*/ int idX = std::abs(VolumeSize-59); int idY = std::abs(VolumeSize-23); int idZ = 0; int component = 0; double val = 33.0; slice->SetScalarComponentFromDouble(idX,idY,idZ,component,val); mitk::Vector3D indx; indx[0] = idX; indx[1] = idY; indx[2] = idZ; sliceInMitk->GetGeometry()->IndexToWorld(indx, indx); /* ============= overwrite slice ============*/ vtkSmartPointer resliceIdx3 = vtkSmartPointer::New(); resliceIdx3->SetOverwriteMode(true); resliceIdx3->SetInputSlice(slice); mitk::ExtractSliceFilter::Pointer overwriter3 = mitk::ExtractSliceFilter::New(resliceIdx3); overwriter3->SetInput(workingImage); overwriter3->SetWorldGeometry(obliquePlane); overwriter3->SetVtkOutputRequest(true); overwriter3->Modified(); overwriter3->Update(); /* ============= check ============*/ areSame = true; int x,y,z; for ( x = 0; x < VolumeSize; ++x){ id[0] = x; for ( y = 0; y < VolumeSize; ++y){ id[1] = y; for ( z = 0; z < VolumeSize; ++z){ id[2] = z; areSame = refImg->GetPixelValueByIndex(id) == workingImage->GetPixelValueByIndex(id); if(!areSame) goto stop3; } } } stop3: //MITK_INFO << "index: [" << x << ", " << y << ", " << z << "]"; //MITK_INFO << indx; MITK_TEST_CONDITION(x==idX && y==z,"overwrited the right index [oblique]"); } /*================ #BEGIN test main ================*/ int mitkOverwriteSliceFilterObliquePlaneTest(int argc, char* argv[]) { MITK_TEST_BEGIN("mitkOverwriteSliceFilterObliquePlaneTest") 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] = VolumeSize; 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 refImage; CastToMitkImage(image, refImage); mitk::Image::Pointer workingImg; CastToMitkImage(image, workingImg); OverwriteObliquePlaneTest(workingImg, refImage); MITK_TEST_END() } diff --git a/Modules/Segmentation/Testing/mitkOverwriteSliceFilterTest.cpp b/Modules/Segmentation/Testing/mitkOverwriteSliceFilterTest.cpp index 8deb76a9bb..c2f2fbaf4d 100644 --- a/Modules/Segmentation/Testing/mitkOverwriteSliceFilterTest.cpp +++ b/Modules/Segmentation/Testing/mitkOverwriteSliceFilterTest.cpp @@ -1,201 +1,201 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 int VolumeSize = 128; /*================ #BEGIN test main ================*/ int mitkOverwriteSliceFilterTest(int argc, char* argv[]) { MITK_TEST_BEGIN("mitkOverwriteSliceFilterTest") 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] = VolumeSize; 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 referenceImage; CastToMitkImage(image, referenceImage); mitk::Image::Pointer workingImage; CastToMitkImage(image, workingImage); /* ============= setup plane ============*/ int sliceindex = 55;//rand() % 32; bool isFrontside = true; bool isRotated = false; mitk::PlaneGeometry::Pointer plane = mitk::PlaneGeometry::New(); - plane->InitializeStandardPlane(workingImage->GetGeometry(), mitk::PlaneGeometry::Transversal, sliceindex, isFrontside, isRotated); + plane->InitializeStandardPlane(workingImage->GetGeometry(), mitk::PlaneGeometry::Axial, 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); /* ============= extract slice ============*/ vtkSmartPointer resliceIdx = vtkSmartPointer::New(); mitk::ExtractSliceFilter::Pointer slicer = mitk::ExtractSliceFilter::New(resliceIdx); slicer->SetInput(workingImage); slicer->SetWorldGeometry(plane); slicer->SetVtkOutputRequest(true); slicer->Modified(); slicer->Update(); vtkSmartPointer slice = vtkSmartPointer::New(); slice = slicer->GetVtkOutput(); /* ============= overwrite slice ============*/ resliceIdx->SetOverwriteMode(true); resliceIdx->Modified(); slicer->Modified(); slicer->Update();//implicit overwrite /* ============= check ref == working ============*/ bool areSame = true; mitk::Index3D id; id[0] = id[1] = id[2] = 0; for (int x = 0; x < VolumeSize; ++x){ id[0] = x; for (int y = 0; y < VolumeSize; ++y){ id[1] = y; for (int z = 0; z < VolumeSize; ++z){ id[2] = z; areSame = referenceImage->GetPixelValueByIndex(id) == workingImage->GetPixelValueByIndex(id); if(!areSame) goto stop; } } } stop: MITK_TEST_CONDITION(areSame,"test overwrite unmodified slice"); /* ============= edit slice ============*/ int idX = std::abs(VolumeSize-59); int idY = std::abs(VolumeSize-23); int idZ = 0; int component = 0; double val = 33.0; slice->SetScalarComponentFromDouble(idX,idY,idZ,component,val); /* ============= overwrite slice ============*/ vtkSmartPointer resliceIdx2 = vtkSmartPointer::New(); resliceIdx2->SetOverwriteMode(true); resliceIdx2->SetInputSlice(slice); mitk::ExtractSliceFilter::Pointer slicer2 = mitk::ExtractSliceFilter::New(resliceIdx2); slicer2->SetInput(workingImage); slicer2->SetWorldGeometry(plane); slicer2->SetVtkOutputRequest(true); slicer2->Modified(); slicer2->Update(); /* ============= check ============*/ areSame = true; int xx,yy,zz; for ( xx = 0; xx < VolumeSize; ++xx){ id[0] = xx; for ( yy = 0; yy < VolumeSize; ++yy){ id[1] = yy; for ( zz = 0; zz < VolumeSize; ++zz){ id[2] = zz; areSame = referenceImage->GetPixelValueByIndex(id) == workingImage->GetPixelValueByIndex(id); if(!areSame) goto stop2; } } } stop2: //MITK_INFO << "index: [" << x << ", " << y << ", " << z << "]"; MITK_TEST_CONDITION(xx==idX && yy==idY && zz==sliceindex,"test overwrite modified slice"); MITK_TEST_END() } diff --git a/Modules/Segmentation/Testing/mitkSegmentationInterpolationTest.cpp b/Modules/Segmentation/Testing/mitkSegmentationInterpolationTest.cpp index cf9f2356aa..3e49318dcb 100644 --- a/Modules/Segmentation/Testing/mitkSegmentationInterpolationTest.cpp +++ b/Modules/Segmentation/Testing/mitkSegmentationInterpolationTest.cpp @@ -1,343 +1,343 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkSegmentationInterpolationController.h" #include "mitkCoreObjectFactory.h" #include "mitkStandardFileLocations.h" #include "mitkDataNodeFactory.h" #include "ipSegmentation.h" #include "mitkCompareImageSliceTestHelper.h" class mitkSegmentationInterpolationTestClass { public: mitkSegmentationInterpolationTestClass() {} ~mitkSegmentationInterpolationTestClass() {} bool Test(std::string filename1, std::string filename2) { return CreateNewInterpolator() && CreateSegmentation() && ClearSegmentation() && CreateTwoSlices(2) && TestInterpolation(2) && ClearSegmentation() && CreateTwoSlices(1) && TestInterpolation(1) && ClearSegmentation() && CreateTwoSlices(0) && TestInterpolation(0) && DeleteInterpolator() && CreateNewInterpolator() && LoadTestImages(filename1, filename2) && CompareInterpolationsToDefinedReference(); } protected: bool CreateNewInterpolator(); bool CreateSegmentation(); bool ClearSegmentation(); bool CreateTwoSlices(int); bool TestInterpolation(int); bool DeleteInterpolator(); bool LoadTestImages(std::string filename1, std::string filename2); bool CompareInterpolationsToDefinedReference(); mitk::Image::Pointer LoadImage(const std::string& filename); mitk::SegmentationInterpolationController::Pointer m_Interpolator; mitk::Image::Pointer m_Image; mitk::Image::Pointer m_ManualSlices; mitk::Image::Pointer m_InterpolatedSlices; unsigned int dim[3]; int pad[3]; }; bool mitkSegmentationInterpolationTestClass::CreateNewInterpolator() { std::cout << "Instantiation" << std::endl; // instantiation m_Interpolator = mitk::SegmentationInterpolationController::New(); if (m_Interpolator.IsNotNull()) { std::cout << " (II) Instantiation works." << std::endl; } else { std::cout << " Instantiation test failed!" << std::endl; return false; } return true; } bool mitkSegmentationInterpolationTestClass::CreateSegmentation() { m_Image = mitk::Image::New(); dim[0]=15; dim[1]=20; dim[2]=25; pad[0]=2; pad[1]=3; pad[2]=4; m_Image->Initialize( mitk::MakeScalarPixelType(), 3, dim); return true; } bool mitkSegmentationInterpolationTestClass::ClearSegmentation() { int* p = (int*)m_Image->GetData(); // pointer to pixel data int size = dim[0]*dim[1]*dim[2]; for(int i=0; iGetData(); // pointer to pixel data int size = dim[0]*dim[1]*dim[2]; for(int i=0; i= pad[xdim]) && (x < ( (signed) dim[xdim]-pad[xdim])) && (y >= pad[ydim]) && (y < ( (signed) dim[ydim]-pad[ydim])) ) { *p = 1; } else { *p = 0; } } m_Interpolator->SetSegmentationVolume( m_Image ); std::cout << " (II) SetSegmentationVolume works (slicedim " << slicedim << ")" << std::endl; return true; } /** * Checks if interpolation would create a square in slice 1 */ bool mitkSegmentationInterpolationTestClass::TestInterpolation(int slicedim) { int slice = 1; - mitk::Image::Pointer interpolated = m_Interpolator->Interpolate( slicedim, slice, 0 ); // interpolate second slice transversal + mitk::Image::Pointer interpolated = m_Interpolator->Interpolate( slicedim, slice, 0 ); // interpolate second slice axial if (interpolated.IsNull()) { std::cerr << " (EE) Interpolation did not return anything for slicedim == " << slicedim << " (although it should)." << std::endl; return false; } int xdim,ydim; switch (slicedim) { case 0: xdim = 1; ydim = 2; // different than above! break; case 1: xdim = 0; ydim = 2; break; case 2: default: xdim = 0; ydim = 1; break; } ipMITKSegmentationTYPE* p = (ipMITKSegmentationTYPE*)interpolated->GetData(); // pointer to pixel data int size = dim[xdim]*dim[ydim]; if ( (signed) interpolated->GetDimension(0) * (signed) interpolated->GetDimension(1) != size ) { std::cout << " (EE) Size of interpolated image differs from original segmentation..." << std::endl; return false; } for(int i=0; i= pad[xdim]) && (x < ((signed) dim[xdim]-pad[xdim])) && (y >= pad[ydim]) && (y < ((signed) dim[ydim]-pad[ydim])) && (value != 1) ) { std::cout << " (EE) Interpolation of a square figure failed" << std::endl; std::cout << " Value at " << x << " " << y << ": " << (int)value << std::endl; return false; } } std::cout << " (II) Interpolation of a square figure works like expected (slicedim " << slicedim << ")" << std::endl; return true; } bool mitkSegmentationInterpolationTestClass::DeleteInterpolator() { std::cout << "Object destruction" << std::endl; // freeing m_Interpolator = NULL; std::cout << " (II) Freeing works." << std::endl; return true; } bool mitkSegmentationInterpolationTestClass::LoadTestImages(std::string filename1, std::string filename2) { m_ManualSlices = LoadImage( filename1 ); m_InterpolatedSlices = LoadImage( filename2 ); return ( m_ManualSlices.IsNotNull() && m_InterpolatedSlices.IsNotNull() ); } mitk::Image::Pointer mitkSegmentationInterpolationTestClass::LoadImage(const std::string& filename) { mitk::Image::Pointer image = NULL; mitk::DataNodeFactory::Pointer factory = mitk::DataNodeFactory::New(); try { factory->SetFileName( filename ); factory->Update(); if(factory->GetNumberOfOutputs()<1) { std::cerr<<"File " << filename << " could not be loaded [FAILED]"<GetOutput( 0 ); image = dynamic_cast(node->GetData()); if(image.IsNull()) { std::cout<<"File " << filename << " is not an image! [FAILED]"<SetSegmentationVolume( m_ManualSlices ); std::cout << "OK" << std::endl; std::cout << " (II) Testing interpolation result for slice " << std::flush; for (unsigned int slice = 1; slice < 98; ++slice) { if (slice % 2 == 0) continue; // these were manually drawn, no interpolation possible std::cout << slice << " " << std::flush; mitk::Image::Pointer interpolation = m_Interpolator->Interpolate( 2, slice, 0 ); if ( interpolation.IsNull() ) { std::cerr << " (EE) Interpolated image is NULL." << std::endl; return false; } if ( !CompareImageSliceTestHelper::CompareSlice( m_InterpolatedSlices, 2, slice, interpolation ) ) { std::cerr << " (EE) interpolated image is not identical to reference in slice " << slice << std::endl; return false; } } std::cout << std::endl; std::cout << " (II) Interpolations are the same as the saved references." << std::endl; return true; } /// ctest entry point int mitkSegmentationInterpolationTest(int argc, char* argv[]) { // one big variable to tell if anything went wrong // std::cout << "Creating CoreObjectFactory" << std::endl; // itk::ObjectFactoryBase::RegisterFactory(mitk::CoreObjectFactory::New()); if (argc < 3) { std::cerr << " (EE) Missing arguments for testing" << std::endl; } mitkSegmentationInterpolationTestClass test; if ( test.Test(argv[1], argv[2]) ) { std::cout << "[PASSED]" << std::endl; return EXIT_SUCCESS; } else { std::cout << "[FAILED]" << std::endl; return EXIT_FAILURE; } } diff --git a/Modules/ToFHardware/Testing/files.cmake b/Modules/ToFHardware/Testing/files.cmake index c4a1a1d76a..84337393f6 100644 --- a/Modules/ToFHardware/Testing/files.cmake +++ b/Modules/ToFHardware/Testing/files.cmake @@ -1,30 +1,30 @@ set(MODULE_TESTS mitkThreadedToFRawDataReconstructionTest.cpp mitkToFCameraMITKPlayerControllerTest.cpp - #mitkToFCameraMITKPlayerDeviceTest.cpp + mitkToFCameraMITKPlayerDeviceTest.cpp mitkToFCameraPMDCamBoardControllerTest.cpp mitkToFCameraPMDCamBoardDeviceTest.cpp - #mitkToFCameraPMDRawDataCamBoardDeviceTest.cpp +# mitkToFCameraPMDRawDataCamBoardDeviceTest.cpp mitkToFCameraPMDCamCubeControllerTest.cpp mitkToFCameraPMDCamCubeDeviceTest.cpp - #mitkToFCameraPMDRawDataCamCubeDeviceTest.cpp +# mitkToFCameraPMDRawDataCamCubeDeviceTest.cpp mitkToFCameraPMDControllerTest.cpp mitkToFCameraPMDDeviceTest.cpp mitkToFCameraPMDRawDataDeviceTest.cpp mitkToFCameraPMDMITKPlayerControllerTest.cpp mitkToFCameraPMDMITKPlayerDeviceTest.cpp mitkToFCameraPMDO3ControllerTest.cpp mitkToFCameraPMDO3DeviceTest.cpp mitkToFCameraPMDPlayerControllerTest.cpp mitkToFCameraPMDPlayerDeviceTest.cpp mitkToFImageCsvWriterTest.cpp mitkToFImageGrabberTest.cpp #mitkToFImageRecorderTest.cpp #mitkToFImageRecorderFilterTest.cpp mitkToFImageWriterTest.cpp - #mitkToFNrrdImageWriterTest.cpp + mitkToFNrrdImageWriterTest.cpp mitkToFOpenCVImageGrabberTest.cpp - #mitkKinectControllerTest.cpp - #mitkKinectDeviceTest.cpp + mitkKinectControllerTest.cpp + mitkKinectDeviceTest.cpp ) diff --git a/Modules/ToFHardware/Testing/mitkToFCameraMITKPlayerDeviceTest.cpp b/Modules/ToFHardware/Testing/mitkToFCameraMITKPlayerDeviceTest.cpp index dbbe16c969..9b54c4b3f2 100644 --- a/Modules/ToFHardware/Testing/mitkToFCameraMITKPlayerDeviceTest.cpp +++ b/Modules/ToFHardware/Testing/mitkToFCameraMITKPlayerDeviceTest.cpp @@ -1,128 +1,133 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 bool CompareFloatArrays(float* array1, float* array2, unsigned int numberOfElements) { bool arraysEqual = true; for (unsigned int i=0; iGetDimension(2); for (int i=0; iGetSliceData(i,0,0)->GetData(); if (CompareFloatArrays(dataArray,array,numberOfElements)) { validFrame = true; } } return validFrame; } /**Documentation * test for the class "ToFCameraMITKPlayerDevice". */ int mitkToFCameraMITKPlayerDeviceTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("ToFCameraMITKPlayerDevice"); std::string dirName = MITK_TOF_DATA_DIR; mitk::ToFCameraMITKPlayerDevice::Pointer tofCameraMITKPlayerDevice = mitk::ToFCameraMITKPlayerDevice::New(); std::string distanceFileName = dirName + "/PMDCamCube2_MF0_IT0_20Images_DistanceImage.pic"; tofCameraMITKPlayerDevice->SetProperty("DistanceImageFileName",mitk::StringProperty::New(distanceFileName)); std::string amplitudeFileName = dirName + "/PMDCamCube2_MF0_IT0_20Images_AmplitudeImage.pic"; tofCameraMITKPlayerDevice->SetProperty("AmplitudeImageFileName",mitk::StringProperty::New(amplitudeFileName)); std::string intensityFileName = dirName + "/PMDCamCube2_MF0_IT0_20Images_IntensityImage.pic"; tofCameraMITKPlayerDevice->SetProperty("IntensityImageFileName",mitk::StringProperty::New(intensityFileName)); MITK_TEST_CONDITION_REQUIRED(tofCameraMITKPlayerDevice->IsCameraActive()==false,"Test IsCameraActive() before start camera"); MITK_TEST_OUTPUT(<< "Start device"); MITK_TEST_CONDITION_REQUIRED(tofCameraMITKPlayerDevice->ConnectCamera(),"Test ConnectCamera()"); tofCameraMITKPlayerDevice->StartCamera(); MITK_TEST_CONDITION_REQUIRED(tofCameraMITKPlayerDevice->IsCameraActive()==true,"Test IsCameraActive() after start camera"); unsigned int captureWidth = tofCameraMITKPlayerDevice->GetCaptureWidth(); unsigned int captureHeight = tofCameraMITKPlayerDevice->GetCaptureHeight(); unsigned int numberOfPixels = captureWidth*captureHeight; float* distances = new float[numberOfPixels]; float* amplitudes = new float[numberOfPixels]; float* intensities = new float[numberOfPixels]; + unsigned char* rgbDataArray = new unsigned char[numberOfPixels*3]; char* sourceDataArray = new char[numberOfPixels]; float* expectedDistances = NULL; float* expectedAmplitudes = NULL; float* expectedIntensities = NULL; int requiredImageSequence = 0; int imageSequence = 0; mitk::PicFileReader::Pointer distanceFileReader = mitk::PicFileReader::New(); distanceFileReader->SetFileName(distanceFileName); distanceFileReader->Update(); mitk::Image::Pointer distanceImage = distanceFileReader->GetOutput(); mitk::PicFileReader::Pointer amplitudeFileReader = mitk::PicFileReader::New(); amplitudeFileReader->SetFileName(amplitudeFileName); amplitudeFileReader->Update(); mitk::Image::Pointer amplitudeImage = amplitudeFileReader->GetOutput(); mitk::PicFileReader::Pointer intensityFileReader = mitk::PicFileReader::New(); intensityFileReader->SetFileName(intensityFileName); intensityFileReader->Update(); mitk::Image::Pointer intensityImage = intensityFileReader->GetOutput(); unsigned int numberOfFrames = distanceImage->GetDimension(2); for (int i=0; iGetDistances(distances,imageSequence); MITK_TEST_CONDITION_REQUIRED(CheckValidFrame(distances,distanceImage,numberOfPixels),"Check frame from GetDistances()"); tofCameraMITKPlayerDevice->GetAmplitudes(amplitudes,imageSequence); MITK_TEST_CONDITION_REQUIRED(CheckValidFrame(amplitudes,amplitudeImage,numberOfPixels),"Check frame from GetAmplitudes()"); tofCameraMITKPlayerDevice->GetIntensities(intensities,imageSequence); MITK_TEST_CONDITION_REQUIRED(CheckValidFrame(intensities,intensityImage,numberOfPixels),"Check frame from GetIntensities()"); - tofCameraMITKPlayerDevice->GetAllImages(distances,amplitudes,intensities,sourceDataArray,requiredImageSequence,imageSequence); + MITK_TEST_OUTPUT(<< "GetAllImages() with rgbDataArray"); + tofCameraMITKPlayerDevice->GetAllImages(distances,amplitudes,intensities,sourceDataArray,requiredImageSequence,imageSequence,rgbDataArray); MITK_TEST_CONDITION_REQUIRED(CheckValidFrame(distances,distanceImage,numberOfPixels),"Check distance frame from GetAllImages()"); MITK_TEST_CONDITION_REQUIRED(CheckValidFrame(amplitudes,amplitudeImage,numberOfPixels),"Check amplitude frame from GetAllImages()"); MITK_TEST_CONDITION_REQUIRED(CheckValidFrame(intensities,intensityImage,numberOfPixels),"Check intensity frame from GetAllImages()"); //expectedDistances = (float*)distanceImage->GetSliceData(i,0,0)->GetData(); + MITK_TEST_OUTPUT(<< "GetAllImages() without rgbDataArray"); + tofCameraMITKPlayerDevice->GetAllImages(distances,amplitudes,intensities,sourceDataArray,requiredImageSequence,imageSequence); } itksys::SystemTools::Delay(1000); tofCameraMITKPlayerDevice->StopCamera(); MITK_TEST_CONDITION_REQUIRED(tofCameraMITKPlayerDevice->IsCameraActive()==false,"Test IsCameraActive() after stop camera"); MITK_TEST_CONDITION_REQUIRED(tofCameraMITKPlayerDevice->DisconnectCamera(),"Test DisconnectCamera()"); delete [] distances; delete [] intensities; delete [] amplitudes; + delete [] rgbDataArray; delete [] sourceDataArray; MITK_TEST_END(); } diff --git a/Modules/ToFHardware/Testing/mitkToFImageCsvWriterTest.cpp b/Modules/ToFHardware/Testing/mitkToFImageCsvWriterTest.cpp index f2271c9868..8797469fe3 100644 --- a/Modules/ToFHardware/Testing/mitkToFImageCsvWriterTest.cpp +++ b/Modules/ToFHardware/Testing/mitkToFImageCsvWriterTest.cpp @@ -1,205 +1,205 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include void CloseCsvFile(FILE* outfile) { fclose(outfile); } void OpenCsvFile(FILE** outfile, std::string outfileName) { (*outfile) = fopen( outfileName.c_str(), "r" ); if( !outfile ) { MITK_ERROR << "Error opening outfile: " << outfileName; throw std::logic_error("Error opening outfile."); return; } } /**Documentation * test for the class "ToFImageCsvWriter". */ int mitkToFImageCsvWriterTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("ToFImageCsvWriter"); mitk::ToFImageCsvWriter::Pointer csvWriter = mitk::ToFImageCsvWriter::New(); MITK_TEST_CONDITION_REQUIRED(csvWriter.GetPointer(), "Testing initialization of test object!"); MITK_TEST_CONDITION_REQUIRED(csvWriter->GetExtension() == ".csv", "Testing correct initialization of member variable extension!"); srand(time(0)); unsigned int dimX = 100 + rand()%100; unsigned int dimY = 100 + rand()%100; unsigned int pixelNumber = dimX*dimY; unsigned int numOfFrames = 1 + rand()%100; MITK_INFO<(dimX, dimY, numOfFrames); mitk::Image::Pointer amplitudeImage = mitk::ImageGenerator::GenerateRandomImage(dimX, dimY, numOfFrames); mitk::Image::Pointer intensityImage = mitk::ImageGenerator::GenerateRandomImage(dimX, dimY, numOfFrames); std::string distanceImageFileName("distImg.csv"); std::string amplitudeImageFileName("amplImg.csv"); std::string intensityImageFileName("intImg.csv"); csvWriter->SetDistanceImageFileName(distanceImageFileName); csvWriter->SetAmplitudeImageFileName(amplitudeImageFileName); csvWriter->SetIntensityImageFileName(intensityImageFileName); - csvWriter->SetCaptureWidth(dimX); - csvWriter->SetCaptureHeight(dimY); + csvWriter->SetToFCaptureWidth(dimX); + csvWriter->SetToFCaptureHeight(dimY); csvWriter->SetToFImageType(mitk::ToFImageWriter::ToFImageType3D); mitk::ImageSliceSelector::Pointer distanceSelector = mitk::ImageSliceSelector::New(); mitk::ImageSliceSelector::Pointer amplitudeSelector = mitk::ImageSliceSelector::New(); mitk::ImageSliceSelector::Pointer intensitySelector = mitk::ImageSliceSelector::New(); mitk::Image::Pointer tmpDistance; mitk::Image::Pointer tmpAmplitude; mitk::Image::Pointer tmpIntensity; distanceSelector->SetInput(distanceImage); amplitudeSelector->SetInput(amplitudeImage); intensitySelector->SetInput(intensityImage); //buffer float* distanceArray; float* amplitudeArray; float* intensityArray; csvWriter->Open(); //open file/stream for(unsigned int i = 0; iSetSliceNr(i); distanceSelector->Update(); tmpDistance = distanceSelector->GetOutput(); distanceArray = (float*)tmpDistance->GetData(); amplitudeSelector->SetSliceNr(i); amplitudeSelector->Update(); tmpAmplitude = amplitudeSelector->GetOutput(); amplitudeArray = (float*)tmpAmplitude->GetData(); intensitySelector->SetSliceNr(i); intensitySelector->Update(); tmpIntensity = intensitySelector->GetOutput(); intensityArray = (float*)tmpIntensity->GetData(); csvWriter->Add(distanceArray, amplitudeArray, intensityArray); } csvWriter->Close(); //close file FILE* distanceInfile = NULL; FILE* amplitudeInfile = NULL; FILE* intensityInfile = NULL; //open file again OpenCsvFile(&(distanceInfile), distanceImageFileName); OpenCsvFile(&(amplitudeInfile), amplitudeImageFileName); OpenCsvFile(&(intensityInfile), intensityImageFileName); float distVal = 0.0, amplVal = 0.0, intenVal = 0.0; int dErr = 0, aErr = 0, iErr = 0; bool readingCorrect = true; //for all frames... for(unsigned int j=0; jSetSliceNr(j); distanceSelector->Update(); tmpDistance = distanceSelector->GetOutput(); distanceArray = (float*)tmpDistance->GetData(); amplitudeSelector->SetSliceNr(j); amplitudeSelector->Update(); tmpAmplitude = amplitudeSelector->GetOutput(); amplitudeArray = (float*)tmpAmplitude->GetData(); intensitySelector->SetSliceNr(j); intensitySelector->Update(); tmpIntensity = intensitySelector->GetOutput(); intensityArray = (float*)tmpIntensity->GetData(); //for all pixels for(unsigned int i=0; i #include -#include +#include +#include #include #include #include #include #include mitk::Image::Pointer CreateTestImage(unsigned int dimX, unsigned int dimY) { typedef itk::Image ItkImageType2D; typedef itk::ImageRegionIterator ItkImageRegionIteratorType2D; ItkImageType2D::Pointer image = ItkImageType2D::New(); ItkImageType2D::IndexType start; start[0] = 0; start[1] = 0; ItkImageType2D::SizeType size; size[0] = dimX; size[1] = dimY; ItkImageType2D::RegionType region; region.SetSize(size); region.SetIndex( start); ItkImageType2D::SpacingType spacing; spacing[0] = 1.0; spacing[1] = 1.0; image->SetRegions( region ); image->SetSpacing ( spacing ); image->Allocate(); //Obtaining image data from ToF camera// //Correlate inten values to PixelIndex// ItkImageRegionIteratorType2D imageIterator(image,image->GetLargestPossibleRegion()); imageIterator.GoToBegin(); itk::Statistics::MersenneTwisterRandomVariateGenerator::Pointer randomGenerator = itk::Statistics::MersenneTwisterRandomVariateGenerator::New(); while (!imageIterator.IsAtEnd()) { double pixelValue = randomGenerator->GetUniformVariate(0.0,1000.0); imageIterator.Set(pixelValue); ++imageIterator; } mitk::Image::Pointer mitkImage = mitk::Image::New(); mitk::CastToMitkImage(image,mitkImage); return mitkImage; } static bool CompareImages(mitk::Image::Pointer image1, mitk::Image::Pointer image2) { //check if epsilon is exceeded unsigned int sliceDimension = image1->GetDimension(0)*image1->GetDimension(1); bool picturesEqual = true; float* floatArray1 = (float*)image1->GetSliceData(0, 0, 0)->GetData(); float* floatArray2 = (float*)image2->GetSliceData(0, 0, 0)->GetData(); for(unsigned int i = 0; i < sliceDimension; i++) { if(!(mitk::Equal(floatArray1[i], floatArray2[i]))) { picturesEqual = false; } } return picturesEqual; } /**Documentation * test for the class "ToFImageRecorderFilter". */ int mitkToFImageRecorderFilterTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("ToFImageRecorder"); mitk::ToFImageRecorderFilter::Pointer tofImageRecorderFilter = mitk::ToFImageRecorderFilter::New(); - + std::string dirName = MITK_TOF_DATA_DIR; MITK_TEST_OUTPUT(<< "Test SetFileName()"); - std::string testFileName = "test.pic"; + std::string testFileName = dirName + "test.pic"; + MITK_TEST_FOR_EXCEPTION_BEGIN(std::logic_error); + tofImageRecorderFilter->SetFileName(testFileName); + MITK_TEST_FOR_EXCEPTION_END(std::logic_error); + testFileName = dirName + "test.nrrd"; tofImageRecorderFilter->SetFileName(testFileName); mitk::ToFImageWriter::Pointer tofImageWriter = tofImageRecorderFilter->GetToFImageWriter(); - std::string requiredName = "test_DistanceImage.pic"; + std::string requiredName = dirName + "test_DistanceImage.nrrd"; std::string name = tofImageWriter->GetDistanceImageFileName(); MITK_TEST_CONDITION_REQUIRED(requiredName==name,"Test for distance image file name"); - requiredName = "test_AmplitudeImage.pic"; + requiredName = dirName + "test_AmplitudeImage.nrrd"; name = tofImageWriter->GetAmplitudeImageFileName(); MITK_TEST_CONDITION_REQUIRED(requiredName==name,"Test for amplitude image file name"); - requiredName = "test_IntensityImage.pic"; + requiredName = dirName + "test_IntensityImage.nrrd"; name = tofImageWriter->GetIntensityImageFileName(); MITK_TEST_CONDITION_REQUIRED(requiredName==name,"Test for intensity image file name"); mitk::Image::Pointer testDistanceImage = CreateTestImage(200,200); mitk::Image::Pointer testAmplitudeImage = CreateTestImage(200,200); mitk::Image::Pointer testIntensityImage = CreateTestImage(200,200); MITK_TEST_OUTPUT(<< "Apply filter"); tofImageRecorderFilter->StartRecording(); tofImageRecorderFilter->SetInput(0,testDistanceImage); tofImageRecorderFilter->SetInput(1,testAmplitudeImage); tofImageRecorderFilter->SetInput(2,testIntensityImage); tofImageRecorderFilter->Update(); MITK_TEST_OUTPUT(<< "Test outputs of filter"); mitk::Image::Pointer outputDistanceImage = tofImageRecorderFilter->GetOutput(0); MITK_TEST_CONDITION_REQUIRED(CompareImages(testDistanceImage,outputDistanceImage),"Test output 0 (distance image)"); mitk::Image::Pointer outputAmplitudeImage = tofImageRecorderFilter->GetOutput(1); MITK_TEST_CONDITION_REQUIRED(CompareImages(testAmplitudeImage,outputAmplitudeImage),"Test output 1 (amplitude image)"); mitk::Image::Pointer outputIntensityImage = tofImageRecorderFilter->GetOutput(2); MITK_TEST_CONDITION_REQUIRED(CompareImages(testIntensityImage,outputIntensityImage),"Test output 2 (intensity image)"); tofImageRecorderFilter->StopRecording(); MITK_TEST_OUTPUT(<< "Test content of written files"); - mitk::PicFileReader::Pointer imageReader = mitk::PicFileReader::New(); - imageReader->SetFileName("test_DistanceImage.pic"); + mitk::ItkImageFileReader::Pointer imageReader = mitk::ItkImageFileReader::New(); + std::string testDistanceImageName = dirName + "test_DistanceImage.nrrd"; + imageReader->SetFileName(testDistanceImageName); imageReader->Update(); mitk::Image::Pointer loadedDistanceImage = imageReader->GetOutput(); MITK_TEST_CONDITION_REQUIRED(CompareImages(testDistanceImage,loadedDistanceImage),"Test loaded image 0 (distance image)"); - imageReader->SetFileName("test_AmplitudeImage.pic"); + std::string testAmplitudeImageName = dirName + "test_AmplitudeImage.nrrd"; + imageReader->SetFileName(testAmplitudeImageName); imageReader->Update(); mitk::Image::Pointer loadedAmplitudeImage = imageReader->GetOutput(); MITK_TEST_CONDITION_REQUIRED(CompareImages(testAmplitudeImage,loadedAmplitudeImage),"Test loaded image 1 (amplitude image)"); - imageReader->SetFileName("test_IntensityImage.pic"); + std::string testIntensityImageName = dirName + "test_IntensityImage.nrrd"; + imageReader->SetFileName(testIntensityImageName); imageReader->Update(); mitk::Image::Pointer loadedIntensityImage = imageReader->GetOutput(); MITK_TEST_CONDITION_REQUIRED(CompareImages(testIntensityImage,loadedIntensityImage),"Test loaded image 2 (intensity image)"); //clean up and delete saved image files - if( remove( "test_DistanceImage.pic" ) != 0 ) + if( remove( testDistanceImageName.c_str() ) != 0 ) { - MITK_ERROR<<"File: test_DistanceImage.pic not successfully deleted!"; + MITK_ERROR<<"File: test_DistanceImage.nrrd not successfully deleted!"; } - if( remove( "test_AmplitudeImage.pic" ) != 0 ) + if( remove( testAmplitudeImageName.c_str() ) != 0 ) { - MITK_ERROR<<"File: test_AmplitudeImage.pic not successfully deleted!"; + MITK_ERROR<<"File: test_AmplitudeImage.nrrd not successfully deleted!"; } - if( remove( "test_IntensityImage.pic" ) != 0 ) + if( remove( testIntensityImageName.c_str() ) != 0 ) { - MITK_ERROR<<"File: test_IntensityImage.pic not successfully deleted!"; + MITK_ERROR<<"File: test_IntensityImage.nrrd not successfully deleted!"; } MITK_TEST_END(); } diff --git a/Modules/ToFHardware/Testing/mitkToFImageRecorderTest.cpp b/Modules/ToFHardware/Testing/mitkToFImageRecorderTest.cpp index 302563ca48..1b325efd9d 100644 --- a/Modules/ToFHardware/Testing/mitkToFImageRecorderTest.cpp +++ b/Modules/ToFHardware/Testing/mitkToFImageRecorderTest.cpp @@ -1,247 +1,249 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 /**Documentation * test for the class "ToFImageRecorder". */ static bool CompareImages(mitk::Image::Pointer image1, mitk::Image::Pointer image2) { //check if epsilon is exceeded unsigned int sliceDimension = image1->GetDimension(0)*image1->GetDimension(1); bool picturesEqual = true; int numOfFrames = image1->GetDimension(2); for (unsigned int i=0; iGetSliceData(i, 0, 0)->GetData(); float* floatArray2 = (float*)image2->GetSliceData(i, 0, 0)->GetData(); for(unsigned int j = 0; j < sliceDimension; j++) { if(!(mitk::Equal(floatArray1[j], floatArray2[j]))) { picturesEqual = false; } } } return picturesEqual; } int mitkToFImageRecorderTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("ToFImageRecorder"); mitk::ToFImageRecorder::Pointer tofImageRecorder = mitk::ToFImageRecorder::New(); MITK_TEST_OUTPUT(<< "Test itk-Set/Get-Makros"); - std::string testFileName_Distance = "test_DistanceImage.pic"; - std::string testFileName_Amplitude = "test_AmplitudeImage.pic"; - std::string testFileName_Intensity = "test_IntensityImage.pic"; + std::string testFileName_Distance = "test_DistanceImage.nrrd"; + std::string testFileName_Amplitude = "test_AmplitudeImage.nrrd"; + std::string testFileName_Intensity = "test_IntensityImage.nrrd"; std::string requiredName_Distance; std::string requiredName_Amplitude; std::string requiredName_Intensity; tofImageRecorder->SetDistanceImageFileName(testFileName_Distance); requiredName_Distance = tofImageRecorder->GetDistanceImageFileName(); MITK_TEST_CONDITION_REQUIRED(requiredName_Distance==testFileName_Distance,"Test for distance image file name"); tofImageRecorder->SetAmplitudeImageFileName(testFileName_Amplitude); requiredName_Amplitude = tofImageRecorder->GetAmplitudeImageFileName(); MITK_TEST_CONDITION_REQUIRED(requiredName_Amplitude==testFileName_Amplitude,"Test for amplitude image file name"); tofImageRecorder->SetIntensityImageFileName(testFileName_Intensity); requiredName_Intensity = tofImageRecorder->GetIntensityImageFileName(); MITK_TEST_CONDITION_REQUIRED(requiredName_Intensity==testFileName_Intensity,"Test for intensity image file name"); bool distanceImageSelected = false; bool amplitudeImageSelected = false; bool intensityImageSelected = false; bool requiredDistanceImageSelected = false; bool requiredAmplitudeImageSelected = false; bool requiredIntensityImageSelected = false; tofImageRecorder->SetDistanceImageSelected(distanceImageSelected); requiredDistanceImageSelected = tofImageRecorder->GetDistanceImageSelected(); MITK_TEST_CONDITION_REQUIRED(distanceImageSelected==requiredDistanceImageSelected,"Test for distance selection"); tofImageRecorder->SetAmplitudeImageSelected(amplitudeImageSelected); requiredAmplitudeImageSelected = tofImageRecorder->GetAmplitudeImageSelected(); MITK_TEST_CONDITION_REQUIRED(amplitudeImageSelected==requiredAmplitudeImageSelected,"Test for amplitude selection"); tofImageRecorder->SetIntensityImageSelected(intensityImageSelected); requiredIntensityImageSelected = tofImageRecorder->GetIntensityImageSelected(); MITK_TEST_CONDITION_REQUIRED(intensityImageSelected==requiredIntensityImageSelected,"Test for intensity selection"); int numOfFrames = 7; tofImageRecorder->SetNumOfFrames(numOfFrames); MITK_TEST_CONDITION_REQUIRED(numOfFrames==tofImageRecorder->GetNumOfFrames(),"Test for get/set number of frames"); - std::string fileFormat = ".pic"; + std::string fileFormat = ".nrrd"; tofImageRecorder->SetFileFormat(fileFormat); MITK_TEST_CONDITION_REQUIRED(fileFormat==tofImageRecorder->GetFileFormat(),"Test for get/set the file format"); MITK_TEST_OUTPUT(<< "Test other methods"); tofImageRecorder->SetRecordMode(mitk::ToFImageRecorder::Infinite); MITK_TEST_CONDITION_REQUIRED(mitk::ToFImageRecorder::Infinite==tofImageRecorder->GetRecordMode(),"Test for get/set the record mode"); mitk::ToFCameraDevice* testDevice = NULL; tofImageRecorder->SetCameraDevice(testDevice); MITK_TEST_CONDITION_REQUIRED(testDevice == tofImageRecorder->GetCameraDevice(),"Test for get/set the camera device"); tofImageRecorder->SetToFImageType(mitk::ToFImageWriter::ToFImageType2DPlusT); MITK_TEST_CONDITION_REQUIRED(mitk::ToFImageWriter::ToFImageType2DPlusT==tofImageRecorder->GetToFImageType(), "Testing set/get ToFImageType"); tofImageRecorder->SetToFImageType(mitk::ToFImageWriter::ToFImageType3D); MITK_TEST_CONDITION_REQUIRED(mitk::ToFImageWriter::ToFImageType3D==tofImageRecorder->GetToFImageType(), "Testing set/get ToFImageType"); MITK_TEST_OUTPUT(<< "Test recording"); tofImageRecorder = mitk::ToFImageRecorder::New(); std::string dirName = MITK_TOF_DATA_DIR; mitk::ToFCameraMITKPlayerDevice::Pointer tofCameraMITKPlayerDevice = mitk::ToFCameraMITKPlayerDevice::New(); tofImageRecorder->SetCameraDevice(tofCameraMITKPlayerDevice); MITK_TEST_CONDITION_REQUIRED(tofCameraMITKPlayerDevice == tofImageRecorder->GetCameraDevice(), "Testing set/get CameraDevice with ToFCameraPlayerDevice"); std::string distanceFileName = dirName + "/PMDCamCube2_MF0_IT0_20Images_DistanceImage.pic"; std::string amplitudeFileName = dirName + "/PMDCamCube2_MF0_IT0_20Images_AmplitudeImage.pic"; std::string intensityFileName = dirName + "/PMDCamCube2_MF0_IT0_20Images_IntensityImage.pic"; tofCameraMITKPlayerDevice->SetProperty("DistanceImageFileName",mitk::StringProperty::New(distanceFileName)); tofCameraMITKPlayerDevice->SetProperty("AmplitudeImageFileName",mitk::StringProperty::New(amplitudeFileName)); tofCameraMITKPlayerDevice->SetProperty("IntensityImageFileName",mitk::StringProperty::New(intensityFileName)); MITK_TEST_OUTPUT(<< "Test ConnectCamera()"); tofCameraMITKPlayerDevice->ConnectCamera(); MITK_TEST_OUTPUT(<< "Test StartCamera()"); tofCameraMITKPlayerDevice->StartCamera(); - std::string distanceTestFileName = "test_distance.pic"; - std::string amplitudeTestFileName = "test_amplitude.pic"; - std::string intensityTestFileName = "test_intensity.pic"; + std::string distanceTestFileName = dirName + "test_distance.nrrd"; + std::string amplitudeTestFileName = dirName + "test_amplitude.nrrd"; + std::string intensityTestFileName = dirName + "test_intensity.nrrd"; tofImageRecorder->SetDistanceImageFileName(distanceTestFileName); MITK_TEST_CONDITION_REQUIRED(tofImageRecorder->GetDistanceImageFileName() == distanceTestFileName, "Testing Set/GetDistanceImageFileName()"); tofImageRecorder->SetAmplitudeImageFileName(amplitudeTestFileName); MITK_TEST_CONDITION_REQUIRED(tofImageRecorder->GetAmplitudeImageFileName() == amplitudeTestFileName, "Testing Set/GetAmplitudeImageFileName()"); tofImageRecorder->SetIntensityImageFileName(intensityTestFileName); MITK_TEST_CONDITION_REQUIRED(tofImageRecorder->GetIntensityImageFileName() == intensityTestFileName, "Testing Set/GetIntensityImageFileName()"); - tofImageRecorder->SetFileFormat(".pic"); - MITK_TEST_CONDITION_REQUIRED(tofImageRecorder->GetFileFormat() == ".pic", "Testing Set/GetFileFormat()"); tofImageRecorder->SetRecordMode(mitk::ToFImageRecorder::PerFrames); MITK_TEST_CONDITION_REQUIRED(tofImageRecorder->GetRecordMode() == mitk::ToFImageRecorder::PerFrames, "Testing Set/GetRecordMode()"); tofImageRecorder->SetNumOfFrames(20); MITK_TEST_CONDITION_REQUIRED(tofImageRecorder->GetNumOfFrames() == 20, "Testing Set/GetNumOfFrames()"); - + tofImageRecorder->SetFileFormat(".nrrd"); MITK_TEST_OUTPUT(<< "Test StartRecording()"); tofImageRecorder->StartRecording(); - itksys::SystemTools::Delay(1000); // wait to allow recording + tofImageRecorder->WaitForThreadBeingTerminated(); // wait to allow recording MITK_TEST_OUTPUT(<< "Test StopRecording()"); tofImageRecorder->StopRecording(); MITK_TEST_OUTPUT(<< "Test StopCamera()"); tofCameraMITKPlayerDevice->StopCamera(); MITK_TEST_OUTPUT(<< "Test DisconnectCamera()"); tofCameraMITKPlayerDevice->DisconnectCamera(); // Load images (recorded and original ones) with PicFileReader for comparison + mitk::ItkImageFileReader::Pointer nrrdReader = mitk::ItkImageFileReader::New(); mitk::PicFileReader::Pointer picFileReader = mitk::PicFileReader::New(); mitk::Image::Pointer originalImage = NULL; mitk::Image::Pointer recordedImage = NULL; MITK_TEST_OUTPUT(<< "Read original distance image using PicFileReader"); picFileReader->SetFileName(distanceFileName); picFileReader->Update(); - originalImage = picFileReader->GetOutput(); + originalImage = picFileReader->GetOutput()->Clone(); - MITK_TEST_OUTPUT(<< "Read recorded distance image using PicFileReader"); - picFileReader->SetFileName(distanceTestFileName); - picFileReader->Update(); - recordedImage = picFileReader->GetOutput(); + MITK_TEST_OUTPUT(<< "Read recorded distance image using ItkImageFileReader"); + nrrdReader->SetFileName(distanceTestFileName); + nrrdReader->Update(); + recordedImage = nrrdReader->GetOutput()->Clone(); - MITK_TEST_CONDITION_REQUIRED(originalImage->GetDimension(0) == tofImageRecorder->GetCaptureWidth(), "Testing capture width"); - MITK_TEST_CONDITION_REQUIRED(originalImage->GetDimension(1) == tofImageRecorder->GetCaptureHeight(), "Testing capture height"); + MITK_TEST_CONDITION_REQUIRED(originalImage->GetDimension(0) == tofImageRecorder->GetToFCaptureWidth(), "Testing capture width"); + MITK_TEST_CONDITION_REQUIRED(originalImage->GetDimension(1) == tofImageRecorder->GetToFCaptureHeight(), "Testing capture height"); + int numFramesOrig = originalImage->GetDimension(2); + int numFramesRec = recordedImage->GetDimension(2); MITK_TEST_CONDITION_REQUIRED(originalImage->GetDimension(2) == recordedImage->GetDimension(2), "Testing number of frames"); MITK_TEST_CONDITION_REQUIRED(CompareImages(originalImage, recordedImage), "Compare original and saved distance image"); MITK_TEST_OUTPUT(<< "Read original amplitude image using PicFileReader"); picFileReader->SetFileName(amplitudeFileName); picFileReader->Update(); - originalImage = picFileReader->GetOutput(); + originalImage = picFileReader->GetOutput()->Clone(); - MITK_TEST_OUTPUT(<< "Read recorded amplitude image using PicFileReader"); - picFileReader->SetFileName(amplitudeTestFileName); - picFileReader->Update(); - recordedImage = picFileReader->GetOutput(); + MITK_TEST_OUTPUT(<< "Read recorded amplitude image using ItkImageFileReader"); + nrrdReader->SetFileName(amplitudeTestFileName); + nrrdReader->Update(); + recordedImage = nrrdReader->GetOutput()->Clone(); - MITK_TEST_CONDITION_REQUIRED(originalImage->GetDimension(0) == tofImageRecorder->GetCaptureWidth(), "Testing capture width"); - MITK_TEST_CONDITION_REQUIRED(originalImage->GetDimension(1) == tofImageRecorder->GetCaptureHeight(), "Testing capture height"); + MITK_TEST_CONDITION_REQUIRED(originalImage->GetDimension(0) == tofImageRecorder->GetToFCaptureWidth(), "Testing capture width"); + MITK_TEST_CONDITION_REQUIRED(originalImage->GetDimension(1) == tofImageRecorder->GetToFCaptureHeight(), "Testing capture height"); MITK_TEST_CONDITION_REQUIRED(originalImage->GetDimension(2) == recordedImage->GetDimension(2), "Testing number of frames"); MITK_TEST_CONDITION_REQUIRED(CompareImages(originalImage, recordedImage), "Compare original and saved amplitude image"); MITK_TEST_OUTPUT(<< "Read original intensity image using PicFileReader"); picFileReader->SetFileName(intensityFileName); picFileReader->Update(); - originalImage = picFileReader->GetOutput(); + originalImage = picFileReader->GetOutput()->Clone(); - MITK_TEST_OUTPUT(<< "Read recorded intensity image using PicFileReader"); - picFileReader->SetFileName(intensityTestFileName); - picFileReader->Update(); - recordedImage = picFileReader->GetOutput(); + MITK_TEST_OUTPUT(<< "Read recorded intensity image using ItkImageFileReader"); + nrrdReader->SetFileName(intensityTestFileName); + nrrdReader->Update(); + recordedImage = nrrdReader->GetOutput()->Clone(); - MITK_TEST_CONDITION_REQUIRED(originalImage->GetDimension(0) == tofImageRecorder->GetCaptureWidth(), "Testing capture width"); - MITK_TEST_CONDITION_REQUIRED(originalImage->GetDimension(1) == tofImageRecorder->GetCaptureHeight(), "Testing capture height"); + MITK_TEST_CONDITION_REQUIRED(originalImage->GetDimension(0) == tofImageRecorder->GetToFCaptureWidth(), "Testing capture width"); + MITK_TEST_CONDITION_REQUIRED(originalImage->GetDimension(1) == tofImageRecorder->GetToFCaptureHeight(), "Testing capture height"); MITK_TEST_CONDITION_REQUIRED(originalImage->GetDimension(2) == recordedImage->GetDimension(2), "Testing number of frames"); MITK_TEST_CONDITION_REQUIRED(CompareImages(originalImage, recordedImage), "Compare original and saved intensity image"); //clean up and delete saved image files - if( remove( "test_distance.pic" ) != 0 ) + if( remove( distanceTestFileName.c_str() ) != 0 ) { - MITK_ERROR<<"File: test_distance.pic not successfully deleted!"; + MITK_ERROR<<"File: test_distance.nrrd not successfully deleted!"; } - if( remove( "test_amplitude.pic" ) != 0 ) + if( remove( amplitudeTestFileName.c_str() ) != 0 ) { - MITK_ERROR<<"File: test_amplitude.pic not successfully deleted!"; + MITK_ERROR<<"File: test_amplitude.nrrd not successfully deleted!"; } - if( remove( "test_intensity.pic" ) != 0 ) + if( remove( intensityTestFileName.c_str() ) != 0 ) { - MITK_ERROR<<"File: test_intensity.pic not successfully deleted!"; + MITK_ERROR<<"File: test_intensity.nrrd not successfully deleted!"; } MITK_TEST_END(); } diff --git a/Modules/ToFHardware/Testing/mitkToFImageWriterTest.cpp b/Modules/ToFHardware/Testing/mitkToFImageWriterTest.cpp index 33c0e0042b..2a11479229 100644 --- a/Modules/ToFHardware/Testing/mitkToFImageWriterTest.cpp +++ b/Modules/ToFHardware/Testing/mitkToFImageWriterTest.cpp @@ -1,75 +1,82 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 /**Documentation * test for the class "ToFImageWriter". */ int mitkToFImageWriterTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("ToFImageWriter"); //testing initialization of object mitk::ToFImageWriter::Pointer tofWriter = mitk::ToFImageWriter::New(); MITK_TEST_CONDITION_REQUIRED(tofWriter.GetPointer(), "Testing initialization of test object!"); MITK_TEST_CONDITION_REQUIRED(tofWriter->GetExtension()!= "", "Test initialization of member extension!"); MITK_TEST_CONDITION_REQUIRED(tofWriter->GetDistanceImageFileName()== "", "Test initialization of member distanceImageFileName!"); MITK_TEST_CONDITION_REQUIRED(tofWriter->GetAmplitudeImageFileName()== "", "Test initialization of member amplitudeImageFileName!"); MITK_TEST_CONDITION_REQUIRED(tofWriter->GetIntensityImageFileName()== "", "Test initialization of member intnensityImageFileName!"); MITK_TEST_CONDITION_REQUIRED(tofWriter->GetDistanceImageSelected(), "Test initialization of member distanceImageSelected!"); MITK_TEST_CONDITION_REQUIRED(tofWriter->GetAmplitudeImageSelected(), "Test initialization of member amplitudeImageSelected!"); - MITK_TEST_CONDITION_REQUIRED(tofWriter->GetIntensityImageSelected(), "Test initialization of member intnensityImageSelected!"); - MITK_TEST_CONDITION_REQUIRED(tofWriter->GetCaptureWidth()== 200, "Test initialization of member captureWidth!"); - MITK_TEST_CONDITION_REQUIRED(tofWriter->GetCaptureHeight()== 200, "Test initialization of member captureHeight!"); + MITK_TEST_CONDITION_REQUIRED(tofWriter->GetIntensityImageSelected(), "Test initialization of member intensityImageSelected!"); + MITK_TEST_CONDITION_REQUIRED(tofWriter->GetRGBImageSelected(), "Test initialization of member rgbImageSelected!"); + MITK_TEST_CONDITION_REQUIRED(tofWriter->GetToFCaptureWidth()== 200, "Test initialization of member captureWidth!"); + MITK_TEST_CONDITION_REQUIRED(tofWriter->GetToFCaptureHeight()== 200, "Test initialization of member captureHeight!"); MITK_TEST_CONDITION_REQUIRED(tofWriter->GetToFImageType()== mitk::ToFImageWriter::ToFImageType3D, "Test initialization of member ToFImageType!"); //set member parameter and test again unsigned int dimX = 255; unsigned int dimY = 188; std::string distanceImageFileName("distImg.pic"); std::string amplitudeImageFileName("amplImg.pic"); std::string intensityImageFileName("intImg.pic"); + std::string rgbImageFileName("rgbImg.pic"); std::string fileExtension(".test"); bool distanceImageSelected = false; bool amplitudeImageSelected = false; bool intensityImageSelected = false; + bool rgbImageSelected = false; - tofWriter->SetCaptureWidth(dimX); - tofWriter->SetCaptureHeight(dimY); + tofWriter->SetToFCaptureWidth(dimX); + tofWriter->SetToFCaptureHeight(dimY); tofWriter->SetDistanceImageFileName(distanceImageFileName); tofWriter->SetAmplitudeImageFileName(amplitudeImageFileName); tofWriter->SetIntensityImageFileName(intensityImageFileName); + tofWriter->SetRGBImageFileName(rgbImageFileName); tofWriter->SetExtension(fileExtension); tofWriter->SetDistanceImageSelected(distanceImageSelected); tofWriter->SetAmplitudeImageSelected(amplitudeImageSelected); tofWriter->SetIntensityImageSelected(intensityImageSelected); + tofWriter->SetRGBImageSelected(rgbImageSelected); tofWriter->SetToFImageType(mitk::ToFImageWriter::ToFImageType2DPlusT); MITK_TEST_CONDITION_REQUIRED(distanceImageFileName==tofWriter->GetDistanceImageFileName(), "Testing set/get distance image file name"); MITK_TEST_CONDITION_REQUIRED(amplitudeImageFileName==tofWriter->GetAmplitudeImageFileName(), "Testing set/get amplitude image file name"); MITK_TEST_CONDITION_REQUIRED(intensityImageFileName==tofWriter->GetIntensityImageFileName(), "Testing set/get intensity image file name"); - MITK_TEST_CONDITION_REQUIRED(dimX==tofWriter->GetCaptureWidth(), "Testing set/get CaptureWidth"); - MITK_TEST_CONDITION_REQUIRED(dimY==tofWriter->GetCaptureHeight(), "Testing set/get CaptureHeight"); + MITK_TEST_CONDITION_REQUIRED(rgbImageFileName==tofWriter->GetRGBImageFileName(), "Testing set/get rgb image file name"); + MITK_TEST_CONDITION_REQUIRED(dimX==tofWriter->GetToFCaptureWidth(), "Testing set/get CaptureWidth"); + MITK_TEST_CONDITION_REQUIRED(dimY==tofWriter->GetToFCaptureHeight(), "Testing set/get CaptureHeight"); MITK_TEST_CONDITION_REQUIRED(distanceImageSelected==tofWriter->GetDistanceImageSelected(), "Testing set/get distance image selection"); MITK_TEST_CONDITION_REQUIRED(amplitudeImageSelected==tofWriter->GetAmplitudeImageSelected(), "Testing set/get amplitude image selection"); MITK_TEST_CONDITION_REQUIRED(intensityImageSelected==tofWriter->GetIntensityImageSelected(), "Testing set/get intensity image selection"); + MITK_TEST_CONDITION_REQUIRED(rgbImageSelected==tofWriter->GetRGBImageSelected(), "Testing set/get rgb image selection"); MITK_TEST_CONDITION_REQUIRED(fileExtension==tofWriter->GetExtension(), "Testing set/get file extension"); MITK_TEST_CONDITION_REQUIRED(mitk::ToFImageWriter::ToFImageType2DPlusT==tofWriter->GetToFImageType(), "Testing set/get ToFImageType"); MITK_TEST_END(); } diff --git a/Modules/ToFHardware/Testing/mitkToFNrrdImageWriterTest.cpp b/Modules/ToFHardware/Testing/mitkToFNrrdImageWriterTest.cpp index 5d142f076e..098120b25c 100644 --- a/Modules/ToFHardware/Testing/mitkToFNrrdImageWriterTest.cpp +++ b/Modules/ToFHardware/Testing/mitkToFNrrdImageWriterTest.cpp @@ -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 #include "mitkItkImageFileReader.h" /**Documentation * test for the class "ToFImageWriter". */ int mitkToFNrrdImageWriterTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("ToFNrrdImageWriter"); mitk::ToFNrrdImageWriter::Pointer tofNrrdWriter = mitk::ToFNrrdImageWriter::New(); // testing correct initialization MITK_TEST_CONDITION_REQUIRED(tofNrrdWriter.GetPointer(), "Testing initialization of test object!"); MITK_TEST_CONDITION_REQUIRED(tofNrrdWriter->GetExtension() == ".nrrd", "testing initialization of extension member variable!"); //GENERATE TEST DATA ////run the test with some unusual parameters unsigned int dimX = 255; unsigned int dimY = 178; unsigned int pixelNumber = dimX*dimY; unsigned int numOfFrames = 23; //or numberOfSlices ////create 3 images filled with random values mitk::Image::Pointer distanceImage = mitk::ImageGenerator::GenerateRandomImage(dimX, dimY, numOfFrames,0, 1.0f, 1.0f); mitk::Image::Pointer amplitudeImage = mitk::ImageGenerator::GenerateRandomImage(dimX, dimY, numOfFrames,0, 0.0f, 2000.0f); mitk::Image::Pointer intensityImage = mitk::ImageGenerator::GenerateRandomImage(dimX, dimY, numOfFrames,0, 0.0f, 100000.0f); //SET NEEDED PARAMETER //file names on the disc std::string distanceImageFileName("distImg.nrrd"); std::string amplitudeImageFileName("amplImg.nrrd"); std::string intensityImageFileName("intImg.nrrd"); // set file name methods tofNrrdWriter->SetDistanceImageFileName(distanceImageFileName); tofNrrdWriter->SetAmplitudeImageFileName(amplitudeImageFileName); tofNrrdWriter->SetIntensityImageFileName(intensityImageFileName); - tofNrrdWriter->SetCaptureWidth(dimX); - tofNrrdWriter->SetCaptureHeight(dimY); + tofNrrdWriter->SetToFCaptureWidth(dimX); + tofNrrdWriter->SetToFCaptureHeight(dimY); tofNrrdWriter->SetToFImageType(mitk::ToFNrrdImageWriter::ToFImageType3D); + tofNrrdWriter->SetRGBImageSelected(false); //buffer for each slice float* distanceArray; float* amplitudeArray; float* intensityArray; float* distanceArrayRead; float* amplitudeArrayRead; float* intensityArrayRead; tofNrrdWriter->Open(); //open file/stream for(unsigned int i = 0; i < numOfFrames ; i++) { distanceArray = (float*)distanceImage->GetSliceData(i, 0, 0)->GetData(); amplitudeArray = (float*)amplitudeImage->GetSliceData(i, 0, 0)->GetData(); intensityArray = (float*)intensityImage->GetSliceData(i, 0, 0)->GetData(); //write (or add) the three slices to the file tofNrrdWriter->Add(distanceArray, amplitudeArray, intensityArray); } tofNrrdWriter->Close(); //close file //read in the three images from disc mitk::ItkImageFileReader::Pointer fileReader = mitk::ItkImageFileReader::New(); fileReader->SetFileName(distanceImageFileName); fileReader->Update(); mitk::Image::Pointer distanceImageRead = fileReader->GetOutput(); fileReader = mitk::ItkImageFileReader::New(); fileReader->SetFileName(amplitudeImageFileName); fileReader->Update(); mitk::Image::Pointer amplitudeImageRead = fileReader->GetOutput(); fileReader = mitk::ItkImageFileReader::New(); fileReader->SetFileName(intensityImageFileName); fileReader->Update(); mitk::Image::Pointer intensityImageRead = fileReader->GetOutput(); bool readingCorrect = true; // for all frames... for(unsigned int j=0; j < numOfFrames; j++) { //get one slice of each image and compare it //original data distanceArray = (float*)distanceImage->GetSliceData(j, 0, 0)->GetData(); amplitudeArray = (float*)amplitudeImage->GetSliceData(j, 0, 0)->GetData(); intensityArray = (float*)intensityImage->GetSliceData(j, 0, 0)->GetData(); //data read from disc distanceArrayRead = (float*)distanceImageRead->GetSliceData(j, 0, 0)->GetData(); amplitudeArrayRead = (float*)amplitudeImageRead->GetSliceData(j, 0, 0)->GetData(); intensityArrayRead = (float*)intensityImageRead->GetSliceData(j, 0, 0)->GetData(); //for all pixels for(unsigned int i=0; i namespace mitk { KinectDevice::KinectDevice() { m_Controller = mitk::KinectController::New(); } KinectDevice::~KinectDevice() { } bool KinectDevice::ConnectCamera() { bool ok = false; if (m_Controller) { ok = m_Controller->OpenCameraConnection(); if (ok) { this->m_CaptureWidth = m_Controller->GetCaptureWidth(); this->m_CaptureHeight = m_Controller->GetCaptureHeight(); this->m_PixelNumber = this->m_CaptureWidth * this->m_CaptureHeight; + + this->m_RGBImageWidth = m_CaptureWidth; + this->m_RGBImageHeight = m_CaptureHeight; + this->m_RGBPixelNumber = this->m_RGBImageWidth * this->m_RGBImageHeight; // allocate buffer this->m_IntensityArray = new float[this->m_PixelNumber]; for(int i=0; im_PixelNumber; i++) {this->m_IntensityArray[i]=0.0;} this->m_DistanceArray = new float[this->m_PixelNumber]; for(int i=0; im_PixelNumber; i++) {this->m_DistanceArray[i]=0.0;} this->m_AmplitudeArray = new float[this->m_PixelNumber]; for(int i=0; im_PixelNumber; i++) {this->m_AmplitudeArray[i]=0.0;} this->m_DistanceDataBuffer = new float*[this->m_MaxBufferSize]; for(int i=0; im_MaxBufferSize; i++) { this->m_DistanceDataBuffer[i] = new float[this->m_PixelNumber]; } this->m_AmplitudeDataBuffer = new float*[this->m_MaxBufferSize]; for(int i=0; im_MaxBufferSize; i++) { this->m_AmplitudeDataBuffer[i] = new float[this->m_PixelNumber]; } this->m_IntensityDataBuffer = new float*[this->m_MaxBufferSize]; for(int i=0; im_MaxBufferSize; i++) { this->m_IntensityDataBuffer[i] = new float[this->m_PixelNumber]; } this->m_RGBDataBuffer = new unsigned char*[this->m_MaxBufferSize]; for (int i=0; im_MaxBufferSize; i++) { this->m_RGBDataBuffer[i] = new unsigned char[this->m_PixelNumber*3]; } m_CameraConnected = true; } } return ok; } bool KinectDevice::DisconnectCamera() { bool ok = false; if (m_Controller) { ok = m_Controller->CloseCameraConnection(); // clean-up only if camera was connected if (m_CameraConnected) { delete [] m_IntensityArray; delete [] m_DistanceArray; delete [] m_AmplitudeArray; for(int i=0; im_MaxBufferSize; i++) { delete[] this->m_DistanceDataBuffer[i]; delete[] this->m_AmplitudeDataBuffer[i]; delete[] this->m_IntensityDataBuffer[i]; delete[] this->m_RGBDataBuffer[i]; } delete[] this->m_DistanceDataBuffer; delete[] this->m_AmplitudeDataBuffer; delete[] this->m_IntensityDataBuffer; delete[] this->m_RGBDataBuffer; m_CameraConnected = false; } } return ok; } void KinectDevice::StartCamera() { if (m_CameraConnected) { // get the first image this->m_Controller->UpdateCamera(); this->m_ImageMutex->Lock(); this->m_Controller->GetAllData(this->m_DistanceDataBuffer[this->m_FreePos],this->m_AmplitudeDataBuffer[this->m_FreePos],this->m_RGBDataBuffer[this->m_FreePos]); this->m_FreePos = (this->m_FreePos+1) % this->m_BufferSize; this->m_CurrentPos = (this->m_CurrentPos+1) % this->m_BufferSize; this->m_ImageSequence++; this->m_ImageMutex->Unlock(); this->m_CameraActiveMutex->Lock(); this->m_CameraActive = true; this->m_CameraActiveMutex->Unlock(); this->m_ThreadID = this->m_MultiThreader->SpawnThread(this->Acquire, this); // wait a little to make sure that the thread is started itksys::SystemTools::Delay(10); } else { MITK_INFO<<"Camera not connected"; } } void KinectDevice::StopCamera() { m_CameraActiveMutex->Lock(); m_CameraActive = false; m_CameraActiveMutex->Unlock(); itksys::SystemTools::Delay(100); if (m_MultiThreader.IsNotNull()) { m_MultiThreader->TerminateThread(m_ThreadID); } // wait a little to make sure that the thread is terminated itksys::SystemTools::Delay(10); } bool KinectDevice::IsCameraActive() { m_CameraActiveMutex->Lock(); bool ok = m_CameraActive; m_CameraActiveMutex->Unlock(); return ok; } void KinectDevice::UpdateCamera() { if (m_Controller) { m_Controller->UpdateCamera(); } } ITK_THREAD_RETURN_TYPE KinectDevice::Acquire(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; if (pInfo == NULL) { return ITK_THREAD_RETURN_VALUE; } if (pInfo->UserData == NULL) { return ITK_THREAD_RETURN_VALUE; } KinectDevice* toFCameraDevice = (KinectDevice*)pInfo->UserData; if (toFCameraDevice!=NULL) { mitk::RealTimeClock::Pointer realTimeClock; realTimeClock = mitk::RealTimeClock::New(); double t1, t2; t1 = realTimeClock->GetCurrentStamp(); int n = 100; bool overflow = false; bool printStatus = false; while (toFCameraDevice->IsCameraActive()) { // update the ToF camera toFCameraDevice->UpdateCamera(); // get the image data from the camera and write it at the next free position in the buffer toFCameraDevice->m_ImageMutex->Lock(); toFCameraDevice->m_Controller->GetAllData(toFCameraDevice->m_DistanceDataBuffer[toFCameraDevice->m_FreePos],toFCameraDevice->m_AmplitudeDataBuffer[toFCameraDevice->m_FreePos],toFCameraDevice->m_RGBDataBuffer[toFCameraDevice->m_FreePos]); toFCameraDevice->m_ImageMutex->Unlock(); // call modified to indicate that cameraDevice was modified toFCameraDevice->Modified(); /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TODO Buffer Handling currently only works for buffer size 1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ //toFCameraDevice->m_ImageSequence++; toFCameraDevice->m_FreePos = (toFCameraDevice->m_FreePos+1) % toFCameraDevice->m_BufferSize; toFCameraDevice->m_CurrentPos = (toFCameraDevice->m_CurrentPos+1) % toFCameraDevice->m_BufferSize; toFCameraDevice->m_ImageSequence++; if (toFCameraDevice->m_FreePos == toFCameraDevice->m_CurrentPos) { // buffer overflow //MITK_INFO << "Buffer overflow!! "; //toFCameraDevice->m_CurrentPos = (toFCameraDevice->m_CurrentPos+1) % toFCameraDevice->m_BufferSize; //toFCameraDevice->m_ImageSequence++; overflow = true; } if (toFCameraDevice->m_ImageSequence % n == 0) { printStatus = true; } if (overflow) { //itksys::SystemTools::Delay(10); overflow = false; } /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! END TODO Buffer Handling currently only works for buffer size 1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ // print current framerate if (printStatus) { t2 = realTimeClock->GetCurrentStamp() - t1; //MITK_INFO << "t2: " << t2 <<" Time (s) for 1 image: " << (t2/1000) / n << " Framerate (fps): " << n / (t2/1000) << " Sequence: " << toFCameraDevice->m_ImageSequence; MITK_INFO << " Framerate (fps): " << n / (t2/1000) << " Sequence: " << toFCameraDevice->m_ImageSequence; t1 = realTimeClock->GetCurrentStamp(); printStatus = false; } } // end of while loop } return ITK_THREAD_RETURN_VALUE; } // TODO: Buffer size currently set to 1. Once Buffer handling is working correctly, method may be reactivated // void KinectDevice::ResetBuffer(int bufferSize) // { // this->m_BufferSize = bufferSize; // this->m_CurrentPos = -1; // this->m_FreePos = 0; // } void KinectDevice::GetAmplitudes(float* amplitudeArray, int& imageSequence) { m_ImageMutex->Lock(); if (m_CameraActive) { // 1) copy the image buffer // 2) Flip around y- axis (vertical axis) /* this->m_Controller->GetAmplitudes(this->m_SourceDataBuffer[this->m_CurrentPos], this->m_AmplitudeArray); for (int i=0; im_CaptureHeight; i++) { for (int j=0; jm_CaptureWidth; j++) { amplitudeArray[i*this->m_CaptureWidth+j] = this->m_AmplitudeArray[(i+1)*this->m_CaptureWidth-1-j]; } } */ for (int i=0; im_PixelNumber; i++) { amplitudeArray[i] = this->m_AmplitudeDataBuffer[this->m_CurrentPos][i]; } imageSequence = this->m_ImageSequence; } else { MITK_WARN("ToF") << "Warning: Data can only be acquired if camera is active."; } m_ImageMutex->Unlock(); } void KinectDevice::GetIntensities(float* intensityArray, int& imageSequence) { m_ImageMutex->Lock(); if (m_CameraActive) { // 1) copy the image buffer // 2) Flip around y- axis (vertical axis) /* this->m_Controller->GetIntensities(this->m_SourceDataBuffer[this->m_CurrentPos], this->m_IntensityArray); for (int i=0; im_CaptureHeight; i++) { for (int j=0; jm_CaptureWidth; j++) { intensityArray[i*this->m_CaptureWidth+j] = this->m_IntensityArray[(i+1)*this->m_CaptureWidth-1-j]; } } */ for (int i=0; im_PixelNumber; i++) { intensityArray[i] = this->m_IntensityDataBuffer[this->m_CurrentPos][i]; } imageSequence = this->m_ImageSequence; } else { MITK_WARN("ToF") << "Warning: Data can only be acquired if camera is active."; } m_ImageMutex->Unlock(); } void KinectDevice::GetDistances(float* distanceArray, int& imageSequence) { m_ImageMutex->Lock(); if (m_CameraActive) { // 1) copy the image buffer // 2) convert the distance values from m to mm // 3) Flip around y- axis (vertical axis) /* this->m_Controller->GetDistances(this->m_SourceDataBuffer[this->m_CurrentPos], this->m_DistanceArray); for (int i=0; im_CaptureHeight; i++) { for (int j=0; jm_CaptureWidth; j++) { distanceArray[i*this->m_CaptureWidth+j] = 1000 * this->m_DistanceArray[(i+1)*this->m_CaptureWidth-1-j]; } } */ for (int i=0; im_PixelNumber; i++) { distanceArray[i] = this->m_DistanceDataBuffer[this->m_CurrentPos][i]; // * 1000 } imageSequence = this->m_ImageSequence; } else { MITK_WARN("ToF") << "Warning: Data can only be acquired if camera is active."; } m_ImageMutex->Unlock(); } void KinectDevice::GetAllImages(float* distanceArray, float* amplitudeArray, float* intensityArray, char* sourceDataArray, int requiredImageSequence, int& capturedImageSequence, unsigned char* rgbDataArray) { if (m_CameraActive) { // 1) copy the image buffer // 2) convert the distance values from m to mm // 3) Flip around y- axis (vertical axis) // check for empty buffer if (this->m_ImageSequence < 0) { // buffer empty MITK_INFO << "Buffer empty!! "; capturedImageSequence = this->m_ImageSequence; return; } // determine position of image in buffer int pos = 0; if ((requiredImageSequence < 0) || (requiredImageSequence > this->m_ImageSequence)) { capturedImageSequence = this->m_ImageSequence; pos = this->m_CurrentPos; //MITK_INFO << "Required image not found! Required: " << requiredImageSequence << " delivered/current: " << this->m_ImageSequence; } else if (requiredImageSequence <= this->m_ImageSequence - this->m_BufferSize) { capturedImageSequence = (this->m_ImageSequence - this->m_BufferSize) + 1; pos = (this->m_CurrentPos + 1) % this->m_BufferSize; //MITK_INFO << "Out of buffer! Required: " << requiredImageSequence << " delivered: " << capturedImageSequence << " current: " << this->m_ImageSequence; } else // (requiredImageSequence > this->m_ImageSequence - this->m_BufferSize) && (requiredImageSequence <= this->m_ImageSequence) { capturedImageSequence = requiredImageSequence; pos = (this->m_CurrentPos + (10-(this->m_ImageSequence - requiredImageSequence))) % this->m_BufferSize; } // write image data to float arrays for (int i=0; im_PixelNumber; i++) { distanceArray[i] = this->m_DistanceDataBuffer[pos][i]; amplitudeArray[i] = this->m_AmplitudeDataBuffer[pos][i]; intensityArray[i] = this->m_IntensityDataBuffer[pos][i]; rgbDataArray[i*3] = this->m_RGBDataBuffer[pos][i*3]; rgbDataArray[i*3+1] = this->m_RGBDataBuffer[pos][i*3+1]; rgbDataArray[i*3+2] = this->m_RGBDataBuffer[pos][i*3+2]; } } else { MITK_WARN("ToF") << "Warning: Data can only be acquired if camera is active."; } } KinectController::Pointer KinectDevice::GetController() { return this->m_Controller; } void KinectDevice::SetProperty( const char *propertyKey, BaseProperty* propertyValue ) { ToFCameraDevice::SetProperty(propertyKey,propertyValue); this->m_PropertyList->SetProperty(propertyKey, propertyValue); if (strcmp(propertyKey, "RGB") == 0) { bool rgb = false; GetBoolProperty(propertyKey, rgb); m_Controller->SetUseIR(!rgb); } else if (strcmp(propertyKey, "IR") == 0) { bool ir = false; GetBoolProperty(propertyKey, ir); m_Controller->SetUseIR(ir); } } + + int KinectDevice::GetRGBCaptureWidth() + { + return this->GetCaptureWidth(); + } + + int KinectDevice::GetRGBCaptureHeight() + { + return this->GetCaptureHeight(); + } } diff --git a/Modules/ToFHardware/mitkKinectDevice.h b/Modules/ToFHardware/mitkKinectDevice.h index 31a5960f3d..5a775cff71 100644 --- a/Modules/ToFHardware/mitkKinectDevice.h +++ b/Modules/ToFHardware/mitkKinectDevice.h @@ -1,147 +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 __mitkKinectDevice_h #define __mitkKinectDevice_h #include "mitkToFHardwareExports.h" #include "mitkCommon.h" #include "mitkToFCameraDevice.h" #include "mitkKinectController.h" #include "itkObject.h" #include "itkObjectFactory.h" #include "itkMultiThreader.h" #include "itkFastMutexLock.h" namespace mitk { /** * @brief Interface for all representations of MESA ToF devices. * KinectDevice internally holds an instance of KinectController and starts a thread * that continuously grabs images from the controller. A buffer structure buffers the last acquired images * to provide the image data loss-less. * * @ingroup ToFHardware */ class MITK_TOFHARDWARE_EXPORT KinectDevice : public ToFCameraDevice { public: mitkClassMacro( KinectDevice , ToFCameraDevice ); itkNewMacro( Self ); /*! \brief opens a connection to the ToF camera */ virtual bool ConnectCamera(); /*! \brief closes the connection to the camera */ virtual bool DisconnectCamera(); /*! \brief starts the continuous updating of the camera. A separate thread updates the source data, the main thread processes the source data and creates images and coordinates */ virtual void StartCamera(); /*! \brief stops the continuous updating of the camera */ virtual void StopCamera(); /*! \brief updates the camera for image acquisition */ virtual void UpdateCamera(); /*! \brief returns whether the camera is currently active or not */ virtual bool IsCameraActive(); /*! \brief gets the amplitude data from the ToF camera as the strength of the active illumination of every pixel. Caution! The user is responsible for allocating and deleting the images. These values can be used to determine the quality of the distance values. The higher the amplitude value, the higher the accuracy of the according distance value \param imageSequence the actually captured image sequence number \param amplitudeArray contains the returned amplitude data as an array. */ virtual void GetAmplitudes(float* amplitudeArray, int& imageSequence); /*! \brief gets the intensity data from the ToF camera as a greyscale image. Caution! The user is responsible for allocating and deleting the images. \param intensityArray contains the returned intensities data as an array. \param imageSequence the actually captured image sequence number */ virtual void GetIntensities(float* intensityArray, int& imageSequence); /*! \brief gets the distance data from the ToF camera measuring the distance between the camera and the different object points in millimeters. Caution! The user is responsible for allocating and deleting the images. \param distanceArray contains the returned distances data as an array. \param imageSequence the actually captured image sequence number */ virtual void GetDistances(float* distanceArray, int& imageSequence); /*! \brief gets the 3 images (distance, amplitude, intensity) from the ToF camera. Caution! The user is responsible for allocating and deleting the images. \param distanceArray contains the returned distance data as an array. \param amplitudeArray contains the returned amplitude data as an array. \param intensityArray contains the returned intensity data as an array. \param sourceDataArray contains the complete source data from the camera device. \param requiredImageSequence the required image sequence number \param capturedImageSequence the actually captured image sequence number */ virtual void GetAllImages(float* distanceArray, float* amplitudeArray, float* intensityArray, char* sourceDataArray, int requiredImageSequence, int& capturedImageSequence, unsigned char* rgbDataArray=NULL); // TODO: Buffer size currently set to 1. Once Buffer handling is working correctly, method may be reactivated // /*! // \brief pure virtual method resetting the buffer using the specified bufferSize. Has to be implemented by sub-classes // \param bufferSize buffer size the buffer should be reset to // */ // virtual void ResetBuffer(int bufferSize) = 0; //TODO add/correct documentation for requiredImageSequence and capturedImageSequence in the GetAllImages, GetDistances, GetIntensities and GetAmplitudes methods. /*! \brief returns the corresponding camera controller */ KinectController::Pointer GetController(); /*! \brief set a BaseProperty */ virtual void SetProperty( const char *propertyKey, BaseProperty* propertyValue ); + /*! + \brief returns the width of the RGB image + */ + int GetRGBCaptureWidth(); + /*! + \brief returns the height of the RGB image + */ + int GetRGBCaptureHeight(); protected: KinectDevice(); ~KinectDevice(); /*! \brief Thread method continuously acquiring images from the ToF hardware */ static ITK_THREAD_RETURN_TYPE Acquire(void* pInfoStruct); /*! \brief moves the position pointer m_CurrentPos to the next position in the buffer if that's not the next free position to prevent reading from an empty buffer */ void GetNextPos(); - KinectController::Pointer m_Controller; ///< corresponding CameraController float** m_DistanceDataBuffer; ///< buffer holding the last distance images float** m_AmplitudeDataBuffer; ///< buffer holding the last amplitude images float** m_IntensityDataBuffer; ///< buffer holding the last intensity images unsigned char** m_RGBDataBuffer; ///< buffer holding the last RGB image private: }; } //END mitk namespace #endif diff --git a/Modules/ToFHardware/mitkToFCameraDevice.cpp b/Modules/ToFHardware/mitkToFCameraDevice.cpp index c8f30aa753..7ea2b5e27a 100644 --- a/Modules/ToFHardware/mitkToFCameraDevice.cpp +++ b/Modules/ToFHardware/mitkToFCameraDevice.cpp @@ -1,134 +1,171 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkToFCameraDevice.h" +#include namespace mitk { ToFCameraDevice::ToFCameraDevice():m_BufferSize(1),m_MaxBufferSize(100),m_CurrentPos(-1),m_FreePos(0), m_CaptureWidth(204),m_CaptureHeight(204),m_PixelNumber(41616),m_SourceDataSize(0), m_ThreadID(0),m_CameraActive(false),m_CameraConnected(false),m_ImageSequence(0) { this->m_AmplitudeArray = NULL; this->m_IntensityArray = NULL; this->m_DistanceArray = NULL; this->m_PropertyList = mitk::PropertyList::New(); this->m_MultiThreader = itk::MultiThreader::New(); this->m_ImageMutex = itk::FastMutexLock::New(); this->m_CameraActiveMutex = itk::FastMutexLock::New(); + + this->m_RGBImageWidth = this->m_CaptureWidth; + this->m_RGBImageHeight = this->m_CaptureHeight; + this->m_RGBPixelNumber = this->m_RGBImageWidth* this->m_RGBImageHeight; } ToFCameraDevice::~ToFCameraDevice() { } void ToFCameraDevice::SetBoolProperty( const char* propertyKey, bool boolValue ) { SetProperty(propertyKey, mitk::BoolProperty::New(boolValue)); } void ToFCameraDevice::SetIntProperty( const char* propertyKey, int intValue ) { SetProperty(propertyKey, mitk::IntProperty::New(intValue)); } void ToFCameraDevice::SetFloatProperty( const char* propertyKey, float floatValue ) { SetProperty(propertyKey, mitk::FloatProperty::New(floatValue)); } void ToFCameraDevice::SetStringProperty( const char* propertyKey, const char* stringValue ) { SetProperty(propertyKey, mitk::StringProperty::New(stringValue)); } void ToFCameraDevice::SetProperty( const char *propertyKey, BaseProperty* propertyValue ) { this->m_PropertyList->SetProperty(propertyKey, propertyValue); } BaseProperty* ToFCameraDevice::GetProperty(const char *propertyKey) { return this->m_PropertyList->GetProperty(propertyKey); } bool ToFCameraDevice::GetBoolProperty(const char *propertyKey, bool& boolValue) { mitk::BoolProperty::Pointer boolprop = dynamic_cast(this->GetProperty(propertyKey)); if(boolprop.IsNull()) return false; boolValue = boolprop->GetValue(); return true; } bool ToFCameraDevice::GetStringProperty(const char *propertyKey, std::string& string) { mitk::StringProperty::Pointer stringProp = dynamic_cast(this->GetProperty(propertyKey)); if(stringProp.IsNull()) { return false; } else { string = stringProp->GetValue(); return true; } } bool ToFCameraDevice::GetIntProperty(const char *propertyKey, int& integer) { mitk::IntProperty::Pointer intProp = dynamic_cast(this->GetProperty(propertyKey)); if(intProp.IsNull()) { return false; } else { integer = intProp->GetValue(); return true; } } void ToFCameraDevice::CleanupPixelArrays() { if (m_IntensityArray) { delete [] m_IntensityArray; } if (m_DistanceArray) { delete [] m_DistanceArray; } if (m_AmplitudeArray) { delete [] m_AmplitudeArray; } } void ToFCameraDevice::AllocatePixelArrays() { // free memory if it was already allocated CleanupPixelArrays(); // allocate buffer this->m_IntensityArray = new float[this->m_PixelNumber]; for(int i=0; im_PixelNumber; i++) {this->m_IntensityArray[i]=0.0;} this->m_DistanceArray = new float[this->m_PixelNumber]; for(int i=0; im_PixelNumber; i++) {this->m_DistanceArray[i]=0.0;} this->m_AmplitudeArray = new float[this->m_PixelNumber]; for(int i=0; im_PixelNumber; i++) {this->m_AmplitudeArray[i]=0.0;} } + + int ToFCameraDevice::GetRGBCaptureWidth() + { + return this->m_RGBImageWidth; + } + + int ToFCameraDevice::GetRGBCaptureHeight() + { + return this->m_RGBImageHeight; + } + + void ToFCameraDevice::StopCamera() + { + m_CameraActiveMutex->Lock(); + m_CameraActive = false; + m_CameraActiveMutex->Unlock(); + itksys::SystemTools::Delay(100); + if (m_MultiThreader.IsNotNull()) + { + m_MultiThreader->TerminateThread(m_ThreadID); + } + // wait a little to make sure that the thread is terminated + itksys::SystemTools::Delay(100); + } + + bool ToFCameraDevice::IsCameraActive() + { + m_CameraActiveMutex->Lock(); + bool ok = m_CameraActive; + m_CameraActiveMutex->Unlock(); + return ok; + } } diff --git a/Modules/ToFHardware/mitkToFCameraDevice.h b/Modules/ToFHardware/mitkToFCameraDevice.h index 13ccdc7160..4ff77e3bc4 100644 --- a/Modules/ToFHardware/mitkToFCameraDevice.h +++ b/Modules/ToFHardware/mitkToFCameraDevice.h @@ -1,215 +1,222 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 __mitkToFCameraDevice_h #define __mitkToFCameraDevice_h #include "mitkToFHardwareExports.h" #include "mitkCommon.h" #include "mitkStringProperty.h" #include "mitkProperties.h" #include "mitkPropertyList.h" #include "itkObject.h" #include "itkObjectFactory.h" #include "itkMultiThreader.h" #include "itkFastMutexLock.h" namespace mitk { /** * @brief Virtual interface and base class for all Time-of-Flight devices. * * @ingroup ToFHardware */ class MITK_TOFHARDWARE_EXPORT ToFCameraDevice : public itk::Object { public: mitkClassMacro(ToFCameraDevice, itk::Object); /*! \brief opens a connection to the ToF camera */ virtual bool ConnectCamera() = 0; /*! \brief closes the connection to the camera */ virtual bool DisconnectCamera() = 0; /*! \brief starts the continuous updating of the camera. A separate thread updates the source data, the main thread processes the source data and creates images and coordinates */ virtual void StartCamera() = 0; /*! \brief stops the continuous updating of the camera */ - virtual void StopCamera() = 0; + virtual void StopCamera(); /*! \brief returns true if the camera is connected and started */ - virtual bool IsCameraActive() = 0; + virtual bool IsCameraActive(); /*! \brief updates the camera for image acquisition */ virtual void UpdateCamera() = 0; /*! \brief gets the amplitude data from the ToF camera as the strength of the active illumination of every pixel These values can be used to determine the quality of the distance values. The higher the amplitude value, the higher the accuracy of the according distance value \param imageSequence the actually captured image sequence number \param amplitudeArray contains the returned amplitude data as an array. */ virtual void GetAmplitudes(float* amplitudeArray, int& imageSequence) = 0; /*! \brief gets the intensity data from the ToF camera as a greyscale image \param intensityArray contains the returned intensities data as an array. \param imageSequence the actually captured image sequence number */ virtual void GetIntensities(float* intensityArray, int& imageSequence) = 0; /*! \brief gets the distance data from the ToF camera measuring the distance between the camera and the different object points in millimeters \param distanceArray contains the returned distances data as an array. \param imageSequence the actually captured image sequence number */ virtual void GetDistances(float* distanceArray, int& imageSequence) = 0; /*! \brief gets the 3 images (distance, amplitude, intensity) from the ToF camera. Caution! The user is responsible for allocating and deleting the images. \param distanceArray contains the returned distance data as an array. \param amplitudeArray contains the returned amplitude data as an array. \param intensityArray contains the returned intensity data as an array. \param sourceDataArray contains the complete source data from the camera device. \param requiredImageSequence the required image sequence number \param capturedImageSequence the actually captured image sequence number */ virtual void GetAllImages(float* distanceArray, float* amplitudeArray, float* intensityArray, char* sourceDataArray, int requiredImageSequence, int& capturedImageSequence, unsigned char* rgbDataArray=NULL) = 0; // TODO: Buffer size currently set to 1. Once Buffer handling is working correctly, method may be reactivated // /*! // \brief pure virtual method resetting the buffer using the specified bufferSize. Has to be implemented by sub-classes // \param bufferSize buffer size the buffer should be reset to // */ // virtual void ResetBuffer(int bufferSize) = 0; //TODO add/correct documentation for requiredImageSequence and capturedImageSequence in the GetAllImages, GetDistances, GetIntensities and GetAmplitudes methods. /*! \brief get the currently set capture width \return capture width */ itkGetMacro(CaptureWidth, int); /*! \brief get the currently set capture height \return capture height */ itkGetMacro(CaptureHeight, int); /*! \brief get the currently set source data size \return source data size */ itkGetMacro(SourceDataSize, int); /*! \brief get the currently set buffer size \return buffer size */ itkGetMacro(BufferSize, int); /*! \brief get the currently set max buffer size \return max buffer size */ itkGetMacro(MaxBufferSize, int); /*! \brief set a bool property in the property list */ void SetBoolProperty( const char* propertyKey, bool boolValue ); /*! \brief set an int property in the property list */ void SetIntProperty( const char* propertyKey, int intValue ); /*! \brief set a float property in the property list */ void SetFloatProperty( const char* propertyKey, float floatValue ); /*! \brief set a string property in the property list */ void SetStringProperty( const char* propertyKey, const char* stringValue ); /*! \brief set a BaseProperty property in the property list */ virtual void SetProperty( const char *propertyKey, BaseProperty* propertyValue ); /*! \brief get a BaseProperty from the property list */ virtual BaseProperty* GetProperty( const char *propertyKey ); /*! \brief get a bool from the property list */ bool GetBoolProperty(const char *propertyKey, bool& boolValue); /*! \brief get a string from the property list */ bool GetStringProperty(const char *propertyKey, std::string& string); /*! \brief get an int from the property list */ bool GetIntProperty(const char *propertyKey, int& integer); + virtual int GetRGBCaptureWidth(); + + virtual int GetRGBCaptureHeight(); + protected: ToFCameraDevice(); ~ToFCameraDevice(); /*! \brief method for allocating memory for pixel arrays m_IntensityArray, m_DistanceArray and m_AmplitudeArray */ virtual void AllocatePixelArrays(); /*! \brief method for cleanup memory allocated for pixel arrays m_IntensityArray, m_DistanceArray and m_AmplitudeArray */ virtual void CleanupPixelArrays(); float* m_IntensityArray; ///< float array holding the intensity image float* m_DistanceArray; ///< float array holding the distance image float* m_AmplitudeArray; ///< float array holding the amplitude image int m_BufferSize; ///< buffer size of the image buffer needed for loss-less acquisition of range data int m_MaxBufferSize; ///< maximal buffer size needed for initialization of data arrays. Default value is 100. int m_CurrentPos; ///< current position in the buffer which will be retrieved by the Get methods int m_FreePos; ///< current position in the buffer which will be filled with data acquired from the hardware int m_CaptureWidth; ///< width of the range image (x dimension) int m_CaptureHeight; ///< height of the range image (y dimension) int m_PixelNumber; ///< number of pixels in the range image (m_CaptureWidth*m_CaptureHeight) + int m_RGBImageWidth; + int m_RGBImageHeight; + int m_RGBPixelNumber; int m_SourceDataSize; ///< size of the PMD source data 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 bool m_CameraActive; ///< flag indicating if the camera is currently active or not. Caution: thread safe access only! bool m_CameraConnected; ///< flag indicating if the camera is successfully connected or not. Caution: thread safe access only! int m_ImageSequence; ///< counter for acquired images PropertyList::Pointer m_PropertyList; ///< a list of the corresponding properties private: }; } //END mitk namespace #endif diff --git a/Modules/ToFHardware/mitkToFCameraMITKPlayerDevice.cpp b/Modules/ToFHardware/mitkToFCameraMITKPlayerDevice.cpp index b8b77c3344..0f101bd693 100644 --- a/Modules/ToFHardware/mitkToFCameraMITKPlayerDevice.cpp +++ b/Modules/ToFHardware/mitkToFCameraMITKPlayerDevice.cpp @@ -1,410 +1,394 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkToFCameraMITKPlayerDevice.h" #include "mitkToFCameraMITKPlayerController.h" #include "mitkRealTimeClock.h" #include "itkMultiThreader.h" #include namespace mitk { ToFCameraMITKPlayerDevice::ToFCameraMITKPlayerDevice() : m_DistanceDataBuffer(NULL), m_AmplitudeDataBuffer(NULL), m_IntensityDataBuffer(NULL), m_RGBDataBuffer(NULL) { m_Controller = ToFCameraMITKPlayerController::New(); } ToFCameraMITKPlayerDevice::~ToFCameraMITKPlayerDevice() { DisconnectCamera(); CleanUpDataBuffers(); } bool ToFCameraMITKPlayerDevice::ConnectCamera() { bool ok = m_Controller->OpenCameraConnection(); if (ok) { this->m_CaptureWidth = m_Controller->GetCaptureWidth(); this->m_CaptureHeight = m_Controller->GetCaptureHeight(); this->m_PixelNumber = this->m_CaptureWidth * this->m_CaptureHeight; AllocatePixelArrays(); AllocateDataBuffers(); m_CameraConnected = true; } return ok; } bool ToFCameraMITKPlayerDevice::DisconnectCamera() { bool ok = m_Controller->CloseCameraConnection(); if (ok) { m_CameraConnected = false; } return ok; } void ToFCameraMITKPlayerDevice::StartCamera() { if (m_CameraConnected) { // get the first image this->m_Controller->UpdateCamera(); this->m_ImageMutex->Lock(); this->m_Controller->GetDistances(this->m_DistanceDataBuffer[this->m_FreePos]); this->m_Controller->GetAmplitudes(this->m_AmplitudeDataBuffer[this->m_FreePos]); this->m_Controller->GetIntensities(this->m_IntensityDataBuffer[this->m_FreePos]); this->m_Controller->GetRgb(this->m_RGBDataBuffer[this->m_FreePos]); this->m_FreePos = (this->m_FreePos+1) % this->m_BufferSize; this->m_CurrentPos = (this->m_CurrentPos+1) % this->m_BufferSize; this->m_ImageSequence++; this->m_ImageMutex->Unlock(); this->m_CameraActiveMutex->Lock(); this->m_CameraActive = true; this->m_CameraActiveMutex->Unlock(); this->m_ThreadID = this->m_MultiThreader->SpawnThread(this->Acquire, this); // wait a little to make sure that the thread is started itksys::SystemTools::Delay(10); } else { MITK_INFO<<"Camera not connected"; } } - void ToFCameraMITKPlayerDevice::StopCamera() - { - m_CameraActiveMutex->Lock(); - m_CameraActive = false; - m_CameraActiveMutex->Unlock(); - itksys::SystemTools::Delay(100); - if (m_MultiThreader.IsNotNull()) - { - m_MultiThreader->TerminateThread(m_ThreadID); - } - // wait a little to make sure that the thread is terminated - itksys::SystemTools::Delay(100); - } - - bool ToFCameraMITKPlayerDevice::IsCameraActive() - { - m_CameraActiveMutex->Lock(); - bool ok = m_CameraActive; - m_CameraActiveMutex->Unlock(); - return ok; - } - void ToFCameraMITKPlayerDevice::UpdateCamera() { m_Controller->UpdateCamera(); } ITK_THREAD_RETURN_TYPE ToFCameraMITKPlayerDevice::Acquire(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; if (pInfo == NULL) { return ITK_THREAD_RETURN_VALUE; } if (pInfo->UserData == NULL) { return ITK_THREAD_RETURN_VALUE; } ToFCameraMITKPlayerDevice* toFCameraDevice = (ToFCameraMITKPlayerDevice*)pInfo->UserData; if (toFCameraDevice!=NULL) { mitk::RealTimeClock::Pointer realTimeClock; realTimeClock = mitk::RealTimeClock::New(); int n = 100; double t1, t2; t1 = realTimeClock->GetCurrentStamp(); bool overflow = false; bool printStatus = false; while (toFCameraDevice->IsCameraActive()) { // update the ToF camera toFCameraDevice->UpdateCamera(); // get image data from controller and write it to the according buffer toFCameraDevice->m_Controller->GetDistances(toFCameraDevice->m_DistanceDataBuffer[toFCameraDevice->m_FreePos]); toFCameraDevice->m_Controller->GetAmplitudes(toFCameraDevice->m_AmplitudeDataBuffer[toFCameraDevice->m_FreePos]); toFCameraDevice->m_Controller->GetIntensities(toFCameraDevice->m_IntensityDataBuffer[toFCameraDevice->m_FreePos]); toFCameraDevice->m_Controller->GetRgb(toFCameraDevice->m_RGBDataBuffer[toFCameraDevice->m_FreePos]); toFCameraDevice->Modified(); /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TODO Buffer Handling currently only works for buffer size 1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ toFCameraDevice->m_ImageMutex->Lock(); toFCameraDevice->m_FreePos = (toFCameraDevice->m_FreePos+1) % toFCameraDevice->m_BufferSize; toFCameraDevice->m_CurrentPos = (toFCameraDevice->m_CurrentPos+1) % toFCameraDevice->m_BufferSize; toFCameraDevice->m_ImageSequence++; if (toFCameraDevice->m_FreePos == toFCameraDevice->m_CurrentPos) { // buffer overflow //MITK_INFO << "Buffer overflow!! "; //toFCameraDevice->m_CurrentPos = (toFCameraDevice->m_CurrentPos+1) % toFCameraDevice->m_BufferSize; //toFCameraDevice->m_ImageSequence++; overflow = true; } if (toFCameraDevice->m_ImageSequence % n == 0) { printStatus = true; } toFCameraDevice->m_ImageMutex->Unlock(); if (overflow) { //itksys::SystemTools::Delay(10); overflow = false; } /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! END TODO Buffer Handling currently only works for buffer size 1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ // print current framerate if (printStatus) { t2 = realTimeClock->GetCurrentStamp() - t1; MITK_INFO << " Framerate (fps): " << n / (t2/1000) << " Sequence: " << toFCameraDevice->m_ImageSequence; t1 = realTimeClock->GetCurrentStamp(); printStatus = false; } } // end of while loop } return ITK_THREAD_RETURN_VALUE; } // TODO: Buffer size currently set to 1. Once Buffer handling is working correctly, method may be reactivated // void ToFCameraMITKPlayerDevice::ResetBuffer(int bufferSize) // { // this->m_BufferSize = bufferSize; // this->m_CurrentPos = -1; // this->m_FreePos = 0; // } void ToFCameraMITKPlayerDevice::GetAmplitudes(float* amplitudeArray, int& imageSequence) { m_ImageMutex->Lock(); /*!!!!!!!!!!!!!!!!!!!!!! TODO Buffer handling??? !!!!!!!!!!!!!!!!!!!!!!!!*/ // write amplitude image data to float array for (int i=0; im_PixelNumber; i++) { amplitudeArray[i] = this->m_AmplitudeDataBuffer[this->m_CurrentPos][i]; } imageSequence = this->m_ImageSequence; m_ImageMutex->Unlock(); } void ToFCameraMITKPlayerDevice::GetIntensities(float* intensityArray, int& imageSequence) { m_ImageMutex->Lock(); /*!!!!!!!!!!!!!!!!!!!!!! TODO Buffer handling??? !!!!!!!!!!!!!!!!!!!!!!!!*/ // write intensity image data to float array for (int i=0; im_PixelNumber; i++) { intensityArray[i] = this->m_IntensityDataBuffer[this->m_CurrentPos][i]; } imageSequence = this->m_ImageSequence; m_ImageMutex->Unlock(); } void ToFCameraMITKPlayerDevice::GetDistances(float* distanceArray, int& imageSequence) { m_ImageMutex->Lock(); /*!!!!!!!!!!!!!!!!!!!!!! TODO Buffer handling??? !!!!!!!!!!!!!!!!!!!!!!!!*/ // write distance image data to float array for (int i=0; im_PixelNumber; i++) { distanceArray[i] = this->m_DistanceDataBuffer[this->m_CurrentPos][i]; } imageSequence = this->m_ImageSequence; m_ImageMutex->Unlock(); } void ToFCameraMITKPlayerDevice::GetRgb(unsigned char* rgbArray, int& imageSequence) { m_ImageMutex->Lock(); /*!!!!!!!!!!!!!!!!!!!!!! TODO Buffer handling??? !!!!!!!!!!!!!!!!!!!!!!!!*/ // write intensity image data to unsigned char array for (int i=0; im_PixelNumber*3; i++) { rgbArray[i] = this->m_RGBDataBuffer[this->m_CurrentPos][i]; } imageSequence = this->m_ImageSequence; m_ImageMutex->Unlock(); } void ToFCameraMITKPlayerDevice::GetAllImages(float* distanceArray, float* amplitudeArray, float* intensityArray, char* /*sourceDataArray*/, int requiredImageSequence, int& capturedImageSequence, unsigned char* rgbDataArray) { /*!!!!!!!!!!!!!!!!!!!!!! TODO Document this method! !!!!!!!!!!!!!!!!!!!!!!!!*/ m_ImageMutex->Lock(); //check for empty buffer if (this->m_ImageSequence < 0) { // buffer empty MITK_INFO << "Buffer empty!! "; capturedImageSequence = this->m_ImageSequence; m_ImageMutex->Unlock(); return; } // determine position of image in buffer int pos = 0; if ((requiredImageSequence < 0) || (requiredImageSequence > this->m_ImageSequence)) { capturedImageSequence = this->m_ImageSequence; pos = this->m_CurrentPos; } else if (requiredImageSequence <= this->m_ImageSequence - this->m_BufferSize) { capturedImageSequence = (this->m_ImageSequence - this->m_BufferSize) + 1; pos = (this->m_CurrentPos + 1) % this->m_BufferSize; } else // (requiredImageSequence > this->m_ImageSequence - this->m_BufferSize) && (requiredImageSequence <= this->m_ImageSequence) { capturedImageSequence = requiredImageSequence; pos = (this->m_CurrentPos + (10-(this->m_ImageSequence - requiredImageSequence))) % this->m_BufferSize; } if(this->m_DistanceDataBuffer&&this->m_AmplitudeDataBuffer&&this->m_IntensityDataBuffer&&this->m_RGBDataBuffer) { // write image data to float arrays for (int i=0; im_PixelNumber; i++) { distanceArray[i] = this->m_DistanceDataBuffer[pos][i]; amplitudeArray[i] = this->m_AmplitudeDataBuffer[pos][i]; intensityArray[i] = this->m_IntensityDataBuffer[pos][i]; - rgbDataArray[i] = this->m_RGBDataBuffer[pos][i]; + if (rgbDataArray) + { + rgbDataArray[i] = this->m_RGBDataBuffer[pos][i]; + } } - for (int j=this->m_PixelNumber; jm_PixelNumber*3; j++) + if (rgbDataArray) { - rgbDataArray[j] = this->m_RGBDataBuffer[pos][j]; + for (int j=this->m_PixelNumber; jm_PixelNumber*3; j++) + { + rgbDataArray[j] = this->m_RGBDataBuffer[pos][j]; + } } } m_ImageMutex->Unlock(); } void ToFCameraMITKPlayerDevice::SetInputFileName(std::string inputFileName) { this->m_InputFileName = inputFileName; this->m_Controller->SetInputFileName(inputFileName); } void ToFCameraMITKPlayerDevice::SetProperty( const char *propertyKey, BaseProperty* propertyValue ) { this->m_PropertyList->SetProperty(propertyKey, propertyValue); ToFCameraMITKPlayerController::Pointer myController = dynamic_cast(this->m_Controller.GetPointer()); std::string strValue; GetStringProperty(propertyKey, strValue); if (strcmp(propertyKey, "DistanceImageFileName") == 0) { myController->SetDistanceImageFileName(strValue); } else if (strcmp(propertyKey, "AmplitudeImageFileName") == 0) { myController->SetAmplitudeImageFileName(strValue); } else if (strcmp(propertyKey, "IntensityImageFileName") == 0) { myController->SetIntensityImageFileName(strValue); } else if (strcmp(propertyKey, "RGBImageFileName") == 0) { myController->SetRGBImageFileName(strValue); } } void ToFCameraMITKPlayerDevice::CleanUpDataBuffers() { if (m_DistanceDataBuffer) { for(int i=0; im_MaxBufferSize; i++) { delete[] this->m_DistanceDataBuffer[i]; } delete[] this->m_DistanceDataBuffer; } if (m_AmplitudeDataBuffer) { for(int i=0; im_MaxBufferSize; i++) { delete[] this->m_AmplitudeDataBuffer[i]; } delete[] this->m_AmplitudeDataBuffer; } if (m_IntensityDataBuffer) { for(int i=0; im_MaxBufferSize; i++) { delete[] this->m_IntensityDataBuffer[i]; } delete[] this->m_IntensityDataBuffer; } if (m_RGBDataBuffer) { for(int i=0; im_MaxBufferSize; i++) { delete[] this->m_RGBDataBuffer[i]; } delete[] this->m_RGBDataBuffer; } } void ToFCameraMITKPlayerDevice::AllocateDataBuffers() { // free memory if it was already allocated this->CleanUpDataBuffers(); // allocate buffers this->m_DistanceDataBuffer = new float*[this->m_MaxBufferSize]; for(int i=0; im_MaxBufferSize; i++) { this->m_DistanceDataBuffer[i] = new float[this->m_PixelNumber]; } this->m_AmplitudeDataBuffer = new float*[this->m_MaxBufferSize]; for(int i=0; im_MaxBufferSize; i++) { this->m_AmplitudeDataBuffer[i] = new float[this->m_PixelNumber]; } this->m_IntensityDataBuffer = new float*[this->m_MaxBufferSize]; for(int i=0; im_MaxBufferSize; i++) { this->m_IntensityDataBuffer[i] = new float[this->m_PixelNumber]; } this->m_RGBDataBuffer = new unsigned char*[this->m_MaxBufferSize]; for(int i=0; im_MaxBufferSize; i++) { this->m_RGBDataBuffer[i] = new unsigned char[this->m_PixelNumber*3]; } } } diff --git a/Modules/ToFHardware/mitkToFCameraMITKPlayerDevice.h b/Modules/ToFHardware/mitkToFCameraMITKPlayerDevice.h index b02392795c..0cb3c0c87f 100644 --- a/Modules/ToFHardware/mitkToFCameraMITKPlayerDevice.h +++ b/Modules/ToFHardware/mitkToFCameraMITKPlayerDevice.h @@ -1,154 +1,146 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 __mitkToFCameraMITKPlayerDevice_h #define __mitkToFCameraMITKPlayerDevice_h #include "mitkToFHardwareExports.h" #include "mitkCommon.h" #include "mitkToFCameraDevice.h" #include "mitkToFCameraMITKPlayerController.h" #include "itkObject.h" #include "itkObjectFactory.h" #include "itkMultiThreader.h" #include "itkFastMutexLock.h" namespace mitk { /** * @brief Device class representing a player for MITK-ToF images. * * @ingroup ToFHardware */ class MITK_TOFHARDWARE_EXPORT ToFCameraMITKPlayerDevice : public ToFCameraDevice { public: mitkClassMacro( ToFCameraMITKPlayerDevice , ToFCameraDevice ); itkNewMacro( Self ); /*! \brief opens a connection to the ToF camera */ virtual bool ConnectCamera(); /*! \brief closes the connection to the camera */ virtual bool DisconnectCamera(); /*! \brief starts the continuous updating of the camera. A separate thread updates the source data, the main thread processes the source data and creates images and coordinates */ virtual void StartCamera(); /*! - \brief stops the continuous updating of the camera - */ - virtual void StopCamera(); - /*! - \brief returns whether the camera is currently active or not - */ - virtual bool IsCameraActive(); - /*! \brief gets the amplitude data from the ToF camera as the strength of the active illumination of every pixel. Caution! The user is responsible for allocating and deleting the images. These values can be used to determine the quality of the distance values. The higher the amplitude value, the higher the accuracy of the according distance value \param imageSequence the actually captured image sequence number \param amplitudeArray contains the returned amplitude data as an array. */ virtual void GetAmplitudes(float* amplitudeArray, int& imageSequence); /*! \brief gets the intensity data from the ToF camera as a greyscale image. Caution! The user is responsible for allocating and deleting the images. \param intensityArray contains the returned intensities data as an array. \param imageSequence the actually captured image sequence number */ virtual void GetIntensities(float* intensityArray, int& imageSequence); /*! \brief gets the rgb data from the ToF camera. Caution! The user is responsible for allocating and deleting the images. \param rgbArray contains the returned rgb data as an array. \param imageSequence the actually captured image sequence number */ virtual void GetRgb(unsigned char* rgbArray, int& imageSequence); /*! \brief gets the distance data from the ToF camera measuring the distance between the camera and the different object points in millimeters. Caution! The user is responsible for allocating and deleting the images. \param distanceArray contains the returned distances data as an array. \param imageSequence the actually captured image sequence number */ virtual void GetDistances(float* distanceArray, int& imageSequence); /*! \brief gets the 3 images (distance, amplitude, intensity) from the ToF camera. Caution! The user is responsible for allocating and deleting the images. \param distanceArray contains the returned distance data as an array. \param amplitudeArray contains the returned amplitude data as an array. \param intensityArray contains the returned intensity data as an array. \param sourceDataArray contains the complete source data from the camera device. \param requiredImageSequence the required image sequence number \param capturedImageSequence the actually captured image sequence number */ virtual void GetAllImages(float* distanceArray, float* amplitudeArray, float* intensityArray, char* sourceDataArray, int requiredImageSequence, int& capturedImageSequence, unsigned char* rgbDataArray=NULL); // TODO: Buffer size currently set to 1. Once Buffer handling is working correctly, method may be reactivated // /*! // \brief pure virtual method resetting the buffer using the specified bufferSize. Has to be implemented by sub-classes // \param bufferSize buffer size the buffer should be reset to // */ // virtual void ResetBuffer(int bufferSize) = 0; //TODO add/correct documentation for requiredImageSequence and capturedImageSequence in the GetAllImages, GetDistances, GetIntensities and GetAmplitudes methods. /*! \brief Set file name where the data is recorded \param inputFileName name of input file which should be played */ virtual void SetInputFileName(std::string inputFileName); /*! \brief set a BaseProperty */ virtual void SetProperty( const char *propertyKey, BaseProperty* propertyValue ); protected: ToFCameraMITKPlayerDevice(); ~ToFCameraMITKPlayerDevice(); /*! \brief updates the camera for image acquisition */ virtual void UpdateCamera(); /*! \brief Thread method continuously acquiring images from the specified input file */ static ITK_THREAD_RETURN_TYPE Acquire(void* pInfoStruct); /*! \brief Clean up memory (pixel buffers) */ void CleanUpDataBuffers(); /*! \brief Allocate pixel buffers */ void AllocateDataBuffers(); ToFCameraMITKPlayerController::Pointer m_Controller; ///< member holding the corresponding controller std::string m_InputFileName; ///< member holding the file name of the current input file private: float** m_DistanceDataBuffer; ///< buffer holding the last distance images float** m_AmplitudeDataBuffer; ///< buffer holding the last amplitude images float** m_IntensityDataBuffer; ///< buffer holding the last intensity images unsigned char** m_RGBDataBuffer; ///< buffer holding the last rgb images }; } //END mitk namespace #endif diff --git a/Modules/ToFHardware/mitkToFCameraPMDController.cpp b/Modules/ToFHardware/mitkToFCameraPMDController.cpp index 2bceef7292..7969c985b5 100644 --- a/Modules/ToFHardware/mitkToFCameraPMDController.cpp +++ b/Modules/ToFHardware/mitkToFCameraPMDController.cpp @@ -1,169 +1,179 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkToFCameraPMDController.h" #include #include PMDHandle m_PMDHandle; //TODO PMDDataDescription m_DataDescription; //TODO struct SourceDataStruct { PMDDataDescription dataDescription; char sourceData; }; namespace mitk { ToFCameraPMDController::ToFCameraPMDController(): m_PMDRes(0), m_PixelNumber(40000), m_NumberOfBytes(0), m_CaptureWidth(200), m_CaptureHeight(200), m_SourceDataSize(0), m_SourceDataStructSize(0), m_ConnectionCheck(false), m_InputFileName("") { } ToFCameraPMDController::~ToFCameraPMDController() { } bool ToFCameraPMDController::CloseCameraConnection() { m_PMDRes = pmdClose(m_PMDHandle); m_ConnectionCheck = ErrorText(m_PMDRes); m_PMDHandle = 0; return m_ConnectionCheck; } bool ToFCameraPMDController::ErrorText(int error) { if(error != PMD_OK) { pmdGetLastError (m_PMDHandle, m_PMDError, 128); MITK_ERROR << "Camera Error " << m_PMDError; return false; } else return true; } bool ToFCameraPMDController::UpdateCamera() { m_PMDRes = pmdUpdate(m_PMDHandle); return ErrorText(m_PMDRes); } bool ToFCameraPMDController::GetAmplitudes(float* amplitudeArray) { this->m_PMDRes = pmdGetAmplitudes(m_PMDHandle, amplitudeArray, this->m_NumberOfBytes); return ErrorText(this->m_PMDRes); } bool ToFCameraPMDController::GetAmplitudes(char* sourceData, float* amplitudeArray) { this->m_PMDRes = pmdCalcAmplitudes(m_PMDHandle, amplitudeArray, this->m_NumberOfBytes, m_DataDescription, &((SourceDataStruct*)sourceData)->sourceData); return ErrorText(this->m_PMDRes); } bool ToFCameraPMDController::GetIntensities(float* intensityArray) { this->m_PMDRes = pmdGetIntensities(m_PMDHandle, intensityArray, this->m_NumberOfBytes); return ErrorText(this->m_PMDRes); } bool ToFCameraPMDController::GetIntensities(char* sourceData, float* intensityArray) { this->m_PMDRes = pmdCalcIntensities(m_PMDHandle, intensityArray, this->m_NumberOfBytes, m_DataDescription, &((SourceDataStruct*)sourceData)->sourceData); return ErrorText(this->m_PMDRes); } bool ToFCameraPMDController::GetDistances(float* distanceArray) { this->m_PMDRes = pmdGetDistances(m_PMDHandle, distanceArray, this->m_NumberOfBytes); return ErrorText(this->m_PMDRes); } bool ToFCameraPMDController::GetDistances(char* sourceData, float* distanceArray) { this->m_PMDRes = pmdCalcDistances(m_PMDHandle, distanceArray, this->m_NumberOfBytes, m_DataDescription, &((SourceDataStruct*)sourceData)->sourceData); return ErrorText(this->m_PMDRes); } bool ToFCameraPMDController::GetSourceData(char* sourceDataArray) { this->m_PMDRes = pmdGetSourceDataDescription(m_PMDHandle, &m_DataDescription); if (!ErrorText(this->m_PMDRes)) { return false; } memcpy(&((SourceDataStruct*)sourceDataArray)->dataDescription, &m_DataDescription, sizeof(m_DataDescription)); this->m_PMDRes = pmdGetSourceData(m_PMDHandle, &((SourceDataStruct*)sourceDataArray)->sourceData, this->m_SourceDataSize); return ErrorText(this->m_PMDRes); } bool ToFCameraPMDController::GetShortSourceData( short* sourceData) { this->m_PMDRes = pmdGetSourceDataDescription(m_PMDHandle,&m_DataDescription); ErrorText( this->m_PMDRes); this->m_PMDRes = pmdGetSourceData(m_PMDHandle,sourceData,m_DataDescription.size); return ErrorText( this->m_PMDRes); } int ToFCameraPMDController::SetIntegrationTime(unsigned int integrationTime) { + if(!m_ConnectionCheck) + { + return integrationTime; + } unsigned int result; - this->m_PMDRes = pmdGetValidIntegrationTime(m_PMDHandle, &result, 0, AtLeast, integrationTime); + this->m_PMDRes = pmdGetValidIntegrationTime(m_PMDHandle, &result, 0, CloseTo, integrationTime); + MITK_INFO << "Valid Integration Time = " << result; ErrorText(this->m_PMDRes); if (this->m_PMDRes != 0) { return 0; } this->m_PMDRes = pmdSetIntegrationTime(m_PMDHandle, 0, result); ErrorText(this->m_PMDRes); return result; } int ToFCameraPMDController::GetIntegrationTime() { unsigned int integrationTime = 0; this->m_PMDRes = pmdGetIntegrationTime(m_PMDHandle, &integrationTime, 0); ErrorText(this->m_PMDRes); return integrationTime; } int ToFCameraPMDController::SetModulationFrequency(unsigned int modulationFrequency) { + if(!m_ConnectionCheck) + { + return modulationFrequency; + } unsigned int result; this->m_PMDRes = pmdGetValidModulationFrequency(m_PMDHandle, &result, 0, AtLeast, (modulationFrequency*1000000)); + MITK_INFO << "Valid Modulation Frequency = " << result; ErrorText(this->m_PMDRes); if (this->m_PMDRes != 0) { return 0; } this->m_PMDRes = pmdSetModulationFrequency(m_PMDHandle, 0, result); ErrorText(this->m_PMDRes); return (result/1000000);; } int ToFCameraPMDController::GetModulationFrequency() { unsigned int modulationFrequency = 0; this->m_PMDRes = pmdGetModulationFrequency (m_PMDHandle, &modulationFrequency, 0); ErrorText(this->m_PMDRes); return (modulationFrequency/1000000); } void ToFCameraPMDController::SetInputFileName(std::string inputFileName) { this->m_InputFileName = inputFileName; } } diff --git a/Modules/ToFHardware/mitkToFCameraPMDDevice.cpp b/Modules/ToFHardware/mitkToFCameraPMDDevice.cpp index 2c94d47052..d7f9c648bd 100644 --- a/Modules/ToFHardware/mitkToFCameraPMDDevice.cpp +++ b/Modules/ToFHardware/mitkToFCameraPMDDevice.cpp @@ -1,414 +1,397 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkToFCameraPMDDevice.h" #include "mitkRealTimeClock.h" #include "itkMultiThreader.h" #include namespace mitk { ToFCameraPMDDevice::ToFCameraPMDDevice() : m_SourceDataBuffer(NULL), m_SourceDataArray(NULL) { } ToFCameraPMDDevice::~ToFCameraPMDDevice() { this->CleanUpSourceData(); CleanupPixelArrays(); } bool ToFCameraPMDDevice::ConnectCamera() { bool ok = false; if (m_Controller) { ok = m_Controller->OpenCameraConnection(); if (ok) { this->m_CaptureWidth = m_Controller->GetCaptureWidth(); this->m_CaptureHeight = m_Controller->GetCaptureHeight(); this->m_SourceDataSize = m_Controller->GetSourceDataStructSize(); this->m_PixelNumber = this->m_CaptureWidth * this->m_CaptureHeight; // allocate buffers this->AllocatePixelArrays(); this->AllocateSourceData(); this->m_CameraConnected = true; } } return ok; } bool ToFCameraPMDDevice::DisconnectCamera() { bool ok = false; if (m_Controller) { ok = m_Controller->CloseCameraConnection(); if (ok) { m_CameraConnected = false; } } return ok; } void ToFCameraPMDDevice::StartCamera() { if (m_CameraConnected) { // get the first image this->m_Controller->UpdateCamera(); this->m_ImageMutex->Lock(); //this->m_Controller->GetSourceData(this->m_SourceDataArray); this->m_Controller->GetSourceData(this->m_SourceDataBuffer[this->m_FreePos]); this->m_FreePos = (this->m_FreePos+1) % this->m_BufferSize; this->m_CurrentPos = (this->m_CurrentPos+1) % this->m_BufferSize; this->m_ImageSequence++; this->m_ImageMutex->Unlock(); this->m_CameraActiveMutex->Lock(); this->m_CameraActive = true; this->m_CameraActiveMutex->Unlock(); this->m_ThreadID = this->m_MultiThreader->SpawnThread(this->Acquire, this); // wait a little to make sure that the thread is started itksys::SystemTools::Delay(10); } else { MITK_INFO<<"Camera not connected"; } } - - void ToFCameraPMDDevice::StopCamera() - { - m_CameraActiveMutex->Lock(); - m_CameraActive = false; - m_CameraActiveMutex->Unlock(); - itksys::SystemTools::Delay(100); - if (m_MultiThreader.IsNotNull()) - { - m_MultiThreader->TerminateThread(m_ThreadID); - } - // wait a little to make sure that the thread is terminated - itksys::SystemTools::Delay(10); - } - - bool ToFCameraPMDDevice::IsCameraActive() - { - m_CameraActiveMutex->Lock(); - bool ok = m_CameraActive; - m_CameraActiveMutex->Unlock(); - return ok; - } - + void ToFCameraPMDDevice::UpdateCamera() { if (m_Controller) { m_Controller->UpdateCamera(); } } ITK_THREAD_RETURN_TYPE ToFCameraPMDDevice::Acquire(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; if (pInfo == NULL) { return ITK_THREAD_RETURN_VALUE; } if (pInfo->UserData == NULL) { return ITK_THREAD_RETURN_VALUE; } ToFCameraPMDDevice* toFCameraDevice = (ToFCameraPMDDevice*)pInfo->UserData; if (toFCameraDevice!=NULL) { mitk::RealTimeClock::Pointer realTimeClock; realTimeClock = mitk::RealTimeClock::New(); double t1, t2; t1 = realTimeClock->GetCurrentStamp(); int n = 100; bool overflow = false; bool printStatus = false; while (toFCameraDevice->IsCameraActive()) { // update the ToF camera toFCameraDevice->UpdateCamera(); // get the source data from the camera and write it at the next free position in the buffer toFCameraDevice->m_ImageMutex->Lock(); toFCameraDevice->m_Controller->GetSourceData(toFCameraDevice->m_SourceDataBuffer[toFCameraDevice->m_FreePos]); + + toFCameraDevice->m_ImageMutex->Unlock(); // call modified to indicate that cameraDevice was modified toFCameraDevice->Modified(); /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TODO Buffer Handling currently only works for buffer size 1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ //toFCameraDevice->m_ImageSequence++; toFCameraDevice->m_FreePos = (toFCameraDevice->m_FreePos+1) % toFCameraDevice->m_BufferSize; toFCameraDevice->m_CurrentPos = (toFCameraDevice->m_CurrentPos+1) % toFCameraDevice->m_BufferSize; toFCameraDevice->m_ImageSequence++; if (toFCameraDevice->m_FreePos == toFCameraDevice->m_CurrentPos) { // buffer overflow //MITK_INFO << "Buffer overflow!! "; //toFCameraDevice->m_CurrentPos = (toFCameraDevice->m_CurrentPos+1) % toFCameraDevice->m_BufferSize; //toFCameraDevice->m_ImageSequence++; overflow = true; } if (toFCameraDevice->m_ImageSequence % n == 0) { printStatus = true; } if (overflow) { - //itksys::SystemTools::Delay(10); overflow = false; } /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! END TODO Buffer Handling currently only works for buffer size 1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ // print current framerate if (printStatus) { t2 = realTimeClock->GetCurrentStamp() - t1; //MITK_INFO << "t2: " << t2 <<" Time (s) for 1 image: " << (t2/1000) / n << " Framerate (fps): " << n / (t2/1000) << " Sequence: " << toFCameraDevice->m_ImageSequence; MITK_INFO << " Framerate (fps): " << n / (t2/1000) << " Sequence: " << toFCameraDevice->m_ImageSequence; t1 = realTimeClock->GetCurrentStamp(); printStatus = false; } } // end of while loop } return ITK_THREAD_RETURN_VALUE; } // TODO: Buffer size currently set to 1. Once Buffer handling is working correctly, method may be reactivated // void ToFCameraPMDDevice::ResetBuffer(int bufferSize) // { // this->m_BufferSize = bufferSize; // this->m_CurrentPos = -1; // this->m_FreePos = 0; // } void ToFCameraPMDDevice::GetAmplitudes(float* amplitudeArray, int& imageSequence) { if (m_CameraActive) { // 1) copy the image buffer // 2) Flip around y- axis (vertical axis) m_ImageMutex->Lock(); this->m_Controller->GetAmplitudes(this->m_SourceDataBuffer[this->m_CurrentPos], this->m_AmplitudeArray); m_ImageMutex->Unlock(); for (int i=0; im_CaptureHeight; i++) { for (int j=0; jm_CaptureWidth; j++) { amplitudeArray[i*this->m_CaptureWidth+j] = this->m_AmplitudeArray[(i+1)*this->m_CaptureWidth-1-j]; } } imageSequence = this->m_ImageSequence; } else { MITK_WARN("ToF") << "Warning: Data can only be acquired if camera is active."; } } void ToFCameraPMDDevice::GetIntensities(float* intensityArray, int& imageSequence) { if (m_CameraActive) { // 1) copy the image buffer // 2) Flip around y- axis (vertical axis) m_ImageMutex->Lock(); this->m_Controller->GetIntensities(this->m_SourceDataBuffer[this->m_CurrentPos], this->m_IntensityArray); m_ImageMutex->Unlock(); for (int i=0; im_CaptureHeight; i++) { for (int j=0; jm_CaptureWidth; j++) { intensityArray[i*this->m_CaptureWidth+j] = this->m_IntensityArray[(i+1)*this->m_CaptureWidth-1-j]; } } imageSequence = this->m_ImageSequence; } else { MITK_WARN("ToF") << "Warning: Data can only be acquired if camera is active."; } m_ImageMutex->Unlock(); } void ToFCameraPMDDevice::GetDistances(float* distanceArray, int& imageSequence) { if (m_CameraActive) { // 1) copy the image buffer // 2) convert the distance values from m to mm // 3) Flip around y- axis (vertical axis) m_ImageMutex->Lock(); this->m_Controller->GetDistances(this->m_SourceDataBuffer[this->m_CurrentPos], this->m_DistanceArray); m_ImageMutex->Unlock(); for (int i=0; im_CaptureHeight; i++) { for (int j=0; jm_CaptureWidth; j++) { distanceArray[i*this->m_CaptureWidth+j] = 1000 * this->m_DistanceArray[(i+1)*this->m_CaptureWidth-1-j]; } } imageSequence = this->m_ImageSequence; } else { MITK_WARN("ToF") << "Warning: Data can only be acquired if camera is active."; } } void ToFCameraPMDDevice::GetAllImages(float* distanceArray, float* amplitudeArray, float* intensityArray, char* sourceDataArray, int requiredImageSequence, int& capturedImageSequence, unsigned char* rgbDataArray) { if (m_CameraActive) { // 1) copy the image buffer // 2) convert the distance values from m to mm // 3) Flip around y- axis (vertical axis) // check for empty buffer if (this->m_ImageSequence < 0) { // buffer empty MITK_INFO << "Buffer empty!! "; capturedImageSequence = this->m_ImageSequence; return; } // determine position of image in buffer int pos = 0; if ((requiredImageSequence < 0) || (requiredImageSequence > this->m_ImageSequence)) { capturedImageSequence = this->m_ImageSequence; pos = this->m_CurrentPos; //MITK_INFO << "Required image not found! Required: " << requiredImageSequence << " delivered/current: " << this->m_ImageSequence; } else if (requiredImageSequence <= this->m_ImageSequence - this->m_BufferSize) { capturedImageSequence = (this->m_ImageSequence - this->m_BufferSize) + 1; pos = (this->m_CurrentPos + 1) % this->m_BufferSize; //MITK_INFO << "Out of buffer! Required: " << requiredImageSequence << " delivered: " << capturedImageSequence << " current: " << this->m_ImageSequence; } else // (requiredImageSequence > this->m_ImageSequence - this->m_BufferSize) && (requiredImageSequence <= this->m_ImageSequence) { capturedImageSequence = requiredImageSequence; pos = (this->m_CurrentPos + (10-(this->m_ImageSequence - requiredImageSequence))) % this->m_BufferSize; } m_ImageMutex->Lock(); this->m_Controller->GetDistances(this->m_SourceDataBuffer[pos], this->m_DistanceArray); this->m_Controller->GetAmplitudes(this->m_SourceDataBuffer[pos], this->m_AmplitudeArray); this->m_Controller->GetIntensities(this->m_SourceDataBuffer[pos], this->m_IntensityArray); memcpy(sourceDataArray, this->m_SourceDataBuffer[this->m_CurrentPos], this->m_SourceDataSize); m_ImageMutex->Unlock(); memcpy(distanceArray, this->m_DistanceArray, this->m_CaptureWidth*this->m_CaptureHeight*sizeof(float)); memcpy(intensityArray, this->m_IntensityArray, this->m_CaptureWidth*this->m_CaptureHeight*sizeof(float)); memcpy(amplitudeArray, this->m_AmplitudeArray, this->m_CaptureWidth*this->m_CaptureHeight*sizeof(float)); //int u, v; //for (int i=0; im_CaptureHeight; i++) //{ // for (int j=0; jm_CaptureWidth; j++) // { // u = i*this->m_CaptureWidth+j; // v = (i+1)*this->m_CaptureWidth-1-j; // distanceArray[u] = 1000 * this->m_DistanceArray[v]; // unit in minimeter // //distanceArray[u] = this->m_DistanceArray[v]; // unit in meter // amplitudeArray[u] = this->m_AmplitudeArray[v]; // intensityArray[u] = this->m_IntensityArray[v]; // } //} } else { MITK_WARN("ToF") << "Warning: Data can only be acquired if camera is active."; } } ToFCameraPMDController::Pointer ToFCameraPMDDevice::GetController() { return this->m_Controller; } void ToFCameraPMDDevice::SetProperty( const char *propertyKey, BaseProperty* propertyValue ) { ToFCameraDevice::SetProperty(propertyKey,propertyValue); - this->m_PropertyList->SetProperty(propertyKey, propertyValue); if (strcmp(propertyKey, "ModulationFrequency") == 0) { int modulationFrequency = 0; GetIntProperty(propertyKey, modulationFrequency); - m_Controller->SetModulationFrequency(modulationFrequency); + modulationFrequency = m_Controller->SetModulationFrequency(modulationFrequency); + static_cast(propertyValue)->SetValue(modulationFrequency); + this->m_PropertyList->SetProperty(propertyKey, propertyValue ); } else if (strcmp(propertyKey, "IntegrationTime") == 0) { int integrationTime = 0; GetIntProperty(propertyKey, integrationTime); - m_Controller->SetIntegrationTime(integrationTime); + integrationTime = m_Controller->SetIntegrationTime(integrationTime); + static_cast(propertyValue)->SetValue(integrationTime); + this->m_PropertyList->SetProperty(propertyKey, propertyValue ); + } - } + } void ToFCameraPMDDevice::AllocateSourceData() { // clean up if array and data have already been allocated CleanUpSourceData(); // (re-) allocate memory this->m_SourceDataArray = new char[this->m_SourceDataSize]; for(int i=0; im_SourceDataSize; i++) {this->m_SourceDataArray[i]=0;} this->m_SourceDataBuffer = new char*[this->m_MaxBufferSize]; for(int i=0; im_MaxBufferSize; i++) { this->m_SourceDataBuffer[i] = new char[this->m_SourceDataSize]; } } void ToFCameraPMDDevice::CleanUpSourceData() { if (m_SourceDataArray) { delete[] m_SourceDataArray; } if (m_SourceDataBuffer) { for(int i=0; im_MaxBufferSize; i++) { delete[] this->m_SourceDataBuffer[i]; } delete[] this->m_SourceDataBuffer; } } } diff --git a/Modules/ToFHardware/mitkToFCameraPMDDevice.h b/Modules/ToFHardware/mitkToFCameraPMDDevice.h index cbaea80758..03d7a186db 100644 --- a/Modules/ToFHardware/mitkToFCameraPMDDevice.h +++ b/Modules/ToFHardware/mitkToFCameraPMDDevice.h @@ -1,153 +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. ===================================================================*/ #ifndef __mitkToFCameraPMDDevice_h #define __mitkToFCameraPMDDevice_h #include "mitkToFHardwareExports.h" #include "mitkCommon.h" #include "mitkToFCameraDevice.h" #include "mitkToFCameraPMDController.h" #include "itkObject.h" #include "itkObjectFactory.h" #include "itkMultiThreader.h" #include "itkFastMutexLock.h" namespace mitk { /** * @brief Interface for all representations of PMD ToF devices. * ToFCameraPMDDevice internally holds an instance of ToFCameraPMDController and starts a thread * that continuously grabs images from the controller. A buffer structure buffers the last acquired images * to provide the image data loss-less. * * @ingroup ToFHardware */ class MITK_TOFHARDWARE_EXPORT ToFCameraPMDDevice : public ToFCameraDevice { public: mitkClassMacro( ToFCameraPMDDevice , ToFCameraDevice ); itkNewMacro( Self ); /*! \brief opens a connection to the ToF camera */ virtual bool ConnectCamera(); /*! \brief closes the connection to the camera */ virtual bool DisconnectCamera(); /*! \brief starts the continuous updating of the camera. A separate thread updates the source data, the main thread processes the source data and creates images and coordinates */ virtual void StartCamera(); /*! - \brief stops the continuous updating of the camera - */ - virtual void StopCamera(); - /*! - \brief updates the camera for image acquisition + \brief updated the controller hold by this device */ virtual void UpdateCamera(); /*! - \brief returns whether the camera is currently active or not - */ - virtual bool IsCameraActive(); - /*! \brief gets the amplitude data from the ToF camera as the strength of the active illumination of every pixel. Caution! The user is responsible for allocating and deleting the images. These values can be used to determine the quality of the distance values. The higher the amplitude value, the higher the accuracy of the according distance value \param imageSequence the actually captured image sequence number \param amplitudeArray contains the returned amplitude data as an array. */ virtual void GetAmplitudes(float* amplitudeArray, int& imageSequence); /*! \brief gets the intensity data from the ToF camera as a greyscale image. Caution! The user is responsible for allocating and deleting the images. \param intensityArray contains the returned intensities data as an array. \param imageSequence the actually captured image sequence number */ virtual void GetIntensities(float* intensityArray, int& imageSequence); /*! \brief gets the distance data from the ToF camera measuring the distance between the camera and the different object points in millimeters. Caution! The user is responsible for allocating and deleting the images. \param distanceArray contains the returned distances data as an array. \param imageSequence the actually captured image sequence number */ virtual void GetDistances(float* distanceArray, int& imageSequence); /*! \brief gets the 3 images (distance, amplitude, intensity) from the ToF camera. Caution! The user is responsible for allocating and deleting the images. \param distanceArray contains the returned distance data as an array. \param amplitudeArray contains the returned amplitude data as an array. \param intensityArray contains the returned intensity data as an array. \param sourceDataArray contains the complete source data from the camera device. \param requiredImageSequence the required image sequence number \param capturedImageSequence the actually captured image sequence number */ virtual void GetAllImages(float* distanceArray, float* amplitudeArray, float* intensityArray, char* sourceDataArray, int requiredImageSequence, int& capturedImageSequence, unsigned char* rgbDataArray=NULL); // TODO: Buffer size currently set to 1. Once Buffer handling is working correctly, method may be reactivated // /*! // \brief pure virtual method resetting the buffer using the specified bufferSize. Has to be implemented by sub-classes // \param bufferSize buffer size the buffer should be reset to // */ // virtual void ResetBuffer(int bufferSize) = 0; //TODO add/correct documentation for requiredImageSequence and capturedImageSequence in the GetAllImages, GetDistances, GetIntensities and GetAmplitudes methods. /*! \brief returns the corresponding camera controller */ ToFCameraPMDController::Pointer GetController(); /*! \brief set a BaseProperty */ virtual void SetProperty( const char *propertyKey, BaseProperty* propertyValue ); protected: ToFCameraPMDDevice(); ~ToFCameraPMDDevice(); /*! \brief method for allocating m_SourceDataArray and m_SourceDataBuffer */ virtual void AllocateSourceData(); /*! \brief method for cleaning up memory allocated for m_SourceDataArray and m_SourceDataBuffer */ virtual void CleanUpSourceData(); /*! \brief Thread method continuously acquiring images from the ToF hardware */ static ITK_THREAD_RETURN_TYPE Acquire(void* pInfoStruct); /*! \brief moves the position pointer m_CurrentPos to the next position in the buffer if that's not the next free position to prevent reading from an empty buffer */ void GetNextPos(); ToFCameraPMDController::Pointer m_Controller; ///< corresponding CameraController char** m_SourceDataBuffer; ///< buffer holding the last acquired images char* m_SourceDataArray; ///< array holding the current PMD source data private: }; } //END mitk namespace #endif diff --git a/Modules/ToFHardware/mitkToFCameraPMDRawDataCamBoardDevice.h b/Modules/ToFHardware/mitkToFCameraPMDRawDataCamBoardDevice.h index 3933c1fb0d..13cfe0a04e 100644 --- a/Modules/ToFHardware/mitkToFCameraPMDRawDataCamBoardDevice.h +++ b/Modules/ToFHardware/mitkToFCameraPMDRawDataCamBoardDevice.h @@ -1,81 +1,81 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkToFCameraPMDRawDataCamBoardDevice_h #define __mitkToFCameraPMDRawDataCamBoardDevice_h #include "mitkToFHardwareExports.h" #include "mitkCommon.h" #include "mitkToFCameraDevice.h" #include "mitkToFCameraPMDRawDataDevice.h" namespace mitk { /** * @brief Device class representing a PMD CamCube camera * * * @ingroup ToFHardwareMBI */ class MITK_TOFHARDWARE_EXPORT ToFCameraPMDRawDataCamBoardDevice : public ToFCameraPMDRawDataDevice { public: mitkClassMacro( ToFCameraPMDRawDataCamBoardDevice , ToFCameraPMDRawDataDevice ); itkNewMacro( Self ); /*! \brief set a BaseProperty */ virtual void SetProperty( const char *propertyKey, BaseProperty* propertyValue ); /*! \brief Transforms the sourceData into an array with four tuples holding the channels for raw data reconstruction. */ virtual void GetChannelSourceData(short* sourceData, vtkShortArray* vtkChannelArray ); /*! \brief Establishes camera connection and sets the class variables */ bool ConnectCamera(); /*! \brief Returns intensity data */ void GetIntensities(float* intensityArray, int& imageSequence); /*! \brief Returns amplitude data */ void GetAmplitudes(float* amplitudeArray, int& imageSequence); /*! \brief Returns distance data */ void GetDistances(float* distanceArray, int& imageSequence); /*! \brief Returns all image data at once. */ - void GetAllImages(float* distanceArray, float* amplitudeArray, float* intensityArray, char* sourceDataArray, int requiredImageSequence, int& capturedImageSequence, unsigned char* rgbDataArray); + void GetAllImages(float* distanceArray, float* amplitudeArray, float* intensityArray, char* sourceDataArray, int requiredImageSequence, int& capturedImageSequence, unsigned char* rgbDataArray=NULL); protected: ToFCameraPMDRawDataCamBoardDevice(); - ~ToFCameraPMDRawDataCamBoardDevice(); + ~ToFCameraPMDRawDataCamBoardDevice(); private: /*! \brief Method performs resizing of the image data and flips it upside down */ void ResizeOutputImage(float* in, float* out); }; } //END mitk namespace #endif // __mitkToFCameraPMDRawDataCamBoardDevice_h diff --git a/Modules/ToFHardware/mitkToFImageCsvWriter.cpp b/Modules/ToFHardware/mitkToFImageCsvWriter.cpp index b39691833c..ec6733eca3 100644 --- a/Modules/ToFHardware/mitkToFImageCsvWriter.cpp +++ b/Modules/ToFHardware/mitkToFImageCsvWriter.cpp @@ -1,124 +1,124 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 namespace mitk { ToFImageCsvWriter::ToFImageCsvWriter(): ToFImageWriter(), m_DistanceOutfile(NULL), m_AmplitudeOutfile(NULL), m_IntensityOutfile(NULL) { this->m_Extension = std::string(".csv"); } ToFImageCsvWriter::~ToFImageCsvWriter() { } void ToFImageCsvWriter::Open() { this->CheckForFileExtension(this->m_DistanceImageFileName); this->CheckForFileExtension(this->m_AmplitudeImageFileName); this->CheckForFileExtension(this->m_IntensityImageFileName); - this->m_PixelNumber = this->m_CaptureWidth * this->m_CaptureHeight; - this->m_ImageSizeInBytes = this->m_PixelNumber * sizeof(float); + this->m_ToFPixelNumber = this->m_ToFCaptureWidth * this->m_ToFCaptureHeight; + this->m_ToFImageSizeInBytes = this->m_ToFPixelNumber * sizeof(float); if (this->m_DistanceImageSelected) { this->OpenCsvFile(&(this->m_DistanceOutfile), this->m_DistanceImageFileName); } if (this->m_AmplitudeImageSelected) { this->OpenCsvFile(&(this->m_AmplitudeOutfile), this->m_AmplitudeImageFileName); } if (this->m_IntensityImageSelected) { this->OpenCsvFile(&(this->m_IntensityOutfile), this->m_IntensityImageFileName); } this->m_NumOfFrames = 0; } void ToFImageCsvWriter::Close() { if (this->m_DistanceImageSelected) { this->CloseCsvFile(this->m_DistanceOutfile); } if (this->m_AmplitudeImageSelected) { this->CloseCsvFile(this->m_AmplitudeOutfile); } if (this->m_IntensityImageSelected) { this->CloseCsvFile(this->m_IntensityOutfile); } } void ToFImageCsvWriter::Add(float* distanceFloatData, float* amplitudeFloatData, float* intensityFloatData, unsigned char* rgbData) { if (this->m_DistanceImageSelected) { this->WriteCsvFile(this->m_DistanceOutfile, distanceFloatData); } if (this->m_AmplitudeImageSelected) { this->WriteCsvFile(this->m_AmplitudeOutfile, amplitudeFloatData); } if (this->m_IntensityImageSelected) { this->WriteCsvFile(this->m_IntensityOutfile, intensityFloatData); } this->m_NumOfFrames++; } void ToFImageCsvWriter::WriteCsvFile(FILE* outfile, float* floatData) { - for(int i=0; im_PixelNumber; i++) + for(int i=0; im_ToFPixelNumber; i++) { if (this->m_NumOfFrames==0 && i==0) { fprintf(outfile, "%f", floatData[i]); } else { fprintf(outfile, ",%f", floatData[i]); } } } void ToFImageCsvWriter::OpenCsvFile(FILE** outfile, std::string outfileName) { (*outfile) = fopen( outfileName.c_str(), "w+" ); if( !outfile ) { MITK_ERROR << "Error opening outfile: " << outfileName; throw std::logic_error("Error opening outfile."); return; } } void ToFImageCsvWriter::CloseCsvFile(FILE* outfile) { if (this->m_NumOfFrames == 0) { fclose(outfile); throw std::logic_error("File is empty."); return; } fclose(outfile); } } diff --git a/Modules/ToFHardware/mitkToFImageGrabber.cpp b/Modules/ToFHardware/mitkToFImageGrabber.cpp index 2ded3427ad..933cad6602 100644 --- a/Modules/ToFHardware/mitkToFImageGrabber.cpp +++ b/Modules/ToFHardware/mitkToFImageGrabber.cpp @@ -1,279 +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. ===================================================================*/ #include "mitkToFImageGrabber.h" #include "mitkToFCameraPMDCamCubeDevice.h" #include "itkCommand.h" namespace mitk { - ToFImageGrabber::ToFImageGrabber():m_CaptureWidth(204),m_CaptureHeight(204),m_PixelNumber(41616),m_ImageSequence(0), + ToFImageGrabber::ToFImageGrabber():m_CaptureWidth(204),m_CaptureHeight(204),m_PixelNumber(41616), + m_ImageSequence(0), m_RGBImageWidth(0), m_RGBImageHeight(0), m_RGBPixelNumber(0), m_IntensityArray(NULL), m_DistanceArray(NULL), m_AmplitudeArray(NULL), m_SourceDataArray(NULL), m_RgbDataArray(NULL) { // Create the output. We use static_cast<> here because we know the default // output must be of type TOutputImage OutputImageType::Pointer output0 = static_cast(this->MakeOutput(0).GetPointer()); OutputImageType::Pointer output1 = static_cast(this->MakeOutput(1).GetPointer()); OutputImageType::Pointer output2 = static_cast(this->MakeOutput(2).GetPointer()); OutputImageType::Pointer output3 = static_cast(this->MakeOutput(3).GetPointer()); mitk::ImageSource::SetNumberOfRequiredOutputs(3); mitk::ImageSource::SetNthOutput(0, output0.GetPointer()); mitk::ImageSource::SetNthOutput(1, output1.GetPointer()); mitk::ImageSource::SetNthOutput(2, output2.GetPointer()); mitk::ImageSource::SetNthOutput(3, output3.GetPointer()); } ToFImageGrabber::~ToFImageGrabber() { if (m_IntensityArray||m_AmplitudeArray||m_DistanceArray||m_RgbDataArray) { if (m_ToFCameraDevice) { m_ToFCameraDevice->RemoveObserver(m_DeviceObserverTag); } this->DisconnectCamera(); this->CleanUpImageArrays(); } } mitk::ImageSource::DataObjectPointer mitk::ImageSource::MakeOutput(unsigned int) { return static_cast(OutputImageType::New().GetPointer()); } void ToFImageGrabber::GenerateData() { int requiredImageSequence = 0; int capturedImageSequence = 0; unsigned int dimensions[3]; dimensions[0] = this->m_ToFCameraDevice->GetCaptureWidth(); dimensions[1] = this->m_ToFCameraDevice->GetCaptureHeight(); dimensions[2] = 1; mitk::PixelType FloatType = MakeScalarPixelType(); // acquire new image data this->m_ToFCameraDevice->GetAllImages(this->m_DistanceArray, this->m_AmplitudeArray, this->m_IntensityArray, this->m_SourceDataArray, requiredImageSequence, this->m_ImageSequence, this->m_RgbDataArray ); mitk::Image::Pointer distanceImage = this->GetOutput(0); if (!distanceImage->IsInitialized()) { distanceImage->ReleaseData(); distanceImage->Initialize(FloatType, 3, dimensions, 1); } mitk::Image::Pointer amplitudeImage = this->GetOutput(1); if (!amplitudeImage->IsInitialized()) { amplitudeImage->ReleaseData(); amplitudeImage->Initialize(FloatType, 3, dimensions, 1); } mitk::Image::Pointer intensityImage = this->GetOutput(2); if (!intensityImage->IsInitialized()) { intensityImage->ReleaseData(); intensityImage->Initialize(FloatType, 3, dimensions, 1); } + unsigned int rgbDimension[3]; + rgbDimension[0] = this->GetRGBImageWidth(); + rgbDimension[1] = this->GetRGBImageHeight(); + rgbDimension[2] = 1 ; mitk::Image::Pointer rgbImage = this->GetOutput(3); if (!rgbImage->IsInitialized()) { rgbImage->ReleaseData(); - rgbImage->Initialize(mitk::PixelType(MakePixelType, 3>()),3,dimensions,1); + rgbImage->Initialize(mitk::PixelType(MakePixelType, 3>()), 3, rgbDimension,1); } capturedImageSequence = this->m_ImageSequence; if (m_DistanceArray) { distanceImage->SetSlice(this->m_DistanceArray, 0, 0, 0); } if (m_AmplitudeArray) { amplitudeImage->SetSlice(this->m_AmplitudeArray, 0, 0, 0); } if (m_IntensityArray) { intensityImage->SetSlice(this->m_IntensityArray, 0, 0, 0); } if (m_RgbDataArray) { rgbImage->SetSlice(this->m_RgbDataArray, 0, 0, 0); } } bool ToFImageGrabber::ConnectCamera() { bool ok = m_ToFCameraDevice->ConnectCamera(); if (ok) { - m_CaptureWidth = m_ToFCameraDevice->GetCaptureWidth(); - m_CaptureHeight = m_ToFCameraDevice->GetCaptureHeight(); - m_PixelNumber = m_CaptureWidth * m_CaptureHeight; - m_SourceDataSize = m_ToFCameraDevice->GetSourceDataSize(); + this->m_CaptureWidth = this->m_ToFCameraDevice->GetCaptureWidth(); + this->m_CaptureHeight = this->m_ToFCameraDevice->GetCaptureHeight(); + this->m_PixelNumber = this->m_CaptureWidth * this->m_CaptureHeight; + + this->m_RGBImageWidth = this->m_ToFCameraDevice->GetRGBCaptureWidth(); + this->m_RGBImageHeight = this->m_ToFCameraDevice->GetRGBCaptureHeight(); + this->m_RGBPixelNumber = this->m_RGBImageWidth * this->m_RGBImageHeight; + + this->m_SourceDataSize = m_ToFCameraDevice->GetSourceDataSize(); this->AllocateImageArrays(); } return ok; } bool ToFImageGrabber::DisconnectCamera() { bool success = m_ToFCameraDevice->DisconnectCamera(); return success; } void ToFImageGrabber::StartCamera() { m_ToFCameraDevice->StartCamera(); } void ToFImageGrabber::StopCamera() { m_ToFCameraDevice->StopCamera(); } bool ToFImageGrabber::IsCameraActive() { return m_ToFCameraDevice->IsCameraActive(); } void ToFImageGrabber::SetCameraDevice(ToFCameraDevice* aToFCameraDevice) { m_ToFCameraDevice = aToFCameraDevice; itk::SimpleMemberCommand::Pointer modifiedCommand = itk::SimpleMemberCommand::New(); modifiedCommand->SetCallbackFunction(this, &ToFImageGrabber::OnToFCameraDeviceModified); m_DeviceObserverTag = m_ToFCameraDevice->AddObserver(itk::ModifiedEvent(), modifiedCommand); this->Modified(); } ToFCameraDevice* ToFImageGrabber::GetCameraDevice() { return m_ToFCameraDevice; } int ToFImageGrabber::GetCaptureWidth() { return m_CaptureWidth; } int ToFImageGrabber::GetCaptureHeight() { return m_CaptureHeight; } int ToFImageGrabber::GetPixelNumber() { return m_PixelNumber; } + int ToFImageGrabber::GetRGBImageWidth() + { + return m_RGBImageWidth; + } + + int ToFImageGrabber::GetRGBImageHeight() + { + return m_RGBImageHeight; + } + + int ToFImageGrabber::GetRGBPixelNumber() + { + return m_RGBPixelNumber; + } + int ToFImageGrabber::SetModulationFrequency(int modulationFrequency) { this->m_ToFCameraDevice->SetProperty("ModulationFrequency",mitk::IntProperty::New(modulationFrequency)); this->Modified(); + modulationFrequency = this->GetModulationFrequency(); // return the new valid modulation frequency from the camera return modulationFrequency; } int ToFImageGrabber::SetIntegrationTime(int integrationTime) { this->m_ToFCameraDevice->SetProperty("IntegrationTime",mitk::IntProperty::New(integrationTime)); this->Modified(); + integrationTime = this->GetIntegrationTime(); // return the new valid integration time from the camera return integrationTime; } int ToFImageGrabber::GetIntegrationTime() { int integrationTime = 0; this->m_ToFCameraDevice->GetIntProperty("IntegrationTime",integrationTime); return integrationTime; } int ToFImageGrabber::GetModulationFrequency() { int modulationFrequency = 0; this->m_ToFCameraDevice->GetIntProperty("ModulationFrequency",modulationFrequency); return modulationFrequency; } void ToFImageGrabber::SetBoolProperty( const char* propertyKey, bool boolValue ) { SetProperty(propertyKey, mitk::BoolProperty::New(boolValue)); } void ToFImageGrabber::SetIntProperty( const char* propertyKey, int intValue ) { SetProperty(propertyKey, mitk::IntProperty::New(intValue)); } void ToFImageGrabber::SetFloatProperty( const char* propertyKey, float floatValue ) { SetProperty(propertyKey, mitk::FloatProperty::New(floatValue)); } void ToFImageGrabber::SetStringProperty( const char* propertyKey, const char* stringValue ) { SetProperty(propertyKey, mitk::StringProperty::New(stringValue)); } void ToFImageGrabber::SetProperty( const char *propertyKey, BaseProperty* propertyValue ) { this->m_ToFCameraDevice->SetProperty(propertyKey, propertyValue); } void ToFImageGrabber::OnToFCameraDeviceModified() { this->Modified(); } void ToFImageGrabber::CleanUpImageArrays() { // free buffer if (m_IntensityArray) { delete [] m_IntensityArray; m_IntensityArray = NULL; } if (m_DistanceArray) { delete [] m_DistanceArray; m_DistanceArray = NULL; } if (m_AmplitudeArray) { delete [] m_AmplitudeArray; m_AmplitudeArray = NULL; } if (m_SourceDataArray) { delete [] m_SourceDataArray; m_SourceDataArray = NULL; } if (m_RgbDataArray) { delete [] m_RgbDataArray; m_RgbDataArray = NULL; } } void ToFImageGrabber::AllocateImageArrays() { // cleanup memory if necessary this->CleanUpImageArrays(); // allocate buffer m_IntensityArray = new float[m_PixelNumber]; m_DistanceArray = new float[m_PixelNumber]; m_AmplitudeArray = new float[m_PixelNumber]; m_SourceDataArray = new char[m_SourceDataSize]; - m_RgbDataArray = new unsigned char[m_PixelNumber*3]; + m_RgbDataArray = new unsigned char[m_RGBPixelNumber*3]; } } diff --git a/Modules/ToFHardware/mitkToFImageGrabber.h b/Modules/ToFHardware/mitkToFImageGrabber.h index 71af0d0802..621388b130 100644 --- a/Modules/ToFHardware/mitkToFImageGrabber.h +++ b/Modules/ToFHardware/mitkToFImageGrabber.h @@ -1,171 +1,190 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 __mitkToFImageGrabber_h #define __mitkToFImageGrabber_h #include "mitkToFHardwareExports.h" #include "mitkCommon.h" #include "mitkImageSource.h" #include "mitkToFCameraDevice.h" #include "itkObject.h" #include "itkObjectFactory.h" namespace mitk { /**Documentation * \brief Image source providing ToF images. Interface for filters provided in ToFProcessing module * * This class internally holds a ToFCameraDevice to access the images acquired by a ToF camera. * * Provided images include: distance image (output 0), amplitude image (output 1), intensity image (output 2) * * \ingroup ToFHardware */ class MITK_TOFHARDWARE_EXPORT ToFImageGrabber : public mitk::ImageSource { public: mitkClassMacro( ToFImageGrabber , ImageSource ); itkNewMacro( Self ); /*! \brief Establish a connection to the ToF camera \param device specifies the actually used ToF Camera. 0: PMD O3D, 1: PMD CamCube 2.0 */ virtual bool ConnectCamera(); /*! \brief Disconnects the ToF camera */ virtual bool DisconnectCamera(); /*! \brief Starts the continuous updating of the camera. A separate thread updates the source data, the main thread processes the source data and creates images and coordinates */ virtual void StartCamera(); /*! \brief Stops the continuous updating of the camera */ virtual void StopCamera(); /*! \brief Returns true if the camera is connected and started */ virtual bool IsCameraActive(); /*! \brief Sets the ToF device, the image grabber is grabbing the images from \param aToFCameraDevice device internally used for grabbing the images from the camera */ void SetCameraDevice(ToFCameraDevice* aToFCameraDevice); /*! \brief Get the currently set ToF camera device \return device currently used for grabbing images from the camera */ ToFCameraDevice* GetCameraDevice(); /*! \brief Set the modulation frequency used by the ToF camera. For default values see the corresponding device classes \param modulationFrequency modulation frequency in Hz */ int SetModulationFrequency(int modulationFrequency); /*! \brief Get the modulation frequency used by the ToF camera. \return modulation frequency in MHz */ int GetModulationFrequency(); /*! \brief Set the integration time used by the ToF camera. For default values see the corresponding device classes \param integrationTime integration time in ms */ int SetIntegrationTime(int integrationTime); /*! \brief Get the integration time in used by the ToF camera. \return integration time in ms */ int GetIntegrationTime(); /*! \brief Get the dimension in x direction of the ToF image \return width of the image */ int GetCaptureWidth(); /*! \brief Get the dimension in y direction of the ToF image \return height of the image */ int GetCaptureHeight(); /*! \brief Get the number of pixel in the ToF image \return number of pixel */ int GetPixelNumber(); + /*! + \brief Get the dimension in x direction of the ToF image + \return width of the image + */ + int GetRGBImageWidth(); + /*! + \brief Get the dimension in y direction of the ToF image + \return height of the image + */ + int GetRGBImageHeight(); + /*! + \brief Get the number of pixel in the ToF image + \return number of pixel + */ + int GetRGBPixelNumber(); + // properties void SetBoolProperty( const char* propertyKey, bool boolValue ); void SetIntProperty( const char* propertyKey, int intValue ); void SetFloatProperty( const char* propertyKey, float floatValue ); void SetStringProperty( const char* propertyKey, const char* stringValue ); void SetProperty( const char *propertyKey, BaseProperty* propertyValue ); protected: /// /// called when the ToFCameraDevice was modified /// void OnToFCameraDeviceModified(); /*! \brief clean up memory allocated for the image arrays m_IntensityArray, m_DistanceArray, m_AmplitudeArray and m_SourceDataArray */ virtual void CleanUpImageArrays(); /*! \brief Allocate memory for the image arrays m_IntensityArray, m_DistanceArray, m_AmplitudeArray and m_SourceDataArray */ virtual void AllocateImageArrays(); - ToFCameraDevice::Pointer m_ToFCameraDevice; ///< Device allowing acces to ToF image data + ToFCameraDevice::Pointer m_ToFCameraDevice; ///< Device allowing access to ToF image data int m_CaptureWidth; ///< Width of the captured ToF image int m_CaptureHeight; ///< Height of the captured ToF image int m_PixelNumber; ///< Number of pixels in the image + int m_RGBImageWidth; + int m_RGBImageHeight; + int m_RGBPixelNumber; int m_ImageSequence; ///< counter for currently acquired images int m_SourceDataSize; ///< size of the source data in bytes float* m_IntensityArray; ///< member holding the current intensity array float* m_DistanceArray; ///< member holding the current distance array float* m_AmplitudeArray; ///< member holding the current amplitude array char* m_SourceDataArray;///< member holding the current source data array unsigned char* m_RgbDataArray; ///< member holding the current rgb data array - unsigned long m_DeviceObserverTag; ///< tag of the oberver for the the ToFCameraDevice + unsigned long m_DeviceObserverTag; ///< tag of the observer for the ToFCameraDevice ToFImageGrabber(); ~ToFImageGrabber(); /*! \brief Method generating the outputs of this filter. Called in the updated process of the pipeline. 0: distance image 1: amplitude image 2: intensity image */ void GenerateData(); private: }; } //END mitk namespace #endif diff --git a/Modules/ToFHardware/mitkToFImageRecorder.cpp b/Modules/ToFHardware/mitkToFImageRecorder.cpp index dde3618564..f9d81167cd 100644 --- a/Modules/ToFHardware/mitkToFImageRecorder.cpp +++ b/Modules/ToFHardware/mitkToFImageRecorder.cpp @@ -1,252 +1,268 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkToFImageRecorder.h" #include "mitkRealTimeClock.h" #include "itkMultiThreader.h" #include #pragma GCC visibility push(default) #include #pragma GCC visibility pop namespace mitk { ToFImageRecorder::ToFImageRecorder() { this->m_ToFCameraDevice = NULL; this->m_MultiThreader = itk::MultiThreader::New(); this->m_AbortMutex = itk::FastMutexLock::New(); this->m_ThreadID = 0; this->m_NumOfFrames = 0; this->m_ToFImageWriter = NULL; this->m_DistanceImageSelected = true; this->m_AmplitudeImageSelected = true; this->m_IntensityImageSelected = true; this->m_RGBImageSelected = true; - this->m_Abort = true; - this->m_CaptureWidth = 0; - this->m_CaptureHeight = 0; + this->m_Abort = false; + this->m_ToFCaptureWidth = 0; + this->m_ToFCaptureHeight = 0; + this->m_RGBCaptureWidth = 0; + this->m_RGBCaptureHeight = 0; this->m_FileFormat = ""; - this->m_PixelNumber = 0; + this->m_ToFPixelNumber = 0; + this->m_RGBPixelNumber = 0; this->m_SourceDataSize = 0; this->m_ToFImageType = ToFImageWriter::ToFImageType3D; this->m_RecordMode = ToFImageRecorder::PerFrames; this->m_DistanceImageFileName = ""; this->m_AmplitudeImageFileName = ""; this->m_IntensityImageFileName = ""; this->m_RGBImageFileName = ""; this->m_ImageSequence = 0; this->m_DistanceArray = NULL; this->m_AmplitudeArray = NULL; this->m_IntensityArray = NULL; this->m_RGBArray = NULL; this->m_SourceDataArray = NULL; } ToFImageRecorder::~ToFImageRecorder() { delete[] m_DistanceArray; delete[] m_AmplitudeArray; delete[] m_IntensityArray; delete[] m_RGBArray; delete[] m_SourceDataArray; } void ToFImageRecorder::StopRecording() { this->m_AbortMutex->Lock(); this->m_Abort = true; this->m_AbortMutex->Unlock(); } void ToFImageRecorder::StartRecording() { if (this->m_ToFCameraDevice.IsNull()) { throw std::invalid_argument("ToFCameraDevice is NULL."); return; } if (this->m_FileFormat.compare(".csv") == 0) { this->m_ToFImageWriter = ToFImageCsvWriter::New(); } else if(this->m_FileFormat.compare(".nrrd") == 0) { this->m_ToFImageWriter = ToFNrrdImageWriter::New(); this->m_ToFImageWriter->SetExtension(m_FileFormat); } else { throw std::logic_error("No file format specified!"); } - this->m_CaptureWidth = this->m_ToFCameraDevice->GetCaptureWidth(); - this->m_CaptureHeight = this->m_ToFCameraDevice->GetCaptureHeight(); - this->m_PixelNumber = this->m_CaptureWidth * this->m_CaptureHeight; + this->m_RGBCaptureWidth = this->m_ToFCameraDevice->GetRGBCaptureWidth(); + this->m_RGBCaptureHeight = this->m_ToFCameraDevice->GetRGBCaptureHeight(); + this->m_RGBPixelNumber = this->m_RGBCaptureWidth * this->m_RGBCaptureHeight; + + this->m_ToFCaptureWidth = this->m_ToFCameraDevice->GetCaptureWidth(); + this->m_ToFCaptureHeight = this->m_ToFCameraDevice->GetCaptureHeight(); + this->m_ToFPixelNumber = this->m_ToFCaptureWidth * this->m_ToFCaptureHeight; + this->m_SourceDataSize = this->m_ToFCameraDevice->GetSourceDataSize(); // allocate buffer if(m_IntensityArray == NULL) { - this->m_IntensityArray = new float[m_PixelNumber]; + this->m_IntensityArray = new float[m_ToFPixelNumber]; } if(this->m_DistanceArray == NULL) { - this->m_DistanceArray = new float[m_PixelNumber]; + this->m_DistanceArray = new float[m_ToFPixelNumber]; } if(this->m_AmplitudeArray == NULL) { - this->m_AmplitudeArray = new float[m_PixelNumber]; + this->m_AmplitudeArray = new float[m_ToFPixelNumber]; } if(this->m_RGBArray == NULL) { - this->m_RGBArray = new unsigned char[m_PixelNumber*3]; + this->m_RGBArray = new unsigned char[m_RGBPixelNumber*3]; } if(this->m_SourceDataArray == NULL) { this->m_SourceDataArray = new char[m_SourceDataSize]; } this->m_ToFImageWriter->SetDistanceImageFileName(this->m_DistanceImageFileName); this->m_ToFImageWriter->SetAmplitudeImageFileName(this->m_AmplitudeImageFileName); this->m_ToFImageWriter->SetIntensityImageFileName(this->m_IntensityImageFileName); this->m_ToFImageWriter->SetRGBImageFileName(this->m_RGBImageFileName); - this->m_ToFImageWriter->SetCaptureWidth(this->m_CaptureWidth); - this->m_ToFImageWriter->SetCaptureHeight(this->m_CaptureHeight); + this->m_ToFImageWriter->SetRGBCaptureWidth(this->m_RGBCaptureWidth); + this->m_ToFImageWriter->SetRGBCaptureHeight(this->m_RGBCaptureHeight); + this->m_ToFImageWriter->SetToFCaptureHeight(this->m_ToFCaptureHeight); + this->m_ToFImageWriter->SetToFCaptureWidth(this->m_ToFCaptureWidth); + this->m_ToFImageWriter->SetToFCaptureHeight(this->m_ToFCaptureHeight); this->m_ToFImageWriter->SetToFImageType(this->m_ToFImageType); this->m_ToFImageWriter->SetDistanceImageSelected(this->m_DistanceImageSelected); this->m_ToFImageWriter->SetAmplitudeImageSelected(this->m_AmplitudeImageSelected); this->m_ToFImageWriter->SetIntensityImageSelected(this->m_IntensityImageSelected); this->m_ToFImageWriter->SetRGBImageSelected(this->m_RGBImageSelected); this->m_ToFImageWriter->Open(); this->m_AbortMutex->Lock(); this->m_Abort = false; this->m_AbortMutex->Unlock(); this->m_ThreadID = this->m_MultiThreader->SpawnThread(this->RecordData, this); } + void ToFImageRecorder::WaitForThreadBeingTerminated() + { + this->m_MultiThreader->TerminateThread(this->m_ThreadID); + } + ITK_THREAD_RETURN_TYPE ToFImageRecorder::RecordData(void* pInfoStruct) { struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; if (pInfo == NULL) { return ITK_THREAD_RETURN_VALUE; } if (pInfo->UserData == NULL) { return ITK_THREAD_RETURN_VALUE; } ToFImageRecorder* toFImageRecorder = (ToFImageRecorder*)pInfo->UserData; if (toFImageRecorder!=NULL) { ToFCameraDevice::Pointer toFCameraDevice = toFImageRecorder->GetCameraDevice(); mitk::RealTimeClock::Pointer realTimeClock; realTimeClock = mitk::RealTimeClock::New(); int n = 100; double t1 = 0; double t2 = 0; t1 = realTimeClock->GetCurrentStamp(); bool overflow = false; bool printStatus = false; int requiredImageSequence = 0; int numOfFramesRecorded = 0; bool abort = false; toFImageRecorder->m_AbortMutex->Lock(); abort = toFImageRecorder->m_Abort; toFImageRecorder->m_AbortMutex->Unlock(); while ( !abort ) { if ( ((toFImageRecorder->m_RecordMode == ToFImageRecorder::PerFrames) && (numOfFramesRecorded < toFImageRecorder->m_NumOfFrames)) || (toFImageRecorder->m_RecordMode == ToFImageRecorder::Infinite) ) { toFCameraDevice->GetAllImages(toFImageRecorder->m_DistanceArray, toFImageRecorder->m_AmplitudeArray, toFImageRecorder->m_IntensityArray, toFImageRecorder->m_SourceDataArray, requiredImageSequence, toFImageRecorder->m_ImageSequence, toFImageRecorder->m_RGBArray ); if (toFImageRecorder->m_ImageSequence >= requiredImageSequence) { if (toFImageRecorder->m_ImageSequence > requiredImageSequence) { MITK_INFO << "Problem! required: " << requiredImageSequence << " captured: " << toFImageRecorder->m_ImageSequence; } requiredImageSequence = toFImageRecorder->m_ImageSequence + 1; toFImageRecorder->m_ToFImageWriter->Add( toFImageRecorder->m_DistanceArray, toFImageRecorder->m_AmplitudeArray, toFImageRecorder->m_IntensityArray, toFImageRecorder->m_RGBArray ); numOfFramesRecorded++; if (numOfFramesRecorded % n == 0) { printStatus = true; } if (printStatus) { t2 = realTimeClock->GetCurrentStamp() - t1; MITK_INFO << " Framerate (fps): " << n / (t2/1000) << " Sequence: " << toFImageRecorder->m_ImageSequence; t1 = realTimeClock->GetCurrentStamp(); printStatus = false; } } toFImageRecorder->m_AbortMutex->Lock(); abort = toFImageRecorder->m_Abort; toFImageRecorder->m_AbortMutex->Unlock(); } else { abort = true; } } // end of while loop toFImageRecorder->InvokeEvent(itk::AbortEvent()); toFImageRecorder->m_ToFImageWriter->Close(); } return ITK_THREAD_RETURN_VALUE; } void ToFImageRecorder::SetCameraDevice(ToFCameraDevice* aToFCameraDevice) { this->m_ToFCameraDevice = aToFCameraDevice; } ToFCameraDevice* ToFImageRecorder::GetCameraDevice() { return this->m_ToFCameraDevice; } ToFImageWriter::ToFImageType ToFImageRecorder::GetToFImageType() { return this->m_ToFImageType; } void ToFImageRecorder::SetToFImageType(ToFImageWriter::ToFImageType toFImageType) { this->m_ToFImageType = toFImageType; } ToFImageRecorder::RecordMode ToFImageRecorder::GetRecordMode() { return this->m_RecordMode; } void ToFImageRecorder::SetRecordMode(ToFImageRecorder::RecordMode recordMode) { this->m_RecordMode = recordMode; } } diff --git a/Modules/ToFHardware/mitkToFImageRecorder.h b/Modules/ToFHardware/mitkToFImageRecorder.h index 4cce490a4a..607758fee5 100644 --- a/Modules/ToFHardware/mitkToFImageRecorder.h +++ b/Modules/ToFHardware/mitkToFImageRecorder.h @@ -1,166 +1,175 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkToFImageRecorder_h #define __mitkToFImageRecorder_h #include "mitkToFHardwareExports.h" #include "mitkCommon.h" #include "mitkToFCameraDevice.h" #include "mitkToFImageCsvWriter.h" #include "mitkToFNrrdImageWriter.h" #include "itkObject.h" #include "itkObjectFactory.h" #include "itkFastMutexLock.h" #include "itkCommand.h" namespace mitk { /** * @brief Recorder class for ToF images * * This class represents a recorder for ToF data. A ToFCameraDevice is used to acquire the data. The acquired images * are then added to a ToFImageWriter that performs the actual writing. * * Recording can be performed either frame-based or continuously * * @ingroup ToFHardware */ class MITK_TOFHARDWARE_EXPORT ToFImageRecorder : public itk::Object { public: ToFImageRecorder(); ~ToFImageRecorder(); mitkClassMacro( ToFImageRecorder , itk::Object ); itkNewMacro( Self ); itkGetMacro( DistanceImageFileName, std::string ); itkGetMacro( AmplitudeImageFileName, std::string ); itkGetMacro( IntensityImageFileName, std::string ); itkGetMacro( RGBImageFileName, std::string ); - itkGetMacro( CaptureWidth, int ); - itkGetMacro( CaptureHeight, int ); + itkGetMacro( ToFCaptureWidth, int ); + itkGetMacro( ToFCaptureHeight, int ); + itkGetMacro( RGBCaptureWidth, int ); + itkGetMacro( RGBCaptureHeight, int ); itkGetMacro( DistanceImageSelected, bool ); itkGetMacro( AmplitudeImageSelected, bool ); itkGetMacro( IntensityImageSelected, bool ); itkGetMacro( RGBImageSelected, bool ); itkGetMacro( NumOfFrames, int ); itkGetMacro( FileFormat, std::string ); itkSetMacro( DistanceImageFileName, std::string ); itkSetMacro( AmplitudeImageFileName, std::string ); itkSetMacro( IntensityImageFileName, std::string ); itkSetMacro(RGBImageFileName, std::string ); itkSetMacro( DistanceImageSelected, bool ); itkSetMacro( AmplitudeImageSelected, bool ); itkSetMacro( IntensityImageSelected, bool ); itkSetMacro( RGBImageSelected, bool ); itkSetMacro( NumOfFrames, int ); itkSetMacro( FileFormat, std::string ); enum RecordMode{ PerFrames, Infinite }; /*! \brief Returns the currently set RecordMode \return record mode: PerFrames ("Record specified number of frames"), Infinite ("Record until abort is required") */ ToFImageRecorder::RecordMode GetRecordMode(); /*! \brief Set the RecordMode \param recordMode: PerFrames ("Record specified number of frames"), Infinite ("Record until abort is required") */ void SetRecordMode(ToFImageRecorder::RecordMode recordMode); /*! \brief Set the device used for acquiring ToF images \param aToFCameraDevice ToF camera device used. */ void SetCameraDevice(ToFCameraDevice* aToFCameraDevice); /*! \brief Get the device used for acquiring ToF images \return ToF camera device used. */ ToFCameraDevice* GetCameraDevice(); /*! \brief Get the type of image to be recorded \return ToF image type: ToFImageType3D (0) or ToFImageType2DPlusT (1) */ ToFImageWriter::ToFImageType GetToFImageType(); /*! \brief Set the type of image to be recorded \param toFImageType type of the ToF image: ToFImageType3D (0) or ToFImageType2DPlusT (1) */ void SetToFImageType(ToFImageWriter::ToFImageType toFImageType); /*! \brief Starts the recording by spawning a Thread which streams the data to a file. Aborting of the record process is controlled by the m_Abort flag */ void StartRecording(); /*! \brief Stops the recording by setting the m_Abort flag to false */ void StopRecording(); + /*! + \brief Wait until thread is terinated + */ + void WaitForThreadBeingTerminated(); protected: /*! \brief Thread method acquiring data via the ToFCameraDevice and recording it to file via the ToFImageWriter */ static ITK_THREAD_RETURN_TYPE RecordData(void* pInfoStruct); // data acquisition ToFCameraDevice::Pointer m_ToFCameraDevice; ///< ToFCameraDevice used for acquiring the images - int m_CaptureWidth; ///< width (x-dimension) of the images to record. - int m_CaptureHeight; ///< height (y-dimension) of the images to record. - int m_PixelNumber; ///< number of pixels (widht*height) of the images to record + int m_ToFCaptureWidth; ///< width (x-dimension) of the images to record. + int m_ToFCaptureHeight; ///< height (y-dimension) of the images to record. + int m_ToFPixelNumber; ///< number of pixels (widht*height) of the images to record + int m_RGBCaptureWidth; ///< width (x-dimension) of the images to record. + int m_RGBCaptureHeight; ///< height (y-dimension) of the images to record. + int m_RGBPixelNumber; ///< number of pixels (widht*height) of the images to record int m_SourceDataSize; ///< size of the source data provided by the device int m_ImageSequence; ///< number of images currently acquired float* m_IntensityArray; ///< array holding the intensity data float* m_DistanceArray; ///< array holding the distance data float* m_AmplitudeArray; ///< array holding the amplitude data unsigned char* m_RGBArray; ///< array holding the RGB data if available (e.g. for Kinect) char* m_SourceDataArray; ///< array holding the source data // data writing ToFImageWriter::Pointer m_ToFImageWriter; ///< image writer writing the acquired images to a file std::string m_DistanceImageFileName; ///< file name for saving the distance image std::string m_AmplitudeImageFileName; ///< file name for saving the amplitude image std::string m_IntensityImageFileName; ///< file name for saving the intensity image std::string m_RGBImageFileName; ///< file name for saving the rgb image int m_NumOfFrames; ///< number of frames to be recorded by this recorder ToFImageWriter::ToFImageType m_ToFImageType; ///< type of image to be recorded: ToFImageType3D (0) or ToFImageType2DPlusT (1) ToFImageRecorder::RecordMode m_RecordMode; ///< mode of recording the images: specified number of frames (PerFrames) or infinite (Infinite) std::string m_FileFormat; ///< file format for saving images. If .csv is chosen, ToFImageCsvWriter is used bool m_DistanceImageSelected; ///< flag indicating if distance image should be recorded bool m_AmplitudeImageSelected; ///< flag indicating if amplitude image should be recorded bool m_IntensityImageSelected; ///< flag indicating if intensity image should be recorded bool m_RGBImageSelected; ///< flag indicating if rgb image should be recorded // threading itk::MultiThreader::Pointer m_MultiThreader; ///< member for thread-handling (ITK-based) int m_ThreadID; ///< ID of the thread recording the data itk::FastMutexLock::Pointer m_AbortMutex; ///< mutex for thread-safe data access of abort flag bool m_Abort; ///< flag controlling the abort mechanism of the recording procedure. For thread-safety only use in combination with m_AbortMutex private: }; } //END mitk namespace #endif diff --git a/Modules/ToFHardware/mitkToFImageRecorderFilter.cpp b/Modules/ToFHardware/mitkToFImageRecorderFilter.cpp index 1d1a7b34c3..bc9274a60b 100644 --- a/Modules/ToFHardware/mitkToFImageRecorderFilter.cpp +++ b/Modules/ToFHardware/mitkToFImageRecorderFilter.cpp @@ -1,163 +1,163 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkToFNrrdImageWriter.h" #include "mitkToFImageCsvWriter.h" // itk includes #include "itksys/SystemTools.hxx" mitk::ToFImageRecorderFilter::ToFImageRecorderFilter(): m_RecordingStarted(false), m_ToFImageWriter(0) { m_FileExtension = ""; } mitk::ToFImageRecorderFilter::~ToFImageRecorderFilter() { } void mitk::ToFImageRecorderFilter::SetFileName(std::string fileName) { std::string name = fileName; m_FileExtension = itksys::SystemTools::GetFilenameLastExtension( fileName ); if(m_FileExtension == ".nrrd") { m_ToFImageWriter = mitk::ToFNrrdImageWriter::New(); } else if(m_FileExtension == ".csv") { m_ToFImageWriter = mitk::ToFImageCsvWriter::New(); } else { throw std::logic_error("The specified file type is not supported, standard file type is .nrrd!"); } int pos = name.find_last_of("."); name.insert(pos,"_DistanceImage"); m_ToFImageWriter->SetDistanceImageFileName(name); name = fileName; name.insert(pos,"_AmplitudeImage"); m_ToFImageWriter->SetAmplitudeImageFileName(name); name = fileName; name.insert(pos,"_IntensityImage"); m_ToFImageWriter->SetIntensityImageFileName(name); } void mitk::ToFImageRecorderFilter::SetImageType(mitk::ToFImageWriter::ToFImageType tofImageType) { m_ToFImageWriter->SetToFImageType(tofImageType); } void mitk::ToFImageRecorderFilter::GenerateData() { mitk::Image::Pointer distanceImageInput = this->GetInput(0); assert(distanceImageInput); mitk::Image::Pointer amplitudeImageInput = this->GetInput(1); assert(amplitudeImageInput); mitk::Image::Pointer intensityImageInput = this->GetInput(2); assert(intensityImageInput); // add current data to file stream float* distanceFloatData = (float*)distanceImageInput->GetSliceData(0, 0, 0)->GetData(); float* amplitudeFloatData = (float*)amplitudeImageInput->GetSliceData(0, 0, 0)->GetData(); float* intensityFloatData = (float*)intensityImageInput->GetSliceData(0, 0, 0)->GetData(); if (m_RecordingStarted) { m_ToFImageWriter->Add(distanceFloatData,amplitudeFloatData,intensityFloatData); } // set outputs to inputs this->SetNthOutput(0,distanceImageInput); this->SetNthOutput(1,amplitudeImageInput); this->SetNthOutput(2,intensityImageInput); } void mitk::ToFImageRecorderFilter::StartRecording() { if(m_ToFImageWriter.IsNull()) { throw std::logic_error("ToFImageWriter is unitialized, set filename first!"); return; } m_ToFImageWriter->Open(); m_RecordingStarted = true; } void mitk::ToFImageRecorderFilter::StopRecording() { m_ToFImageWriter->Close(); m_RecordingStarted = false; } mitk::ToFImageWriter::Pointer mitk::ToFImageRecorderFilter::GetToFImageWriter() { return m_ToFImageWriter; } void mitk::ToFImageRecorderFilter::SetToFImageWriter(mitk::ToFImageWriter::Pointer tofImageWriter) { m_ToFImageWriter = tofImageWriter; } void mitk::ToFImageRecorderFilter::SetInput( mitk::Image* input ) { this->SetInput(0,input); } void mitk::ToFImageRecorderFilter::SetInput( unsigned int idx, mitk::Image* input ) { if ((input == NULL) && (idx == this->GetNumberOfInputs() - 1)) // if the last input is set to NULL, reduce the number of inputs by one { this->SetNumberOfInputs(this->GetNumberOfInputs() - 1); } - else + else if(idx == 0 || idx == 1 || idx == 2) { this->ProcessObject::SetNthInput(idx, input); // Process object is not const-correct so the const_cast is required here unsigned int xDim = input->GetDimension(0); unsigned int yDim = input->GetDimension(1); - m_ToFImageWriter->SetCaptureWidth(xDim); - m_ToFImageWriter->SetCaptureWidth(yDim); + m_ToFImageWriter->SetToFCaptureWidth(xDim); + m_ToFImageWriter->SetToFCaptureWidth(yDim); } this->CreateOutputsForAllInputs(); } mitk::Image* mitk::ToFImageRecorderFilter::GetInput() { return this->GetInput(0); } mitk::Image* mitk::ToFImageRecorderFilter::GetInput( unsigned int idx ) { if (this->GetNumberOfInputs() < 1) return NULL; return static_cast< mitk::Image*>(this->ProcessObject::GetInput(idx)); } void mitk::ToFImageRecorderFilter::CreateOutputsForAllInputs() { this->SetNumberOfOutputs(this->GetNumberOfInputs()); // create outputs for all inputs for (unsigned int idx = 0; idx < this->GetNumberOfOutputs(); ++idx) if (this->GetOutput(idx) == NULL) { DataObjectPointer newOutput = this->MakeOutput(idx); this->SetNthOutput(idx, newOutput); } this->Modified(); } diff --git a/Modules/ToFHardware/mitkToFImageWriter.cpp b/Modules/ToFHardware/mitkToFImageWriter.cpp index cde6276aa2..e8708684c4 100644 --- a/Modules/ToFHardware/mitkToFImageWriter.cpp +++ b/Modules/ToFHardware/mitkToFImageWriter.cpp @@ -1,65 +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. ===================================================================*/ #include #include // itk includes #include "itksys/SystemTools.hxx" namespace mitk { ToFImageWriter::ToFImageWriter():m_Extension(".nrrd"), m_DistanceImageFileName(), m_AmplitudeImageFileName(), m_IntensityImageFileName(), m_RGBImageFileName(), m_NumOfFrames(0), m_DistanceImageSelected(true), m_AmplitudeImageSelected(true), - m_IntensityImageSelected(true), m_RGBImageSelected(true), m_CaptureWidth(200),m_CaptureHeight(200), - m_PixelNumber(0), m_ImageSizeInBytes(0), + m_IntensityImageSelected(true), m_RGBImageSelected(true), m_ToFCaptureWidth(200),m_ToFCaptureHeight(200), + m_RGBCaptureWidth(200),m_RGBCaptureHeight(200), + m_ToFPixelNumber(0), m_ToFImageSizeInBytes(0), + m_RGBPixelNumber(0), m_RGBImageSizeInBytes(0), m_ToFImageType(ToFImageWriter::ToFImageType3D) { } ToFImageWriter::~ToFImageWriter() { } void ToFImageWriter::CheckForFileExtension(std::string& fileName) { std::string baseFilename = itksys::SystemTools::GetFilenameWithoutLastExtension( fileName ); std::string extension = itksys::SystemTools::GetFilenameLastExtension( fileName ); if( extension.length() != 0 && extension != this->m_Extension) { MITK_ERROR << "Wrong file extension! The default extension is " << this->m_Extension.c_str() << ", currently the requested file extension is " << extension.c_str() <<"!"; this->m_Extension = extension; } size_t found = fileName.find( this->m_Extension ); // !!! HAS to be at the very end of the filename (not somewhere in the middle) if( found == std::string::npos) { fileName.append(this->m_Extension); } } ToFImageWriter::ToFImageType ToFImageWriter::GetToFImageType() { return this->m_ToFImageType; } void ToFImageWriter::SetToFImageType(ToFImageWriter::ToFImageType toFImageType) { this->m_ToFImageType = toFImageType; } } // end namespace mitk diff --git a/Modules/ToFHardware/mitkToFImageWriter.h b/Modules/ToFHardware/mitkToFImageWriter.h index ccf139354b..109f27bb17 100644 --- a/Modules/ToFHardware/mitkToFImageWriter.h +++ b/Modules/ToFHardware/mitkToFImageWriter.h @@ -1,128 +1,136 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 __mitkToFImageWriter_h #define __mitkToFImageWriter_h #include "mitkToFHardwareExports.h" #include "mitkCommon.h" #include "mitkToFImageGrabber.h" #include "itkObject.h" #include "itkObjectFactory.h" namespace mitk { /** * @brief Writer class for ToF images * * This writer class allows streaming of ToF data into a file. The .pic file format is used for writing the data. * Image information is included in the header of the pic file. * Writer can simultaneously save "distance", "intensity" and "amplitude" image. * Images can be written as 3D volume (ToFImageType::ToFImageType3D) or temporal image stack (ToFImageType::ToFImageType2DPlusT) * * @ingroup ToFHardware */ class MITK_TOFHARDWARE_EXPORT ToFImageWriter : public itk::Object { public: ToFImageWriter(); ~ToFImageWriter(); mitkClassMacro( ToFImageWriter , itk::Object ); itkNewMacro( Self ); itkGetMacro( DistanceImageFileName, std::string ); itkGetMacro( AmplitudeImageFileName, std::string ); itkGetMacro( IntensityImageFileName, std::string ); itkGetMacro( RGBImageFileName, std::string ); itkGetMacro( Extension, std::string ); - itkGetMacro( CaptureWidth, int ); - itkGetMacro( CaptureHeight, int ); + itkGetMacro( ToFCaptureWidth, int ); + itkGetMacro( ToFCaptureHeight, int ); + itkGetMacro( RGBCaptureWidth, int ); + itkGetMacro( RGBCaptureHeight, int ); itkGetMacro( DistanceImageSelected, bool ); itkGetMacro( AmplitudeImageSelected, bool ); itkGetMacro( IntensityImageSelected, bool ); itkGetMacro( RGBImageSelected, bool ); itkSetMacro( DistanceImageFileName, std::string ); itkSetMacro( AmplitudeImageFileName, std::string ); itkSetMacro( IntensityImageFileName, std::string ); itkSetMacro( RGBImageFileName, std::string ); itkSetMacro( Extension, std::string ); - itkSetMacro( CaptureWidth, int ); - itkSetMacro( CaptureHeight, int ); + itkSetMacro( ToFCaptureWidth, int ); + itkSetMacro( ToFCaptureHeight, int ); + itkSetMacro( RGBCaptureWidth, int ); + itkSetMacro( RGBCaptureHeight, int ); itkSetMacro( DistanceImageSelected, bool ); itkSetMacro( AmplitudeImageSelected, bool ); itkSetMacro( IntensityImageSelected, bool ); itkSetMacro( RGBImageSelected, bool ); enum ToFImageType{ ToFImageType3D, ToFImageType2DPlusT }; /*! \brief Get the type of image to be written \return ToF image type: ToFImageType3D (0) or ToFImageType2DPlusT (1) */ ToFImageWriter::ToFImageType GetToFImageType(); /*! \brief Set the type of image to be written \param toFImageType type of the ToF image: ToFImageType3D (0) or ToFImageType2DPlusT (1) */ void SetToFImageType(ToFImageWriter::ToFImageType toFImageType); /*! \brief Open file(s) for writing */ virtual void Open(){}; /*! \brief Close file(s) add .pic header and write */ virtual void Close(){}; /*! \brief Add new data to file. */ virtual void Add(float* distanceFloatData, float* amplitudeFloatData, float* intensityFloatData, unsigned char* rgbData=0){}; protected: /*! \brief Checks file name if file extension exists. If not an error message is returned */ void CheckForFileExtension(std::string& fileName); // member variables std::string m_DistanceImageFileName; ///< file name for saving the distance image std::string m_AmplitudeImageFileName; ///< file name for saving the amplitude image std::string m_IntensityImageFileName; ///< file name for saving the intensity image std::string m_RGBImageFileName; ///< file name for saving the RGB image std::string m_Extension; ///< file extension used for saving images - int m_CaptureWidth; ///< width (x-dimension) of the images to record. - int m_CaptureHeight; ///< height (y-dimension) of the images to record. - int m_PixelNumber; ///< number of pixels (widht*height) of the images to record - int m_ImageSizeInBytes; ///< size of the image to save in bytes + int m_ToFCaptureWidth; ///< width (x-dimension) of the images to record. + int m_ToFCaptureHeight; ///< height (y-dimension) of the images to record. + int m_ToFPixelNumber; ///< number of pixels (widht*height) of the images to record + int m_ToFImageSizeInBytes; ///< size of the image to save in bytes + int m_RGBCaptureWidth; ///< width (x-dimension) of the images to record. + int m_RGBCaptureHeight; ///< height (y-dimension) of the images to record. + int m_RGBPixelNumber; ///< number of pixels (widht*height) of the images to record + int m_RGBImageSizeInBytes; ///< size of the image to save in bytes int m_NumOfFrames; ///< number of frames written to the image. Used for pic header. ToFImageWriter::ToFImageType m_ToFImageType; ///< type of image to be recorded: ToFImageType3D (0) or ToFImageType2DPlusT (1) bool m_DistanceImageSelected; ///< flag indicating if distance image should be recorded bool m_AmplitudeImageSelected; ///< flag indicating if amplitude image should be recorded bool m_IntensityImageSelected; ///< flag indicating if intensity image should be recorded bool m_RGBImageSelected; ///< flag indicating if RGB image should be recorded private: }; } //END mitk namespace #endif // __mitkToFImageWriter_h diff --git a/Modules/ToFHardware/mitkToFNrrdImageWriter.cpp b/Modules/ToFHardware/mitkToFNrrdImageWriter.cpp index 864090dc7c..c99809bcbe 100644 --- a/Modules/ToFHardware/mitkToFNrrdImageWriter.cpp +++ b/Modules/ToFHardware/mitkToFNrrdImageWriter.cpp @@ -1,251 +1,271 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 includes #include // itk includes #include "itksys/SystemTools.hxx" #include "itkNrrdImageIO.h" namespace mitk { ToFNrrdImageWriter::ToFNrrdImageWriter(): ToFImageWriter(), m_DistanceOutfile(), m_AmplitudeOutfile(), m_IntensityOutfile() { m_Extension = std::string(".nrrd"); } ToFNrrdImageWriter::~ToFNrrdImageWriter() { } void ToFNrrdImageWriter::Open() { this->CheckForFileExtension(this->m_DistanceImageFileName); this->CheckForFileExtension(this->m_AmplitudeImageFileName); this->CheckForFileExtension(this->m_IntensityImageFileName); this->CheckForFileExtension(this->m_RGBImageFileName); - this->m_PixelNumber = this->m_CaptureWidth * this->m_CaptureHeight; - this->m_ImageSizeInBytes = this->m_PixelNumber * sizeof(float); + this->m_ToFPixelNumber = this->m_ToFCaptureWidth * this->m_ToFCaptureHeight; + this->m_ToFImageSizeInBytes = this->m_ToFPixelNumber * sizeof(float); + + this->m_RGBPixelNumber = this->m_RGBCaptureWidth * this->m_RGBCaptureHeight; + this->m_RGBImageSizeInBytes = this->m_RGBPixelNumber * sizeof(unsigned char) * 3; if (this->m_DistanceImageSelected) { this->OpenStreamFile( this->m_DistanceOutfile, this->m_DistanceImageFileName); } if (this->m_AmplitudeImageSelected) { this->OpenStreamFile(this->m_AmplitudeOutfile, this->m_AmplitudeImageFileName); } if (this->m_IntensityImageSelected) { this->OpenStreamFile(this->m_IntensityOutfile, this->m_IntensityImageFileName); } if (this->m_RGBImageSelected) { this->OpenStreamFile(this->m_RGBOutfile, this->m_RGBImageFileName); } this->m_NumOfFrames = 0; } void ToFNrrdImageWriter::Close() { if (this->m_DistanceImageSelected) { this->CloseStreamFile(this->m_DistanceOutfile, this->m_DistanceImageFileName); } if (this->m_AmplitudeImageSelected) { this->CloseStreamFile(this->m_AmplitudeOutfile, this->m_AmplitudeImageFileName); } if (this->m_IntensityImageSelected) { this->CloseStreamFile(this->m_IntensityOutfile, this->m_IntensityImageFileName); } if (this->m_RGBImageSelected) { this->CloseStreamFile(this->m_RGBOutfile, this->m_RGBImageFileName); } } void ToFNrrdImageWriter::Add(float* distanceFloatData, float* amplitudeFloatData, float* intensityFloatData, unsigned char* rgbData) { if (this->m_DistanceImageSelected) { - this->m_DistanceOutfile.write( (char*) distanceFloatData, this->m_ImageSizeInBytes); + this->m_DistanceOutfile.write( (char*) distanceFloatData, this->m_ToFImageSizeInBytes); } if (this->m_AmplitudeImageSelected) { - this->m_AmplitudeOutfile.write( (char*)amplitudeFloatData, this->m_ImageSizeInBytes); + this->m_AmplitudeOutfile.write( (char*)amplitudeFloatData, this->m_ToFImageSizeInBytes); } if (this->m_IntensityImageSelected) { - this->m_IntensityOutfile.write(( char* )intensityFloatData, this->m_ImageSizeInBytes); + this->m_IntensityOutfile.write(( char* )intensityFloatData, this->m_ToFImageSizeInBytes); } if (this->m_RGBImageSelected) { - this->m_RGBOutfile.write(( char* )rgbData, this->m_PixelNumber*3 * sizeof(unsigned char)); + this->m_RGBOutfile.write(( char* )rgbData, this->m_RGBImageSizeInBytes); } this->m_NumOfFrames++; } void ToFNrrdImageWriter::OpenStreamFile( std::ofstream &outfile, std::string outfileName ) { outfile.open(outfileName.c_str(), std::ofstream::binary); if(!outfile.is_open()) { MITK_ERROR << "Error opening outfile: " << outfileName; throw std::logic_error("Error opening outfile."); return; } } void ToFNrrdImageWriter::CloseStreamFile( std::ofstream &outfile, std::string fileName ) { if (this->m_NumOfFrames == 0) { outfile.close(); throw std::logic_error("File is empty."); return; } // flush the last data to the file and convert the stream data to nrrd file outfile.flush(); this->ConvertStreamToNrrdFormat( fileName ); outfile.close(); } void ToFNrrdImageWriter::ConvertStreamToNrrdFormat( std::string fileName ) { + int CaptureWidth = 0; + int CaptureHeight = 0; + int PixelNumber = 0; + int ImageSizeInBytes = 0; + if (fileName==this->m_RGBImageFileName) + { + CaptureWidth = this->m_RGBCaptureWidth; + CaptureHeight = this->m_RGBCaptureHeight; + PixelNumber = this->m_RGBPixelNumber; + ImageSizeInBytes = this->m_RGBImageSizeInBytes; + } else + { + CaptureWidth = this->m_ToFCaptureWidth; + CaptureHeight = this->m_ToFCaptureHeight; + PixelNumber = this->m_ToFPixelNumber; + ImageSizeInBytes = this->m_ToFImageSizeInBytes; + } Image::Pointer imageTemplate = Image::New(); int dimension ; unsigned int* dimensions; if(m_ToFImageType == ToFImageType2DPlusT) { dimension = 4; dimensions = new unsigned int[dimension]; - dimensions[0] = this->m_CaptureWidth; - dimensions[1] = this->m_CaptureHeight; + dimensions[0] = CaptureWidth; + dimensions[1] = CaptureHeight; dimensions[2] = 1; dimensions[3] = this->m_NumOfFrames; } else if( m_ToFImageType == ToFImageType3D) { dimension = 3; dimensions = new unsigned int[dimension]; - dimensions[0] = this->m_CaptureWidth; - dimensions[1] = this->m_CaptureHeight; + dimensions[0] = CaptureWidth; + dimensions[1] = CaptureHeight; dimensions[2] = this->m_NumOfFrames; } else { throw std::logic_error("No image type set, please choose between 2D+t and 3D!"); } float* floatData; unsigned char* rgbData; if (fileName==this->m_RGBImageFileName) { - rgbData = new unsigned char[this->m_PixelNumber*3]; - for(int i=0; im_PixelNumber*3; i++) + rgbData = new unsigned char[PixelNumber*3]; + for(int i=0; i, 3>(); imageTemplate->Initialize( RGBType,dimension, dimensions, 1); imageTemplate->SetSlice(rgbData, 0, 0, 0); } else { - floatData = new float[this->m_PixelNumber]; - for(int i=0; im_PixelNumber; i++) + floatData = new float[PixelNumber]; + for(int i=0; i(); imageTemplate->Initialize( FloatType,dimension, dimensions, 1); imageTemplate->SetSlice(floatData, 0, 0, 0); } itk::NrrdImageIO::Pointer nrrdWriter = itk::NrrdImageIO::New(); nrrdWriter->SetNumberOfDimensions(dimension); nrrdWriter->SetPixelTypeInfo(imageTemplate->GetPixelType().GetTypeId()); if(imageTemplate->GetPixelType().GetNumberOfComponents() > 1) { nrrdWriter->SetNumberOfComponents(imageTemplate->GetPixelType().GetNumberOfComponents()); } itk::ImageIORegion ioRegion( dimension ); mitk::Vector3D spacing = imageTemplate->GetGeometry()->GetSpacing(); mitk::Point3D origin = imageTemplate->GetGeometry()->GetOrigin(); for(unsigned int i = 0; i < dimension; i++) { nrrdWriter->SetDimensions(i,dimensions[i]); nrrdWriter->SetSpacing(i,spacing[i]); nrrdWriter->SetOrigin(i,origin[i]); mitk::Vector3D direction; direction.Set_vnl_vector(imageTemplate->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(i)); vnl_vector< double > axisDirection(dimension); for(unsigned int j = 0; j < dimension; j++) { axisDirection[j] = direction[j]/spacing[i]; } nrrdWriter->SetDirection( i, axisDirection ); ioRegion.SetSize(i, imageTemplate->GetLargestPossibleRegion().GetSize(i) ); ioRegion.SetIndex(i, imageTemplate->GetLargestPossibleRegion().GetIndex(i) ); } nrrdWriter->SetIORegion(ioRegion); nrrdWriter->SetFileName(fileName); nrrdWriter->SetUseStreamedWriting(true); std::ifstream stream(fileName.c_str(), std::ifstream::binary); if (fileName==m_RGBImageFileName) { - unsigned int size = this->m_PixelNumber*3 * this->m_NumOfFrames; + unsigned int size = PixelNumber*3 * this->m_NumOfFrames; unsigned int sizeInBytes = size * sizeof(unsigned char); unsigned char* data = new unsigned char[size]; stream.read((char*)data, sizeInBytes); nrrdWriter->Write(data); stream.close(); delete[] data; } else { - unsigned int size = this->m_PixelNumber * this->m_NumOfFrames; + unsigned int size = PixelNumber * this->m_NumOfFrames; unsigned int sizeInBytes = size * sizeof(float); float* data = new float[size]; stream.read((char*)data, sizeInBytes); nrrdWriter->Write(data); stream.close(); delete[] data; } delete[] dimensions; if (fileName==m_RGBImageFileName) { delete[] rgbData; } else { delete[] floatData; } } } // end namespace mitk diff --git a/Modules/ToFProcessing/mitkToFDistanceImageToPointSetFilter.cpp b/Modules/ToFProcessing/mitkToFDistanceImageToPointSetFilter.cpp index 4bef65a24d..101d0986ac 100644 --- a/Modules/ToFProcessing/mitkToFDistanceImageToPointSetFilter.cpp +++ b/Modules/ToFProcessing/mitkToFDistanceImageToPointSetFilter.cpp @@ -1,200 +1,205 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkToFDistanceImageToPointSetFilter.h" #include "mitkImageDataItem.h" #include "mitkPointSet.h" #include "mitkToFProcessingCommon.h" mitk::ToFDistanceImageToPointSetFilter::ToFDistanceImageToPointSetFilter() : m_Subset(NULL), m_CameraIntrinsics(), m_InterPixelDistance() { m_InterPixelDistance.Fill(0.045); m_CameraIntrinsics = mitk::CameraIntrinsics::New(); m_CameraIntrinsics->SetFocalLength(295.78960196187319,296.1255427948447); m_CameraIntrinsics->SetPrincipalPoint(113.29063841714108,97.243216122015184); m_CameraIntrinsics->SetDistorsionCoeffs(-0.36874385358645773f,-0.14339503290129013,0.0033210108720361795,-0.004277703352074105); } mitk::ToFDistanceImageToPointSetFilter::~ToFDistanceImageToPointSetFilter() { } void mitk::ToFDistanceImageToPointSetFilter::SetInput(const mitk::Image* distanceImage ) { this->SetInput(0,distanceImage); } void mitk::ToFDistanceImageToPointSetFilter::SetInput( unsigned int idx,const mitk::Image* distanceImage ) { if ((distanceImage == NULL) && (idx == this->GetNumberOfInputs() - 1)) // if the last input is set to NULL, reduce the number of inputs by one { this->SetNumberOfInputs(this->GetNumberOfInputs() - 1); } else { this->ProcessObject::SetNthInput(idx, const_cast(distanceImage)); // Process object is not const-correct so the const_cast is required here this->CreateOutputsForAllInputs(); } } mitk::Image* mitk::ToFDistanceImageToPointSetFilter::GetInput() { return this->GetInput(0); } mitk::Image* mitk::ToFDistanceImageToPointSetFilter::GetInput( unsigned int idx ) { if (this->GetNumberOfInputs() < 1) return NULL; return static_cast< mitk::Image*>(this->ProcessObject::GetInput(idx)); } void mitk::ToFDistanceImageToPointSetFilter::SetSubset(std::vector subset) { // check if points of PointSet are inside the input image mitk::Image::Pointer input = this->GetInput(); unsigned int xDim = input->GetDimension(0); unsigned int yDim = input->GetDimension(1); bool pointSetValid = true; for (unsigned int i=0; ixDim||currentIndex[1]<0||currentIndex[1]>yDim) { pointSetValid = false; } } if (pointSetValid) { m_Subset = subset; } else { MITK_ERROR<<"One or more indizes are located outside the image domain"; } } void mitk::ToFDistanceImageToPointSetFilter::SetSubset( mitk::PointSet::Pointer pointSet) { std::vector subset; for (int i=0; iGetSize(); i++) { mitk::Point3D currentPoint = pointSet->GetPoint(i); mitk::Index3D currentIndex; currentIndex[0] = currentPoint[0]; currentIndex[1] = currentPoint[1]; currentIndex[2] = currentPoint[2]; subset.push_back(currentIndex); } this->SetSubset(subset); } void mitk::ToFDistanceImageToPointSetFilter::GenerateData() { //calculate world coordinates mitk::ToFProcessingCommon::ToFPoint2D focalLengthInPixelUnits; mitk::ToFProcessingCommon::ToFScalarType focalLengthInMm; if (m_ReconstructionMode) { focalLengthInPixelUnits[0] = m_CameraIntrinsics->GetFocalLengthX(); focalLengthInPixelUnits[1] = m_CameraIntrinsics->GetFocalLengthY(); } else focalLengthInMm = (m_CameraIntrinsics->GetFocalLengthX()*m_InterPixelDistance[0]+m_CameraIntrinsics->GetFocalLengthY()*m_InterPixelDistance[1])/2.0; mitk::ToFProcessingCommon::ToFPoint2D principalPoint; principalPoint[0] = m_CameraIntrinsics->GetPrincipalPointX(); principalPoint[1] = m_CameraIntrinsics->GetPrincipalPointY(); mitk::PointSet::Pointer output = this->GetOutput(); assert(output); mitk::Image::Pointer input = this->GetInput(); assert(input); //compute subset of points if input PointSet is defined if (m_Subset.size()!=0) { for (unsigned int i=0; iGetPixelValueByIndex(currentIndex); mitk::Point3D currentPoint; if (m_ReconstructionMode) currentPoint = mitk::ToFProcessingCommon::IndexToCartesianCoordinates(currentIndex,distance,focalLengthInPixelUnits,principalPoint); else currentPoint = mitk::ToFProcessingCommon::IndexToCartesianCoordinatesWithInterpixdist(currentIndex,distance,focalLengthInMm,m_InterPixelDistance,principalPoint); output->InsertPoint(i,currentPoint); } } else //compute PointSet holding cartesian coordinates for every image point { int xDimension = (int)input->GetDimension(0); int yDimension = (int)input->GetDimension(1); int pointCount = 0; for (int j=0; jGetPixelValueByIndex(pixel); mitk::Point3D currentPoint; if (m_ReconstructionMode) currentPoint = mitk::ToFProcessingCommon::IndexToCartesianCoordinates(i,j,distance,focalLengthInPixelUnits,principalPoint); else currentPoint = mitk::ToFProcessingCommon::IndexToCartesianCoordinatesWithInterpixdist(i,j,distance,focalLengthInMm,m_InterPixelDistance,principalPoint); if (distance>mitk::eps) { output->InsertPoint( pointCount, currentPoint ); pointCount++; } } } } } void mitk::ToFDistanceImageToPointSetFilter::CreateOutputsForAllInputs() { this->SetNumberOfOutputs(this->GetNumberOfInputs()); // create outputs for all inputs for (unsigned int idx = 0; idx < this->GetNumberOfOutputs(); ++idx) if (this->GetOutput(idx) == NULL) { DataObjectPointer newOutput = this->MakeOutput(idx); this->SetNthOutput(idx, newOutput); } this->Modified(); } void mitk::ToFDistanceImageToPointSetFilter::GenerateOutputInformation() { this->GetOutput(); itkDebugMacro(<<"GenerateOutputInformation()"); } void mitk::ToFDistanceImageToPointSetFilter::SetReconstructionMode(bool withoutInterpixdist) { this->m_ReconstructionMode = withoutInterpixdist; } + +bool mitk::ToFDistanceImageToPointSetFilter::GetReconstructionMode() +{ + return (this->m_ReconstructionMode); +} diff --git a/Modules/ToFProcessing/mitkToFDistanceImageToPointSetFilter.h b/Modules/ToFProcessing/mitkToFDistanceImageToPointSetFilter.h index 518bc37542..dc09f4ced3 100644 --- a/Modules/ToFProcessing/mitkToFDistanceImageToPointSetFilter.h +++ b/Modules/ToFProcessing/mitkToFDistanceImageToPointSetFilter.h @@ -1,133 +1,138 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 __mitkToFDistanceImageToPointSetFilter_h #define __mitkToFDistanceImageToPointSetFilter_h #include #include "mitkImage.h" #include "mitkPointSet.h" #include #include "mitkImageSource.h" #include #include "mitkToFProcessingExports.h" namespace mitk { /** * @brief Converts a Time-of-Flight (ToF) distance image to a PointSet using the pinhole camera model for coordinate computation. * The intrinsic parameters of the camera (FocalLength, PrincipalPoint, InterPixelDistance) are set via SetIntrinsicParameters(). The * measured distance for each pixel corresponds to the distance between the object point and the corresponding image point on the * image plane. * If a subset of indizes of the image is defined via SetSubset(), the output PointSet will only contain the cartesian coordinates * of the corresponding 3D points. * * The coordinate conversion follows the model of a common pinhole camera where the origin of the camera * coordinate system (world coordinates) is at the pinhole * \image html ../Modules/ToFProcessing/Documentation/PinholeCameraModel.png * The definition of the image plane and its coordinate systems (pixel and mm) is depicted in the following image * \image html ../Modules/ToFProcessing/Documentation/ImagePlane.png * * @ingroup SurfaceFilters * @ingroup ToFProcessing */ class mitkToFProcessing_EXPORT ToFDistanceImageToPointSetFilter : public PointSetSource { public: mitkClassMacro( ToFDistanceImageToPointSetFilter , PointSetSource ); itkNewMacro( Self ); itkSetMacro(CameraIntrinsics,mitk::CameraIntrinsics::Pointer); itkGetMacro(CameraIntrinsics,mitk::CameraIntrinsics::Pointer); itkSetMacro(InterPixelDistance,mitk::ToFProcessingCommon::ToFPoint2D); itkGetMacro(InterPixelDistance,mitk::ToFProcessingCommon::ToFPoint2D); /*! \brief Sets the input of this filter \param distanceImage input is the distance image of e.g. a ToF camera */ virtual void SetInput(const Image* distanceImage); /*! \brief Sets the input of this filter at idx \param idx number of the current input \param distanceImage input is the distance image of e.g. a ToF camera */ virtual void SetInput(unsigned int idx,const Image* distanceImage); /*! \brief Returns the input of this filter */ Image* GetInput(); /*! \brief Returns the input with id idx of this filter */ Image* GetInput(unsigned int idx); /*! \brief If this subset is defined, the cartesian coordinates are only computed for the contained indizes. Make sure the indizes are contained in the input image \param subset index subset specified in index coordinates. */ void SetSubset( std::vector subset); /*! \brief Sets the subset of indizes used for caluclation of output PointSet as a PointSet. Warning: make sure the points in your PointSet are index coordinates. \param PointSet specified in index coordinates. */ void SetSubset( mitk::PointSet::Pointer pointSet); /*! - \brief Set the reconstruction mode, if using no interpixeldistances and focal lenghts in pixel units (=true) or interpixeldistances and focal length in mm (=false) + \brief Sets the reconstruction mode, if using no interpixeldistances and focal lenghts in pixel units (=true) or interpixeldistances and focal length in mm (=false) */ void SetReconstructionMode(bool withoutInterpixdist = true); + /*! + \brief Returns the reconstruction mode + */ + bool GetReconstructionMode(); + protected: /*! \brief Standard constructor */ ToFDistanceImageToPointSetFilter(); /*! \brief Standard destructor */ ~ToFDistanceImageToPointSetFilter(); virtual void GenerateOutputInformation(); /*! \brief Method generating the output of this filter. Called in the updated process of the pipeline. This method generates the output of the ToFSurfaceSource: The generated surface of the 3d points */ virtual void GenerateData(); /** * \brief Create an output for each input * * This Method sets the number of outputs to the number of inputs * and creates missing outputs objects. * \warning any additional outputs that exist before the method is called are deleted */ void CreateOutputsForAllInputs(); std::vector m_Subset; ///< If this subset is specified only the contained indizes are converted to cartesian coordinates mitk::CameraIntrinsics::Pointer m_CameraIntrinsics; ///< Member holding the intrinsic parameters needed for PointSet calculation ToFProcessingCommon::ToFPoint2D m_InterPixelDistance; ///< distance in mm between two adjacent pixels on the ToF camera chip bool m_ReconstructionMode; ///< true = Reconstruction without interpixeldistance and with focal lengths in pixel units. false = Reconstruction with interpixeldistance and with focal length in mm. }; } //END mitk namespace #endif diff --git a/Modules/ToFProcessing/mitkToFProcessingCommon.h b/Modules/ToFProcessing/mitkToFProcessingCommon.h index c0ec21d5a2..d2ae785fe9 100644 --- a/Modules/ToFProcessing/mitkToFProcessingCommon.h +++ b/Modules/ToFProcessing/mitkToFProcessingCommon.h @@ -1,267 +1,267 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 MITKTOFPROCESSINGCOMMON_H #define MITKTOFPROCESSINGCOMMON_H #include "mitkToFProcessingExports.h" #include "mitkVector.h" #include namespace mitk { /** * @brief Helper class providing functions which are useful for multiple usage * * Currently the following methods are provided: *
    *
  • Conversion from 2D image coordinates to 3D world coordinates (IndexToCartesianCoordinates()) *
  • Conversion from 3D world coordinates to 2D image coordinates (CartesianToIndexCoordinates()) *
* The coordinate conversion follows the model of a common pinhole camera where the origin of the camera * coordinate system (world coordinates) is at the pinhole * \image html ../Modules/ToFProcessing/Documentation/PinholeCameraModel.png * The definition of the image plane and its coordinate systems (pixel and mm) is depicted in the following image * \image html ../Modules/ToFProcessing/Documentation/ImagePlane.png * @ingroup ToFProcessing */ class mitkToFProcessing_EXPORT ToFProcessingCommon { public: typedef double ToFScalarType; typedef itk::Point ToFPoint2D; typedef itk::Point ToFPoint3D; typedef itk::Vector ToFVector2D; typedef itk::Vector ToFVector3D; /*! \brief Convert index based distances to cartesian coordinates \param i index in x direction of image plane \param j index in y direction of image plane \param distance distance value at given index in mm \param focalLengthX focal length of optical system in pixel units in x-direction (mostly obtained from camera calibration) \param focalLengthY focal length of optical system in pixel units in y-direction (mostly obtained from camera calibration) \param principalPointX x coordinate of principal point on image plane in pixel \param principalPointY y coordinate of principal point on image plane in pixel \return cartesian coordinates for current index will be written here */ static ToFPoint3D IndexToCartesianCoordinates(unsigned int i, unsigned int j, ToFScalarType distance, ToFScalarType focalLengthX, ToFScalarType focalLengthY, ToFScalarType principalPointX, ToFScalarType principalPointY); /*! \brief Convert index based distances to cartesian coordinates \param i index in x direction of image plane \param j index in y direction of image plane \param distance distance value at given index in mm \param focalLength focal length of optical system in pixel units (mostly obtained from camera calibration) \param principalPoint coordinates of principal point on image plane in pixel \return cartesian coordinates for current index will be written here */ inline static ToFPoint3D IndexToCartesianCoordinates(unsigned int i, unsigned int j, ToFScalarType distance, ToFPoint2D focalLength, ToFPoint2D principalPoint) { return IndexToCartesianCoordinates(i,j,distance,focalLength[0],focalLength[1],principalPoint[0],principalPoint[1]); } /*! \brief Convert index based distances to cartesian coordinates \param index index coordinates \param distance distance value at given index in mm \param focalLength focal length of optical system in pixel units (mostly obtained from camera calibration) \param principalPoint coordinates of principal point on image plane in pixel \return cartesian coordinates for current index will be written here */ inline static ToFPoint3D IndexToCartesianCoordinates(mitk::Index3D index, ToFScalarType distance, ToFPoint2D focalLength, ToFPoint2D principalPoint) { return IndexToCartesianCoordinates(index[0],index[1],distance,focalLength[0],focalLength[1],principalPoint[0], principalPoint[1]); } /*! \brief Convenience method to convert index based distances to cartesian coordinates using array as input \param i index in x direction of image plane \param j index in y direction of image plane \param distance distance value at given index in mm \param focalLength focal length of optical system in pixel units (mostly obtained from camera calibration) \param principalPoint coordinates of principal point on image plane in pixel \return cartesian coordinates for current index will be written here */ inline static ToFPoint3D IndexToCartesianCoordinates(unsigned int i, unsigned int j, ToFScalarType distance, ToFScalarType focalLength[2], ToFScalarType principalPoint[2]) { return IndexToCartesianCoordinates(i,j,distance,focalLength[0],focalLength[1],principalPoint[0],principalPoint[1]); } /*! \brief Convert index based distances to cartesian coordinates \param i index in x direction of image plane \param j index in y direction of image plane \param distance distance value at given index in mm \param focalLength focal length of optical system in mm (mostly obtained from camera calibration) \param interPixelDistanceX distance in x direction between adjacent pixels in mm \param interPixelDistanceY distance in y direction between adjacent pixels in mm \param principalPointX x coordinate of principal point on image plane in pixel \param principalPointY y coordinate of principal point on image plane in pixel \return cartesian coordinates for current index will be written here */ static ToFPoint3D IndexToCartesianCoordinatesWithInterpixdist(unsigned int i, unsigned int j, ToFScalarType distance, ToFScalarType focalLength, ToFScalarType interPixelDistanceX, ToFScalarType interPixelDistanceY, ToFScalarType principalPointX, ToFScalarType principalPointY); /*! \brief Convert index based distances to cartesian coordinates \param i index in x direction of image plane \param j index in y direction of image plane \param distance distance value at given index in mm \param focalLength focal length of optical system in mm (mostly obtained from camera calibration) \param interPixelDistance distance between adjacent pixels in mm \param principalPoint coordinates of principal point on image plane in pixel \return cartesian coordinates for current index will be written here */ inline static ToFPoint3D IndexToCartesianCoordinatesWithInterpixdist(unsigned int i, unsigned int j, ToFScalarType distance, ToFScalarType focalLength, ToFPoint2D interPixelDistance, ToFPoint2D principalPoint) { return IndexToCartesianCoordinatesWithInterpixdist(i,j,distance,focalLength,interPixelDistance[0],interPixelDistance[1],principalPoint[0],principalPoint[1]); } /*! \brief Convert index based distances to cartesian coordinates \param index index coordinates \param distance distance value at given index in mm \param focalLength focal length of optical system (mostly obtained from camera calibration) \param interPixelDistance distance between adjacent pixels in mm for x and y direction \param principalPoint coordinates of principal point on image plane in pixel \return cartesian coordinates for current index will be written here */ inline static ToFPoint3D IndexToCartesianCoordinatesWithInterpixdist(mitk::Index3D index, ToFScalarType distance, ToFScalarType focalLength, ToFPoint2D interPixelDistance, ToFPoint2D principalPoint) { - return IndexToCartesianCoordinatesWithInterpixdist(index[0],index[1],distance,focalLength,interPixelDistance[0], interPixelDistance[0],principalPoint[0], principalPoint[0]); + return IndexToCartesianCoordinatesWithInterpixdist(index[0],index[1],distance,focalLength,interPixelDistance[0], interPixelDistance[1],principalPoint[0], principalPoint[1]); } /*! \brief Convenience method to convert index based distances to cartesian coordinates using array as input \param i index in x direction of image plane \param j index in y direction of image plane \param distance distance value at given index in mm \param focalLength focal length of optical system in mm (mostly obtained from camera calibration) \param interPixelDistance distance between adjacent pixels in mm \param principalPoint coordinates of principal point on image plane in pixel \return cartesian coordinates for current index will be written here */ inline static ToFPoint3D IndexToCartesianCoordinatesWithInterpixdist(unsigned int i, unsigned int j, ToFScalarType distance, ToFScalarType focalLength, ToFScalarType interPixelDistance[2], ToFScalarType principalPoint[2]) { return IndexToCartesianCoordinatesWithInterpixdist(i,j,distance,focalLength,interPixelDistance[0],interPixelDistance[1],principalPoint[0],principalPoint[1]); } /*! \brief Convert cartesian coordinates to index based distances \param cartesianPointX x coordinate of point (of a surface or point set) to convert in 3D coordinates \param cartesianPointY y coordinate of point (of a surface or point set) to convert in 3D coordinates \param cartesianPointZ z coordinate of point (of a surface or point set) to convert in 3D coordinates \param focalLengthX focal length of optical system in pixel units in x-direction (mostly obtained from camera calibration) \param focalLengthY focal length of optical system in pixel units in y-direction (mostly obtained from camera calibration) \param principalPointX x coordinate of principal point on image plane in pixel \param principalPointY y coordinate of principal point on image plane in pixel \param calculateDistance if this flag is set, the distance value is stored in the z position of the output otherwise z=0 \return a ToFPoint3D. (int)ToFPoint3D[0]+0.5 and (int)ToFPoint3D[0]+0.5 will return the x and y index coordinates. ToFPoint3D[2] contains the distance value */ static ToFPoint3D CartesianToIndexCoordinates(ToFScalarType cartesianPointX, ToFScalarType cartesianPointY,ToFScalarType cartesianPointZ, ToFScalarType focalLengthX, ToFScalarType focalLengthY, ToFScalarType principalPointX, ToFScalarType principalPointY, bool calculateDistance=true); /*! \brief Convenience method to convert cartesian coordinates to index based distances using arrays \param cartesianPoint point (of a surface or point set) to convert in 3D coordinates \param focalLength focal length of optical system in pixel units (mostly obtained from camera calibration) \param principalPoint coordinates of principal point on image plane in pixel \param calculateDistance if this flag is set, the distance value is stored in the z position of the output otherwise z=0 \return a ToFPoint3D. (int)ToFPoint3D[0]+0.5 and (int)ToFPoint3D[0]+0.5 will return the x and y index coordinates. ToFPoint3D[2] contains the distance value */ inline static ToFPoint3D CartesianToIndexCoordinates(ToFScalarType cartesianPoint[3], ToFScalarType focalLength[2], ToFScalarType principalPoint[2], bool calculateDistance=true) { return CartesianToIndexCoordinates(cartesianPoint[0],cartesianPoint[1],cartesianPoint[2],focalLength[0], focalLength[1], principalPoint[0],principalPoint[1],calculateDistance); } /*! \brief Convert cartesian coordinates to index based distances \param cartesianPoint point (of a surface or point set) to convert in 3D coordinates \param focalLength focal length of optical system in pixel units (mostly obtained from camera calibration) \param principalPoint coordinates of principal point on image plane in pixel \param calculateDistance if this flag is set, the distance value is stored in the z position of the output otherwise z=0 \return a ToFPoint3D. (int)ToFPoint3D[0]+0.5 and (int)ToFPoint3D[0]+0.5 will return the x and y index coordinates. ToFPoint3D[2] contains the distance value */ inline static ToFPoint3D CartesianToIndexCoordinates(ToFPoint3D cartesianPoint, ToFPoint2D focalLength, ToFPoint2D principalPoint, bool calculateDistance=true) { return CartesianToIndexCoordinates(cartesianPoint[0],cartesianPoint[1],cartesianPoint[2],focalLength[0], focalLength[1], principalPoint[0],principalPoint[1],calculateDistance); } /*! \brief Convert cartesian coordinates to index based distances \param cartesianPointX x coordinate of point (of a surface or point set) to convert in 3D coordinates \param cartesianPointY y coordinate of point (of a surface or point set) to convert in 3D coordinates \param cartesianPointZ z coordinate of point (of a surface or point set) to convert in 3D coordinates \param focalLength focal length of optical system in mm (mostly obtained from camera calibration) \param interPixelDistanceX distance in x direction between adjacent pixels in mm \param interPixelDistanceY distance in y direction between adjacent pixels in mm \param principalPointX x coordinate of principal point on image plane in pixel \param principalPointY y coordinate of principal point on image plane in pixel \param calculateDistance if this flag is set, the distance value is stored in the z position of the output otherwise z=0 \return a ToFPoint3D. (int)ToFPoint3D[0]+0.5 and (int)ToFPoint3D[0]+0.5 will return the x and y index coordinates. ToFPoint3D[2] contains the distance value */ static ToFPoint3D CartesianToIndexCoordinatesWithInterpixdist(ToFScalarType cartesianPointX, ToFScalarType cartesianPointY,ToFScalarType cartesianPointZ, ToFScalarType focalLength, ToFScalarType interPixelDistanceX, ToFScalarType interPixelDistanceY, ToFScalarType principalPointX, ToFScalarType principalPointY, bool calculateDistance=true); /*! \brief Convenience method to convert cartesian coordinates to index based distances using arrays \param cartesianPoint point (of a surface or point set) to convert in 3D coordinates \param focalLength focal length of optical system in mm (mostly obtained from camera calibration) \param interPixelDistance distance between adjacent pixels in mm for x and y direction \param principalPoint coordinates of principal point on image plane in pixel \param calculateDistance if this flag is set, the distance value is stored in the z position of the output otherwise z=0 \return a ToFPoint3D. (int)ToFPoint3D[0]+0.5 and (int)ToFPoint3D[0]+0.5 will return the x and y index coordinates. ToFPoint3D[2] contains the distance value */ inline static ToFPoint3D CartesianToIndexCoordinatesWithInterpixdist(ToFScalarType cartesianPoint[3], ToFScalarType focalLength, ToFScalarType interPixelDistance[2], ToFScalarType principalPoint[2], bool calculateDistance=true) { return CartesianToIndexCoordinatesWithInterpixdist(cartesianPoint[0],cartesianPoint[1],cartesianPoint[2],focalLength, interPixelDistance[0],interPixelDistance[1],principalPoint[0],principalPoint[1],calculateDistance); } /*! \brief Convert cartesian coordinates to index based distances \param cartesianPoint point (of a surface or point set) to convert in 3D coordinates \param focalLength focal length of optical system in mm (mostly obtained from camera calibration) \param interPixelDistance distance between adjacent pixels in mm for x and y direction \param principalPoint coordinates of principal point on image plane in pixel \param calculateDistance if this flag is set, the distance value is stored in the z position of the output otherwise z=0 \return a ToFPoint3D. (int)ToFPoint3D[0]+0.5 and (int)ToFPoint3D[0]+0.5 will return the x and y index coordinates. ToFPoint3D[2] contains the distance value */ inline static ToFPoint3D CartesianToIndexCoordinatesWithInterpixdist(ToFPoint3D cartesianPoint, ToFScalarType focalLength, ToFPoint2D interPixelDistance, ToFPoint2D principalPoint, bool calculateDistance=true) { return CartesianToIndexCoordinatesWithInterpixdist(cartesianPoint[0],cartesianPoint[1],cartesianPoint[2],focalLength, interPixelDistance[0],interPixelDistance[1],principalPoint[0],principalPoint[1],calculateDistance); } }; } #endif diff --git a/Modules/ToFUI/Qmitk/QmitkToFConnectionWidget.cpp b/Modules/ToFUI/Qmitk/QmitkToFConnectionWidget.cpp index 0c9bb8caaf..88c056d68a 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFConnectionWidget.cpp +++ b/Modules/ToFUI/Qmitk/QmitkToFConnectionWidget.cpp @@ -1,344 +1,345 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 #include #include #include //mitk headers #include "mitkToFConfig.h" #include "mitkToFCameraPMDCamCubeDevice.h" #include "mitkToFCameraPMDRawDataCamCubeDevice.h" #include "mitkToFCameraPMDCamBoardDevice.h" #include "mitkToFCameraPMDRawDataCamBoardDevice.h" #include "mitkToFCameraPMDO3Device.h" #include "mitkToFCameraPMDPlayerDevice.h" #include "mitkToFCameraPMDMITKPlayerDevice.h" #include "mitkToFCameraMITKPlayerDevice.h" #include "mitkToFCameraMESASR4000Device.h" #include "mitkKinectDevice.h" //itk headers #include const std::string QmitkToFConnectionWidget::VIEW_ID = "org.mitk.views.qmitktofconnectionwidget"; QmitkToFConnectionWidget::QmitkToFConnectionWidget(QWidget* parent, Qt::WindowFlags f): QWidget(parent, f) { this->m_IntegrationTime = 0; this->m_ModulationFrequency = 0; this->m_ToFImageGrabber = mitk::ToFImageGrabber::New(); m_Controls = NULL; CreateQtPartControl(this); } QmitkToFConnectionWidget::~QmitkToFConnectionWidget() { } void QmitkToFConnectionWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkToFConnectionWidgetControls; m_Controls->setupUi(parent); this->CreateConnections(); // set available cameras to combo box QString string(MITK_TOF_CAMERAS); string.replace(";"," "); QStringList list = string.split(","); m_Controls->m_SelectCameraCombobox->addItems(list); ShowParameterWidget(); } } void QmitkToFConnectionWidget::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->m_ConnectCameraButton), SIGNAL(clicked()),(QObject*) this, SLOT(OnConnectCamera()) ); connect( m_Controls->m_SelectCameraCombobox, SIGNAL(currentIndexChanged(const QString)), this, SLOT(OnSelectCamera(const QString)) ); connect( m_Controls->m_SelectCameraCombobox, SIGNAL(activated(const QString)), this, SLOT(OnSelectCamera(const QString)) ); connect( m_Controls->m_SelectCameraCombobox, SIGNAL(activated(const QString)), this, SIGNAL(ToFCameraSelected(const QString)) ); } } void QmitkToFConnectionWidget::ShowParameterWidget() { QString selectedCamera = m_Controls->m_SelectCameraCombobox->currentText(); this->OnSelectCamera(selectedCamera); } mitk::ToFImageGrabber* QmitkToFConnectionWidget::GetToFImageGrabber() { return m_ToFImageGrabber; } void QmitkToFConnectionWidget::OnSelectCamera(const QString selectedCamera) { if ((selectedCamera == "PMD CamCube 2.0/3.0")||(selectedCamera == "PMD CamBoard")||(selectedCamera=="PMD O3D")|| (selectedCamera=="PMD CamBoardRaw")||(selectedCamera=="PMD CamCubeRaw 2.0/3.0") ) { + this->HideAllParameterWidgets(); this->m_Controls->m_PMDParameterWidget->show(); - this->m_Controls->m_MESAParameterWidget->hide(); - this->m_Controls->m_KinectParameterWidget->hide(); } else if (selectedCamera=="MESA Swissranger 4000") { - this->m_Controls->m_PMDParameterWidget->hide(); + this->HideAllParameterWidgets(); this->m_Controls->m_MESAParameterWidget->show(); - this->m_Controls->m_KinectParameterWidget->hide(); } else if (selectedCamera=="Microsoft Kinect") { - this->m_Controls->m_PMDParameterWidget->hide(); - this->m_Controls->m_MESAParameterWidget->hide(); + this->HideAllParameterWidgets(); this->m_Controls->m_KinectParameterWidget->show(); } else { - this->m_Controls->m_PMDParameterWidget->hide(); - this->m_Controls->m_MESAParameterWidget->hide(); - this->m_Controls->m_KinectParameterWidget->hide(); + this->HideAllParameterWidgets(); } } +void QmitkToFConnectionWidget::HideAllParameterWidgets() +{ + this->m_Controls->m_PMDParameterWidget->hide(); + this->m_Controls->m_MESAParameterWidget->hide(); + this->m_Controls->m_KinectParameterWidget->hide(); +} + void QmitkToFConnectionWidget::OnConnectCamera() { bool playerMode = false; if (m_Controls->m_ConnectCameraButton->text()=="Connect") { //reset the status of the GUI buttons m_Controls->m_ConnectCameraButton->setEnabled(false); m_Controls->m_SelectCameraCombobox->setEnabled(false); //repaint the widget this->repaint(); QString tmpFileName(""); QString fileFilter(""); //select the camera to connect with QString selectedCamera = m_Controls->m_SelectCameraCombobox->currentText(); if (selectedCamera == "PMD CamCube 2.0/3.0") { //PMD CamCube this->m_ToFImageGrabber->SetCameraDevice(mitk::ToFCameraPMDCamCubeDevice::New()); } else if (selectedCamera == "PMD CamCubeRaw 2.0/3.0") { //PMD CamCube this->m_ToFImageGrabber->SetCameraDevice(mitk::ToFCameraPMDRawDataCamCubeDevice::New()); } else if (selectedCamera == "PMD CamBoard") { //PMD CamBoard this->m_ToFImageGrabber->SetCameraDevice(mitk::ToFCameraPMDCamBoardDevice::New()); } else if (selectedCamera == "PMD CamBoardRaw") { //PMD CamBoard this->m_ToFImageGrabber->SetCameraDevice(mitk::ToFCameraPMDRawDataCamBoardDevice::New()); } else if (selectedCamera == "PMD O3D") {//PMD O3 this->m_ToFImageGrabber->SetCameraDevice(mitk::ToFCameraPMDO3Device::New()); } else if (selectedCamera == "MESA Swissranger 4000") {//MESA SR4000 this->m_ToFImageGrabber->SetCameraDevice(mitk::ToFCameraMESASR4000Device::New()); } else if (selectedCamera == "Microsoft Kinect") {//KINECT this->m_ToFImageGrabber->SetCameraDevice(mitk::KinectDevice::New()); } else if (selectedCamera == "PMD Player") {//PMD player playerMode = true; fileFilter.append("PMD Files (*.pmd)"); this->m_ToFImageGrabber->SetCameraDevice(mitk::ToFCameraPMDPlayerDevice::New()); } else if (selectedCamera == "PMD Raw Data Player") {//PMD MITK player playerMode = true; fileFilter.append("NRRD Images (*.nrrd);;PIC Images - deprecated (*.pic)"); this->m_ToFImageGrabber->SetCameraDevice(mitk::ToFCameraPMDRawDataDevice::New()); } else if (selectedCamera == "MITK Player") {//MITK player playerMode = true; fileFilter.append("NRRD Images (*.nrrd);;PIC Images - deprecated (*.pic)"); this->m_ToFImageGrabber->SetCameraDevice(mitk::ToFCameraMITKPlayerDevice::New()); } // if a player was selected ... if (playerMode) { //... open a QFileDialog to chose the corresponding file from the disc tmpFileName = QFileDialog::getOpenFileName(NULL, "Play Image From...", "", fileFilter); if (tmpFileName.isEmpty()) { m_Controls->m_ConnectCameraButton->setChecked(false); m_Controls->m_ConnectCameraButton->setEnabled(true); m_Controls->m_SelectCameraCombobox->setEnabled(true); this->OnSelectCamera(m_Controls->m_SelectCameraCombobox->currentText()); QMessageBox::information( this, "Template functionality", "Please select a valid image before starting some action."); return; } if(selectedCamera == "PMD Player") { //set the PMD file name this->m_ToFImageGrabber->SetStringProperty("PMDFileName", tmpFileName.toStdString().c_str() ); } if (selectedCamera == "PMD Raw Data Player" || selectedCamera == "MITK Player") { std::string msg = ""; try { //get 3 corresponding file names std::string dir = itksys::SystemTools::GetFilenamePath( tmpFileName.toStdString() ); std::string baseFilename = itksys::SystemTools::GetFilenameWithoutLastExtension( tmpFileName.toStdString() ); std::string extension = itksys::SystemTools::GetFilenameLastExtension( tmpFileName.toStdString() ); if (extension != ".pic" && extension != ".nrrd") { msg = msg + "Invalid file format, please select a \".nrrd\"-file"; throw std::logic_error(msg.c_str()); } int found = baseFilename.rfind("_DistanceImage"); if (found == std::string::npos) { found = baseFilename.rfind("_AmplitudeImage"); } if (found == std::string::npos) { found = baseFilename.rfind("_IntensityImage"); } if (found == std::string::npos) { found = baseFilename.rfind("_RGBImage"); } if (found == std::string::npos) { msg = msg + "Input file name must end with \"_DistanceImage\", \"_AmplitudeImage\", \"_IntensityImage\" or \"_RGBImage\"!"; throw std::logic_error(msg.c_str()); } std::string baseFilenamePrefix = baseFilename.substr(0,found); std::string distanceImageFileName = dir + "/" + baseFilenamePrefix + "_DistanceImage" + extension; std::string amplitudeImageFileName = dir + "/" + baseFilenamePrefix + "_AmplitudeImage" + extension; std::string intensityImageFileName = dir + "/" + baseFilenamePrefix + "_IntensityImage" + extension; std::string rgbImageFileName = dir + "/" + baseFilenamePrefix + "_RGBImage" + extension; if (!itksys::SystemTools::FileExists(distanceImageFileName.c_str(), true)) { this->m_ToFImageGrabber->SetStringProperty("DistanceImageFileName", ""); } else { this->m_ToFImageGrabber->SetStringProperty("DistanceImageFileName", distanceImageFileName.c_str()); } if (!itksys::SystemTools::FileExists(amplitudeImageFileName.c_str(), true)) { - this->m_ToFImageGrabber->SetStringProperty("AmplitudeImageFileName", ""); } else { this->m_ToFImageGrabber->SetStringProperty("AmplitudeImageFileName", amplitudeImageFileName.c_str()); } if (!itksys::SystemTools::FileExists(intensityImageFileName.c_str(), true)) { this->m_ToFImageGrabber->SetStringProperty("IntensityImageFileName", ""); } else { this->m_ToFImageGrabber->SetStringProperty("IntensityImageFileName", intensityImageFileName.c_str()); } if (!itksys::SystemTools::FileExists(rgbImageFileName.c_str(), true)) { this->m_ToFImageGrabber->SetStringProperty("RGBImageFileName", ""); } else { this->m_ToFImageGrabber->SetStringProperty("RGBImageFileName", rgbImageFileName.c_str()); } } catch (std::exception &e) { MITK_ERROR << e.what(); QMessageBox::critical( this, "Error", e.what() ); m_Controls->m_ConnectCameraButton->setChecked(false); m_Controls->m_ConnectCameraButton->setEnabled(true); m_Controls->m_SelectCameraCombobox->setEnabled(true); this->OnSelectCamera(m_Controls->m_SelectCameraCombobox->currentText()); return; } } - - } - - this->m_Controls->m_PMDParameterWidget->SetToFImageGrabber(this->m_ToFImageGrabber); - this->m_Controls->m_MESAParameterWidget->SetToFImageGrabber(this->m_ToFImageGrabber); - this->m_Controls->m_KinectParameterWidget->SetToFImageGrabber(this->m_ToFImageGrabber); - - if ((selectedCamera == "PMD CamCube 2.0/3.0")||(selectedCamera == "PMD CamBoard")||(selectedCamera=="PMD O3D")|| - (selectedCamera=="PMD CamBoardRaw")||(selectedCamera=="PMD CamCubeRaw 2.0/3.0")) - { - this->m_Controls->m_PMDParameterWidget->ActivateAllParameters(); - } - else if (selectedCamera=="MESA Swissranger 4000") - { - this->m_Controls->m_MESAParameterWidget->ActivateAllParameters(); - } - else if (selectedCamera=="Microsoft Kinect") - { - this->m_Controls->m_KinectParameterWidget->ActivateAllParameters(); } m_Controls->m_ConnectCameraButton->setText("Disconnect"); //if a connection could be established if (this->m_ToFImageGrabber->ConnectCamera()) { + this->m_Controls->m_PMDParameterWidget->SetToFImageGrabber(this->m_ToFImageGrabber); + this->m_Controls->m_MESAParameterWidget->SetToFImageGrabber(this->m_ToFImageGrabber); + this->m_Controls->m_KinectParameterWidget->SetToFImageGrabber(this->m_ToFImageGrabber); + + if ((selectedCamera == "PMD CamCube 2.0/3.0") || (selectedCamera == "PMD CamBoard") || + (selectedCamera== "PMD O3D") || (selectedCamera== "PMD CamBoardRaw") || + (selectedCamera== "PMD CamCubeRaw 2.0/3.0")) + { + this->m_Controls->m_PMDParameterWidget->ActivateAllParameters(); + } + else if (selectedCamera=="MESA Swissranger 4000") + { + this->m_Controls->m_MESAParameterWidget->ActivateAllParameters(); + } + else if (selectedCamera=="Microsoft Kinect") + { + this->m_Controls->m_KinectParameterWidget->ActivateAllParameters(); + } + // send connect signal to the caller functionality emit ToFCameraConnected(); } else { QMessageBox::critical( this, "Error", "Connection failed. Check if you have installed the latest driver for your system." ); m_Controls->m_ConnectCameraButton->setChecked(false); m_Controls->m_ConnectCameraButton->setEnabled(true); m_Controls->m_SelectCameraCombobox->setEnabled(true); this->OnSelectCamera(m_Controls->m_SelectCameraCombobox->currentText()); return; } m_Controls->m_ConnectCameraButton->setEnabled(true); } else if (m_Controls->m_ConnectCameraButton->text()=="Disconnect") { this->m_ToFImageGrabber->StopCamera(); this->m_ToFImageGrabber->DisconnectCamera(); m_Controls->m_ConnectCameraButton->setText("Connect"); m_Controls->m_SelectCameraCombobox->setEnabled(true); this->OnSelectCamera(m_Controls->m_SelectCameraCombobox->currentText()); // send disconnect signal to the caller functionality emit ToFCameraDisconnected(); } } diff --git a/Modules/ToFUI/Qmitk/QmitkToFConnectionWidget.h b/Modules/ToFUI/Qmitk/QmitkToFConnectionWidget.h index 44a546bb21..6aa11a382e 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFConnectionWidget.h +++ b/Modules/ToFUI/Qmitk/QmitkToFConnectionWidget.h @@ -1,104 +1,106 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 _QMITKTOFCONNECTIONWIDGET_H_INCLUDED #define _QMITKTOFCONNECTIONWIDGET_H_INCLUDED #include "mitkTOFUIExports.h" #include "ui_QmitkToFConnectionWidgetControls.h" //QT headers #include //mitk headers #include "mitkToFImageGrabber.h" /** * @brief Widget allowing to connect to different ToF / range cameras (located in module ToFProcessing) * * The widget basically allows to connect/disconnect to different ToF cameras * * @ingroup ToFUI */ class mitkTOFUI_EXPORT QmitkToFConnectionWidget :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; QmitkToFConnectionWidget(QWidget* p = 0, Qt::WindowFlags f1 = 0); virtual ~QmitkToFConnectionWidget(); /* @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 returns the ToFImageGrabber which was configured after selecting a camera / player \return ToFImageGrabber currently used by the widget */ mitk::ToFImageGrabber* GetToFImageGrabber(); signals: /*! \brief This signal is sent if the user has connected the TOF camera. * The ToFImageGrabber is now availiable if the method GetToFImageGrabber() is called. */ void ToFCameraConnected(); /*! \brief This signal is sent if the user has disconnect the TOF camera. */ void ToFCameraDisconnected(); /*! \brief signal that is emitted when a ToF camera is selected in the combo box */ void ToFCameraSelected(const QString selectedText); + void ChangeCoronalWindowSelection(int); + protected slots: /*! \brief slot called when the "Connect Camera" button was pressed * According to the selection in the camera combo box, the widget provides * the desired instance of the ToFImageGrabber */ void OnConnectCamera(); /*! \brief slot updating the GUI elements after the selection of the camera combo box has changed */ void OnSelectCamera(const QString selectedCamera); protected: Ui::QmitkToFConnectionWidgetControls* m_Controls; ///< member holding the UI elements of this widget mitk::ToFImageGrabber::Pointer m_ToFImageGrabber; ///< member holding the current ToFImageGrabber int m_IntegrationTime; ///< member for the current integration time of the ToF device int m_ModulationFrequency; ///< member for the current modulation frequency of the ToF device private: void ShowParameterWidget(); - + void HideAllParameterWidgets(); }; #endif // _QMITKTOFCONNECTIONWIDGET_H_INCLUDED diff --git a/Modules/ToFUI/Qmitk/QmitkToFConnectionWidgetControls.ui b/Modules/ToFUI/Qmitk/QmitkToFConnectionWidgetControls.ui index 6110dd201b..ea73fb20f4 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFConnectionWidgetControls.ui +++ b/Modules/ToFUI/Qmitk/QmitkToFConnectionWidgetControls.ui @@ -1,142 +1,142 @@ QmitkToFConnectionWidgetControls 0 0 405 - 139 + 307 0 0 QmitkToFConnection 11 ToF camera connection 0 0 0 50 10 -1 7 QComboBox::InsertAtBottom QComboBox::AdjustToContents true 0 50 10 Connect to camera Connect :/images/powerRed.png :/images/powerGreen.png:/images/powerRed.png 30 30 true QmitkToFPMDParameterWidget QWidget
QmitkToFPMDParameterWidget.h
1
QmitkToFMESAParameterWidget QWidget
QmitkToFMESAParameterWidget.h
1
QmitkKinectParameterWidget QWidget
QmitkKinectParameterWidget.h
1
diff --git a/Modules/ToFUI/Qmitk/QmitkToFPMDParameterWidget.cpp b/Modules/ToFUI/Qmitk/QmitkToFPMDParameterWidget.cpp index 4129706207..da40733213 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFPMDParameterWidget.cpp +++ b/Modules/ToFUI/Qmitk/QmitkToFPMDParameterWidget.cpp @@ -1,137 +1,147 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 #include #include #include //itk headers #include const std::string QmitkToFPMDParameterWidget::VIEW_ID = "org.mitk.views.qmitktofpmdparameterwidget"; QmitkToFPMDParameterWidget::QmitkToFPMDParameterWidget(QWidget* parent, Qt::WindowFlags f): QWidget(parent, f) { this->m_IntegrationTime = 0; this->m_ModulationFrequency = 0; this->m_ToFImageGrabber = NULL; m_Controls = NULL; CreateQtPartControl(this); } QmitkToFPMDParameterWidget::~QmitkToFPMDParameterWidget() { } void QmitkToFPMDParameterWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkToFPMDParameterWidgetControls; m_Controls->setupUi(parent); this->CreateConnections(); } } void QmitkToFPMDParameterWidget::CreateConnections() { if ( m_Controls ) { connect( m_Controls->m_IntegrationTimeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnChangeIntegrationTimeSpinBox(int)) ); connect( m_Controls->m_ModulationFrequencySpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnChangeModulationFrequencySpinBox(int)) ); } } mitk::ToFImageGrabber* QmitkToFPMDParameterWidget::GetToFImageGrabber() { return this->m_ToFImageGrabber; } void QmitkToFPMDParameterWidget::SetToFImageGrabber(mitk::ToFImageGrabber* aToFImageGrabber) { this->m_ToFImageGrabber = aToFImageGrabber; } void QmitkToFPMDParameterWidget::ActivateAllParameters() { this->m_IntegrationTime = m_Controls->m_IntegrationTimeSpinBox->value(); this->m_IntegrationTime = this->m_ToFImageGrabber->SetIntegrationTime(this->m_IntegrationTime); this->m_ModulationFrequency = m_Controls->m_ModulationFrequencySpinBox->value(); this->m_ModulationFrequency = this->m_ToFImageGrabber->SetModulationFrequency(this->m_ModulationFrequency); //set the PMD calibration according to the check boxes bool boolValue = false; boolValue = m_Controls->m_FPNCalibCB->isChecked(); this->m_ToFImageGrabber->SetBoolProperty("SetFPNCalibration", boolValue); boolValue = m_Controls->m_FPPNCalibCB->isChecked(); this->m_ToFImageGrabber->SetBoolProperty("SetFPPNCalibration", boolValue); boolValue = m_Controls->m_LinearityCalibCB->isChecked(); this->m_ToFImageGrabber->SetBoolProperty("SetLinearityCalibration", boolValue); boolValue = m_Controls->m_LensCorrection->isChecked(); this->m_ToFImageGrabber->SetBoolProperty("SetLensCalibration", boolValue); boolValue = m_Controls->m_ExposureModeCB->isChecked(); this->m_ToFImageGrabber->SetBoolProperty("SetExposureMode", boolValue); //reset the GUI elements - m_Controls->m_IntegrationTimeSpinBox->setValue(this->m_IntegrationTime); - m_Controls->m_ModulationFrequencySpinBox->setValue(this->m_ModulationFrequency); + m_Controls->m_IntegrationTimeSpinBox->setValue(this->m_ToFImageGrabber->GetIntegrationTime()); + m_Controls->m_ModulationFrequencySpinBox->setValue(this->m_ToFImageGrabber->GetModulationFrequency()); } void QmitkToFPMDParameterWidget::OnChangeIntegrationTimeSpinBox(int value) { if (this->m_ToFImageGrabber != NULL) { // stop camera if active bool active = m_ToFImageGrabber->IsCameraActive(); if (active) { m_ToFImageGrabber->StopCamera(); } this->m_IntegrationTime = m_Controls->m_IntegrationTimeSpinBox->value(); - this->m_IntegrationTime = this->m_ToFImageGrabber->SetIntegrationTime(this->m_IntegrationTime); + int validIntegrationTime = this->m_ToFImageGrabber->SetIntegrationTime(this->m_IntegrationTime); + if(validIntegrationTime != m_IntegrationTime) + { + this->m_Controls->m_IntegrationTimeSpinBox->setValue(validIntegrationTime); + this->m_IntegrationTime = validIntegrationTime; + } if (active) { m_ToFImageGrabber->StartCamera(); } } } void QmitkToFPMDParameterWidget::OnChangeModulationFrequencySpinBox(int value) { if (this->m_ToFImageGrabber != NULL) { // stop camera if active bool active = m_ToFImageGrabber->IsCameraActive(); if (active) { m_ToFImageGrabber->StopCamera(); } this->m_ModulationFrequency = m_Controls->m_ModulationFrequencySpinBox->value(); - this->m_ModulationFrequency = this->m_ToFImageGrabber->SetModulationFrequency(this->m_ModulationFrequency); + int validMFrequency = this->m_ToFImageGrabber->SetModulationFrequency(this->m_ModulationFrequency); + if(validMFrequency != m_ModulationFrequency) + { + this->m_Controls->m_ModulationFrequencySpinBox->setValue(validMFrequency); + this->m_ModulationFrequency = validMFrequency; + } if (active) { m_ToFImageGrabber->StartCamera(); } } } diff --git a/Modules/ToFUI/Qmitk/QmitkToFPMDParameterWidgetControls.ui b/Modules/ToFUI/Qmitk/QmitkToFPMDParameterWidgetControls.ui index 6344a5f536..ee53195720 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFPMDParameterWidgetControls.ui +++ b/Modules/ToFUI/Qmitk/QmitkToFPMDParameterWidgetControls.ui @@ -1,198 +1,198 @@ QmitkToFPMDParameterWidgetControls 0 0 425 130 0 0 QmitkToFPMDParameter 0 0 PMD Camera Parameter 10 Integr. Time/μs 0 0 60 23 0 50000 100 500 10 Mod.Freq./MHz 0 0 18 - 40 + 100 1 20 0 0 Calibration Parameter FPN true true FPPN true true Linearity false true 8 LensCorrection true ExposureMode false diff --git a/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.cpp b/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.cpp index 5edd1199bd..f363df4062 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.cpp +++ b/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.cpp @@ -1,357 +1,429 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) -Copyright (c) German Cancer Research Center, +Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR +This software is distributed WITHOUT ANY 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 "QmitkToFPointSetWidget.h" #include #include #include #include const std::string QmitkToFPointSetWidget::VIEW_ID = "org.mitk.views.qmitktofpointsetwidget"; QmitkToFPointSetWidget::QmitkToFPointSetWidget(QWidget* parent, Qt::WindowFlags f): QWidget(parent, f) +, m_DataStorage(NULL) +, m_DistanceImage(NULL) , m_CameraIntrinsics(NULL) , m_VtkTextActor(NULL) , m_ForegroundRenderer1(NULL) , m_ForegroundRenderer2(NULL) , m_ForegroundRenderer3(NULL) , m_RenderWindow1(NULL) , m_RenderWindow2(NULL) , m_RenderWindow3(NULL) , m_MeasurementPointSet2D(NULL) , m_MeasurementPointSet3DNode(NULL) , m_PointSet2D(NULL) , m_PointSet3DNode(NULL) , m_PointSetInteractor(NULL) , m_MeasurementPointSetInteractor(NULL) , m_MeasurementPointSetChangedObserverTag(0) , m_PointSetChangedObserverTag(0) , m_WindowHeight(0) { m_Controls = NULL; CreateQtPartControl(this); } QmitkToFPointSetWidget::~QmitkToFPointSetWidget() { - if (m_MeasurementPointSet2D.IsNotNull()) - { - m_MeasurementPointSet2D->RemoveObserver(m_MeasurementPointSetChangedObserverTag); - } - if (m_PointSet2D.IsNotNull()) - { - m_PointSet2D->RemoveObserver(m_PointSetChangedObserverTag); - } -// if (m_MultiWidget) -// { - if (m_ForegroundRenderer1&&m_RenderWindow1) - { - if (mitk::VtkLayerController::GetInstance(m_RenderWindow1)) - { - mitk::VtkLayerController::GetInstance(m_RenderWindow1)->RemoveRenderer(m_ForegroundRenderer1); - } - } - if (m_ForegroundRenderer2&&m_RenderWindow2) - { - if (mitk::VtkLayerController::GetInstance(m_RenderWindow2)) - { - mitk::VtkLayerController::GetInstance(m_RenderWindow2)->RemoveRenderer(m_ForegroundRenderer2); - } - } - if (m_ForegroundRenderer3&&m_RenderWindow3) - { - if (mitk::VtkLayerController::GetInstance(m_RenderWindow3)) - { - mitk::VtkLayerController::GetInstance(m_RenderWindow3)->RemoveRenderer(m_ForegroundRenderer3); - } - } -// } - if (mitk::RenderingManager::GetInstance()) - { - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - } + this->CleanUpWidget(); } void QmitkToFPointSetWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkToFPointSetWidgetControls; m_Controls->setupUi(parent); this->CreateConnections(); } } void QmitkToFPointSetWidget::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->measureButton), SIGNAL(clicked()),(QObject*) this, SLOT(OnMeasurement()) ); connect( (QObject*)(m_Controls->pointSetButton), SIGNAL(clicked()),(QObject*) this, SLOT(OnPointSet()) ); } } -void QmitkToFPointSetWidget::InitializeWidget(QHash renderWindowHashMap, mitk::DataStorage::Pointer dataStorage, mitk::Image::Pointer distanceImage) +void QmitkToFPointSetWidget::InitializeWidget(QHash renderWindowHashMap, mitk::DataStorage::Pointer dataStorage, mitk::CameraIntrinsics::Pointer cameraIntrinsics) { // initialize members -// m_RenderWindowPart = renderWindowPart; - m_RenderWindow1 = renderWindowHashMap.value("transversal")->GetRenderWindow(); - m_RenderWindow2 = renderWindowHashMap.value("sagittal")->GetRenderWindow(); - m_RenderWindow3 = renderWindowHashMap.value("coronal")->GetRenderWindow(); - m_RenderWindow4 = renderWindowHashMap.value("3d")->GetRenderWindow(); - m_DistanceImage = distanceImage; + m_CameraIntrinsics = cameraIntrinsics; + m_DataStorage = dataStorage; + // m_RenderWindowPart = renderWindowPart; + m_RenderWindow1 = renderWindowHashMap.value("axial")->GetRenderWindow(); + m_RenderWindow2 = renderWindowHashMap.value("sagittal")->GetRenderWindow(); + m_RenderWindow3 = renderWindowHashMap.value("coronal")->GetRenderWindow(); + m_RenderWindow4 = renderWindowHashMap.value("3d")->GetRenderWindow(); if ((m_RenderWindow1 != NULL) && (m_RenderWindow2 != NULL) && (m_RenderWindow3 != NULL) && (m_RenderWindow4 != NULL) && (dataStorage.IsNotNull())) { // enable buttons m_Controls->pointSetButton->setEnabled(true); m_Controls->measureButton->setEnabled(true); // initialize overlays this->m_VtkTextActor = vtkSmartPointer::New(); this->m_VtkTextActor->SetInput("Choose measurement points with SHIFT+Click"); - m_WindowHeight = renderWindowHashMap.value("transversal")->GetRenderer()->GetSizeY(); + m_WindowHeight = renderWindowHashMap.value("axial")->GetRenderer()->GetSizeY(); this->m_VtkTextActor->SetDisplayPosition(10,m_WindowHeight-30); this->m_VtkTextActor->GetTextProperty()->SetFontSize(16); -// this->m_VtkTextActor->GetTextProperty()->SetColor(1,0,0); + // this->m_VtkTextActor->GetTextProperty()->SetColor(1,0,0); this->m_VtkTextActor->GetTextProperty()->BoldOn(); this->m_VtkTextActor->SetVisibility(0); - this->m_ForegroundRenderer1 = vtkSmartPointer::New(); - this->m_ForegroundRenderer1->AddActor(m_VtkTextActor); - mitk::VtkLayerController::GetInstance(m_RenderWindow1)->InsertForegroundRenderer(m_ForegroundRenderer1,true); - this->m_ForegroundRenderer2 = vtkSmartPointer::New(); - this->m_ForegroundRenderer2->AddActor(m_VtkTextActor); - mitk::VtkLayerController::GetInstance(m_RenderWindow2)->InsertForegroundRenderer(m_ForegroundRenderer2,true); - this->m_ForegroundRenderer3 =vtkSmartPointer::New(); - this->m_ForegroundRenderer3->AddActor(m_VtkTextActor); - mitk::VtkLayerController::GetInstance(m_RenderWindow3)->InsertForegroundRenderer(m_ForegroundRenderer3,true); + if (m_ForegroundRenderer1==NULL) + { + this->m_ForegroundRenderer1 = vtkSmartPointer::New(); + this->m_ForegroundRenderer1->AddActor(m_VtkTextActor); + mitk::VtkLayerController::GetInstance(m_RenderWindow1)->InsertForegroundRenderer(m_ForegroundRenderer1,true); + } + if (m_ForegroundRenderer2==NULL) + { + this->m_ForegroundRenderer2 = vtkSmartPointer::New(); + this->m_ForegroundRenderer2->AddActor(m_VtkTextActor); + mitk::VtkLayerController::GetInstance(m_RenderWindow2)->InsertForegroundRenderer(m_ForegroundRenderer2,true); + } + if (m_ForegroundRenderer3==NULL) + { + this->m_ForegroundRenderer3 =vtkSmartPointer::New(); + this->m_ForegroundRenderer3->AddActor(m_VtkTextActor); + mitk::VtkLayerController::GetInstance(m_RenderWindow3)->InsertForegroundRenderer(m_ForegroundRenderer3,true); + } + mitk::DataNode::Pointer measurementPointSet2DNode = dataStorage->GetNamedNode("Measurement PointSet 2D") ; + if(dataStorage->Exists(measurementPointSet2DNode)) + { + dataStorage->Remove(measurementPointSet2DNode); + } // initialize 2D measurement point set m_MeasurementPointSet2D = mitk::PointSet::New(); - mitk::DataNode::Pointer measurementNode2D = mitk::DataNode::New(); - measurementNode2D->SetName("Measurement PointSet 2D"); - measurementNode2D->SetBoolProperty("helper object",true); - measurementNode2D->SetBoolProperty("show contour",true); - measurementNode2D->SetVisibility(false, renderWindowHashMap.value("3d")->GetRenderer()); - measurementNode2D->SetData(m_MeasurementPointSet2D); - dataStorage->Add(measurementNode2D); - m_MeasurementPointSetInteractor = mitk::PointSetInteractor::New("pointsetinteractor",measurementNode2D,2); + measurementPointSet2DNode = mitk::DataNode::New(); + measurementPointSet2DNode->SetName("Measurement PointSet 2D"); + measurementPointSet2DNode->SetBoolProperty("helper object",true); + measurementPointSet2DNode->SetBoolProperty("show contour",true); + measurementPointSet2DNode->SetVisibility(false, renderWindowHashMap.value("3d")->GetRenderer()); + measurementPointSet2DNode->SetData(m_MeasurementPointSet2D); + dataStorage->Add(measurementPointSet2DNode); + m_MeasurementPointSetInteractor = mitk::PointSetInteractor::New("pointsetinteractor",measurementPointSet2DNode,2); // create observer for m_MeasurementPointSet2D itk::SimpleMemberCommand::Pointer measurementPointSetChangedCommand; measurementPointSetChangedCommand = itk::SimpleMemberCommand::New(); measurementPointSetChangedCommand->SetCallbackFunction(this, &QmitkToFPointSetWidget::MeasurementPointSetChanged); m_MeasurementPointSetChangedObserverTag = m_MeasurementPointSet2D->AddObserver(itk::ModifiedEvent(), measurementPointSetChangedCommand); // initialize 3D measurement PointSet + m_MeasurementPointSet3DNode = dataStorage->GetNamedNode("Measurement PointSet 3D"); + if(dataStorage->Exists(m_MeasurementPointSet3DNode)) + { + dataStorage->Remove(m_MeasurementPointSet3DNode); + } m_MeasurementPointSet3DNode = mitk::DataNode::New(); m_MeasurementPointSet3DNode->SetName("Measurement PointSet 3D"); m_MeasurementPointSet3DNode->SetBoolProperty("helper object",true); m_MeasurementPointSet3DNode->SetBoolProperty("show contour",true); m_MeasurementPointSet3DNode->SetFloatProperty("pointsize",5.0f); mitk::PointSet::Pointer measurementPointSet3D = mitk::PointSet::New(); m_MeasurementPointSet3DNode->SetData(measurementPointSet3D); dataStorage->Add(m_MeasurementPointSet3DNode); + // initialize PointSets - if(!dataStorage->Exists(dataStorage->GetNamedNode("ToF PointSet 2D"))) + mitk::DataNode::Pointer pointSet2DNode = dataStorage->GetNamedNode("ToF PointSet 2D") ; + if(dataStorage->Exists(pointSet2DNode)) { - m_PointSet2D = mitk::PointSet::New(); - mitk::DataNode::Pointer pointSet2DNode = mitk::DataNode::New(); - pointSet2DNode->SetName("ToF PointSet 2D"); - pointSet2DNode->SetVisibility(false, renderWindowHashMap.value("3d")->GetRenderer()); - pointSet2DNode->SetData(m_PointSet2D); - dataStorage->Add(pointSet2DNode); - m_PointSetInteractor = mitk::PointSetInteractor::New("pointsetinteractor",pointSet2DNode); + dataStorage->Remove(pointSet2DNode); } + m_PointSet2D = mitk::PointSet::New(); + pointSet2DNode = mitk::DataNode::New(); + pointSet2DNode->SetName("ToF PointSet 2D"); + pointSet2DNode->SetVisibility(false, renderWindowHashMap.value("3d")->GetRenderer()); + pointSet2DNode->SetData(m_PointSet2D); + dataStorage->Add(pointSet2DNode); + m_PointSetInteractor = mitk::PointSetInteractor::New("pointsetinteractor",pointSet2DNode); + // create observer for m_MeasurementPointSet2D itk::SimpleMemberCommand::Pointer pointSetChangedCommand; pointSetChangedCommand = itk::SimpleMemberCommand::New(); pointSetChangedCommand->SetCallbackFunction(this, &QmitkToFPointSetWidget::PointSetChanged); m_PointSetChangedObserverTag = m_PointSet2D->AddObserver(itk::ModifiedEvent(), pointSetChangedCommand); // initialize 3D point set - if(!dataStorage->Exists(dataStorage->GetNamedNode("ToF PointSet 3D"))) + mitk::DataNode::Pointer pointSet3DNode = dataStorage->GetNamedNode("ToF PointSet 3D"); + if(dataStorage->Exists(pointSet3DNode)) { - m_PointSet3DNode = mitk::DataNode::New(); - m_PointSet3DNode->SetName("ToF PointSet 3D"); - m_PointSet3DNode->SetFloatProperty("pointsize",5.0f); - mitk::PointSet::Pointer pointSet3D = mitk::PointSet::New(); - m_PointSet3DNode->SetData(pointSet3D); - dataStorage->Add(m_PointSet3DNode); + dataStorage->Remove(pointSet3DNode); } + m_PointSet3DNode = mitk::DataNode::New(); + m_PointSet3DNode->SetName("ToF PointSet 3D"); + m_PointSet3DNode->SetFloatProperty("pointsize",5.0f); + mitk::PointSet::Pointer pointSet3D = mitk::PointSet::New(); + m_PointSet3DNode->SetData(pointSet3D); + dataStorage->Add(m_PointSet3DNode); } } -void QmitkToFPointSetWidget::SetCameraIntrinsics(mitk::CameraIntrinsics::Pointer cameraIntrinsics) +void QmitkToFPointSetWidget::CleanUpWidget() { - m_CameraIntrinsics = cameraIntrinsics; + // toggle button state + if (m_Controls->measureButton->isChecked()) + { + m_Controls->measureButton->setChecked(false); + this->OnMeasurement(); + } + if (m_Controls->pointSetButton->isChecked()) + { + m_Controls->pointSetButton->setChecked(false); + this->OnMeasurement(); + } + // remove observer + if (m_MeasurementPointSet2D.IsNotNull()) + { + m_MeasurementPointSet2D->RemoveObserver(m_MeasurementPointSetChangedObserverTag); + } + if (m_PointSet2D.IsNotNull()) + { + m_PointSet2D->RemoveObserver(m_PointSetChangedObserverTag); + } +// if (m_DistanceImage.IsNotNull()) +// { +// m_DistanceImage->RemoveObserver(m_DistanceImageChangedObserverTag); +// } + // remove foreground renderer + if (m_ForegroundRenderer1&&m_RenderWindow1) + { + if (mitk::VtkLayerController::GetInstance(m_RenderWindow1)) + { + mitk::VtkLayerController::GetInstance(m_RenderWindow1)->RemoveRenderer(m_ForegroundRenderer1); + } + m_ForegroundRenderer1 = NULL; + } + if (m_ForegroundRenderer2&&m_RenderWindow2) + { + if (mitk::VtkLayerController::GetInstance(m_RenderWindow2)) + { + mitk::VtkLayerController::GetInstance(m_RenderWindow2)->RemoveRenderer(m_ForegroundRenderer2); + } + m_ForegroundRenderer2 = NULL; + } + if (m_ForegroundRenderer3&&m_RenderWindow3) + { + if (mitk::VtkLayerController::GetInstance(m_RenderWindow3)) + { + mitk::VtkLayerController::GetInstance(m_RenderWindow3)->RemoveRenderer(m_ForegroundRenderer3); + } + m_ForegroundRenderer3 = NULL; + } + if (mitk::RenderingManager::GetInstance()) + { + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } +} + +void QmitkToFPointSetWidget::SetDistanceImage(mitk::Image::Pointer distanceImage) +{ +// // remove existing observer +// if (m_DistanceImage.IsNotNull()) +// { +// m_DistanceImage->RemoveObserver(m_DistanceImageChangedObserverTag); +// } + m_DistanceImage = distanceImage; +// // create observer for m_DistanceImage +// itk::SimpleMemberCommand::Pointer distanceImageChangedCommand; +// distanceImageChangedCommand = itk::SimpleMemberCommand::New(); +// distanceImageChangedCommand->SetCallbackFunction(this, &QmitkToFPointSetWidget::MeasurementPointSetChanged); +// m_DistanceImageChangedObserverTag = m_DistanceImage->AddObserver(itk::ModifiedEvent(), distanceImageChangedCommand); } void QmitkToFPointSetWidget::OnMeasurement() { + // always show 2D PointSet in foreground + mitk::DataNode::Pointer pointSetNode = m_DataStorage->GetNamedNode("Measurement PointSet 2D"); + if (pointSetNode.IsNotNull()) + { + pointSetNode->SetIntProperty("layer",100); + } if (m_Controls->measureButton->isChecked()) { // disable point set interaction if (m_Controls->pointSetButton->isChecked()) { m_Controls->pointSetButton->setChecked(false); // remove interactor mitk::GlobalInteraction::GetInstance()->RemoveInteractor(m_PointSetInteractor); } // show overlays m_VtkTextActor->SetVisibility(1); this->m_VtkTextActor->SetInput("Choose measurement points with SHIFT+Click"); // enable interactor mitk::GlobalInteraction::GetInstance()->AddInteractor(m_MeasurementPointSetInteractor); // initial update of measurement this->MeasurementPointSetChanged(); } else { // hide overlays m_VtkTextActor->SetVisibility(0); // disable interactor mitk::GlobalInteraction::GetInstance()->RemoveInteractor(m_MeasurementPointSetInteractor); } } void QmitkToFPointSetWidget::OnPointSet() { + // always show 2D PointSet in foreground + mitk::DataNode::Pointer pointSetNode = m_DataStorage->GetNamedNode("ToF PointSet 2D"); + if (pointSetNode.IsNotNull()) + { + pointSetNode->SetIntProperty("layer",100); + } if (m_Controls->pointSetButton->isChecked()) { // disable measurement if (m_Controls->measureButton->isChecked()) { m_Controls->measureButton->setChecked(false); // remove interactor mitk::GlobalInteraction::GetInstance()->RemoveInteractor(m_MeasurementPointSetInteractor); } // show overlays m_VtkTextActor->SetVisibility(1); this->m_VtkTextActor->SetInput("Choose points with SHIFT+Click"); // enable interactor mitk::GlobalInteraction::GetInstance()->AddInteractor(m_PointSetInteractor); // initial update of PointSet this->PointSetChanged(); } else { // hide overlays m_VtkTextActor->SetVisibility(0); // disable interactor mitk::GlobalInteraction::GetInstance()->RemoveInteractor(m_PointSetInteractor); } } void QmitkToFPointSetWidget::MeasurementPointSetChanged() { // replace text actor this->m_VtkTextActor->SetDisplayPosition(10,m_WindowHeight-30); - // check if points are inside the image range - int imageSizeX = m_DistanceImage->GetDimensions()[0]; - int imageSizeY = m_DistanceImage->GetDimensions()[1]; - mitk::Point3D point1 = m_MeasurementPointSet2D->GetPoint(0); - mitk::Point3D point2 = m_MeasurementPointSet2D->GetPoint(1); - if (m_MeasurementPointSet2D->GetSize()>0) + if (m_MeasurementPointSet2D->GetSize()==2) { + // check if points are inside the image range + int imageSizeX = m_DistanceImage->GetDimensions()[0]; + int imageSizeY = m_DistanceImage->GetDimensions()[1]; + mitk::Point3D point1 = m_MeasurementPointSet2D->GetPoint(0); + mitk::Point3D point2 = m_MeasurementPointSet2D->GetPoint(1); if ((point1[0]>=0.0f)&&(point1[0]=0)&&(point1[1]=0.0f)&&(point2[0]=0)&&(point2[1]SetCameraIntrinsics(m_CameraIntrinsics); } toFDistanceImageToPointSetFilter->SetInput(m_DistanceImage); toFDistanceImageToPointSetFilter->SetSubset(m_MeasurementPointSet2D); toFDistanceImageToPointSetFilter->Update(); mitk::PointSet::Pointer measurementPointSet3D = toFDistanceImageToPointSetFilter->GetOutput(); m_MeasurementPointSet3DNode->SetData(measurementPointSet3D); // calculate distance between points if (measurementPointSet3D->GetSize()==2) { mitk::Point3D point1 = measurementPointSet3D->GetPoint(0); mitk::Point3D point2 = measurementPointSet3D->GetPoint(1); float distance = point1.EuclideanDistanceTo(point2); std::stringstream stream; stream<m_VtkTextActor->SetInput(stream.str().c_str()); } else { this->m_VtkTextActor->SetInput("Choose measurement points with SHIFT+Click"); } } else { this->m_VtkTextActor->SetInput("Measurement outside image range."); } } else { // initialize 3D pointset empty mitk::PointSet::Pointer pointSet3D = mitk::PointSet::New(); m_MeasurementPointSet3DNode->SetData(pointSet3D); } } void QmitkToFPointSetWidget::PointSetChanged() { int imageSizeX = m_DistanceImage->GetDimensions()[0]; int imageSizeY = m_DistanceImage->GetDimensions()[1]; int pointSetValid = 1; for (int i=0; iGetSize(); i++) { mitk::Point3D currentPoint = m_PointSet2D->GetPoint(i); if ((currentPoint[0]>=0.0f)&&(currentPoint[0]=0)&&(currentPoint[1]GetSize()>0) { if (pointSetValid) { // create PointSet filter mitk::ToFDistanceImageToPointSetFilter::Pointer toFDistanceImageToPointSetFilter = mitk::ToFDistanceImageToPointSetFilter::New(); if (m_CameraIntrinsics.IsNotNull()) { toFDistanceImageToPointSetFilter->SetCameraIntrinsics(m_CameraIntrinsics); } toFDistanceImageToPointSetFilter->SetInput(m_DistanceImage); toFDistanceImageToPointSetFilter->SetSubset(m_PointSet2D); toFDistanceImageToPointSetFilter->Update(); mitk::PointSet::Pointer pointSet3D = toFDistanceImageToPointSetFilter->GetOutput(); m_PointSet3DNode->SetData(pointSet3D); this->m_VtkTextActor->SetInput("Choose points with SHIFT+Click"); } else { this->m_VtkTextActor->SetInput("Point set outside image range."); } } else { // initialize 3D pointset empty mitk::PointSet::Pointer pointSet3D = mitk::PointSet::New(); m_PointSet3DNode->SetData(pointSet3D); } } diff --git a/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.h b/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.h index 3127c78f01..42bf039d02 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.h +++ b/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.h @@ -1,131 +1,143 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) -Copyright (c) German Cancer Research Center, +Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR +This software is distributed WITHOUT ANY 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 _QmitkToFPointSetWidget_H_INCLUDED #define _QmitkToFPointSetWidget_H_INCLUDED #include "mitkTOFUIExports.h" #include "ui_QmitkToFPointSetWidgetControls.h" //mitk headers #include #include #include #include #include #include //Qmitk headers #include // vtk includes #include #include #include /** * @brief Widget allowing interaction with point sets for measurement and PointSet definition * * The widget allows to * 1. Measure the distance between two points in 3D ToF space by clicking the points in the 2D slices * 2. Defining a ToF PointSet both in 2D and 3D. CameraIntrinsics are used for calculation between 2D and 3D * +* NOTE: +* You have to make sure that the widget is initialized at a position in the plugin using it, where the distance +* image is available. CleanUp has to be called to make sure that all observers and renderers are removed correctly. +* * @ingroup ToFUI */ class mitkTOFUI_EXPORT QmitkToFPointSetWidget :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; QmitkToFPointSetWidget(QWidget* p = 0, Qt::WindowFlags f1 = 0); virtual ~QmitkToFPointSetWidget(); /* @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 initializes the widget + \brief initializes the widget. Observers to the change events of the point sets are created, text actors are activated + to be rendered into the foreground of the render window. \param stdMultiWidget QmitkStdMultiWidget used for painting overlays for measurement \param dataStorage DataStorage to add PointSets \param distanceImage range image used to calculate 3D PointSet from 2D index */ - void InitializeWidget(QHash renderWindowHashMap, mitk::DataStorage::Pointer dataStorage, mitk::Image::Pointer distanceImage); - + void InitializeWidget(QHash renderWindowHashMap, mitk::DataStorage::Pointer dataStorage, mitk::CameraIntrinsics::Pointer cameraIntrinsics=NULL); /*! - \brief specify the intrinsic parameters of the camera (holds focal length, principal point, distortion coefficients) + \brief cleans up the widget when it's functionality is not used anymore. + Removes observers and deletes foreground renderer */ - void SetCameraIntrinsics(mitk::CameraIntrinsics::Pointer cameraIntrinsics); + void CleanUpWidget(); + /*! + \brief set the image holding the distance information used for measuring + */ + void SetDistanceImage(mitk::Image::Pointer distanceImage); signals: protected slots: /*! \brief Activates the interactor for the measurement point set */ void OnMeasurement(); /*! \brief Activates the interactor for the point set */ void OnPointSet(); protected: /*! \brief function called when the 2D measurement PointSet has changed */ void MeasurementPointSetChanged(); /*! \brief function called when the 2D PointSet has changed */ void PointSetChanged(); Ui::QmitkToFPointSetWidgetControls* m_Controls; ///< member holding the UI elements of this widget + mitk::DataStorage::Pointer m_DataStorage; ///< member holding the set DataStorage + mitk::Image::Pointer m_DistanceImage; ///< image holding the range data of the ToF camera mitk::CameraIntrinsics::Pointer m_CameraIntrinsics; ///< intrinsic parameters of the camera vtkSmartPointer m_VtkTextActor; ///< actor containing the text of the overlay vtkSmartPointer m_ForegroundRenderer1; ///< renderer responsible for text rendering in the foreground of widget 1 vtkSmartPointer m_ForegroundRenderer2; ///< renderer responsible for text rendering in the foreground of widget 2 vtkSmartPointer m_ForegroundRenderer3; ///< renderer responsible for text rendering in the foreground of widget 3 vtkSmartPointer m_RenderWindow1; ///< vtk render window used for showing overlay in widget 1 vtkSmartPointer m_RenderWindow2; ///< vtk render window used for showing overlay in widget 2 vtkSmartPointer m_RenderWindow3; ///< vtk render window used for showing overlay in widget 3 vtkSmartPointer m_RenderWindow4; ///< vtk render window used for showing overlay in widget 3 mitk::PointSet::Pointer m_MeasurementPointSet2D; ///< PointSet holding the 2D ToF image point selection used for measuring mitk::DataNode::Pointer m_MeasurementPointSet3DNode; ///< DataNode holding the 3D ToF coordinates used for measuring mitk::PointSet::Pointer m_PointSet2D; ///< PointSet holding the 2D ToF image points mitk::DataNode::Pointer m_PointSet3DNode; ///< DataNode holding the 3D ToF coordinates mitk::PointSetInteractor::Pointer m_PointSetInteractor; ///< PointSetInteractor used for PointSet definition mitk::PointSetInteractor::Pointer m_MeasurementPointSetInteractor; ///< PointSetInteractor used for measurement long m_MeasurementPointSetChangedObserverTag; ///< observer tag for measurement PointSet observer long m_PointSetChangedObserverTag; ///< observer tag for PointSet observer +// long m_DistanceImageChangedObserverTag; ///< observer tag for distance image observer int m_WindowHeight; ///< Height of the renderWindow private: }; #endif // _QmitkToFPointSetWidget_H_INCLUDED diff --git a/Modules/ToFUI/Qmitk/QmitkToFVisualisationSettingsWidget.h b/Modules/ToFUI/Qmitk/QmitkToFVisualisationSettingsWidget.h index 0454362bf3..dd05124367 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFVisualisationSettingsWidget.h +++ b/Modules/ToFUI/Qmitk/QmitkToFVisualisationSettingsWidget.h @@ -1,166 +1,166 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 _QMITKTOFVISUALISATIONSETTINGSWIDGET_H_INCLUDED #define _QMITKTOFVISUALISATIONSETTINGSWIDGET_H_INCLUDED #include "mitkTOFUIExports.h" #include "ui_QmitkToFVisualisationSettingsWidgetControls.h" #include "mitkDataNode.h" // QT headers #include // vtk includes #include class QmitkStdMultiWidget; /** Documentation: * Widget controlling the visualization of Time-of-Flight image data. A color transfer function can be configured for * a given distance, amplitude and intensity image. The pre-configured vtkColorTransferFunctions can be accessed as * an output of the widget. * * \ingroup ToFUI */ class mitkTOFUI_EXPORT QmitkToFVisualisationSettingsWidget :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; QmitkToFVisualisationSettingsWidget (QWidget* p = 0, Qt::WindowFlags f1 = 0); virtual ~QmitkToFVisualisationSettingsWidget (); /* @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 initialize the widget with the images to be shown \param distanceImage image holding the range image of a ToF camera \param amplitudeImage image holding the amplitude image of a ToF camera \param intensityImage image holding the intensity image of a ToF camera */ void Initialize(mitk::DataNode* distanceImageNode=NULL, mitk::DataNode* amplitudeImageNode=NULL, mitk::DataNode* intensityImageNode=NULL); /*! \brief Access the color transfer function of widget 1 (distance image) \return vtkColorTransferFunction that can be used to define a TransferFunctionProperty */ vtkColorTransferFunction* GetWidget1ColorTransferFunction(); /*! \brief Access the color transfer function of widget 2 (distance image) \return vtkColorTransferFunction that can be used to define a TransferFunctionProperty */ vtkColorTransferFunction* GetWidget2ColorTransferFunction(); /*! \brief Access the color transfer function of widget 3 (distance image) \return vtkColorTransferFunction that can be used to define a TransferFunctionProperty */ vtkColorTransferFunction* GetWidget3ColorTransferFunction(); /*! \brief Access the color transfer of the currently selected widget \return vtkColorTransferFunction that can be used to define a TransferFunctionProperty */ vtkColorTransferFunction* GetSelectedColorTransferFunction(); /*! \brief Return the index of the selected image: 0 = Distance, 1 = Amplitude, 2 = Intensity */ int GetSelectedImageIndex(); protected slots: void OnSetXValueColor(); /*! \brief Slot invoking a reset of the RangeSlider to the minimal and maximal values of the according image */ void OnResetSlider(); /*! \brief Slot called when the range span has changed. */ void OnSpanChanged (int lower, int upper); /*! \brief Resets the transfer function according to the currently selected widget / image */ void OnTransferFunctionReset(); /*! \brief Updates the GUI according to the widget / image selection */ void OnWidgetSelected(int index); /*! \brief Slot called when the line edit of the maximal value of the range slider has changed. Leads to an update of the range slider. */ void OnRangeSliderMaxChanged(); /*! \brief Slot called when the line edit of the minimal value of the range slider has changed. Leads to an update of the range slider. */ void OnRangeSliderMinChanged(); /*! \brief Sets the TransferFunctionType members according to the selection of the widget and the transfer type. */ void OnTransferFunctionTypeSelected(int index); protected: /*! \brief Invokes an update of the ColorTransferFunctionCanvas. Called when the ColorTransferFunction has changed */ void UpdateCanvas(); /*! \brief Resets the ColorTransferFunctionCanvas according to the lower and upper value of the RangeSlider */ void UpdateRanges(); Ui::QmitkToFVisualisationSettingsWidgetControls* m_Controls; int m_RangeSliderMin; ///< Minimal value of the transfer function range. Initialized to the minimal value of the corresponding image. int m_RangeSliderMax; ///< Maximal value of the transfer function range. Initialized to the maximal value of the corresponding image. mitk::DataNode::Pointer m_MitkDistanceImageNode; ///< DataNode holding the range image of the ToF camera as set by Initialize() mitk::DataNode::Pointer m_MitkAmplitudeImageNode; ///< DataNode holding the amplitude image of the ToF camera as set by Initialize() mitk::DataNode::Pointer m_MitkIntensityImageNode; ///< DataNode holding the intensity image of the ToF camera as set by Initialize() vtkColorTransferFunction* m_Widget1ColorTransferFunction; ///< vtkColorTransferFunction of widget 1 (distance) that can be used to define a TransferFunctionProperty vtkColorTransferFunction* m_Widget2ColorTransferFunction; ///< vtkColorTransferFunction of widget 2 (amplitude) that can be used to define a TransferFunctionProperty vtkColorTransferFunction* m_Widget3ColorTransferFunction; ///< vtkColorTransferFunction of widget 3 (intensity) that can be used to define a TransferFunctionProperty int m_Widget1TransferFunctionType; ///< member holding the type of the transfer function applied to the image shown in widget 1 (distance image): 0 = gray scale, 1 = color int m_Widget2TransferFunctionType; ///< member holding the type of the transfer function applied to the image shown in widget 2 (amplitude image): 0 = gray scale, 1 = color int m_Widget3TransferFunctionType; ///< member holding the type of the transfer function applied to the image shown in widget 3 (intensity image): 0 = gray scale, 1 = color private: /*! \brief Reset the color transfer function to the given type and range \param colorTransferFunction vtkColorTransferfunction to be resetted \param type type of the transfer function: 0 = gray scale, 1 = color \param min minimal value to be set to the transfer function \param max maximal value to be set to the transfer function */ void ResetTransferFunction(vtkColorTransferFunction* colorTransferFunction, int type, double min, double max); /*! \brief Reset the color transfer function for the given widget - \param widget 0: transversal, 1: coronal, 2: sagittal + \param widget 0: axial, 1: coronal, 2: sagittal \param type: type of the transfer function: 0 = gray scale, 1 = color */ void ReinitTransferFunction(int widget, int type); }; #endif // _QMITKTOFVISUALISATIONSETTINGSWIDGET_H_INCLUDED diff --git a/Modules/US/USModel/mitkUSDevice.cpp b/Modules/US/USModel/mitkUSDevice.cpp index 3bb0aace67..bef6ed4736 100644 --- a/Modules/US/USModel/mitkUSDevice.cpp +++ b/Modules/US/USModel/mitkUSDevice.cpp @@ -1,282 +1,294 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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::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_Metadata->SetDeviceClass(GetDeviceClass()); m_IsActive = 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_Metadata->SetDeviceClass(GetDeviceClass()); m_IsActive = 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() { } - -// Constructing Service Properties for the device mitk::ServiceProperties mitk::USDevice::ConstructServiceProperties() { ServiceProperties props; std::string yes = "true"; std::string no = "false"; if(this->GetIsActive()) - props["IsActive"] = yes; + props[mitk::USDevice::US_PROPKEY_ISACTIVE] = yes; else - props["IsActive"] = no; + 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[ "DeviceClass" ] = GetDeviceClass(); + 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() { - //TODO Throw Exception is already activated before connection - + 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; // Get Context and Module mitk::ModuleContext* context = GetModuleContext(); ServiceProperties props = ConstructServiceProperties(); m_ServiceRegistration = context->RegisterService(this, props); - return true; -} + // 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; // 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; } -//Changed bool mitk::USDevice::Activate() { if (! this->GetIsConnected()) return false; 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 must be changed, should more complicated SDK applications emerge + // 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; } -void mitk::USDevice::GenerateData() -{ - -} - - 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 service + // 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 90020b90f3..f2cfff5045 100644 --- a/Modules/US/USModel/mitkUSDevice.h +++ b/Modules/US/USModel/mitkUSDevice.h @@ -1,297 +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 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); - /** - * \brief Enforces minimal Metadata to be set. - */ - // mitkNewMacro3Param(Self, std::string, std::string, bool); - - - /** - * \brief Constructs a device with the given Metadata. Make sure the Metadata contains meaningful content! - * + /** + *\brief These constants are used in conjunction with Microservices */ - // mitkNewMacro2Param(Self, mitk::USImageMetadata::Pointer, bool); - + 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); - + std::string GetDeviceManufacturer(); std::string GetDeviceModel(); std::string GetDeviceComment(); protected: mitk::USProbe::Pointer m_ActiveProbe; std::vector m_ConnectedProbes; bool m_IsActive; /* * \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(); + 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/USUI/Qmitk/QmitkUSDeviceListWidget.cpp b/Modules/USUI/Qmitk/QmitkUSDeviceListWidget.cpp deleted file mode 100644 index 75acd872b2..0000000000 --- a/Modules/USUI/Qmitk/QmitkUSDeviceListWidget.cpp +++ /dev/null @@ -1,167 +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. - -===================================================================*/ - -//#define _USE_MATH_DEFINES -#include -#include - -//QT headers -#include - -//mitk headers - - -//itk headers - -//microservices -#include -#include -#include - - -const std::string QmitkUSDeviceListWidget::VIEW_ID = "org.mitk.views.QmitkUSDeviceListWidget"; - -QmitkUSDeviceListWidget::QmitkUSDeviceListWidget(QWidget* parent, Qt::WindowFlags f): QWidget(parent, f) -{ - m_Controls = NULL; - CreateQtPartControl(this); - - // get ModuleContext - mitk::Module* mitkUS = mitk::ModuleRegistry::GetModule("MitkUS"); - m_MitkUSContext = mitkUS->GetModuleContext(); - -} - -QmitkUSDeviceListWidget::~QmitkUSDeviceListWidget() -{ - -} - -//////////////////// INITIALIZATION ///////////////////// - -void QmitkUSDeviceListWidget::CreateQtPartControl(QWidget *parent) -{ - if (!m_Controls) - { - // create GUI widgets - m_Controls = new Ui::QmitkUSDeviceListWidgetControls; - m_Controls->setupUi(parent); - this->CreateConnections(); - } -} - -void QmitkUSDeviceListWidget::CreateConnections() -{ - if ( m_Controls ) - { - connect( m_Controls->m_DeviceList, SIGNAL(currentItemChanged( QListWidgetItem *, QListWidgetItem *)), this, SLOT(OnDeviceSelectionChanged()) ); - } -} - -void QmitkUSDeviceListWidget::Initialize(std::string filter) -{ - m_Filter = filter; - m_MitkUSContext->AddServiceListener(this, &QmitkUSDeviceListWidget::OnServiceEvent, m_Filter); -} - - -///////////////////////// Getter & Setter ///////////////////////////////// - -mitk::USDevice::Pointer QmitkUSDeviceListWidget::GetSelectedDevice() -{ - return this->GetDeviceForListItem(this->m_Controls->m_DeviceList->currentItem()); -} - -///////////// Methods & Slots Handling Direct Interaction ///////////////// - - -void QmitkUSDeviceListWidget::OnDeviceSelectionChanged(){ - mitk::USDevice::Pointer device = this->GetDeviceForListItem(this->m_Controls->m_DeviceList->currentItem()); - if (device.IsNull()) return; - emit (DeviceSelected(device)); -} - - -///////////////// Methods & Slots Handling Logic ////////////////////////// - -void QmitkUSDeviceListWidget::OnServiceEvent(const mitk::ServiceEvent event){ - // Empty ListWidget - this->m_ListContent.clear(); - m_Controls->m_DeviceList->clear(); - - - - // get Active Devices - std::vector devices = this->GetAllRegisteredDevices(); - // Transfer them to the List - for(std::vector::iterator it = devices.begin(); it != devices.end(); ++it) - { - QListWidgetItem *newItem = ConstructItemFromDevice(it->GetPointer()); - //Add new item to QListWidget - m_Controls->m_DeviceList->addItem(newItem); - // Construct link and add to internal List for reference - QmitkUSDeviceListWidget::DeviceListLink link; - link.device = it->GetPointer(); - link.item = newItem; - m_ListContent.push_back(link); - } -} - - -/////////////////////// HOUSEHOLDING CODE ///////////////////////////////// - -QListWidgetItem* QmitkUSDeviceListWidget::ConstructItemFromDevice(mitk::USDevice::Pointer device){ - QListWidgetItem *result = new QListWidgetItem; - std::string text = device->GetDeviceManufacturer() + "|" + device->GetDeviceModel(); - - if (device->GetIsActive()) - { - result->foreground().setColor(Qt::blue); - text += "|(ON)"; - } else text += "|(OFF)"; - - result->setText(text.c_str()); - - return result; -} - - -mitk::USDevice::Pointer QmitkUSDeviceListWidget::GetDeviceForListItem(QListWidgetItem* item) -{ - for(std::vector::iterator it = m_ListContent.begin(); it != m_ListContent.end(); ++it) - { - if (item == it->item) return it->device; - } - return 0; -} - - -std::vector QmitkUSDeviceListWidget::GetAllRegisteredDevices(){ - - //Get Service References - std::list serviceRefs = m_MitkUSContext->GetServiceReferences(m_Filter); - - // Convert Service References to US Devices - std::vector* result = new std::vector; - std::list::const_iterator iterator; - for (iterator = serviceRefs.begin(); iterator != serviceRefs.end(); ++iterator) - { - mitk::USDevice::Pointer device = m_MitkUSContext->GetService(*iterator); - if (device) result->push_back(device); - } - - return *result; -} \ No newline at end of file diff --git a/Modules/USUI/Qmitk/QmitkUSDeviceListWidget.h b/Modules/USUI/Qmitk/QmitkUSDeviceListWidget.h deleted file mode 100644 index 4cdbd671c4..0000000000 --- a/Modules/USUI/Qmitk/QmitkUSDeviceListWidget.h +++ /dev/null @@ -1,158 +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 _QmitkUSDeviceListWidget_H_INCLUDED -#define _QmitkUSDeviceListWidget_H_INCLUDED - -#include "MitkUSUIExports.h" -#include "ui_QmitkUSDeviceListWidgetControls.h" -#include "mitkUSDevice.h" -#include - -//QT headers -#include -#include - -//mitk header - -//Microservices -#include "usServiceReference.h" -#include "usModuleContext.h" -#include "usServiceEvent.h" -#include "usServiceTrackerCustomizer.h" - -/** -* @brief TODO -* -* @ingroup USUI -*/ -class MitkUSUI_EXPORT QmitkUSDeviceListWidget :public QWidget //, public mitk::ServiceTrackerCustomizer<> // this extension is necessary if one wants to use ServiceTracking instead of filtering -{ - - //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; - - QmitkUSDeviceListWidget(QWidget* p = 0, Qt::WindowFlags f1 = 0); - virtual ~QmitkUSDeviceListWidget(); - - /* @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 Initializes the connection to the registry. The string filter is an LDAP parsable String, compare mitk::ModuleContext for examples on filtering. - */ - void Initialize(std::string filter); - - /* - * \brief Returns the currently selected device, or null if none is selected. - */ - mitk::USDevice::Pointer GetSelectedDevice(); - - /* - *\brief This Function listens to ServiceRegistry changes and updates the - * list of devices accordingly. - */ - void OnServiceEvent(const mitk::ServiceEvent event); - - - - signals: - - /* - *\brief Emitted when a new device mathing the filter connects - */ - void DeviceConnected(mitk::USDevice::Pointer); - /* - *\brief Emitted directly before device matching the filter disconnects - */ - void DeviceDisconnected(mitk::USDevice::Pointer); - /* - *\brief Emitted when a new device mathing the filter changes it's state. This does of now only compromise changes to activity. - */ - void DeviceChanged(mitk::USDevice::Pointer); - - /* - *\brief Emitted the user selects a device from the list - */ - void DeviceSelected(mitk::USDevice::Pointer); - - - - public slots: - - protected slots: - - /* - \brief Called, when the selection in the devicelist changes - */ - void OnDeviceSelectionChanged(); - - - protected: - - Ui::QmitkUSDeviceListWidgetControls* m_Controls; ///< member holding the UI elements of this widget - - /* - * \brief Internal Structure used to link devices to their QListWidget Items - */ - struct DeviceListLink { - mitk::USDevice::Pointer device; - QListWidgetItem* item; - }; - - /* - * \brief Contains a list of currently active devices and their entires in the list. This is wiped with every ServiceRegistryEvent. - */ - std::vector m_ListContent; - - /* - * \brief Constructs a ListItem from the given device for display in the list of active devices. - */ - QListWidgetItem* ConstructItemFromDevice(mitk::USDevice::Pointer device); - - /* - * \brief Returns the device corresponding to the given ListEntry or null if none was found (which really shouldnt happen). - */ - mitk::USDevice::Pointer GetDeviceForListItem(QListWidgetItem* item); - - //mitk::ServiceTracker ConstructServiceTracker(); - - /* - * \brief Returns a List of US Devices that are currently connected by querying the service registry. - */ - std::vector GetAllRegisteredDevices(); - - - - - private: - - mitk::ModuleContext* m_MitkUSContext; - std::string m_Filter; - - - - - -}; - -#endif // _QmitkUSDeviceListWidget_H_INCLUDED diff --git a/Modules/USUI/Qmitk/QmitkUSDeviceManagerWidget.cpp b/Modules/USUI/Qmitk/QmitkUSDeviceManagerWidget.cpp index 4117083a44..00b08bddfe 100644 --- a/Modules/USUI/Qmitk/QmitkUSDeviceManagerWidget.cpp +++ b/Modules/USUI/Qmitk/QmitkUSDeviceManagerWidget.cpp @@ -1,183 +1,101 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 - -//QT headers -#include - -//mitk headers - - - -//itk headers - -//microservices -#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); - - // get ModuleContext - mitk::Module* mitkUS = mitk::ModuleRegistry::GetModule("MitkUS"); - m_MitkUSContext = mitkUS->GetModuleContext(); - - //ServiceTracker* tracker = new ServiceTracker(m_MitkUSContext, this); - - // Register this Widget as a listener for Registry changes. - // If devices are registered, unregistered or changed, notifications will go there - std::string filter = "(&("; - filter += mitk::ServiceConstants::OBJECTCLASS(); - filter += "="; - //filter += us_service_interface_iid(); - filter += "org.mitk.services.UltrasoundDevice)(IsActive=false))"; - m_MitkUSContext->AddServiceListener(this, &QmitkUSDeviceManagerWidget::OnServiceEvent, filter); } 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(currentItemChanged( QListWidgetItem *, QListWidgetItem *)), this, SLOT(OnDeviceSelectionChanged()) ); + 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_INFO << "Activated Device"; - mitk::USDevice::Pointer device = this->GetDeviceForListItem(this->m_Controls->m_ConnectedDevices->currentItem()); + 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_INFO << "Disconnected Device"; - mitk::USDevice::Pointer device = this->GetDeviceForListItem(this->m_Controls->m_ConnectedDevices->currentItem()); + mitk::USDevice::Pointer device = m_Controls->m_ConnectedDevices->GetSelectedService(); if (device.IsNull()) return; device->Disconnect(); } -void QmitkUSDeviceManagerWidget::OnDeviceSelectionChanged(){ - mitk::USDevice::Pointer device = this->GetDeviceForListItem(this->m_Controls->m_ConnectedDevices->currentItem()); - if (device.IsNull()) return; - if (device->GetIsActive()) m_Controls->m_BtnActivate->setText("Deactivate"); - else m_Controls->m_BtnActivate->setText("Activate"); -} - - -///////////////// Methods & Slots Handling Logic ////////////////////////// - -void QmitkUSDeviceManagerWidget::OnServiceEvent(const mitk::ServiceEvent event){ - // Empty ListWidget - this->m_ListContent.clear(); - m_Controls->m_ConnectedDevices->clear(); - - - - // get Active Devices - std::vector devices = this->GetAllRegisteredDevices(); - // Transfer them to the List - for(std::vector::iterator it = devices.begin(); it != devices.end(); ++it) +void QmitkUSDeviceManagerWidget::OnDeviceSelectionChanged(mitk::ServiceReference reference){ + if (! reference) { - QListWidgetItem *newItem = ConstructItemFromDevice(it->GetPointer()); - //Add new item to QListWidget - m_Controls->m_ConnectedDevices->addItem(newItem); - // Construct Link and add to internal List for reference - QmitkUSDeviceManagerWidget::DeviceListLink link; - link.device = it->GetPointer(); - link.item = newItem; - m_ListContent.push_back(link); + m_Controls->m_BtnActivate->setEnabled(false); + m_Controls->m_BtnDisconnect->setEnabled(false); + return; } -} - - -/////////////////////// HOUSEHOLDING CODE ///////////////////////////////// - -QListWidgetItem* QmitkUSDeviceManagerWidget::ConstructItemFromDevice(mitk::USDevice::Pointer device){ - QListWidgetItem *result = new QListWidgetItem; - std::string text = device->GetDeviceManufacturer() + "|" + device->GetDeviceModel(); - - if (device->GetIsActive()) + std::string isActive = reference.GetProperty( mitk::USDevice::US_PROPKEY_ISACTIVE ).ToString(); + if (isActive.compare("true") == 0) { - result->foreground().setColor(Qt::blue); - text += "|(ON)"; - } else text += "|(OFF)"; - - result->setText(text.c_str()); - - return result; -} - - -mitk::USDevice::Pointer QmitkUSDeviceManagerWidget::GetDeviceForListItem(QListWidgetItem* item) -{ - for(std::vector::iterator it = m_ListContent.begin(); it != m_ListContent.end(); ++it) - { - if (item == it->item) return it->device; + m_Controls->m_BtnActivate->setEnabled(true); + m_Controls->m_BtnDisconnect->setEnabled(false); + m_Controls->m_BtnActivate->setText("Deactivate"); } - return 0; -} - -std::vector QmitkUSDeviceManagerWidget::GetAllRegisteredDevices(){ - - //Get Service References - std::list serviceRefs = m_MitkUSContext->GetServiceReferences(); - - // Convert Service References to US Devices - std::vector* result = new std::vector; - std::list::const_iterator iterator; - for (iterator = serviceRefs.begin(); iterator != serviceRefs.end(); ++iterator) + else { - mitk::USDevice::Pointer device = m_MitkUSContext->GetService(*iterator); - if (device) result->push_back(device); + m_Controls->m_BtnActivate->setEnabled(true); + m_Controls->m_BtnDisconnect->setEnabled(true); + m_Controls->m_BtnActivate->setText("Activate"); } +} - return *result; -} \ No newline at end of file diff --git a/Modules/USUI/Qmitk/QmitkUSDeviceManagerWidget.h b/Modules/USUI/Qmitk/QmitkUSDeviceManagerWidget.h index 96cdf84c2b..425ee54ca1 100644 --- a/Modules/USUI/Qmitk/QmitkUSDeviceManagerWidget.h +++ b/Modules/USUI/Qmitk/QmitkUSDeviceManagerWidget.h @@ -1,135 +1,85 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _QmitkUSDeviceManagerWidget_H_INCLUDED #define _QmitkUSDeviceManagerWidget_H_INCLUDED #include "MitkUSUIExports.h" #include "ui_QmitkUSDeviceManagerWidgetControls.h" #include "mitkUSDevice.h" #include //QT headers #include #include -//mitk header -//Microservices -#include "usServiceReference.h" -#include "usModuleContext.h" -#include "usServiceEvent.h" /** * @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 //, public mitk::ServiceTrackerCustomizer<> // this extension is necessary if one wants to use ServiceTracking instead of filtering +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 This Function listens to ServiceRegistry changes and updates the - * list of devices accordingly. - */ - void OnServiceEvent(const mitk::ServiceEvent event); - - - - signals: - - /* - \brief Sent, when the user clicks "Activate Device" - */ - void USDeviceActivated(); public slots: protected slots: /* - \brief Called, when the button "Activate Device" was clicked + \brief Called, when the button "Activate Device" was clicked. */ void OnClickedActivateDevice(); /* - \brief Called, when the button "Disconnect Device" was clicked + \brief Called, when the button "Disconnect Device" was clicked. */ void OnClickedDisconnectDevice(); /* - \brief Called, when the selection in the devicelist changes + \brief Called, when the selection in the devicelist changes. */ - void OnDeviceSelectionChanged(); + void OnDeviceSelectionChanged(mitk::ServiceReference reference); protected: Ui::QmitkUSDeviceManagerWidgetControls* m_Controls; ///< member holding the UI elements of this widget - /* - * \brief Internal Structure used to link devices to their QListWidget Items - */ - struct DeviceListLink { - mitk::USDevice::Pointer device; - QListWidgetItem* item; - }; - - /* - * \brief Contains a list of currently active devices and their entires in the list. This is wiped with every ServiceRegistryEvent. - */ - std::vector m_ListContent; - - /* - * \brief Constructs a ListItem from the given device for display in the list of active devices. - */ - QListWidgetItem* ConstructItemFromDevice(mitk::USDevice::Pointer device); - - /* - * \brief Returns the device corresponding to the given ListEntry or null if none was found (which really shouldnt happen). - */ - mitk::USDevice::Pointer GetDeviceForListItem(QListWidgetItem* item); - - //mitk::ServiceTracker ConstructServiceTracker(); - - /* - * \brief Returns a List of US Devices that are currently connected by querying the service registry. - */ - std::vector GetAllRegisteredDevices(); - private: - mitk::ModuleContext* m_MitkUSContext; - }; #endif // _QmitkUSDeviceManagerWidget_H_INCLUDED diff --git a/Modules/USUI/Qmitk/QmitkUSDeviceManagerWidgetControls.ui b/Modules/USUI/Qmitk/QmitkUSDeviceManagerWidgetControls.ui index 12e83cb191..309ec77405 100644 --- a/Modules/USUI/Qmitk/QmitkUSDeviceManagerWidgetControls.ui +++ b/Modules/USUI/Qmitk/QmitkUSDeviceManagerWidgetControls.ui @@ -1,57 +1,53 @@ QmitkUSDeviceManagerWidgetControls 0 0 405 231 0 0 QmitkUSDeviceManagerWidget - - - - - 11 - - - - Connected Devices: - - - - + Activate Device - + Disconnect Device - - + + + + + QmitkServiceListWidget + QWidget +
QmitkServiceListWidget.h
+ 1 +
+
diff --git a/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.cpp b/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.cpp index 24420ec71b..ae83d08a98 100644 --- a/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.cpp +++ b/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.cpp @@ -1,167 +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. ===================================================================*/ //#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); } 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; - MITK_INFO << "NewDeviceWidget: ClickedDone()"; // 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; - MITK_INFO << "NewDeviceWidget: OnClickedCancel()"; 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(); } - MITK_INFO << "NewDeviceWidget: EditDevice()"; m_TargetDevice = static_cast (device.GetPointer()); m_Active = true; } void QmitkUSNewVideoDeviceWidget::CreateNewDevice() { - MITK_INFO << "NewDeviceWidget: 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/QmitkUSNewVideoDeviceWidget.h b/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.h index 22bf408b68..da109202cf 100644 --- a/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.h +++ b/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.h @@ -1,122 +1,122 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _QmitkUSNewVideoDeviceWidget_H_INCLUDED #define _QmitkUSNewVideoDeviceWidget_H_INCLUDED #include "MitkUSUIExports.h" #include "ui_QmitkUSNewVideoDeviceWidgetControls.h" #include "mitkUSVideoDevice.h" #include "mitkUSImageMetadata.h" //QT headers #include #include //mitk header /** -* @brief TODO +* @brief This Widget enables the USer to create and connect Video Devices. * * @ingroup USUI */ class MitkUSUI_EXPORT QmitkUSNewVideoDeviceWidget :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; QmitkUSNewVideoDeviceWidget(QWidget* p = 0, Qt::WindowFlags f1 = 0); virtual ~QmitkUSNewVideoDeviceWidget(); /* @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(); signals: void Finished(); public slots: /* \brief Activates the widget and displays the given device's Data to edit. */ void EditDevice(mitk::USDevice::Pointer device); /* \brief Activates the widget with fields empty. */ void CreateNewDevice(); protected slots: /* \brief Called, when the the user clicks the "Done" button (Labeled either "Add Device" or "Edit Device", depending on the situation. */ void OnClickedDone(); /* \brief Called, when the button "Cancel" was clicked */ void OnClickedCancel(); /* \brief Called, when the Use selects one of the Radiobuttons */ void OnDeviceTypeSelection(); protected: Ui::QmitkUSNewVideoDeviceWidgetControls* m_Controls; ///< member holding the UI elements of this widget /* \brief Constructs a ListItem from the given device for display in the list of active devices */ QListWidgetItem* ConstructItemFromDevice(mitk::USDevice::Pointer device); /* \brief Initializes the Widget's ListItems with the given Metadata Object. */ void InitFields(mitk::USImageMetadata::Pointer); /* \brief Displays whether this widget is active or not. It gets activated by either sending a Signal to * the "CreateNewDevice" Slot or to the "EditDevice" Slot. If the user finishes editing the device, a * "EditingComplete" Signal is sent, and the widget is set to inactive again. Clicking Cancel also * deactivates it. */ bool m_Active; /** * \brief This is the device to edit. It is either the device transmitted in the "EditDevice" signal, or a new one * if the "CreateNewDevice slot was called. */ mitk::USVideoDevice::Pointer m_TargetDevice; }; #endif // _QmitkUSNewVideoDeviceWidget_H_INCLUDED diff --git a/Modules/USUI/files.cmake b/Modules/USUI/files.cmake index fb6be5c93c..0747fcff17 100644 --- a/Modules/USUI/files.cmake +++ b/Modules/USUI/files.cmake @@ -1,22 +1,19 @@ set(CPP_FILES Qmitk/QmitkUSDeviceManagerWidget.cpp Qmitk/QmitkUSNewVideoDeviceWidget.cpp - Qmitk/QmitkUSDeviceListWidget.cpp ) set(UI_FILES - Qmitk/QmitkUSDeviceListWidgetControls.ui Qmitk/QmitkUSDeviceManagerWidgetControls.ui Qmitk/QmitkUSNewVideoDeviceWidgetControls.ui ) set(MOC_H_FILES Qmitk/QmitkUSDeviceManagerWidget.h - Qmitk/QmitkUSDeviceListWidget.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/org.mitk.core.services/src/internal/mitkPluginActivator.cpp b/Plugins/org.mitk.core.services/src/internal/mitkPluginActivator.cpp index e12d319526..5376638a94 100644 --- a/Plugins/org.mitk.core.services/src/internal/mitkPluginActivator.cpp +++ b/Plugins/org.mitk.core.services/src/internal/mitkPluginActivator.cpp @@ -1,273 +1,277 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkLog.h" #include #include #include "internal/mitkDataStorageService.h" #include #include #include +#include +#include namespace mitk { class ITKLightObjectToQObjectAdapter : public QObject { public: ITKLightObjectToQObjectAdapter(const QStringList& clazzes, itk::LightObject* service) : interfaceNames(clazzes), mitkService(service) {} // This method is called by the Qt meta object system. It is usually // generated by the moc, but we create it manually to be able to return // a MITK micro service object (derived from itk::LightObject). It basically // works as if the micro service class had used the Q_INTERFACES macro in // its declaration. Now we can successfully do a // qobject_cast(lightObjectToQObjectAdapter) void* qt_metacast(const char *_clname) { if (!_clname) return 0; if (!strcmp(_clname, "ITKLightObjectToQObjectAdapter")) return static_cast(const_cast(this)); if (interfaceNames.contains(QString(_clname))) return static_cast(mitkService); return QObject::qt_metacast(_clname); } private: QStringList interfaceNames; itk::LightObject* mitkService; }; const std::string org_mitk_core_services_Activator::PLUGIN_ID = "org.mitk.core.services"; void org_mitk_core_services_Activator::start(ctkPluginContext* context) { pluginContext = context; //initialize logging mitk::LoggingBackend::Register(); QString filename = "mitk.log"; QFileInfo path = context->getDataFile(filename); mitk::LoggingBackend::SetLogFile(path.absoluteFilePath().toStdString().c_str()); + mitk::VtkLoggingAdapter::Initialize(); + mitk::ItkLoggingAdapter::Initialize(); //initialize data storage service DataStorageService* service = new DataStorageService(); dataStorageService = IDataStorageService::Pointer(service); context->registerService(service); // Get the MitkCore Module Context mitkContext = mitk::ModuleRegistry::GetModule(1)->GetModuleContext(); // Process all already registered services std::list refs = mitkContext->GetServiceReferences(""); for (std::list::const_iterator i = refs.begin(); i != refs.end(); ++i) { this->AddMitkService(*i); } mitkContext->AddServiceListener(this, &org_mitk_core_services_Activator::MitkServiceChanged); } void org_mitk_core_services_Activator::stop(ctkPluginContext* /*context*/) { mitkContext->RemoveServiceListener(this, &org_mitk_core_services_Activator::MitkServiceChanged); foreach(ctkServiceRegistration reg, mapMitkIdToRegistration.values()) { reg.unregister(); } mapMitkIdToRegistration.clear(); qDeleteAll(mapMitkIdToAdapter); mapMitkIdToAdapter.clear(); //clean up logging mitk::LoggingBackend::Unregister(); dataStorageService = 0; mitkContext = 0; pluginContext = 0; } void org_mitk_core_services_Activator::MitkServiceChanged(const mitk::ServiceEvent event) { switch (event.GetType()) { case mitk::ServiceEvent::REGISTERED: { this->AddMitkService(event.GetServiceReference()); break; } case mitk::ServiceEvent::UNREGISTERING: { long mitkServiceId = mitk::any_cast(event.GetServiceReference().GetProperty(mitk::ServiceConstants::SERVICE_ID())); ctkServiceRegistration reg = mapMitkIdToRegistration.take(mitkServiceId); if (reg) { reg.unregister(); } delete mapMitkIdToAdapter.take(mitkServiceId); break; } case mitk::ServiceEvent::MODIFIED: { long mitkServiceId = mitk::any_cast(event.GetServiceReference().GetProperty(mitk::ServiceConstants::SERVICE_ID())); ctkDictionary newProps = CreateServiceProperties(event.GetServiceReference()); mapMitkIdToRegistration[mitkServiceId].setProperties(newProps); break; } default: break; // do nothing } } void org_mitk_core_services_Activator::AddMitkService(const mitk::ServiceReference& ref) { // Get the MITK micro service object itk::LightObject* mitkService = mitkContext->GetService(ref); if (mitkService == 0) return; // Get the interface names against which the service was registered std::list clazzes = mitk::any_cast >(ref.GetProperty(mitk::ServiceConstants::OBJECTCLASS())); QStringList qclazzes; for(std::list::const_iterator clazz = clazzes.begin(); clazz != clazzes.end(); ++clazz) { qclazzes << QString::fromStdString(*clazz); } long mitkServiceId = mitk::any_cast(ref.GetProperty(mitk::ServiceConstants::SERVICE_ID())); QObject* adapter = new ITKLightObjectToQObjectAdapter(qclazzes, mitkService); mapMitkIdToAdapter[mitkServiceId] = adapter; ctkDictionary props = CreateServiceProperties(ref); mapMitkIdToRegistration[mitkServiceId] = pluginContext->registerService(qclazzes, adapter, props); } ctkDictionary org_mitk_core_services_Activator::CreateServiceProperties(const ServiceReference &ref) { ctkDictionary props; long mitkServiceId = mitk::any_cast(ref.GetProperty(mitk::ServiceConstants::SERVICE_ID())); props.insert("mitk.serviceid", QVariant::fromValue(mitkServiceId)); // Add all other properties from the MITK micro service std::vector keys; ref.GetPropertyKeys(keys); for (std::vector::const_iterator it = keys.begin(); it != keys.end(); ++it) { QString key = QString::fromStdString(*it); mitk::Any value = ref.GetProperty(*it); // We cannot add any mitk::Any object, we need to query the type const std::type_info& objType = value.Type(); if (objType == typeid(std::string)) { props.insert(key, QString::fromStdString(ref_any_cast(value))); } else if (objType == typeid(std::vector)) { const std::vector& list = ref_any_cast >(value); QStringList qlist; for (std::vector::const_iterator str = list.begin(); str != list.end(); ++str) { qlist << QString::fromStdString(*str); } props.insert(key, qlist); } else if (objType == typeid(std::list)) { const std::list& list = ref_any_cast >(value); QStringList qlist; for (std::list::const_iterator str = list.begin(); str != list.end(); ++str) { qlist << QString::fromStdString(*str); } props.insert(key, qlist); } else if (objType == typeid(char)) { props.insert(key, QChar(ref_any_cast(value))); } else if (objType == typeid(unsigned char)) { props.insert(key, QChar(ref_any_cast(value))); } else if (objType == typeid(bool)) { props.insert(key, any_cast(value)); } else if (objType == typeid(short)) { props.insert(key, any_cast(value)); } else if (objType == typeid(unsigned short)) { props.insert(key, any_cast(value)); } else if (objType == typeid(int)) { props.insert(key, any_cast(value)); } else if (objType == typeid(unsigned int)) { props.insert(key, any_cast(value)); } else if (objType == typeid(float)) { props.insert(key, any_cast(value)); } else if (objType == typeid(double)) { props.insert(key, any_cast(value)); } else if (objType == typeid(long long int)) { props.insert(key, any_cast(value)); } else if (objType == typeid(unsigned long long int)) { props.insert(key, any_cast(value)); } } return props; } org_mitk_core_services_Activator::org_mitk_core_services_Activator() : mitkContext(0), pluginContext(0) { } } Q_EXPORT_PLUGIN2(org_mitk_core_services, mitk::org_mitk_core_services_Activator) diff --git a/Plugins/org.mitk.gui.common/src/mitkIRenderWindowPart.h b/Plugins/org.mitk.gui.common/src/mitkIRenderWindowPart.h index f2097ee5e3..4721586aae 100644 --- a/Plugins/org.mitk.gui.common/src/mitkIRenderWindowPart.h +++ b/Plugins/org.mitk.gui.common/src/mitkIRenderWindowPart.h @@ -1,230 +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. ===================================================================*/ #ifndef MITKIRENDERWINDOWPART_H #define MITKIRENDERWINDOWPART_H #include #include #include #include #include #include #include class QmitkRenderWindow; namespace mitk { struct IRenderingManager; class SliceNavigationController; /** * \ingroup org_mitk_gui_common * * \brief Interface for a MITK Workbench Part providing a render window. * * This interface allows generic access to Workbench parts which provide some * kind of render window. The interface is intended to be implemented by * subclasses of berry::IWorkbenchPart. Usually, the interface is implemented * by a Workbench editor. * * A IRenderWindowPart provides zero or more QmitkRenderWindow instances which can * be controlled via this interface. QmitkRenderWindow instances have an associated * \e id, which is implementation specific. However, implementations should consider * to use one of the following ids for certain QmitkRenderWindow instances to maximize * reusability (they are free to map multiple ids to one QmitkRenderWindow internally): *
    - *
  • transversal
  • + *
  • transversal (deprecated, use axial instead)
  • + *
  • axial
  • *
  • sagittal
  • *
  • coronal
  • *
  • 3d
  • *
* * \see ILinkedRenderWindowPart * \see IRenderWindowPartListener * \see QmitkAbstractRenderEditor */ struct MITK_GUI_COMMON_PLUGIN IRenderWindowPart { static const QString DECORATION_BORDER; // = "border" static const QString DECORATION_LOGO; // = "logo" static const QString DECORATION_MENU; // = "menu" static const QString DECORATION_BACKGROUND; // = "background; static const QString INTERACTOR_OFF; // - "off" static const QString INTERACTOR_MITK; // = "mitk" static const QString INTERACTOR_PACS; // = "pacs" virtual ~IRenderWindowPart(); + /** + * Get the currently active (focused) render window. + * Focus handling is implementation specific. + * + * \return The active QmitkRenderWindow instance; NULL + * if no render window is active. + * + * \deprecated The method is deprecated, use the IRenderWindowPart::GetActiveQmitkRenderWindow() instead + */ + DEPRECATED( virtual QmitkRenderWindow* GetActiveRenderWindow() const) + { + return GetActiveQmitkRenderWindow(); + } + + /** + * Get all render windows with their ids. + * + * \return A hash map mapping the render window id to the QmitkRenderWindow instance. + * + * \deprecated The method is deprecated, use the IRenderWindowPart::GetQmitkRenderWindows() instead + */ + DEPRECATED( virtual QHash GetRenderWindows() const ) + { + return GetQmitkRenderWindows(); + } + + /** + * Get a render window with a specific id. + * + * \param id The render window id. + * \return The QmitkRenderWindow instance for id + * + * \deprecated The method is deprecated, use the IRenderWindowPart::GetQmitkRenderWindow(const QString& id) instead + */ + DEPRECATED( virtual QmitkRenderWindow* GetRenderWindow(const QString& id) const ) + { + return GetQmitkRenderWindow( id ); + } + /** * Get the currently active (focused) render window. * Focus handling is implementation specific. * * \return The active QmitkRenderWindow instance; NULL * if no render window is active. */ - virtual QmitkRenderWindow* GetActiveRenderWindow() const = 0; + virtual QmitkRenderWindow* GetActiveQmitkRenderWindow() const = 0; /** * Get all render windows with their ids. * * \return A hash map mapping the render window id to the QmitkRenderWindow instance. */ - virtual QHash GetRenderWindows() const = 0; + virtual QHash GetQmitkRenderWindows() const = 0; /** * Get a render window with a specific id. * * \param id The render window id. * \return The QmitkRenderWindow instance for id */ - virtual QmitkRenderWindow* GetRenderWindow(const QString& id) const = 0; + virtual QmitkRenderWindow* GetQmitkRenderWindow(const QString& id) const = 0; /** * Get the rendering manager used by this render window part. * * \return The current IRenderingManager instance or NULL * if no rendering manager is used. */ virtual mitk::IRenderingManager* GetRenderingManager() const = 0; /** * Request an update of all render windows. * * \param requestType Specifies the type of render windows for which an update * will be requested. */ virtual void RequestUpdate(mitk::RenderingManager::RequestType requestType = mitk::RenderingManager::REQUEST_UPDATE_ALL) = 0; /** * Force an immediate update of all render windows. * * \param requestType Specifies the type of render windows for which an immediate update * will be requested. */ virtual void ForceImmediateUpdate(mitk::RenderingManager::RequestType requestType = mitk::RenderingManager::REQUEST_UPDATE_ALL) = 0; /** * Get the SliceNavigationController for controlling time positions. * * \return A SliceNavigationController if the render window supports this * operation; otherwise returns NULL. */ virtual mitk::SliceNavigationController* GetTimeNavigationController() const = 0; /** * Get the selected position in the render window with id id * or in the active render window if id is NULL. * * \param id The render window id. * \return The currently selected position in world coordinates. */ virtual mitk::Point3D GetSelectedPosition(const QString& id = QString()) const = 0; /** * Set the selected position in the render window with id id * or in the active render window if id is NULL. * * \param pos The position in world coordinates which should be selected. * \param id The render window id in which the selection should take place. */ virtual void SetSelectedPosition(const mitk::Point3D& pos, const QString& id = QString()) = 0; /** * Enable \e decorations like colored borders, menu widgets, logos, text annotations, etc. * * Decorations are implementation specific. A set of standardized decoration names is listed * in GetDecorations(). * * \param enable If true enable the decorations specified in decorations, * otherwise disable them. * \param decorations A list of decoration names. If empty, all supported decorations are affected. * * \see GetDecorations() */ virtual void EnableDecorations(bool enable, const QStringList& decorations = QStringList()) = 0; /** * Return if a specific decoration is enabled. * * \return true if the decoration is enabled, false if it is disabled * or unknown. * * \see GetDecorations() */ virtual bool IsDecorationEnabled(const QString& decoration) const = 0; /** * Get a list of supported decorations. * * The following decoration names are standardized and should not be used for other decoration types: *
    *
  • \e DECORATION_BORDER Any border decorations like colored rectangles, etc. *
  • \e DECORATION_MENU Menus associated with render windows *
  • \e DECORATION_BACKGROUND All kinds of backgrounds (patterns, gradients, etc.) except for solid colored backgrounds *
  • \e DECORATION_LOGO Any kind of logo overlayed on the rendered scene *
* * \return A list of supported decoration names. */ virtual QStringList GetDecorations() const = 0; /** * Enable \e interactors like mouse interactors, keyboard interactors, etc. * * Interactors are implementation specific. A set of standardized interactor names is listed in * GetInteractors(); * * \param enable If true enable the interactors specified in interactors, * otherwise disable them. * \param interactors A list of interactor names. If empty, all supported interactors are affected. * * \see GetInteractors() */ virtual void EnableInteractors(bool enable, const QStringList& interactors = QStringList()) = 0; /** * Return if a specific interactor is enabled. * * \return true if the interactor is enabled, false if it is disabled or unknown. * * \see GetInteractors() */ virtual bool IsInteractorEnabled(const QString& interactor) const = 0; /** * Get a list of supported interactors. * * The following interactor names are standardized and should not be used for other interactor types: *
    *
  • \e INTERACTOR_MITK *
  • \e INTERACTOR_PACS *
* * \return A list of supported decoration names. */ virtual QStringList GetInteractors() const = 0; }; } Q_DECLARE_INTERFACE(mitk::IRenderWindowPart, "org.mitk.ui.IRenderWindowPart") #endif // MITKIRENDERWINDOWPART_H diff --git a/Plugins/org.mitk.gui.qt.basicimageprocessing/documentation/UserManual/QmitkBasicImageProcessing.dox b/Plugins/org.mitk.gui.qt.basicimageprocessing/documentation/UserManual/QmitkBasicImageProcessing.dox index 0beadaea65..6fd28a3e43 100644 --- a/Plugins/org.mitk.gui.qt.basicimageprocessing/documentation/UserManual/QmitkBasicImageProcessing.dox +++ b/Plugins/org.mitk.gui.qt.basicimageprocessing/documentation/UserManual/QmitkBasicImageProcessing.dox @@ -1,132 +1,132 @@ /** -\bundlemainpage{org_basicimageprocessing} The Basic Image Processing Module +\page org_mitk_views_basicimageprocessing The Basic Image Processing Module \image html ImageProcessing_48.png "Icon of the Module" \section QmitkBasicImageProcessingUserManualSummary Summary This module provides an easy interface to fundamental image preprocessing and enhancement filters. It offers filter operations on 3D and 4D images in the areas of noise suppression, morphological operations, edge detection and image arithmetics, as well as image inversion and downsampling. Please see \ref QmitkBasicImageProcessingUserManualDetails for more detailed information on usage and supported filters. If you encounter problems using the module, please have a look at the \ref QmitkBasicImageProcessingUserManualTrouble page. \section QmitkBasicImageProcessingUserManualDetails Details Manual sections: - \ref QmitkBasicImageProcessingUserManualOverview - \ref QmitkBasicImageProcessingUserManualFilters - \ref QmitkBasicImageProcessingUserManualUsage - \ref QmitkBasicImageProcessingUserManualTrouble \section QmitkBasicImageProcessingUserManualOverview Overview This module provides an easy interface to fundamental image preprocessing and image enhancement filters. It offers a variety of filter operations in the areas of noise suppression, morphological operations, edge detection and image arithmetics. At the moment, the module can be used with all 3D and 4D image types loadable by MITK. 2D image support will be added in the future. All filters are encapsulated from the Insight Segmentation and Registration Toolkit (ITK, www.itk.org). \image html BIP_Overview.png "MITK with the Basic Image Processing module" This document will tell you how to use this module, but it is assumed that you already know how to use MITK in general. \section QmitkBasicImageProcessingUserManualFilters Filters This section will not describe the fundamental functioning of the single filters in detail, though. If you want to know more about a single filter, please have a look at http://www.itk.org/Doxygen316/html/classes.html or in any good digital image processing book. For total denoising filter, please see Tony F. Chan et al., "The digital TV filter and nonlinear denoising". Available filters are:

\a Single image operations

  • Noise Suppression
    • Gaussian Denoising
    • Median Filtering
    • Total Variation Denoising
  • Morphological Operations
    • Dilation
    • Erosion
    • Opening
    • Closing
  • %Edge Detection
    • Gradient Image
    • Laplacian Operator (Second Derivative)
    • Sobel Operator
  • Misc
    • Threshold
    • Image Inversion
    • Downsampling (isotropic)

\a Dual image operations

  • Image Arithmetics
    • Add two images
    • Subtract two images
    • Multiply two images
    • Divide two images
  • Binary Operations
    • Logical AND
    • Logical OR
    • Logical XOR
\section QmitkBasicImageProcessingUserManualUsage Usage All you have to do to use a filter is to:
  • Load an image into MITK
  • Select it in data manager
  • Select which filter you want to use via the drop down list
  • Press the execute button
A busy cursor appeares; when it vanishes, the operation is completed. Your filtered image is displayed and selected for further processing. (If the checkbox "Hide original image" is not selected, you will maybe not see the filter result imideately, because your filtered image is possibly hidden by the original.) For two image operations, please make sure that the correct second image is selected in the drop down menu, and the image order is correct. For sure, image order only plays a role for image subtraction and division. These are conducted (Image1 - Image2) or (Image1 / Image2), respectively. Please Note: When you select a 4D image, you can select the time step for the filter to work on via the time slider at the top of the GUI. The 3D image at this time step is extracted and processed. The result will also be a 3D image. This means, a true 4D filtering is not yet supported. \section QmitkBasicImageProcessingUserManualTrouble Troubleshooting I get an error when using a filter on a 2D image.
2D images are not yet supported... I use a filter on a 4D image, and the output is 3D.
When you select a 4D image, you can select the time step for the filter to work on via the time slider at the top of the GUI. The 3D image at this time step is extracted and processed. The result will also be a 3D image. This means, a true 4D filtering is not supported by now. A filter crashes during execution.
Maybe your image is too large. Some filter operations, like derivatives, take a lot of memory. Try downsampling your image first. 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.datamanager/documentation/UserManual/QmitkDatamanager.dox b/Plugins/org.mitk.gui.qt.datamanager/documentation/UserManual/QmitkDatamanager.dox index 6034939a5e..8d95aeb632 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/documentation/UserManual/QmitkDatamanager.dox +++ b/Plugins/org.mitk.gui.qt.datamanager/documentation/UserManual/QmitkDatamanager.dox @@ -1,108 +1,108 @@ /** -\bundlemainpage{org_datamanager} The DataManager +\page org_mitk_views_datamanager The DataManager \image html DataManager_48.png "Icon of the Module" \section QmitkDataManagerIntroduction Introduction The Datamanager is the central componenent to manage medical data like images, surfaces, etc.. After loading one or more data into the Datamanager the data are shown in the four-view window, the so called Standard View. The user can now start working on the data by just clicking into the standard view or by using the MITK-modules such as "Segmentation" or "Basic Image Processing". Available sections: - \ref QmitkDataManagerIntroduction - \ref QmitkDataManagerLoading - \ref QmitkDataManagerSaving - \ref QmitkDataManagerProperties - - \ref QmitkDataManagerPropertiesList - - \ref QmitkDataManagerPropertiesVisibility - - \ref QmitkDataManagerPropertiesRepresentation - - \ref QmitkDataManagerPropertiesPreferences + - \ref QmitkDataManagerPropertiesList + - \ref QmitkDataManagerPropertiesVisibility + - \ref QmitkDataManagerPropertiesRepresentation + - \ref QmitkDataManagerPropertiesPreferences - \ref QmitkDataManagerPropertyList \image html Overview.png "How MITK looks when starting" \section QmitkDataManagerLoading Loading Data There are three ways of loading data into the Datamanager as so called Data-Elements. The user can just drag and drop data into the Datamanager or directly into one of the four parts of the Standard View. He can as well use the Open-Button in the right upper corner. Or he can use the standard "File->Open"-Dialog on the top. A lot of file-formats can be loaded into MITK, for example
  • 2D-images/3D-volumes with or without several timesteps (*.dcm, *.ima, *.pic, ...)
  • Surfaces (*.stl, *.vtk, ...)
  • Pointsets (*.mps)
  • ...
The user can also load a series of 2D images (e.g. image001.png, image002.png ...) to a MITK 3D volume. To do this, just drag and drop one of those 2D data files into the Datamanager by holding the ALT key. After loading one or more data into the Datamanager they appear as Data-Elements in a sorted list inside the Datamanager. Data-Elements can also be sorted hierarchically as a parent-child-relation. For example after using the Segmentation-Module on Data-Element1 the result is created as Data-Element2, which is a child of Data-Element1 (see Screenshot1). The order can be changed by drag and drop. \image html Parent-Child.png "Screenshot1" The listed Data-Elements are shown in the standard view. Here the user can scale or rotate the medical objects or he can change the cutting planes of the object by just using the mouse inside this view. \section QmitkDataManagerSaving Saving Data There are two ways of saving data from the Datamanger. The user can either save the whole project with all Data-Elements by clicking on "File"->"Save Project" or he can save single Data-Elements by right-clicking->"Save", directly on a Data-Element. When saving the whole project, the sorting of Data-Elements is saved as well. By contrast the sorting is lost, when saving a single Data-Element. \section QmitkDataManagerProperties Working with the Datamanager \subsection QmitkDataManagerPropertiesList List of Data-Elements The Data-Elements are listed in the Datamanager. As described above the elements can be sorted hierarchically as a parent-child-relation. For example after using the Segmentation-Module on Data-Element1 the result is created as Data-Element2, which is a child of Data-Element1 (see Screenshot1). By drag and drop the sorting of Data-Elements and their hierarchical relation can be changed. \subsection QmitkDataManagerPropertiesVisibility Visibility of Data-Elements By default all loaded Data-Elements are visible in the standard view. The visibility can be changed by right-clicking on the Data-Element and then choosing "Toogle visibility". The box in front of the Data-Element in the Datamanager shows the visibility. A green-filled box means a visible Data-Element, an empty box means an invisible Data-Element (see Screenshot1). \subsection QmitkDataManagerPropertiesRepresentation Representation of Data-Elements There are different types of representations how to show the Data-Element inside the standard view. By right-clicking on the Data-Element all options are listed (see Screenshot2 and Screenshot 3).
  • An arbitrary color can be chosen
  • The opacity can be changed with a slide control
  • In case of images a texture interpolation can be switched on or off. The texture interpolation smoothes the image, so that no single pixels are visible anymore.
  • In case of surfaces the surface representation can be changed between points, wireframe or surface.
  • Global reinit updates all windows to contain all the current data. Reinit updates a single data item fits the windows to contain this data item.
\image html Image_properties.png "Screenshot2: Properties for images" \image html Surface_Properties.png "Screenshot3: Properties for surfaces" \subsection QmitkDataManagerPropertiesPreferences Preferences For the datamanager there are already some default hotkeys like the del-key for deleting a Data-Element. The whole list is seen in Screenshot4. From here the Hotkeys can also be changed. The preference page is found in "Window"->"Preferences". \image html Preferences.png "Screenshot4" \section QmitkDataManagerPropertyList Property List The Property List displays all the properties the currently selected Data-Element has. Which properties these are depends on the Data-Element. Examples are opacity, shader, visibility. These properties can be changed by clicking on the appropriate field in the "value" column. \image html PropertyList.png "Screenshot5: Property List" */ diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeModel.cpp b/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeModel.cpp index 53b7553e29..36d62a7a61 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeModel.cpp +++ b/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeModel.cpp @@ -1,313 +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. ===================================================================*/ #include "QmitkPropertyTreeItem.h" #include "QmitkPropertyTreeModel.h" #include #include #include #include #include #include QmitkPropertyTreeModel::QmitkPropertyTreeModel(QObject *parent) : QAbstractItemModel(parent), m_Properties(NULL), m_RootItem(NULL) { CreateRootItem(); } void QmitkPropertyTreeModel::SetProperties(mitk::PropertyList *properties) { if (properties == m_Properties) return; beginResetModel(); if (m_RootItem != NULL) { delete m_RootItem; m_RootItem = NULL; m_Properties = NULL; } CreateRootItem(); if (properties != NULL && !properties->IsEmpty()) { m_Properties = properties; std::map::const_iterator end = properties->GetMap()->end(); for (std::map::const_iterator iter = properties->GetMap()->begin(); iter != end; ++iter) { QList data; data << iter->first.c_str() << QVariant::fromValue((reinterpret_cast(iter->second.GetPointer()))); m_RootItem->AppendChild(new QmitkPropertyTreeItem(data)); } } endResetModel(); } void QmitkPropertyTreeModel::CreateRootItem() { if (m_RootItem == NULL) { QList rootData; rootData << "Property" << "Value"; m_RootItem = new QmitkPropertyTreeItem(rootData); } } QmitkPropertyTreeModel::~QmitkPropertyTreeModel() { delete m_RootItem; } int QmitkPropertyTreeModel::columnCount(const QModelIndex &parent) const { if (parent.isValid()) return static_cast(parent.internalPointer())->GetColumnCount(); else return m_RootItem->GetColumnCount(); } QVariant QmitkPropertyTreeModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (index.column() == 0 && role == Qt::DisplayRole) return static_cast(index.internalPointer())->GetData(index.column()); if (index.column() == 1 && static_cast(index.internalPointer())->GetData(index.column()).isValid()) { mitk::BaseProperty *property = reinterpret_cast(static_cast(index.internalPointer())->GetData(index.column()).value()); if (mitk::ColorProperty *colorProperty = dynamic_cast(property)) { if (role == Qt::DisplayRole || role == Qt::EditRole) { mitk::Color mitkColor = colorProperty->GetColor(); QColor qtColor(static_cast(mitkColor.GetRed() * 255), static_cast(mitkColor.GetGreen() * 255), static_cast(mitkColor.GetBlue() * 255)); return QVariant::fromValue(qtColor); } } else if (mitk::BoolProperty *boolProperty = dynamic_cast(property)) { if (role == Qt::CheckStateRole) return boolProperty->GetValue() ? Qt::Checked : Qt::Unchecked; } else if (mitk::StringProperty *stringProperty = dynamic_cast(property)) { if (role == Qt::DisplayRole || role == Qt::EditRole) return QString(stringProperty->GetValue()); } else if (mitk::IntProperty *intProperty = dynamic_cast(property)) { if (role == Qt::DisplayRole || role == Qt::EditRole) return intProperty->GetValue(); } else if (mitk::FloatProperty *floatProperty = dynamic_cast(property)) { if (role == Qt::DisplayRole || role == Qt::EditRole) return floatProperty->GetValue(); } else if (mitk::DoubleProperty *doubleProperty = dynamic_cast(property)) { if (role == Qt::DisplayRole || role == Qt::EditRole) return doubleProperty->GetValue(); } else if (mitk::EnumerationProperty *enumProperty = dynamic_cast(property)) { if (role == Qt::DisplayRole) { return QString::fromStdString(enumProperty->GetValueAsString()); } else if (role == Qt::EditRole) { QStringList values; for (mitk::EnumerationProperty::EnumConstIterator iter = enumProperty->Begin(); iter != enumProperty->End(); ++iter) values << QString::fromStdString(iter->second); return QVariant(values); } } else { if (role == Qt::DisplayRole) return QString::fromStdString(property->GetValueAsString()); } } return QVariant(); } Qt::ItemFlags QmitkPropertyTreeModel::flags(const QModelIndex &index) const { Qt::ItemFlags flags = QAbstractItemModel::flags(index); if (index.column() == 1) { if (index.data(Qt::EditRole).isValid()) flags |= Qt::ItemIsEditable; if (index.data(Qt::CheckStateRole).isValid()) flags |= Qt::ItemIsUserCheckable; } return flags; } QVariant QmitkPropertyTreeModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) return m_RootItem->GetData(section); return QVariant(); } QModelIndex QmitkPropertyTreeModel::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) return QModelIndex(); QmitkPropertyTreeItem *parentItem = parent.isValid() ? static_cast(parent.internalPointer()) : m_RootItem; QmitkPropertyTreeItem *childItem = parentItem->GetChild(row); if (childItem != NULL) return createIndex(row, column, childItem); else return QModelIndex(); } QModelIndex QmitkPropertyTreeModel::parent(const QModelIndex &child) const { if (!child.isValid()) return QModelIndex(); QmitkPropertyTreeItem *parentItem = static_cast(child.internalPointer())->GetParent(); if (parentItem == m_RootItem) return QModelIndex(); return createIndex(parentItem->GetRow(), 0, parentItem); } int QmitkPropertyTreeModel::rowCount(const QModelIndex &parent) const { if (parent.column() > 0) return 0; QmitkPropertyTreeItem *parentItem = parent.isValid() ? static_cast(parent.internalPointer()) : m_RootItem; return parentItem->GetChildCount(); } bool QmitkPropertyTreeModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (index.isValid() && (role == Qt::EditRole || role == Qt::CheckStateRole)) { if (index.column() == 1) { mitk::BaseProperty *property = reinterpret_cast(static_cast(index.internalPointer())->GetData(index.column()).value()); if (mitk::ColorProperty *colorProperty = dynamic_cast(property)) { QColor qtColor = value.value(); if (!qtColor.isValid()) return false; mitk::Color mitkColor = colorProperty->GetColor(); mitkColor.SetRed(qtColor.red() / 255.0); mitkColor.SetGreen(qtColor.green() / 255.0); mitkColor.SetBlue(qtColor.blue() / 255.0); colorProperty->SetColor(mitkColor); m_Properties->InvokeEvent(itk::ModifiedEvent()); m_Properties->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if (mitk::BoolProperty *boolProperty = dynamic_cast(property)) { boolProperty->SetValue(value.toInt() == Qt::Checked ? true : false); m_Properties->InvokeEvent(itk::ModifiedEvent()); m_Properties->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if (mitk::StringProperty *stringProperty = dynamic_cast(property)) { stringProperty->SetValue(value.toString().toStdString()); m_Properties->InvokeEvent(itk::ModifiedEvent()); m_Properties->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if (mitk::IntProperty *intProperty = dynamic_cast(property)) { int intValue = value.toInt(); if (intValue != intProperty->GetValue()) { intProperty->SetValue(intValue); m_Properties->InvokeEvent(itk::ModifiedEvent()); m_Properties->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } else if (mitk::FloatProperty *floatProperty = dynamic_cast(property)) { - int floatValue = value.toFloat(); + float floatValue = value.toFloat(); - if (floatValue != floatProperty->GetValue()) + if (abs(floatValue - floatProperty->GetValue()) >= mitk::eps) { floatProperty->SetValue(floatValue); m_Properties->InvokeEvent(itk::ModifiedEvent()); m_Properties->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } else if (mitk::EnumerationProperty *enumProperty = dynamic_cast(property)) { std::string activatedItem = value.toString().toStdString(); if (activatedItem != enumProperty->GetValueAsString()) { enumProperty->SetValue(activatedItem); m_Properties->InvokeEvent(itk::ModifiedEvent()); m_Properties->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } } emit dataChanged(index, index); return true; } return false; } diff --git a/Plugins/org.mitk.gui.qt.dicom./resources/dicom.qrc b/Plugins/org.mitk.gui.qt.dicom./resources/dicom.qrc index bf16525381..0cdc545472 100644 --- a/Plugins/org.mitk.gui.qt.dicom./resources/dicom.qrc +++ b/Plugins/org.mitk.gui.qt.dicom./resources/dicom.qrc @@ -1,10 +1,11 @@ drive-harddisk_32.png folder_32.png media-optical_32.png network-workgroup_32.png network-idle_16.png network-offline_16.png + network-error_16.png diff --git a/Plugins/org.mitk.gui.qt.dicom/CMakeLists.txt b/Plugins/org.mitk.gui.qt.dicom/CMakeLists.txt index f19077c93f..82b57c1fd6 100644 --- a/Plugins/org.mitk.gui.qt.dicom/CMakeLists.txt +++ b/Plugins/org.mitk.gui.qt.dicom/CMakeLists.txt @@ -1,15 +1,22 @@ project(org_mitk_gui_qt_dicom) set(QT_USE_QTSQL 1) +set(DCMTK_INSTALL_BIN ${DCMTK_DIR}/bin) include_directories(${CTK_INCLUDE_DIRS}) -MITK_INSTALL(PROGRAMS ${VAR_STORESCP}) +find_program(MITK_STORESCP storescp PATH ${DCMTK_INSTALL_BIN}) +mark_as_advanced(MITK_STORESCP) + +configure_file( org_mitk_gui_qt_dicom_config.h.in org_mitk_gui_qt_dicom_config.h @ONLY) + +MITK_INSTALL_HELPER_APP(${MITK_STORESCP}) + MACRO_CREATE_MITK_CTK_PLUGIN( EXPORT_DIRECTIVE DICOM_EXPORT EXPORTED_INCLUDE_SUFFIXES src MODULE_DEPENDENCIES QmitkExt mitkDicomUI ) target_link_libraries(${PLUGIN_TARGET} ${CTK_LIBRARIES}) diff --git a/Plugins/org.mitk.gui.qt.dicom/documentation/Manual/Manual.dox b/Plugins/org.mitk.gui.qt.dicom/documentation/Manual/Manual.dox index 4cefeb9067..56f79ae50a 100644 --- a/Plugins/org.mitk.gui.qt.dicom/documentation/Manual/Manual.dox +++ b/Plugins/org.mitk.gui.qt.dicom/documentation/Manual/Manual.dox @@ -1,19 +1,19 @@ /** -\bundlemainpage{org_mitk_gui_qt_dicom} Dicom +\page org_mitk_gui_qt_dicom Dicom \image html icon.png "Icon of Dicom" Available sections: - \ref org_mitk_gui_qt_dicomOverview \section org_mitk_gui_qt_dicomOverview Describe the features of your awesome plugin here
  • Increases productivity
  • Creates beautiful images
  • Generates PhD thesis
  • Brings world peace
*/ diff --git a/Plugins/org.mitk.gui.qt.dicom/org_mitk_gui_qt_dicom_config.h.in b/Plugins/org.mitk.gui.qt.dicom/org_mitk_gui_qt_dicom_config.h.in new file mode 100644 index 0000000000..6492b4438b --- /dev/null +++ b/Plugins/org.mitk.gui.qt.dicom/org_mitk_gui_qt_dicom_config.h.in @@ -0,0 +1,3 @@ +// Generated file, do not edit! + +#define MITK_STORESCP "@MITK_STORESCP@" \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.dicom/resources/dicom.qrc b/Plugins/org.mitk.gui.qt.dicom/resources/dicom.qrc index bf16525381..0cdc545472 100644 --- a/Plugins/org.mitk.gui.qt.dicom/resources/dicom.qrc +++ b/Plugins/org.mitk.gui.qt.dicom/resources/dicom.qrc @@ -1,10 +1,11 @@ drive-harddisk_32.png folder_32.png media-optical_32.png network-workgroup_32.png network-idle_16.png network-offline_16.png + network-error_16.png diff --git a/Plugins/org.mitk.gui.qt.dicom/src/internal/DicomEventHandler.cpp b/Plugins/org.mitk.gui.qt.dicom/src/internal/DicomEventHandler.cpp index 5ce9c09daf..fb1e9b04a0 100644 --- a/Plugins/org.mitk.gui.qt.dicom/src/internal/DicomEventHandler.cpp +++ b/Plugins/org.mitk.gui.qt.dicom/src/internal/DicomEventHandler.cpp @@ -1,99 +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. ===================================================================*/ #include "mitkPluginActivator.h" #include "DicomEventHandler.h" #include #include #include #include #include #include #include #include #include #include DicomEventHandler::DicomEventHandler() { } DicomEventHandler::~DicomEventHandler() { } void DicomEventHandler::OnSignalAddSeriesToDataManager(const ctkEvent& ctkEvent) { QString patientName = ctkEvent.getProperty("PatientName").toString(); QString studyUID = ctkEvent.getProperty("StudyUID").toString(); QString studyName = ctkEvent.getProperty("StudyName").toString(); QString seriesUID = ctkEvent.getProperty("SeriesUID").toString(); QString seriesName = ctkEvent.getProperty("SeriesName").toString(); QString path = ctkEvent.getProperty("Path").toString(); std::list qualifiedUIDs; mitk::DicomSeriesReader::StringContainer seriesToLoad; std::size_t found; mitk::DicomSeriesReader::UidFileNamesMap dicomSeriesMap = mitk::DicomSeriesReader::GetSeries(path.toStdString(),false); mitk::DicomSeriesReader::UidFileNamesMap::const_iterator qualifiedSeriesInstanceUIDIterator; for(qualifiedSeriesInstanceUIDIterator = dicomSeriesMap.begin(); qualifiedSeriesInstanceUIDIterator != dicomSeriesMap.end(); ++qualifiedSeriesInstanceUIDIterator) { found = qualifiedSeriesInstanceUIDIterator->first.find(seriesUID.toStdString()); if(found!= qualifiedSeriesInstanceUIDIterator->first.npos) { qualifiedUIDs.push_back(qualifiedSeriesInstanceUIDIterator->first); seriesToLoad = qualifiedSeriesInstanceUIDIterator->second; } } mitk::DataNode::Pointer node = mitk::DicomSeriesReader::LoadDicomSeries(seriesToLoad); if (node.IsNull()) { MITK_ERROR << "Could not load series: " << seriesUID.toStdString(); } else - { + { + //Get Reference for default data storage. ctkServiceReference serviceReference =mitk::PluginActivator::getContext()->getServiceReference(); mitk::IDataStorageService* storageService = mitk::PluginActivator::getContext()->getService(serviceReference); + mitk::DataStorage* dataStorage = storageService->GetDefaultDataStorage().GetPointer()->GetDataStorage(); + + dataStorage->Add(node); + + // Initialize the RenderWindow + mitk::TimeSlicedGeometry::Pointer geometry = dataStorage->ComputeBoundingGeometry3D(dataStorage->GetAll()); + mitk::RenderingManager::GetInstance()->InitializeViews(geometry); + - storageService->GetActiveDataStorage().GetPointer()->GetDataStorage()->Add(node); - mitk::RenderingManager::GetInstance()->SetDataStorage(storageService->GetActiveDataStorage().GetPointer()->GetDataStorage()); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void DicomEventHandler::OnSignalRemoveSeriesFromStorage(const ctkEvent& ctkEvent) { } void DicomEventHandler::SubscribeSlots() { ctkServiceReference ref = mitk::PluginActivator::getContext()->getServiceReference(); if (ref) { ctkEventAdmin* eventAdmin = mitk::PluginActivator::getContext()->getService(ref); ctkDictionary properties; properties[ctkEventConstants::EVENT_TOPIC] = "org/mitk/gui/qt/dicom/ADD"; eventAdmin->subscribeSlot(this, SLOT(OnSignalAddSeriesToDataManager(ctkEvent)), properties); properties[ctkEventConstants::EVENT_TOPIC] = "org/mitk/gui/qt/dicom/DELETED"; eventAdmin->subscribeSlot(this, SLOT(OnSignalRemoveSeriesFromStorage(ctkEvent)), properties); } } diff --git a/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkDicomDirectoryListener.cpp b/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkDicomDirectoryListener.cpp index 07de69a223..993a39b8a7 100644 --- a/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkDicomDirectoryListener.cpp +++ b/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkDicomDirectoryListener.cpp @@ -1,116 +1,148 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "QmitkDicomDirectoryListener.h" #include #include #include #include +#include QmitkDicomDirectoryListener::QmitkDicomDirectoryListener() : m_FileSystemWatcher(new QFileSystemWatcher()) +, m_IsListening(true) { - connect(m_FileSystemWatcher,SIGNAL(directoryChanged(const QString&)),this,SLOT(OnDirectoryChanged(const QString&))); + connect(m_FileSystemWatcher,SIGNAL(directoryChanged(const QString&)),this,SLOT(OnDirectoryChanged(const QString&))); } QmitkDicomDirectoryListener::~QmitkDicomDirectoryListener() { + m_IsListening = false; + RemoveTemporaryFiles(); delete m_FileSystemWatcher; } - void QmitkDicomDirectoryListener::OnDirectoryChanged(const QString&) -{ - SetFilesToImport(); - m_ImportingFiles.append(m_FilesToImport); - emit SignalAddDicomData(m_FilesToImport); -} - -void QmitkDicomDirectoryListener::OnDicomImportFinished(const QStringList& finishedFiles) { - RemoveFilesFromDirectoryAndImportingFilesList(finishedFiles); -} - -void QmitkDicomDirectoryListener::SetFilesToImport() -{ - m_FilesToImport.clear(); - QDir listenerDirectory(m_DicomListenerDirectory); - QFileInfoList entries = listenerDirectory.entryInfoList(QDir::Files); - if(!entries.isEmpty()) + if(m_IsListening) { - QFileInfoList::const_iterator file; - for(file = entries.constBegin(); file != entries.constEnd(); ++file ) + QDirIterator it( m_DicomListenerDirectory.absolutePath() , QDir::Files , QDirIterator::Subdirectories); + QString currentPath; + + m_FilesToImport.clear(); + while(it.hasNext()) { - if(!m_ImportingFiles.contains((*file).absoluteFilePath())) + it.next(); + currentPath = it.fileInfo().absoluteFilePath(); + if(!m_AlreadyImportedFiles.contains(currentPath)) { - m_FilesToImport.append((*file).absoluteFilePath()); + m_AlreadyImportedFiles.insert( currentPath , currentPath ); + m_FilesToImport.append(currentPath); } } - } + if(!m_FilesToImport.isEmpty()) + { + emit SignalStartDicomImport(m_FilesToImport); + } + } } -void QmitkDicomDirectoryListener::RemoveFilesFromDirectoryAndImportingFilesList(const QStringList& files) +void QmitkDicomDirectoryListener::OnImportFinished() { - QStringListIterator fileToDeleteIterator(files); - while(fileToDeleteIterator.hasNext()) + m_IsListening = false; + RemoveTemporaryFiles(); + m_AlreadyImportedFiles.clear(); + m_IsListening = true; +} + +void QmitkDicomDirectoryListener::OnDicomNetworkError(const QString& errorMsg) +{ + m_IsListening = false; + m_AlreadyImportedFiles.clear(); + m_IsListening = true; +} + +void QmitkDicomDirectoryListener::RemoveAlreadyImportedEntries(const QStringList& fileEntries) +{ + QStringListIterator it(fileEntries); + QString currentEntry; + while(it.hasNext()) { - QFile file(fileToDeleteIterator.next()); - if(m_ImportingFiles.contains(file.fileName())) + currentEntry = m_DicomListenerDirectory.absoluteFilePath(it.next()); + if(m_AlreadyImportedFiles.contains(currentEntry)) { - m_ImportingFiles.removeOne(file.fileName()); - file.remove(); + m_AlreadyImportedFiles.remove(currentEntry); } } } -void QmitkDicomDirectoryListener::SetDicomListenerDirectory(const QString& directory) +void QmitkDicomDirectoryListener::RemoveTemporaryFiles(const QStringList& fileEntries) { - if(isOnlyListenedDirectory(directory)) + /** + QStringListIterator it(fileEntries); + QString currentEntry; + while(it.hasNext()) { - QDir listenerDirectory = QDir(directory); - CreateListenerDirectory(listenerDirectory); - - m_DicomListenerDirectory=listenerDirectory.absolutePath(); - m_FileSystemWatcher->addPath(m_DicomListenerDirectory); - MITK_INFO << m_DicomListenerDirectory.toStdString(); + currentEntry = m_DicomListenerDirectory.absoluteFilePath(it.next()); + m_DicomListenerDirectory.remove(currentEntry); } + */ } -const QString& QmitkDicomDirectoryListener::GetDicomListenerDirectory() +void QmitkDicomDirectoryListener::RemoveTemporaryFiles() { - return m_DicomListenerDirectory; -} - -void QmitkDicomDirectoryListener::CreateListenerDirectory(const QDir& directory) -{ - if(!directory.exists()) +/** +* dangerous code !!! + + QDirIterator it( m_DicomListenerDirectory.absolutePath() , QDir::AllEntries , QDirIterator::Subdirectories); + while(it.hasNext()) { - directory.mkpath(directory.absolutePath()); + it.next(); + m_DicomListenerDirectory.remove(it.fileInfo().absoluteFilePath()); } +*/ } -bool QmitkDicomDirectoryListener::isOnlyListenedDirectory(const QString& directory) +void QmitkDicomDirectoryListener::SetDicomListenerDirectory(const QString& directory) { - bool isOnlyListenedDirectory = false; - if(m_FileSystemWatcher->directories().count()==0||m_FileSystemWatcher->directories().count()==1) + QDir dir(directory); + if(dir.exists()) { - if(!m_FileSystemWatcher->directories().contains(directory)) - { - isOnlyListenedDirectory = true; - } + m_DicomListenerDirectory=dir; + m_FileSystemWatcher->addPath(m_DicomListenerDirectory.absolutePath()); } - return isOnlyListenedDirectory; -} \ No newline at end of file + else + { + dir.mkpath(directory); + m_DicomListenerDirectory=dir; + m_FileSystemWatcher->addPath(m_DicomListenerDirectory.absolutePath()); + } +} + +QString QmitkDicomDirectoryListener::GetDicomListenerDirectory() +{ + return m_DicomListenerDirectory.absolutePath(); +} + +bool QmitkDicomDirectoryListener::IsListening() +{ + return m_IsListening; +} + +void QmitkDicomDirectoryListener::SetListening(bool listening) +{ + m_IsListening = listening; +} diff --git a/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkDicomDirectoryListener.h b/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkDicomDirectoryListener.h index 010cda4e90..43ac3967da 100644 --- a/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkDicomDirectoryListener.h +++ b/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkDicomDirectoryListener.h @@ -1,78 +1,95 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 QmitkDicomDirectoryListener_h #define QmitkDicomDirectoryListener_h #include #include +#include #include #include #include #include class QmitkDicomDirectoryListener : public QObject { Q_OBJECT public: QmitkDicomDirectoryListener(); - + virtual ~QmitkDicomDirectoryListener(); /// @brief sets listened directory, note that only one directory can be set. void SetDicomListenerDirectory(const QString&); /// @brief get filepath to the listened directory. - const QString& GetDicomListenerDirectory(); + QString GetDicomListenerDirectory(); + + /// @brief get the status whether the directorey listener is listening or not. + bool IsListening(); + + /// @brief set the directory listener listening. + void SetListening(bool listening); signals: - /// @brief signal starts the dicom import of the given file (the QStringList will only contain one file here). - void SignalAddDicomData(const QStringList&); + /// @brief signal starts the dicom import of the given file list. + void SignalStartDicomImport(const QStringList&); public slots: /// \brief called when listener directory changes void OnDirectoryChanged(const QString&); - /// \brief called when import is finished - void OnDicomImportFinished(const QStringList&); + /// \brief called when error occours during dicom store request + void OnDicomNetworkError(const QString&); + /// \brief called when import of files is finished. + void OnImportFinished(); protected: - /// \brief creates directory if it's not already existing. + /// \brief creates directory if it's not already existing. void CreateListenerDirectory(const QDir& directory); - /// \brief checks wheter the given directory is the only directory that is listened. - bool isOnlyListenedDirectory(const QString& directory); - - /// \brief Composes the filename and initializes m_LastRetrievedFile with it + /// \brief Composes the filename and initializes m_LastRetrievedFile with it. void SetFilesToImport(); - /// \brief removes files from - void RemoveFilesFromDirectoryAndImportingFilesList(const QStringList& files); + /// \brief removes files from listener directory. + void RemoveTemporaryFiles(); + + /// \brief removes files in the files list from listener directory. + void RemoveTemporaryFiles(const QStringList& files); + + /// \brief removes entries from m_AlreadyImportedFiles hash table. + void RemoveAlreadyImportedEntries(const QStringList& files); QFileSystemWatcher* m_FileSystemWatcher; + QStringList m_FilesToImport; - QStringList m_ImportingFiles; - QString m_DicomListenerDirectory; + + QHash m_AlreadyImportedFiles; + + QDir m_DicomListenerDirectory; + + bool m_IsListening; }; #endif // QmitkDicomListener_h \ No newline at end of file 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 b2039387f9..76343944d3 100644 --- a/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkDicomEditor.cpp +++ b/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkDicomEditor.cpp @@ -1,249 +1,323 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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"; 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_Handler; delete m_Publisher; delete m_StoreSCPLauncher; delete m_Thread; delete m_DicomDirectoryListener; + 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"); SetListenerDirectory("ListenerDirectory"); StartDicomDirectoryListener(); - m_Controls.m_ctkDICOMQueryRetrieveWidget->useProgressDialog(true); + SetupImportDialog(); + SetupProgressDialog(parent); - connect(m_Controls.externalDataWidget,SIGNAL(SignalAddDicomData(const QString&)),m_Controls.internalDataWidget,SLOT(StartDicomImport(const QString&))); - connect(m_Controls.externalDataWidget,SIGNAL(SignalAddDicomData(const QStringList&)),m_Controls.internalDataWidget,SLOT(StartDicomImport(const QStringList&))); + 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(const QStringList&)),this,SLOT(OnViewButtonAddToDataManager(const QStringList&))); connect(m_Controls.externalDataWidget,SIGNAL(SignalChangePage(int)), this, SLOT(OnChangePage(int))); - connect(m_Controls.internalDataWidget,SIGNAL(FinishedImport(const QString&)),this,SLOT(OnDicomImportFinished(const QString&))); - connect(m_Controls.internalDataWidget,SIGNAL(FinishedImport(const QStringList&)),this,SLOT(OnDicomImportFinished(const QStringList&))); + connect(m_Controls.internalDataWidget,SIGNAL(SignalFinishedImport()),this,SLOT(OnDicomImportFinished())); connect(m_Controls.internalDataWidget,SIGNAL(SignalDicomToDataManager(const QStringList&)),this,SLOT(OnViewButtonAddToDataManager(const QStringList&))); - connect(m_Controls.CDButton, SIGNAL(clicked()), m_Controls.externalDataWidget, SLOT(OnFolderCDImport())); - connect(m_Controls.FolderButton, SIGNAL(clicked()), m_Controls.externalDataWidget, SLOT(OnFolderCDImport())); + 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_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.radioButton,SIGNAL(clicked()),this,SLOT(StartStopStoreSCP())); +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(const QString&) -{ -} - -void QmitkDicomEditor::OnDicomImportFinished(const QStringList&) +void QmitkDicomEditor::OnDicomImportFinished() { } void QmitkDicomEditor::StartDicomDirectoryListener() { if(!m_Thread->isRunning()) { m_DicomDirectoryListener->SetDicomListenerDirectory(m_ListenerDirectory); - connect(m_DicomDirectoryListener,SIGNAL(SignalAddDicomData(const QStringList&)),m_Controls.internalDataWidget,SLOT(StartDicomImport(const QStringList&)),Qt::DirectConnection); - connect(m_Controls.internalDataWidget,SIGNAL(FinishedImport(const QStringList&)),m_DicomDirectoryListener,SLOT(OnDicomImportFinished(const QStringList&)),Qt::DirectConnection); + 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(const QStringList& eventProperties) { ctkDictionary properties; properties["PatientName"] = eventProperties.at(0); properties["StudyUID"] = eventProperties.at(1); properties["StudyName"] = eventProperties.at(2); properties["SeriesUID"] = eventProperties.at(3); properties["SeriesName"] = eventProperties.at(4); properties["Path"] = eventProperties.at(5); 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_ListenerDirectory); 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::SetListenerDirectory(const QString& listenerDirectory) { m_ListenerDirectory.clear(); m_ListenerDirectory.append(m_PluginDirectory); m_ListenerDirectory.append(listenerDirectory); } diff --git a/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkDicomEditor.h b/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkDicomEditor.h index 7493e1c02e..1e0234bdb6 100644 --- a/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkDicomEditor.h +++ b/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkDicomEditor.h @@ -1,135 +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 QmitkDicomEditor_h #define QmitkDicomEditor_h #include #include #include #include "ui_QmitkDicomEditorControls.h" #include "QmitkDicomDirectoryListener.h" #include "QmitkStoreSCPLauncher.h" #include "QmitkStoreSCPLauncherBuilder.h" #include "DicomEventHandler.h" #include "QmitkDicomDataEventPublisher.h" +#include #include #include #include #include #include #include #include #include #include +#include +#include +#include #include /*! \brief QmitkDicomEditor \warning This class is not yet documented. Use "git blame" and ask the author to provide basic documentation. \sa QmitkFunctionality \ingroup ${plugin_target}_internal */ class DICOM_EXPORT QmitkDicomEditor : public berry::QtEditorPart, virtual public berry::IPartListener { - // this is needed for all Qt objects that should have a Qt meta-object +// 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(QmitkDicomEditor) static const std::string EDITOR_ID; QmitkDicomEditor(); virtual ~QmitkDicomEditor(); 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; } signals: + void SignalStartDicomImport(const QString&); - protected slots: +protected slots: - /// \brief Called when StoreSCP shold start - void StartStoreSCP(); + void OnImportProgress(int progress); - /// \brief Called when StoreSCP should stop - void StopStoreSCP(); + /// \brief Called when import is finished + void OnDicomImportFinished(); - /// \brief Called when import is finished - void OnDicomImportFinished(const QString& path); + /// \brief Called when Query Retrieve or Import Folder was clicked. + void OnQueryRetrieve(); - /// \brief Called when import is finished - void OnDicomImportFinished(const QStringList& path); + /// \brief Called when LocalStorageButton was clicked. + void OnLocalStorage(); - /// \brief Called when Query Retrieve or Import Folder was clicked. - void OnQueryRetrieve(); + /// \brief Called when FolderCDButton was clicked. + void OnFolderCDImport(); - /// \brief Called when LocalStorageButton was clicked. - void OnLocalStorage(); + /// \brief Called when ok on import dialog is clicked was clicked. + void OnFileSelected(QString); - /// \brief Called when FolderCDButton was clicked. - void OnFolderCDImport(); + /// \brief Called when view button is clicked. Sends out an event for adding the current selected file to the mitkDataStorage. + void OnViewButtonAddToDataManager(const QStringList& eventProperties); - /// \brief Called when view button is clicked. Sends out an event for adding the current selected file to the mitkDataStorage. - void OnViewButtonAddToDataManager(const QStringList& eventProperties); + void OnChangePage(int); - void StartDicomDirectoryListener(); + void OnStoreSCPStatusChanged(const QString& status); - void OnChangePage(int); + void OnDicomNetworkError(const QString& status); - void OnStoreSCPStatusChanged(const QString& status); +protected: - void TestHandler(); + /// \brief Called when StoreSCP shold start + void StartStoreSCP(); - void SetDatabaseDirectory(const QString& databaseDirectory); - - void SetListenerDirectory(const QString& listenerDirectory); + /// \brief Called when StoreSCP should stop + void StopStoreSCP(); -protected: + void TestHandler(); + + void SetDatabaseDirectory(const QString& databaseDirectory); + + void SetListenerDirectory(const QString& listenerDirectory); + + void StartDicomDirectoryListener(); + + void SetupProgressDialog(QWidget* parent); + + void SetupImportDialog(); + + ctkFileDialog* m_ImportDialog; + + QProgressDialog* m_ProgressDialog; + + QLabel* m_ProgressDialogLabel; void CreateQtPartControl(QWidget *parent); void SetPluginDirectory(); Events::Types GetPartEventTypes() const; Ui::QmitkDicomEditorControls m_Controls; QThread* m_Thread; QmitkDicomDirectoryListener* m_DicomDirectoryListener; QmitkStoreSCPLauncherBuilder m_Builder; QmitkStoreSCPLauncher* m_StoreSCPLauncher; DicomEventHandler* m_Handler; QmitkDicomDataEventPublisher* m_Publisher; QString m_PluginDirectory; QString m_ListenerDirectory; QString m_DatabaseDirectory; }; #endif // QmitkDicomEditor_h diff --git a/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkStoreSCPLauncher.cpp b/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkStoreSCPLauncher.cpp index 9ae32ca814..ddd9c54abb 100644 --- a/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkStoreSCPLauncher.cpp +++ b/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkStoreSCPLauncher.cpp @@ -1,146 +1,221 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "QmitkStoreSCPLauncher.h" -#include #include #include #include #include #include #include #include #include #include +#include #include +#include "org_mitk_gui_qt_dicom_config.h" QmitkStoreSCPLauncher::QmitkStoreSCPLauncher(QmitkStoreSCPLauncherBuilder* builder) : m_StoreSCP(new QProcess()) { connect( m_StoreSCP, SIGNAL(error(QProcess::ProcessError)),this, SLOT(OnProcessError(QProcess::ProcessError))); connect( m_StoreSCP, SIGNAL(stateChanged(QProcess::ProcessState)),this, SLOT(OnStateChanged(QProcess::ProcessState))); + //connect( m_StoreSCP, SIGNAL(readyReadStandardError()),this, SLOT(OnReadyProcessError())); + connect( m_StoreSCP, SIGNAL(readyReadStandardOutput()),this, SLOT(OnReadyProcessOutput())); SetArgumentList(builder); + //m_StoreSCP->setStandardOutputFile("OutputLog.log"); + //m_StoreSCP->setStandardErrorFile("ErrorLog.log"); } QmitkStoreSCPLauncher::~QmitkStoreSCPLauncher() { m_StoreSCP->close(); m_StoreSCP->waitForFinished(1000); + DeleteTemporaryData(); delete m_StoreSCP; } void QmitkStoreSCPLauncher::StartStoreSCP() { FindPathToStoreSCP(); MITK_INFO << m_PathToStoreSCP.toStdString(); MITK_INFO << m_ArgumentList[7].toStdString(); m_StoreSCP->start(m_PathToStoreSCP,m_ArgumentList); } void QmitkStoreSCPLauncher::FindPathToStoreSCP() { QString appPath= QCoreApplication::applicationDirPath(); if(m_PathToStoreSCP.isEmpty()) { QString fileName; #ifdef _WIN32 - - appPath.append("/../../../DCMTK-install/bin"); fileName = "/storescp.exe"; #else - appPath.append("/../../DCMTK-install/bin"); fileName = "/storescp"; #endif - m_PathToStoreSCP.clear(); - m_PathToStoreSCP.append(fileName); + + m_PathToStoreSCP = fileName; //In developement the storescp isn't copied into bin directory if(!QFile::exists(m_PathToStoreSCP)) { - m_PathToStoreSCP = appPath; - m_PathToStoreSCP.append(fileName); + m_PathToStoreSCP = static_cast(MITK_STORESCP); } } } +void QmitkStoreSCPLauncher::OnReadyProcessOutput() +{ + QString out(m_StoreSCP->readAllStandardOutput()); + QStringList allDataList,importList; + + allDataList = out.split("\n",QString::SkipEmptyParts); + QStringListIterator it(allDataList); + + while(it.hasNext()) + { + QString output = it.next(); + if (output.contains("E: ")) + { + output.replace("E: ",""); + m_ErrorText = output; + OnProcessError(QProcess::UnknownError); + return; + } + if(output.contains("I: storing DICOM file: ")) + { + output.replace("I: storing DICOM file: ",""); + importList += output; + } + } + if(!importList.isEmpty()) + { + emit SignalStartImport(importList); + } +} + void QmitkStoreSCPLauncher::OnProcessError(QProcess::ProcessError err) { switch(err) { case QProcess::FailedToStart: - m_ErrorText = QString("Failed to start storage provider: ").append(m_StoreSCP->errorString()); + m_ErrorText.prepend("Failed to start storage provider: "); + m_ErrorText.append(m_StoreSCP->errorString()); + emit SignalStoreSCPError(m_ErrorText); + m_ErrorText.clear(); break; case QProcess::Crashed: - m_ErrorText = QString("Storage provider crashed: ").append(m_StoreSCP->errorString()); + m_ErrorText.prepend("Storage provider closed: "); + m_ErrorText.append(m_StoreSCP->errorString()); + emit SignalStoreSCPError(m_ErrorText); + m_ErrorText.clear(); break; case QProcess::Timedout: - m_ErrorText = QString("Storage provider timeout: ").append(m_StoreSCP->errorString()); + m_ErrorText.prepend("Storage provider timeout: "); + m_ErrorText.append(m_StoreSCP->errorString()); + emit SignalStoreSCPError(m_ErrorText); + m_ErrorText.clear(); break; case QProcess::WriteError: - m_ErrorText = QString("Storage provider write error: ").append(m_StoreSCP->errorString()); + m_ErrorText.prepend("Storage provider write error: "); + m_ErrorText.append(m_StoreSCP->errorString()); + emit SignalStoreSCPError(m_ErrorText); + m_ErrorText.clear(); break; case QProcess::ReadError: - m_ErrorText = QString("Storage provider read error: ").append(m_StoreSCP->errorString()); + m_ErrorText.prepend("Storage provider read error: "); + m_ErrorText.append(m_StoreSCP->errorString()); + emit SignalStoreSCPError(m_ErrorText); + m_ErrorText.clear(); break; case QProcess::UnknownError: - m_ErrorText = QString("Storage provider unknown error: ").append(m_StoreSCP->errorString()); + m_ErrorText.prepend("Storage provider unknown error: "); + m_ErrorText.append(m_StoreSCP->errorString()); + emit SignalStoreSCPError(m_ErrorText); + m_ErrorText.clear(); break; default: - m_ErrorText = QString("Storage provider unknown error: ").append(m_StoreSCP->errorString()); + m_ErrorText.prepend("Storage provider unknown error: "); + m_ErrorText.append(m_StoreSCP->errorString()); + emit SignalStoreSCPError(m_ErrorText); + m_ErrorText.clear(); break; } } void QmitkStoreSCPLauncher::OnStateChanged(QProcess::ProcessState status) { switch(status) { case QProcess::NotRunning: - m_StatusText = QString("Storage provider not running: "); + m_StatusText.prepend("Storage provider not running!"); emit SignalStatusOfStoreSCP(m_StatusText); + m_StatusText.clear(); break; case QProcess::Starting: - m_StatusText = QString("Starting ").append(m_ArgumentList[2]).append(" on port ").append(m_ArgumentList[0]); + m_StatusText.prepend("Starting storage provider!"); emit SignalStatusOfStoreSCP(m_StatusText); + m_StatusText.clear(); break; case QProcess::Running: - m_StatusText = QString("Running ").append(m_ArgumentList[2]).append(" on port ").append(m_ArgumentList[0]);; + m_StatusText.prepend(m_ArgumentList[0]).prepend(" Port: ").prepend(m_ArgumentList[2]).prepend(" AET: ").prepend("Storage provider running! "); emit SignalStatusOfStoreSCP(m_StatusText); + m_StatusText.clear(); break; default: - m_StatusText = QString("Storage provider unknown error: "); + m_StatusText.prepend("Storage provider unknown error!"); emit SignalStatusOfStoreSCP(m_StatusText); + m_StatusText.clear(); break; } } void QmitkStoreSCPLauncher::SetArgumentList(QmitkStoreSCPLauncherBuilder* builder) { m_ArgumentList << *builder->GetPort() << QString("-aet") <<*builder->GetAETitle() << *builder->GetTransferSyntax() << *builder->GetOtherNetworkOptions() << *builder->GetMode() << QString("-od") << *builder->GetOutputDirectory(); } +void QmitkStoreSCPLauncher::DeleteTemporaryData() +{ + MITK_INFO << "About to delete: " << m_ArgumentList[7].toStdString(); + + /* + * Dangerous code, see bug 13021 + * + + QDir dir(m_ArgumentList[7]); + QDirIterator it(dir); + while(it.hasNext()) + { + it.next(); + dir.remove(it.fileInfo().absoluteFilePath()); + } + */ +} + QString QmitkStoreSCPLauncher::ArgumentListToQString() { QString argumentString; QStringListIterator argumentIterator(m_ArgumentList); while(argumentIterator.hasNext()) { argumentString.append(" "); argumentString.append(argumentIterator.next()); } return argumentString; } diff --git a/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkStoreSCPLauncher.h b/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkStoreSCPLauncher.h index bcfe057920..e9e9db18b7 100644 --- a/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkStoreSCPLauncher.h +++ b/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkStoreSCPLauncher.h @@ -1,51 +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 QmitkStoreSCPLauncher_h #define QmitkStoreSCPLauncher_h #include #include #include "QmitkStoreSCPLauncherBuilder.h" class QmitkStoreSCPLauncher : public QObject { Q_OBJECT public: QmitkStoreSCPLauncher(QmitkStoreSCPLauncherBuilder* builder); virtual ~QmitkStoreSCPLauncher(); public slots: void StartStoreSCP(); void OnProcessError(QProcess::ProcessError error); void OnStateChanged(QProcess::ProcessState status); + void OnReadyProcessOutput(); signals: void SignalStatusOfStoreSCP(const QString&); + void SignalStoreSCPError(const QString& errorText = ""); + void SignalStartImport(const QStringList&); + void SignalFinishedImport(); private: + void DeleteTemporaryData(); void FindPathToStoreSCP(); void SetArgumentList(QmitkStoreSCPLauncherBuilder* builder); QString ArgumentListToQString(); QString m_PathToStoreSCP; QString m_ErrorText; QString m_StatusText; QProcess* m_StoreSCP; QStringList m_ArgumentList; + QStringList m_ImportFilesList; }; #endif //QmitkStoreSCPLauncher_h \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkStoreSCPLauncherBuilder.h b/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkStoreSCPLauncherBuilder.h index 1f0e532069..d59eb34bd0 100644 --- a/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkStoreSCPLauncherBuilder.h +++ b/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkStoreSCPLauncherBuilder.h @@ -1,51 +1,51 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 QmitkStoreSCPLauncherBuilder_h #define QmitkStoreSCPLauncherBuilder_h #include #include class QmitkStoreSCPLauncherBuilder : public QObject { Q_OBJECT public: QmitkStoreSCPLauncherBuilder(); virtual ~QmitkStoreSCPLauncherBuilder(); QmitkStoreSCPLauncherBuilder* AddPort(const QString& port = QString("105")); QmitkStoreSCPLauncherBuilder* AddAETitle(const QString& aeTitle = QString("STORESCP")); QmitkStoreSCPLauncherBuilder* AddTransferSyntax(const QString& transferSyntax = QString("+x=")); QmitkStoreSCPLauncherBuilder* AddOtherNetworkOptions(const QString& otherNetworkOptions = QString("-pm")); - QmitkStoreSCPLauncherBuilder* AddMode(const QString& mode = QString("-d")); + QmitkStoreSCPLauncherBuilder* AddMode(const QString& mode = QString("-v")); QmitkStoreSCPLauncherBuilder* AddOutputDirectory(const QString& outputDirectory); QString* GetPort(); QString* GetAETitle(); QString* GetTransferSyntax(); QString* GetOtherNetworkOptions(); QString* GetMode(); QString* GetOutputDirectory(); private: QString* m_Port; QString* m_AETitle; QString* m_TransferSyntax; QString* m_OtherNetworkOptions; QString* m_Mode; QString* m_OutputDirectory; }; #endif diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkBrainNetworkAnalysis.dox b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkBrainNetworkAnalysis.dox index 81963a008a..bc4a10931b 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkBrainNetworkAnalysis.dox +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkBrainNetworkAnalysis.dox @@ -1,69 +1,69 @@ /** -\page org_brainnetworkanalysis The Brain Network Analysis Module +\page org_mitk_views_brainnetworkanalysis The Brain Network Analysis Module \image html QmitkBrainNetworkAnalysisViewIcon_64.png "Icon of the Module" \section QmitkBrainNetworkAnalysisUserManualSummary Summary This module can be used to create a network from a parcellation and a fiber image as well as to calculate and display network statistics. This document will tell you how to use this module, but it is assumed that you already know how to use MITK in general. Please see \ref QmitkBrainNetworkAnalysisUserManualDetails for more detailed information on usage and supported filters. If you encounter problems using the module, please have a look at the \ref QmitkBrainNetworkAnalysisUserManualTrouble page. \section QmitkBrainNetworkAnalysisUserManualDetails Details Manual sections: - \ref QmitkBrainNetworkAnalysisUserManualOverview - \ref QmitkBrainNetworkAnalysisUserManualUsage - \ref QmitkBrainNetworkAnalysisUserManualTrouble \section QmitkBrainNetworkAnalysisUserManualOverview Overview This module is currently under heavy development and as such the interface as well as the capabilities are likely to change significantly between different versions. This documentation describes the features of this current version. \image html QmitkBrainNetworkAnalysisInterface.png "The interface" \section QmitkBrainNetworkAnalysisUserManualUsage Usage To create a network select first a parcellation of the brain (e.g. as provided by freesurfer ) by CTRL+Leftclick and secondly a fiber image ( as created using tractography module). Then click on the "Create Network" button. To calculate network statistics select a network in the datamanager. At this time the following statistics are calculated for the entire network:
  • The number of vertices in the network
  • The number of edges in the network
  • The number of edges which have the same vertex as beginning and end point
  • The average degree of the nodes in the network
  • The connection density the network (the number of edges divided by the number of possible edges)
  • The unweighted efficiency of the network ( 1 divided by average path length, this is zero for disconnected graphs)
  • The global clustering
Furthermore some statistics are calculated on a per node basis and displayed as histograms:
  • The degree of each node
  • The (unweighted) betweenness centrality of each node
  • The spread of shortest paths between each pair of nodes (For disconnected graphs the shortest paths with infinite length are omitted for readability)
Additionally you have the option to create artificial networks, for testing purposes. Currently choices are:
  • A regular lattice, where each node is placed in a cubic pattern and only connected to its neighbours
  • A heterogenic sphere, where one node is placed in the center and connected to all nodes on the shell
  • A random network, where nodes are randomly placed on a spherical shell and randomly connected
\section QmitkBrainNetworkAnalysisUserManualTrouble 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.diffusionimaging/documentation/UserManual/QmitkDiffusionImagingUserManual.dox b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkDiffusionImagingUserManual.dox index d39b26362c..696214e6d4 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkDiffusionImagingUserManual.dox +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkDiffusionImagingUserManual.dox @@ -1,122 +1,122 @@ /** -\bundlemainpage{org_diffusion} MITK Diffusion Imaging (MITK-DI) +\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 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 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 bundle 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 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. \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 \subpage DiffusionImagingPropertiesPage . \section QmitkDiffusionImagingUserManualSubManuals Manuals of componentes The MITK Diffusion tools consist of further components, which have their own documentation, see: - \li \subpage org_fiberprocessing - \li \subpage org_gibbstracking - \li \subpage org_odfdetails - \li \subpage org_pvanalysis - \li \subpage screenshot_maker - \li \subpage org_stochastictracking - \li \subpage org_ivim - \li \subpage org_brainnetworkanalysis - \li \subpage org_tractbasedspatialstatistics + \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_views_brainnetworkanalysis + \li \subpage org_mitk_views_tractbasedspatialstatistics */ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkFiberProcessingViewUserManual.dox b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkFiberProcessingViewUserManual.dox index 9c1e982b69..6f1f6d6963 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkFiberProcessingViewUserManual.dox +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkFiberProcessingViewUserManual.dox @@ -1,23 +1,23 @@ /** -\page org_fiberprocessing Fiber Processing View +\page org_mitk_views_fiberprocessing Fiber Processing View This view provides everything needed to process fiber bundles. \image html fiberprocessing.png The Fiber Processing View Fiber extraction: Place ROIs in the 2D render widgets (cricles or polygons) and extract fibers from the bundle that pass through these ROIs by selecting the according ROI and fiber bundle in the datamanger and starting the extraction. The ROIs can be combined via logical operations. All fibers that pass through the thus generated composite ROI are extracted. The extraction can also be performed using 3D ROIs represented as closed surface meshes. In this extraction method, the logical operations are not implemented at the moment. The selected fiber bundle can be smoothed by interpolating the fiber points using Kochanek splines with the specified number of points per cm. If a float image with pixel values between 0 and 1 is selcted, the fiber bundle can be colored according to the pixel values. Generation of additional data from fiber bundles: \li Tract density image: generate a 2D heatmap from a fiber bundle \li Binary envelope: generate a binary image from a fiber bundle \li Fiber bundle image: generate a 2D rgba image representation of the fiber bundle \li Fiber endings image: generate a 2D binary image showing the locations of fiber endpoints \li Fiber endings pointset: generate a poinset containing the locations of fiber endpoints */ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkGibbsTrackingViewUserManual.dox b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkGibbsTrackingViewUserManual.dox index 433c4e7775..8424ea110f 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkGibbsTrackingViewUserManual.dox +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkGibbsTrackingViewUserManual.dox @@ -1,44 +1,44 @@ /** -\page org_gibbstracking Gibbs Tracking View +\page org_mitk_views_gibbstracking Gibbs Tracking View This view provides the user interface for the Gibbs Tracking algorithm, a global fiber tracking algorithm, originally proposed by Reisert et.al. [1]. Available sections: - \ref QmitkGibbsTrackingUserManualInputData - \ref QmitkGibbsTrackingUserManualParameters - \ref QmitkGibbsTrackingUserManualTrackingSurveillance - \ref QmitkGibbsTrackingUserManualReferences \image html gibbstrackingview.png The Gibbs Tracking View \section QmitkGibbsTrackingUserManualInputData Input Data Mandatory Input: \li One Q-Ball image selected in the datamanager Optional Input: \li Mask Image: Float image used as probability mask for the generation of fiber segments. Usually used as binary brain mask to reduce the searchspace of the algorithm and to avoid fibers resulting from noise outside of the brain. \section QmitkGibbsTrackingUserManualParameters Q-Ball Reconstruction \li Number of iterations: More iterations causes the algorithm to be more stable but also to take longer to finish the tracking. Rcommended: 10â·-10â¹ iterations. \li Particle length/width/weight controlling the contribution of each particle to the model M \li Start and end temperature controlling how fast the process reaches a stable state. (usually no change needed) \li Weighting between the internal (affinity of the model to long and straigt fibers) and external energy (affinity of the model towards the data). (usually no change needed). \li Minimum fiber length constraint (in mm). Shorter fibers are discarded after the tracking. The automatic selection of parameters for the particle length/width and weight are determined directly from the input image using information about the image spacing and GFA. \image html gibbstrackingviewadvanced.png Advanced Tracking Parameters \section QmitkGibbsTrackingUserManualTrackingSurveillance Surveilance of the tracking process Once started, the tracking can be monitored via the textual output that informs about the tracking progress and several stats of the current state of the algorithm. If enabled, the intermediate tracking results are displayed in the renderwindows each second. This live visualization should usually be disabled for performance reasons. It can be turned on and off during the tracking process via the according checkbox. The button next to this checkbox allows the visualization of only the next iteration step. \section QmitkGibbsTrackingUserManualReferences References [1] Reisert, M., Mader, I., Anastasopoulos, C., Weigel, M., Schnell, S., Kiselev, V.: Global fiber reconstruction becomes practical. Neuroimage 54 (2011) 955-962 */ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkOdfDetailsViewUserManual.dox b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkOdfDetailsViewUserManual.dox index 7885ebd5dc..f54439baa9 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkOdfDetailsViewUserManual.dox +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkOdfDetailsViewUserManual.dox @@ -1,8 +1,8 @@ /** -\page org_odfdetails ODF Details View +\page org_mitk_views_odfdetails ODF Details View This view provides detailed information about the orentation distribution function at the current crosshair position (if a Tensor/Q-Ball image is selected). A visualization of the ODF as well as statistical information are displayed. \image html odfdetails.png The Gibbs Tracking View */ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkPartialVolumeAnalysisViewManual.dox b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkPartialVolumeAnalysisViewManual.dox index a515ad40fc..7308a7018d 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkPartialVolumeAnalysisViewManual.dox +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkPartialVolumeAnalysisViewManual.dox @@ -1,23 +1,23 @@ /** -\page org_pvanalysis Partial Volume Analysis +\page org_mitk_views_partialvolumeanalysisview Partial Volume Analysis The "Partial Volume Analysis" view can be found in the "Quantification" perspective. It allows for robust quantification of diffusion or other scalar measures in the presents of two classes (e.g. fiber vs. non-fiber) and partial volume between them. The algorithm estimates a probabilistic segmentation of the three classes and returns a weighted average of the measure of interest within the each class. \image html pvanalysisview.png The Partial Volume Analysis View \section QmitkPVAAnalysisUserManualExport Export All measures are automatically written to the clipboard once the estimation is updated. The histogram export is provided by the button underneath the histogram. The values can be pasted to excel or any text editor. \section QmitkPVAAnalysisUserManualAdvancedSettings Advanced Settings Are not recommended for use yet. \section QmitkPVAAnalysisUserManualSuggestedReadings Suggested Readings Diffusion tensor imaging in primary brain tumors: reproducible quantitative analysis of corpus callosum infiltration and contralateral involvement using a probabilistic mixture model. Stieltjes B, Schlüter M, Didinger B, Weber MA, Hahn HK, Parzer P, Rexilius J, Konrad-Verse O, Peitgen HO, Essig M. Neuroimage. 2006 Jun;31(2):531-42. Epub 2006 Feb 14. PMID: 16478665 */ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkStochasticTrackingViewUserManual.dox b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkStochasticTrackingViewUserManual.dox index 7573738c5e..0ed40d2add 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkStochasticTrackingViewUserManual.dox +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkStochasticTrackingViewUserManual.dox @@ -1,31 +1,31 @@ /** -\page org_stochastictracking Stochastic Tracking View +\page org_mitk_views_stochasticfibertracking Stochastic Tracking View This view provides the user interface for the Stochastic Fibertracking algorithm, proposed by Ngo [1]. Available sections: - \ref QmitkStochasticTrackingUserManualInputData - \ref QmitkStochasticTrackingUserManualParameters - \ref QmitkStochasticTrackingUserManualReferences \image html stochastictrackingview.png Stochastic Tracking View \section QmitkStochasticTrackingUserManualInputData Input Data Mandatory Input: \li One DWI Image image selected in the datamanager \li One or more ROIs selected in the datamanager For a successful execution of the stochastic tractography filter, a DWI input and a binary image defining the desired ROI are required. The ROI serves as the origin from where on the fibers are beeing tracked. To generate the seed ROI the segmentation view in the quantification perspective can be used or a binary image can be loaded. \section QmitkStochasticTrackingUserManualParameters Input Parameters \li Parameters such as max. tract length, number of seeds per voxel and likelihood cache size in MB can be controlled individually. \li After successfully setting necessary Input and Parameter, pressing the command button executes the algorithm. \section QmitkStochasticTrackingUserManualReferences References [1] Tri M. Ngo, Polina Golland, and Tri M. Ngo. A stochastic tractography system and applications, 2007 */ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkTbssViewUserManual.dox b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkTbssViewUserManual.dox index 26b49bbb0a..2a199fd3a9 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkTbssViewUserManual.dox +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkTbssViewUserManual.dox @@ -1,59 +1,59 @@ /** -\page org_tractbasedspatialstatistics The TBSS Module +\page org_mitk_views_tractbasedspatialstatistics The TBSS Module \image html tbss.png "Icon of the Module" \section QmitkTractbasedSpatialStatistics Summary This module can be used to locally explore data resulting from preprocessing with the TBSS module of FSL This document will tell you how to use this module, but it is assumed that you already know how to use MITK in general and how to work with the TBSS module of FSL. If you encounter problems using the module, please have a look at the \ref QmitkTractbasedSpatialStatisticsUserManualTrouble page. Sections: - \ref QmitkTractbasedSpatialStatisticsUserManualOverview - \ref QmitkTractbasedSpatialStatisticsUserManualFSLImport - \ref QmitkTractbasedSpatialStatisticsUserManualRois - \ref QmitkTractbasedSpatialStatisticsUserManualProfiles - \ref QmitkTractbasedSpatialStatisticsUserManualTroubleshooting - \ref QmitkTractbasedSpatialStatisticsUserManualReferences \section QmitkTractbasedSpatialStatisticsUserManualOverview Overview This module is currently under development and as such the interface as well as the capabilities are likely to change significantly between different versions. This documentation describes the features of this current version. \section QmitkTractbasedSpatialStatisticsUserManualFSLImport FSL Import The FSL import allows to import data that has been preprocessed by FSL. FSL creates output images that typically have names like all_FA_skeletonized.nii.gz that are 4-dimensional images that contain registered images of all subjects. By loading this 4D image into the datamanager and listing the groups with the correct number of subjects, in the order of occurrence in the 4D image, in the TBSS-View using the Add button and clicking the import subject data a TBSS file is created that contains all the information needed for tract analysis. The diffusion measure of the image can be set as well. \image html fslimport.png "FSL Import" \section QmitkTractbasedSpatialStatisticsUserManualRois Regions of Interest (ROIs) To create a ROI the mean FA skeleton (typically called mean_FA_skeleton.nii.gz) that is created by FSL should be loaded in to the datamanager and selected. By using the Pointlistwidget points should be set on the skeleton (make sure to select points with relatively high FA values). Points are set by first selecting the button with the '+' and than shift-leftclick in the image. When the correct image is selected in the datamanager the Create ROI button is enabled. Clicking this will create a region of interest that passes through the previously selected points. The roi appears in the datamanager. Before doing so, the name of the roi and the information on the structure on which the ROI lies can be set. This will be saved as extra information in the roi-image. Before the ROI is calculated, a pop-up window will ask the user to provide a threshold value. This should be the same threshold that was previously used in FSL to create a binary mask of the FA skeleton. When this is not done correctly, the region of interest will possible contain zero-valued voxels. \image html tbssRoi.png "Regions of Interest (ROIs)" \section QmitkTractbasedSpatialStatisticsUserManualProfiles y selecting a tbss image with group information and a region of interest image (as was created in a previous stap). A profile plot is drawn in the plot canvas. By clicking in the graph the crosshairs jump to the corresponding location in the image. \image html profiles.png "Profile plots" \section QmitkTractbasedSpatialStatisticsUserManualTroubleshooting Troubleshooting Please report to the MITK mailing list. See http://www.mitk.org/wiki/Mailinglist on how to do this. \section QmitkTractbasedSpatialStatisticsUserManualReferences References 1. S.M. Smith, M. Jenkinson, H. Johansen-Berg, D. Rueckert, T.E. Nichols, C.E. Mackay, K.E. Watkins, O. Ciccarelli, M.Z. Cader, P.M. Matthews, and T.E.J. Behrens. Tract-based spatial statistics: Voxelwise analysis of multi-subject diffusion data. NeuroImage, 31:1487-1505, 2006. 2. S.M. Smith, M. Jenkinson, M.W. Woolrich, C.F. Beckmann, T.E.J. Behrens, H. Johansen-Berg, P.R. Bannister, M. De Luca, I. Drobnjak, D.E. Flitney, R. Niazy, J. Saunders, J. Vickers, Y. Zhang, N. De Stefano, J.M. Brady, and P.M. Matthews. Advances in functional and structural MR image analysis and implementation as FSL. NeuroImage, 23(S1):208-219, 2004. */ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkUserIVIMViewManual.dox b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkUserIVIMViewManual.dox index 1ed8f2af10..b46d32f9dd 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkUserIVIMViewManual.dox +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkUserIVIMViewManual.dox @@ -1,41 +1,41 @@ /** -\page org_ivim Intra-voxel incoherent motion estimation (IVIM) +\page org_mitk_views_ivim Intra-voxel incoherent motion estimation (IVIM) The required input for the "Intra-voxel incoherent motion estimation" (IVIM) is a diffusion weighted image (.dwi or .hdwi) that was acquired with several different b-values. \image html ivimview.png The IVIM View Once an input image is selected in the datamanager, the IVIM view allows for interactive exploration of the dataset (click around in the image and watch the estimated parameters in the figure of the view) as well as generation of f-, D-, and D*-maps (activate the checkmarks and press "Generate Output Images"). The "neglect b<" threshold allows you to ignore b-values smaller then a threshold for the initial fit of f and D. D* is then estimated using all measurements. The exact values of the current fit are always given in the legend underneath the figure. \section QmitkDiffusionImagingUserManualInputData Region of interest analysis Create region of interest: To create a new segmentatin, open the "quantification" perspective, select the tab "Segmentation", and create a segmentation of the structure of interest. Alternatively, of course, you may also load a binary image from file or generate your segmentation in any other possible way. IVIM in region of interset: Go back to the "IVIM" perspective and select both, the diffusion image and the segmentation (holding the CTRL key). A red message should appear "Averaging N voxels". \section QmitkDiffusionImagingUserManualInputData Export All model parameters and corresponding curves can be exported to clipboard using the buttons underneath the figure. \section QmitkDiffusionImagingUserManualInputData Advanced Settings Advanced users, that know what they are doing, can change the method for the model-fit under "Advanced Settings" on the very bottom of the view. 3-param fit, linear fit of f/D, and fix D* are among the options. \section QmitkDiffusionImagingUserManualInputData Suggested Readings Toward an optimal distribution of b values for intravoxel incoherent motion imaging. Lemke A, Stieltjes B, Schad LR, Laun FB. Magn Reson Imaging. 2011 Jul;29(6):766-76. Epub 2011 May 5. PMID: 21549538 Differentiation of pancreas carcinoma from healthy pancreatic tissue using multiple b-values: comparison of apparent diffusion coefficient and intravoxel incoherent motion derived parameters. Lemke A, Laun FB, Klauss M, Re TJ, Simon D, Delorme S, Schad LR, Stieltjes B. Invest Radiol. 2009 Dec;44(12):769-75. PMID: 19838121 */ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.cpp index 32ad82d638..cba1435f56 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.cpp @@ -1,1774 +1,1776 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "QmitkControlVisualizationPropertiesView.h" #include "mitkNodePredicateDataType.h" #include "mitkDataNodeObject.h" #include "mitkOdfNormalizationMethodProperty.h" #include "mitkOdfScaleByProperty.h" #include "mitkResliceMethodProperty.h" #include "mitkRenderingManager.h" #include "mitkTbssImage.h" #include "mitkPlanarFigure.h" #include "mitkFiberBundleX.h" #include "QmitkDataStorageComboBox.h" #include "QmitkStdMultiWidget.h" #include "mitkFiberBundleInteractor.h" #include "mitkPlanarFigureInteractor.h" #include #include #include #include "mitkGlobalInteraction.h" #include "mitkGeometry2D.h" #include "mitkSegTool2D.h" #include "berryIWorkbenchWindow.h" #include "berryIWorkbenchPage.h" #include "berryISelectionService.h" #include "berryConstants.h" #include "berryPlatformUI.h" #include "itkRGBAPixel.h" #include #include "qwidgetaction.h" #include "qcolordialog.h" const std::string QmitkControlVisualizationPropertiesView::VIEW_ID = "org.mitk.views.controlvisualizationpropertiesview"; using namespace berry; struct CvpSelListener : ISelectionListener { berryObjectMacro(CvpSelListener); CvpSelListener(QmitkControlVisualizationPropertiesView* view) { m_View = view; } void ApplySettings(mitk::DataNode::Pointer node) { bool tex_int; node->GetBoolProperty("texture interpolation", tex_int); if(tex_int) { m_View->m_Controls->m_TextureIntON->setIcon(*m_View->m_IconTexON); m_View->m_Controls->m_TextureIntON->setChecked(true); m_View->m_TexIsOn = true; } else { m_View->m_Controls->m_TextureIntON->setIcon(*m_View->m_IconTexOFF); m_View->m_Controls->m_TextureIntON->setChecked(false); m_View->m_TexIsOn = false; } int val; node->GetIntProperty("ShowMaxNumber", val); m_View->m_Controls->m_ShowMaxNumber->setValue(val); m_View->m_Controls->m_NormalizationDropdown->setCurrentIndex(dynamic_cast(node->GetProperty("Normalization"))->GetValueAsId()); float fval; node->GetFloatProperty("Scaling",fval); m_View->m_Controls->m_ScalingFactor->setValue(fval); m_View->m_Controls->m_AdditionalScaling->setCurrentIndex(dynamic_cast(node->GetProperty("ScaleBy"))->GetValueAsId()); node->GetFloatProperty("IndexParam1",fval); m_View->m_Controls->m_IndexParam1->setValue(fval); node->GetFloatProperty("IndexParam2",fval); m_View->m_Controls->m_IndexParam2->setValue(fval); } void DoSelectionChanged(ISelection::ConstPointer selection) { // save current selection in member variable m_View->m_CurrentSelection = selection.Cast(); m_View->m_Controls->m_VisibleOdfsON_T->setVisible(false); m_View->m_Controls->m_VisibleOdfsON_S->setVisible(false); m_View->m_Controls->m_VisibleOdfsON_C->setVisible(false); m_View->m_Controls->m_TextureIntON->setVisible(false); m_View->m_Controls->m_ImageControlsFrame->setVisible(false); m_View->m_Controls->m_PlanarFigureControlsFrame->setVisible(false); m_View->m_Controls->m_BundleControlsFrame->setVisible(false); m_View->m_SelectedNode = 0; if(m_View->m_CurrentSelection.IsNull()) return; if(m_View->m_CurrentSelection->Size() == 1) { mitk::DataNodeObject::Pointer nodeObj = m_View->m_CurrentSelection->Begin()->Cast(); if(nodeObj.IsNotNull()) { mitk::DataNode::Pointer node = nodeObj->GetDataNode(); // check if node has data, // if some helper nodes are shown in the DataManager, the GetData() returns 0x0 which would lead to SIGSEV mitk::BaseData* nodeData = node->GetData(); if(nodeData != NULL ) { if(dynamic_cast(nodeData) != 0) { m_View->m_Controls->m_PlanarFigureControlsFrame->setVisible(true); m_View->m_SelectedNode = node; float val; node->GetFloatProperty("planarfigure.line.width", val); m_View->m_Controls->m_PFWidth->setValue((int)(val*10.0)); QString label = "Width %1"; label = label.arg(val); m_View->m_Controls->label_pfwidth->setText(label); float color[3]; node->GetColor( color, NULL, "planarfigure.default.line.color"); QString styleSheet = "background-color:rgb("; styleSheet.append(QString::number(color[0]*255.0)); styleSheet.append(","); styleSheet.append(QString::number(color[1]*255.0)); styleSheet.append(","); styleSheet.append(QString::number(color[2]*255.0)); styleSheet.append(")"); m_View->m_Controls->m_PFColor->setAutoFillBackground(true); m_View->m_Controls->m_PFColor->setStyleSheet(styleSheet); node->GetColor( color, NULL, "color"); styleSheet = "background-color:rgb("; styleSheet.append(QString::number(color[0]*255.0)); styleSheet.append(","); styleSheet.append(QString::number(color[1]*255.0)); styleSheet.append(","); styleSheet.append(QString::number(color[2]*255.0)); styleSheet.append(")"); m_View->PlanarFigureFocus(); } if(dynamic_cast(nodeData) != 0) { m_View->m_Controls->m_BundleControlsFrame->setVisible(true); m_View->m_SelectedNode = node; if(m_View->m_CurrentPickingNode != 0 && node.GetPointer() != m_View->m_CurrentPickingNode) { m_View->m_Controls->m_Crosshair->setEnabled(false); } else { m_View->m_Controls->m_Crosshair->setEnabled(true); } float val; node->GetFloatProperty("TubeRadius", val); m_View->m_Controls->m_TubeRadius->setValue((int)(val * 100.0)); QString label = "Radius %1"; label = label.arg(val); m_View->m_Controls->label_tuberadius->setText(label); int width; node->GetIntProperty("LineWidth", width); m_View->m_Controls->m_LineWidth->setValue(width); label = "Width %1"; label = label.arg(width); m_View->m_Controls->label_linewidth->setText(label); float range; node->GetFloatProperty("Fiber2DSliceThickness",range); label = "Range %1"; label = label.arg(range*0.1); m_View->m_Controls->label_range->setText(label); } } // check node data != NULL } } if(m_View->m_CurrentSelection->Size() > 0 && m_View->m_SelectedNode == 0) { m_View->m_Controls->m_ImageControlsFrame->setVisible(true); bool foundDiffusionImage = false; bool foundQBIVolume = false; bool foundTensorVolume = false; bool foundImage = false; bool foundMultipleOdfImages = false; bool foundRGBAImage = false; bool foundTbssImage = false; // do something with the selected items if(m_View->m_CurrentSelection) { // 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::BaseData* nodeData = node->GetData(); if(nodeData != NULL ) { // only look at interesting types if(QString("DiffusionImage").compare(nodeData->GetNameOfClass())==0) { foundDiffusionImage = true; bool tex_int; node->GetBoolProperty("texture interpolation", tex_int); if(tex_int) { m_View->m_Controls->m_TextureIntON->setIcon(*m_View->m_IconTexON); m_View->m_Controls->m_TextureIntON->setChecked(true); m_View->m_TexIsOn = true; } else { m_View->m_Controls->m_TextureIntON->setIcon(*m_View->m_IconTexOFF); m_View->m_Controls->m_TextureIntON->setChecked(false); m_View->m_TexIsOn = false; } int val; node->GetIntProperty("DisplayChannel", val); m_View->m_Controls->m_DisplayIndex->setValue(val); QString label = "Channel %1"; label = label.arg(val); m_View->m_Controls->label_channel->setText(label); int maxVal = (dynamic_cast* >(nodeData))->GetVectorImage()->GetVectorLength(); m_View->m_Controls->m_DisplayIndex->setMaximum(maxVal-1); } if(QString("TbssImage").compare(nodeData->GetNameOfClass())==0) { foundTbssImage = true; bool tex_int; node->GetBoolProperty("texture interpolation", tex_int); if(tex_int) { m_View->m_Controls->m_TextureIntON->setIcon(*m_View->m_IconTexON); m_View->m_Controls->m_TextureIntON->setChecked(true); m_View->m_TexIsOn = true; } else { m_View->m_Controls->m_TextureIntON->setIcon(*m_View->m_IconTexOFF); m_View->m_Controls->m_TextureIntON->setChecked(false); m_View->m_TexIsOn = false; } int val; node->GetIntProperty("DisplayChannel", val); m_View->m_Controls->m_DisplayIndex->setValue(val); QString label = "Channel %1"; label = label.arg(val); m_View->m_Controls->label_channel->setText(label); int maxVal = (dynamic_cast(nodeData))->GetImage()->GetVectorLength(); m_View->m_Controls->m_DisplayIndex->setMaximum(maxVal-1); } else if(QString("QBallImage").compare(nodeData->GetNameOfClass())==0) { foundMultipleOdfImages = foundQBIVolume || foundTensorVolume; foundQBIVolume = true; ApplySettings(node); } else if(QString("TensorImage").compare(nodeData->GetNameOfClass())==0) { foundMultipleOdfImages = foundQBIVolume || foundTensorVolume; foundTensorVolume = true; ApplySettings(node); } else if(QString("Image").compare(nodeData->GetNameOfClass())==0) { foundImage = true; mitk::Image::Pointer img = dynamic_cast(nodeData); - if(img.IsNotNull() && img->GetPixelType().GetPixelTypeId() == typeid(itk::RGBAPixel) ) + if(img.IsNotNull() + && img->GetPixelType().GetPixelTypeId() == itk::ImageIOBase::RGBA + && img->GetPixelType().GetTypeId() == typeid(unsigned char) ) { foundRGBAImage = true; } bool tex_int; node->GetBoolProperty("texture interpolation", tex_int); if(tex_int) { m_View->m_Controls->m_TextureIntON->setIcon(*m_View->m_IconTexON); m_View->m_Controls->m_TextureIntON->setChecked(true); m_View->m_TexIsOn = true; } else { m_View->m_Controls->m_TextureIntON->setIcon(*m_View->m_IconTexOFF); m_View->m_Controls->m_TextureIntON->setChecked(false); m_View->m_TexIsOn = false; } } } // END CHECK node != NULL } } } m_View->m_FoundSingleOdfImage = (foundQBIVolume || foundTensorVolume) && !foundMultipleOdfImages; m_View->m_Controls->m_NumberGlyphsFrame->setVisible(m_View->m_FoundSingleOdfImage); m_View->m_Controls->m_NormalizationDropdown->setVisible(m_View->m_FoundSingleOdfImage); m_View->m_Controls->label->setVisible(m_View->m_FoundSingleOdfImage); m_View->m_Controls->m_ScalingFactor->setVisible(m_View->m_FoundSingleOdfImage); m_View->m_Controls->m_AdditionalScaling->setVisible(m_View->m_FoundSingleOdfImage); m_View->m_Controls->m_NormalizationScalingFrame->setVisible(m_View->m_FoundSingleOdfImage); m_View->m_Controls->OpacMinFrame->setVisible(foundRGBAImage || m_View->m_FoundSingleOdfImage); // changed for SPIE paper, Principle curvature scaling //m_View->m_Controls->params_frame->setVisible(m_View->m_FoundSingleOdfImage); m_View->m_Controls->params_frame->setVisible(false); m_View->m_Controls->m_VisibleOdfsON_T->setVisible(m_View->m_FoundSingleOdfImage); m_View->m_Controls->m_VisibleOdfsON_S->setVisible(m_View->m_FoundSingleOdfImage); m_View->m_Controls->m_VisibleOdfsON_C->setVisible(m_View->m_FoundSingleOdfImage); bool foundAnyImage = foundDiffusionImage || foundQBIVolume || foundTensorVolume || foundImage || foundTbssImage; m_View->m_Controls->m_Reinit->setVisible(foundAnyImage); m_View->m_Controls->m_TextureIntON->setVisible(foundAnyImage); m_View->m_Controls->m_TSMenu->setVisible(foundAnyImage); } } 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); } } } QmitkControlVisualizationPropertiesView* m_View; }; QmitkControlVisualizationPropertiesView::QmitkControlVisualizationPropertiesView() : QmitkFunctionality(), m_Controls(NULL), m_MultiWidget(NULL), m_NodeUsedForOdfVisualization(NULL), m_IconTexOFF(new QIcon(":/QmitkDiffusionImaging/texIntOFFIcon.png")), m_IconTexON(new QIcon(":/QmitkDiffusionImaging/texIntONIcon.png")), m_IconGlyOFF_T(new QIcon(":/QmitkDiffusionImaging/glyphsoff_T.png")), m_IconGlyON_T(new QIcon(":/QmitkDiffusionImaging/glyphson_T.png")), m_IconGlyOFF_C(new QIcon(":/QmitkDiffusionImaging/glyphsoff_C.png")), m_IconGlyON_C(new QIcon(":/QmitkDiffusionImaging/glyphson_C.png")), m_IconGlyOFF_S(new QIcon(":/QmitkDiffusionImaging/glyphsoff_S.png")), m_IconGlyON_S(new QIcon(":/QmitkDiffusionImaging/glyphson_S.png")), m_CurrentSelection(0), m_CurrentPickingNode(0), m_GlyIsOn_S(false), m_GlyIsOn_C(false), m_GlyIsOn_T(false), m_FiberBundleObserverTag(0), m_Color(NULL) { currentThickSlicesMode = 1; m_MyMenu = NULL; } QmitkControlVisualizationPropertiesView::QmitkControlVisualizationPropertiesView(const QmitkControlVisualizationPropertiesView& other) { Q_UNUSED(other) throw std::runtime_error("Copy constructor not implemented"); } QmitkControlVisualizationPropertiesView::~QmitkControlVisualizationPropertiesView() { if(m_SlicesRotationObserverTag1 ) { mitk::SlicesCoordinator* coordinator = m_MultiWidget->GetSlicesRotator(); if( coordinator) coordinator->RemoveObserver(m_SlicesRotationObserverTag1); } if( m_SlicesRotationObserverTag2) { mitk::SlicesCoordinator* coordinator = m_MultiWidget->GetSlicesRotator(); if( coordinator ) coordinator->RemoveObserver(m_SlicesRotationObserverTag1); } this->GetSite()->GetWorkbenchWindow()->GetSelectionService()->RemovePostSelectionListener(/*"org.mitk.views.datamanager",*/ m_SelListener); } void QmitkControlVisualizationPropertiesView::OnThickSlicesModeSelected( QAction* action ) { currentThickSlicesMode = action->data().toInt(); switch(currentThickSlicesMode) { default: case 1: this->m_Controls->m_TSMenu->setText("MIP"); break; case 2: this->m_Controls->m_TSMenu->setText("SUM"); break; case 3: this->m_Controls->m_TSMenu->setText("WEIGH"); break; } mitk::DataNode* n; n = this->m_MultiWidget->GetWidgetPlane1(); if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); n = this->m_MultiWidget->GetWidgetPlane2(); if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); n = this->m_MultiWidget->GetWidgetPlane3(); if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); mitk::BaseRenderer::Pointer renderer = this->GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer(); if(renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer = this->GetActiveStdMultiWidget()->GetRenderWindow2()->GetRenderer(); if(renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer = this->GetActiveStdMultiWidget()->GetRenderWindow3()->GetRenderer(); if(renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer->GetRenderingManager()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::OnTSNumChanged(int num) { if(num==0) { mitk::DataNode* n; n = this->m_MultiWidget->GetWidgetPlane1(); if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( 0 ) ); n = this->m_MultiWidget->GetWidgetPlane2(); if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( 0 ) ); n = this->m_MultiWidget->GetWidgetPlane3(); if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( 0 ) ); } else { mitk::DataNode* n; n = this->m_MultiWidget->GetWidgetPlane1(); if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); n = this->m_MultiWidget->GetWidgetPlane2(); if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); n = this->m_MultiWidget->GetWidgetPlane3(); if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); n = this->m_MultiWidget->GetWidgetPlane1(); if(n) n->SetProperty( "reslice.thickslices.num", mitk::IntProperty::New( num ) ); n = this->m_MultiWidget->GetWidgetPlane2(); if(n) n->SetProperty( "reslice.thickslices.num", mitk::IntProperty::New( num ) ); n = this->m_MultiWidget->GetWidgetPlane3(); if(n) n->SetProperty( "reslice.thickslices.num", mitk::IntProperty::New( num ) ); } m_TSLabel->setText(QString::number(num*2+1)); mitk::BaseRenderer::Pointer renderer = this->GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer(); if(renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer = this->GetActiveStdMultiWidget()->GetRenderWindow2()->GetRenderer(); if(renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer = this->GetActiveStdMultiWidget()->GetRenderWindow3()->GetRenderer(); if(renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer->GetRenderingManager()->RequestUpdateAll(mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); } void QmitkControlVisualizationPropertiesView::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkControlVisualizationPropertiesViewControls; m_Controls->setupUi(parent); this->CreateConnections(); // hide warning (ODFs in rotated planes) m_Controls->m_lblRotatedPlanesWarning->hide(); m_MyMenu = new QMenu(parent); connect( m_MyMenu, SIGNAL( aboutToShow() ), this, SLOT(OnMenuAboutToShow()) ); // button for changing rotation mode m_Controls->m_TSMenu->setMenu( m_MyMenu ); //m_CrosshairModeButton->setIcon( QIcon( iconCrosshairMode_xpm ) ); m_Controls->params_frame->setVisible(false); QIcon icon5(":/QmitkDiffusionImaging/Refresh_48.png"); m_Controls->m_Reinit->setIcon(icon5); m_Controls->m_Focus->setIcon(icon5); QIcon iconColor(":/QmitkDiffusionImaging/color24.gif"); m_Controls->m_PFColor->setIcon(iconColor); m_Controls->m_Color->setIcon(iconColor); QIcon iconReset(":/QmitkDiffusionImaging/reset.png"); m_Controls->m_ResetColoring->setIcon(iconReset); m_Controls->m_PFColor->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); QIcon iconCrosshair(":/QmitkDiffusionImaging/crosshair.png"); m_Controls->m_Crosshair->setIcon(iconCrosshair); // was is los QIcon iconPaint(":/QmitkDiffusionImaging/paint2.png"); m_Controls->m_TDI->setIcon(iconPaint); QIcon iconFiberFade(":/QmitkDiffusionImaging/MapperEfx2D.png"); m_Controls->m_FiberFading2D->setIcon(iconFiberFade); m_Controls->m_TextureIntON->setCheckable(true); #ifndef DIFFUSION_IMAGING_EXTENDED int size = m_Controls->m_AdditionalScaling->count(); for(int t=0; tm_AdditionalScaling->itemText(t).toStdString() == "Scale by ASR") { m_Controls->m_AdditionalScaling->removeItem(t); } } #endif m_Controls->m_OpacitySlider->setRange(0.0,1.0); m_Controls->m_OpacitySlider->setLowerValue(0.0); m_Controls->m_OpacitySlider->setUpperValue(0.0); m_Controls->m_ScalingFrame->setVisible(false); m_Controls->m_NormalizationFrame->setVisible(false); m_Controls->frame_tube->setVisible(false); m_Controls->frame_wire->setVisible(false); } m_IsInitialized = false; m_SelListener = berry::ISelectionListener::Pointer(new CvpSelListener(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); m_IsInitialized = true; } void QmitkControlVisualizationPropertiesView::OnMenuAboutToShow () { // THICK SLICE SUPPORT QMenu *myMenu = m_MyMenu; myMenu->clear(); QActionGroup* thickSlicesActionGroup = new QActionGroup(myMenu); thickSlicesActionGroup->setExclusive(true); mitk::BaseRenderer::Pointer renderer = this->GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer(); int currentTSMode = 0; { mitk::ResliceMethodProperty::Pointer m = dynamic_cast(renderer->GetCurrentWorldGeometry2DNode()->GetProperty( "reslice.thickslices" )); if( m.IsNotNull() ) currentTSMode = m->GetValueAsId(); } const int maxTS = 30; int currentNum = 0; { mitk::IntProperty::Pointer m = dynamic_cast(renderer->GetCurrentWorldGeometry2DNode()->GetProperty( "reslice.thickslices.num" )); if( m.IsNotNull() ) { currentNum = m->GetValue(); if(currentNum < 0) currentNum = 0; if(currentNum > maxTS) currentNum = maxTS; } } if(currentTSMode==0) currentNum=0; QSlider *m_TSSlider = new QSlider(myMenu); m_TSSlider->setMinimum(0); m_TSSlider->setMaximum(maxTS-1); m_TSSlider->setValue(currentNum); m_TSSlider->setOrientation(Qt::Horizontal); connect( m_TSSlider, SIGNAL( valueChanged(int) ), this, SLOT( OnTSNumChanged(int) ) ); QHBoxLayout* _TSLayout = new QHBoxLayout; _TSLayout->setContentsMargins(4,4,4,4); _TSLayout->addWidget(m_TSSlider); _TSLayout->addWidget(m_TSLabel=new QLabel(QString::number(currentNum*2+1),myMenu)); QWidget* _TSWidget = new QWidget; _TSWidget->setLayout(_TSLayout); QActionGroup* thickSliceModeActionGroup = new QActionGroup(myMenu); thickSliceModeActionGroup->setExclusive(true); QWidgetAction *m_TSSliderAction = new QWidgetAction(myMenu); m_TSSliderAction->setDefaultWidget(_TSWidget); myMenu->addAction(m_TSSliderAction); QAction* mipThickSlicesAction = new QAction(myMenu); mipThickSlicesAction->setActionGroup(thickSliceModeActionGroup); mipThickSlicesAction->setText("MIP (max. intensity proj.)"); mipThickSlicesAction->setCheckable(true); mipThickSlicesAction->setChecked(currentThickSlicesMode==1); mipThickSlicesAction->setData(1); myMenu->addAction( mipThickSlicesAction ); QAction* sumThickSlicesAction = new QAction(myMenu); sumThickSlicesAction->setActionGroup(thickSliceModeActionGroup); sumThickSlicesAction->setText("SUM (sum intensity proj.)"); sumThickSlicesAction->setCheckable(true); sumThickSlicesAction->setChecked(currentThickSlicesMode==2); sumThickSlicesAction->setData(2); myMenu->addAction( sumThickSlicesAction ); QAction* weightedThickSlicesAction = new QAction(myMenu); weightedThickSlicesAction->setActionGroup(thickSliceModeActionGroup); weightedThickSlicesAction->setText("WEIGHTED (gaussian proj.)"); weightedThickSlicesAction->setCheckable(true); weightedThickSlicesAction->setChecked(currentThickSlicesMode==3); weightedThickSlicesAction->setData(3); myMenu->addAction( weightedThickSlicesAction ); connect( thickSliceModeActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(OnThickSlicesModeSelected(QAction*)) ); } void QmitkControlVisualizationPropertiesView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; if (m_MultiWidget) { mitk::SlicesCoordinator* coordinator = m_MultiWidget->GetSlicesRotator(); if (coordinator) { itk::ReceptorMemberCommand::Pointer command2 = itk::ReceptorMemberCommand::New(); command2->SetCallbackFunction( this, &QmitkControlVisualizationPropertiesView::SliceRotation ); m_SlicesRotationObserverTag1 = coordinator->AddObserver( mitk::SliceRotationEvent(), command2 ); } coordinator = m_MultiWidget->GetSlicesSwiveller(); if (coordinator) { itk::ReceptorMemberCommand::Pointer command2 = itk::ReceptorMemberCommand::New(); command2->SetCallbackFunction( this, &QmitkControlVisualizationPropertiesView::SliceRotation ); m_SlicesRotationObserverTag2 = coordinator->AddObserver( mitk::SliceRotationEvent(), command2 ); } } } void QmitkControlVisualizationPropertiesView::SliceRotation(const itk::EventObject&) { // test if plane rotated if( m_GlyIsOn_T || m_GlyIsOn_C || m_GlyIsOn_S ) { if( this->IsPlaneRotated() ) { // show label m_Controls->m_lblRotatedPlanesWarning->show(); } else { //hide label m_Controls->m_lblRotatedPlanesWarning->hide(); } } } void QmitkControlVisualizationPropertiesView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } void QmitkControlVisualizationPropertiesView::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->m_DisplayIndex), SIGNAL(valueChanged(int)), this, SLOT(DisplayIndexChanged(int)) ); connect( (QObject*)(m_Controls->m_TextureIntON), SIGNAL(clicked()), this, SLOT(TextIntON()) ); connect( (QObject*)(m_Controls->m_Reinit), SIGNAL(clicked()), this, SLOT(Reinit()) ); connect( (QObject*)(m_Controls->m_VisibleOdfsON_T), SIGNAL(clicked()), this, SLOT(VisibleOdfsON_T()) ); connect( (QObject*)(m_Controls->m_VisibleOdfsON_S), SIGNAL(clicked()), this, SLOT(VisibleOdfsON_S()) ); connect( (QObject*)(m_Controls->m_VisibleOdfsON_C), SIGNAL(clicked()), this, SLOT(VisibleOdfsON_C()) ); connect( (QObject*)(m_Controls->m_ShowMaxNumber), SIGNAL(editingFinished()), this, SLOT(ShowMaxNumberChanged()) ); connect( (QObject*)(m_Controls->m_NormalizationDropdown), SIGNAL(currentIndexChanged(int)), this, SLOT(NormalizationDropdownChanged(int)) ); connect( (QObject*)(m_Controls->m_ScalingFactor), SIGNAL(valueChanged(double)), this, SLOT(ScalingFactorChanged(double)) ); connect( (QObject*)(m_Controls->m_AdditionalScaling), SIGNAL(currentIndexChanged(int)), this, SLOT(AdditionalScaling(int)) ); connect( (QObject*)(m_Controls->m_IndexParam1), SIGNAL(valueChanged(double)), this, SLOT(IndexParam1Changed(double)) ); connect( (QObject*)(m_Controls->m_IndexParam2), SIGNAL(valueChanged(double)), this, SLOT(IndexParam2Changed(double)) ); connect( (QObject*)(m_Controls->m_ScalingCheckbox), SIGNAL(clicked()), this, SLOT(ScalingCheckbox()) ); connect( (QObject*)(m_Controls->m_OpacitySlider), SIGNAL(spanChanged(double,double)), this, SLOT(OpacityChanged(double,double)) ); connect((QObject*) m_Controls->m_Wire, SIGNAL(clicked()), (QObject*) this, SLOT(BundleRepresentationWire())); connect((QObject*) m_Controls->m_Tube, SIGNAL(clicked()), (QObject*) this, SLOT(BundleRepresentationTube())); connect((QObject*) m_Controls->m_Color, SIGNAL(clicked()), (QObject*) this, SLOT(BundleRepresentationColor())); connect((QObject*) m_Controls->m_ResetColoring, SIGNAL(clicked()), (QObject*) this, SLOT(BundleRepresentationResetColoring())); connect((QObject*) m_Controls->m_Focus, SIGNAL(clicked()), (QObject*) this, SLOT(PlanarFigureFocus())); connect((QObject*) m_Controls->m_FiberFading2D, SIGNAL(clicked()), (QObject*) this, SLOT( Fiber2DfadingEFX() ) ); connect((QObject*) m_Controls->m_FiberThicknessSlider, SIGNAL(sliderReleased()), (QObject*) this, SLOT( FiberSlicingThickness2D() ) ); connect((QObject*) m_Controls->m_FiberThicknessSlider, SIGNAL(valueChanged(int)), (QObject*) this, SLOT( FiberSlicingUpdateLabel(int) )); connect((QObject*) m_Controls->m_Crosshair, SIGNAL(clicked()), (QObject*) this, SLOT(SetInteractor())); connect((QObject*) m_Controls->m_PFWidth, SIGNAL(valueChanged(int)), (QObject*) this, SLOT(PFWidth(int))); connect((QObject*) m_Controls->m_PFColor, SIGNAL(clicked()), (QObject*) this, SLOT(PFColor())); connect((QObject*) m_Controls->m_TDI, SIGNAL(clicked()), (QObject*) this, SLOT(GenerateTdi())); connect((QObject*) m_Controls->m_LineWidth, SIGNAL(valueChanged(int)), (QObject*) this, SLOT(LineWidthChanged(int))); connect((QObject*) m_Controls->m_TubeRadius, SIGNAL(valueChanged(int)), (QObject*) this, SLOT(TubeRadiusChanged(int))); connect((QObject*) m_Controls->m_Welcome, SIGNAL(clicked()), (QObject*) this, SLOT(Welcome())); } } void QmitkControlVisualizationPropertiesView::Activated() { berry::ISelection::ConstPointer sel( this->GetSite()->GetWorkbenchWindow()->GetSelectionService()->GetSelection("org.mitk.views.datamanager")); m_CurrentSelection = sel.Cast(); m_SelListener.Cast()->DoSelectionChanged(sel); QmitkFunctionality::Activated(); } void QmitkControlVisualizationPropertiesView::Deactivated() { QmitkFunctionality::Deactivated(); } int QmitkControlVisualizationPropertiesView::GetSizeFlags(bool width) { if(!width) { return berry::Constants::MIN | berry::Constants::MAX | berry::Constants::FILL; } else { return 0; } } int QmitkControlVisualizationPropertiesView::ComputePreferredSize(bool width, int /*availableParallel*/, int /*availablePerpendicular*/, int preferredResult) { if(width==false) { return m_FoundSingleOdfImage ? 120 : 80; } else { return preferredResult; } } // set diffusion image channel to b0 volume void QmitkControlVisualizationPropertiesView::NodeAdded(const mitk::DataNode *node) { mitk::DataNode* notConst = const_cast(node); if (dynamic_cast*>(notConst->GetData())) { mitk::DiffusionImage::Pointer dimg = dynamic_cast*>(notConst->GetData()); // if there is no b0 image in the dataset, the GetB0Indices() returns a vector of size 0 // and hence we cannot set the Property directly to .front() int displayChannelPropertyValue = 0; if( dimg->GetB0Indices().size() > 0) displayChannelPropertyValue = dimg->GetB0Indices().front(); notConst->SetIntProperty("DisplayChannel", displayChannelPropertyValue ); } } /* OnSelectionChanged is registered to SelectionService, therefore no need to implement SelectionService Listener explicitly */ void QmitkControlVisualizationPropertiesView::OnSelectionChanged( std::vector nodes ) { if ( !this->IsVisible() ) { // do nothing if nobody wants to see me :-( return; } // deactivate channel slider if no diffusion weighted image or tbss image is selected m_Controls->m_DisplayIndex->setVisible(false); m_Controls->label_channel->setVisible(false); for( std::vector::iterator it = nodes.begin(); it != nodes.end(); ++it ) { mitk::DataNode::Pointer node = *it; // check if node has data, // if some helper nodes are shown in the DataManager, the GetData() returns 0x0 which would lead to SIGSEV mitk::BaseData* nodeData = node->GetData(); if(nodeData == NULL) continue; if (node.IsNotNull() && (dynamic_cast(nodeData) || dynamic_cast*>(nodeData))) { m_Controls->m_DisplayIndex->setVisible(true); m_Controls->label_channel->setVisible(true); } else if (node.IsNotNull() && dynamic_cast(node->GetData())) { if (m_Color.IsNotNull()) m_Color->RemoveObserver(m_FiberBundleObserverTag); itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction( this, &QmitkControlVisualizationPropertiesView::SetFiberBundleCustomColor ); m_Color = dynamic_cast(node->GetProperty("color", NULL)); if (m_Color.IsNotNull()) m_FiberBundleObserverTag = m_Color->AddObserver( itk::ModifiedEvent(), command ); } } for( std::vector::iterator it = nodes.begin(); it != nodes.end(); ++it ) { mitk::DataNode::Pointer node = *it; // check if node has data, // if some helper nodes are shown in the DataManager, the GetData() returns 0x0 which would lead to SIGSEV mitk::BaseData* nodeData = node->GetData(); if(nodeData == NULL) continue; if( node.IsNotNull() && (dynamic_cast(nodeData) || dynamic_cast(nodeData)) ) { if(m_NodeUsedForOdfVisualization.IsNotNull()) { m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_S", false); m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_C", false); m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_T", false); } m_NodeUsedForOdfVisualization = node; m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_S", m_GlyIsOn_S); m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_C", m_GlyIsOn_C); m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_T", m_GlyIsOn_T); if(m_MultiWidget) m_MultiWidget->RequestUpdate(); m_Controls->m_TSMenu->setVisible(false); // deactivate mip etc. for tensor and q-ball images break; } else m_Controls->m_TSMenu->setVisible(true); } } mitk::DataStorage::SetOfObjects::Pointer QmitkControlVisualizationPropertiesView::ActiveSet(std::string classname) { 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(); // check if node has data, // if some helper nodes are shown in the DataManager, the GetData() returns 0x0 which would lead to SIGSEV const mitk::BaseData* nodeData = node->GetData(); if(nodeData == NULL) continue; if(QString(classname.c_str()).compare(nodeData->GetNameOfClass())==0) { set->InsertElement(at++, node); } } } return set; } return 0; } void QmitkControlVisualizationPropertiesView::SetBoolProp( mitk::DataStorage::SetOfObjects::Pointer set, std::string name, bool value) { if(set.IsNotNull()) { mitk::DataStorage::SetOfObjects::const_iterator itemiter( set->begin() ); mitk::DataStorage::SetOfObjects::const_iterator itemiterend( set->end() ); while ( itemiter != itemiterend ) { (*itemiter)->SetBoolProperty(name.c_str(), value); ++itemiter; } } } void QmitkControlVisualizationPropertiesView::SetIntProp( mitk::DataStorage::SetOfObjects::Pointer set, std::string name, int value) { if(set.IsNotNull()) { mitk::DataStorage::SetOfObjects::const_iterator itemiter( set->begin() ); mitk::DataStorage::SetOfObjects::const_iterator itemiterend( set->end() ); while ( itemiter != itemiterend ) { (*itemiter)->SetIntProperty(name.c_str(), value); ++itemiter; } } } void QmitkControlVisualizationPropertiesView::SetFloatProp( mitk::DataStorage::SetOfObjects::Pointer set, std::string name, float value) { if(set.IsNotNull()) { mitk::DataStorage::SetOfObjects::const_iterator itemiter( set->begin() ); mitk::DataStorage::SetOfObjects::const_iterator itemiterend( set->end() ); while ( itemiter != itemiterend ) { (*itemiter)->SetFloatProperty(name.c_str(), value); ++itemiter; } } } void QmitkControlVisualizationPropertiesView::SetLevelWindowProp( mitk::DataStorage::SetOfObjects::Pointer set, std::string name, mitk::LevelWindow value) { if(set.IsNotNull()) { mitk::LevelWindowProperty::Pointer prop = mitk::LevelWindowProperty::New(value); mitk::DataStorage::SetOfObjects::const_iterator itemiter( set->begin() ); mitk::DataStorage::SetOfObjects::const_iterator itemiterend( set->end() ); while ( itemiter != itemiterend ) { (*itemiter)->SetProperty(name.c_str(), prop); ++itemiter; } } } void QmitkControlVisualizationPropertiesView::SetEnumProp( mitk::DataStorage::SetOfObjects::Pointer set, std::string name, mitk::EnumerationProperty::Pointer value) { if(set.IsNotNull()) { mitk::DataStorage::SetOfObjects::const_iterator itemiter( set->begin() ); mitk::DataStorage::SetOfObjects::const_iterator itemiterend( set->end() ); while ( itemiter != itemiterend ) { (*itemiter)->SetProperty(name.c_str(), value); ++itemiter; } } } void QmitkControlVisualizationPropertiesView::DisplayIndexChanged(int dispIndex) { QString label = "Channel %1"; label = label.arg(dispIndex); m_Controls->label_channel->setText(label); std::vector sets; sets.push_back("DiffusionImage"); sets.push_back("TbssImage"); std::vector::iterator it = sets.begin(); while(it != sets.end()) { std::string s = *it; mitk::DataStorage::SetOfObjects::Pointer set = ActiveSet(s); if(set.IsNotNull()) { mitk::DataStorage::SetOfObjects::const_iterator itemiter( set->begin() ); mitk::DataStorage::SetOfObjects::const_iterator itemiterend( set->end() ); while ( itemiter != itemiterend ) { (*itemiter)->SetIntProperty("DisplayChannel", dispIndex); ++itemiter; } //m_MultiWidget->RequestUpdate(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } it++; } } void QmitkControlVisualizationPropertiesView::Reinit() { if (m_CurrentSelection) { mitk::DataNodeObject::Pointer nodeObj = m_CurrentSelection->Begin()->Cast(); mitk::DataNode::Pointer node = nodeObj->GetDataNode(); 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(); } } } void QmitkControlVisualizationPropertiesView::TextIntON() { if(m_TexIsOn) { m_Controls->m_TextureIntON->setIcon(*m_IconTexOFF); } else { m_Controls->m_TextureIntON->setIcon(*m_IconTexON); } mitk::DataStorage::SetOfObjects::Pointer set = ActiveSet("DiffusionImage"); SetBoolProp(set,"texture interpolation", !m_TexIsOn); set = ActiveSet("TensorImage"); SetBoolProp(set,"texture interpolation", !m_TexIsOn); set = ActiveSet("QBallImage"); SetBoolProp(set,"texture interpolation", !m_TexIsOn); set = ActiveSet("Image"); SetBoolProp(set,"texture interpolation", !m_TexIsOn); m_TexIsOn = !m_TexIsOn; if(m_MultiWidget) m_MultiWidget->RequestUpdate(); } void QmitkControlVisualizationPropertiesView::VisibleOdfsON_S() { m_GlyIsOn_S = m_Controls->m_VisibleOdfsON_S->isChecked(); if (m_NodeUsedForOdfVisualization.IsNull()) { MITK_WARN << "ODF visualization activated but m_NodeUsedForOdfVisualization is NULL"; return; } m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_S", m_GlyIsOn_S); VisibleOdfsON(0); } void QmitkControlVisualizationPropertiesView::VisibleOdfsON_T() { m_GlyIsOn_T = m_Controls->m_VisibleOdfsON_T->isChecked(); if (m_NodeUsedForOdfVisualization.IsNull()) { MITK_WARN << "ODF visualization activated but m_NodeUsedForOdfVisualization is NULL"; return; } m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_T", m_GlyIsOn_T); VisibleOdfsON(1); } void QmitkControlVisualizationPropertiesView::VisibleOdfsON_C() { m_GlyIsOn_C = m_Controls->m_VisibleOdfsON_C->isChecked(); if (m_NodeUsedForOdfVisualization.IsNull()) { MITK_WARN << "ODF visualization activated but m_NodeUsedForOdfVisualization is NULL"; return; } m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_C", m_GlyIsOn_C); VisibleOdfsON(2); } bool QmitkControlVisualizationPropertiesView::IsPlaneRotated() { // for all 2D renderwindows of m_MultiWidget check alignment mitk::PlaneGeometry::ConstPointer displayPlane = dynamic_cast( m_MultiWidget->GetRenderWindow1()->GetRenderer()->GetCurrentWorldGeometry2D() ); if (displayPlane.IsNull()) return false; mitk::Image* currentImage = dynamic_cast( m_NodeUsedForOdfVisualization->GetData() ); if( currentImage == NULL ) { MITK_ERROR << " Casting problems. Returning false"; return false; } int affectedDimension(-1); int affectedSlice(-1); return !(mitk::SegTool2D::DetermineAffectedImageSlice( currentImage, displayPlane, affectedDimension, affectedSlice )); } void QmitkControlVisualizationPropertiesView::VisibleOdfsON(int view) { if(m_MultiWidget) m_MultiWidget->RequestUpdate(); } void QmitkControlVisualizationPropertiesView::ShowMaxNumberChanged() { int maxNr = m_Controls->m_ShowMaxNumber->value(); if ( maxNr < 1 ) { m_Controls->m_ShowMaxNumber->setValue( 1 ); maxNr = 1; } mitk::DataStorage::SetOfObjects::Pointer set = ActiveSet("QBallImage"); SetIntProp(set,"ShowMaxNumber", maxNr); set = ActiveSet("TensorImage"); SetIntProp(set,"ShowMaxNumber", maxNr); if(m_MultiWidget) m_MultiWidget->RequestUpdate(); } void QmitkControlVisualizationPropertiesView::NormalizationDropdownChanged(int normDropdown) { typedef mitk::OdfNormalizationMethodProperty PropType; PropType::Pointer normMeth = PropType::New(); switch(normDropdown) { case 0: normMeth->SetNormalizationToMinMax(); break; case 1: normMeth->SetNormalizationToMax(); break; case 2: normMeth->SetNormalizationToNone(); break; case 3: normMeth->SetNormalizationToGlobalMax(); break; default: normMeth->SetNormalizationToMinMax(); } mitk::DataStorage::SetOfObjects::Pointer set = ActiveSet("QBallImage"); SetEnumProp(set,"Normalization", normMeth.GetPointer()); set = ActiveSet("TensorImage"); SetEnumProp(set,"Normalization", normMeth.GetPointer()); // if(m_MultiWidget) // m_MultiWidget->RequestUpdate(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::ScalingFactorChanged(double scalingFactor) { mitk::DataStorage::SetOfObjects::Pointer set = ActiveSet("QBallImage"); SetFloatProp(set,"Scaling", scalingFactor); set = ActiveSet("TensorImage"); SetFloatProp(set,"Scaling", scalingFactor); if(m_MultiWidget) m_MultiWidget->RequestUpdate(); } void QmitkControlVisualizationPropertiesView::AdditionalScaling(int additionalScaling) { typedef mitk::OdfScaleByProperty PropType; PropType::Pointer scaleBy = PropType::New(); switch(additionalScaling) { case 0: scaleBy->SetScaleByNothing(); break; case 1: scaleBy->SetScaleByGFA(); //m_Controls->params_frame->setVisible(true); break; #ifdef DIFFUSION_IMAGING_EXTENDED case 2: scaleBy->SetScaleByPrincipalCurvature(); // commented in for SPIE paper, Principle curvature scaling //m_Controls->params_frame->setVisible(true); break; #endif default: scaleBy->SetScaleByNothing(); } mitk::DataStorage::SetOfObjects::Pointer set = ActiveSet("QBallImage"); SetEnumProp(set,"ScaleBy", scaleBy.GetPointer()); set = ActiveSet("TensorImage"); SetEnumProp(set,"ScaleBy", scaleBy.GetPointer()); if(m_MultiWidget) m_MultiWidget->RequestUpdate(); } void QmitkControlVisualizationPropertiesView::IndexParam1Changed(double param1) { mitk::DataStorage::SetOfObjects::Pointer set = ActiveSet("QBallImage"); SetFloatProp(set,"IndexParam1", param1); set = ActiveSet("TensorImage"); SetFloatProp(set,"IndexParam1", param1); if(m_MultiWidget) m_MultiWidget->RequestUpdate(); } void QmitkControlVisualizationPropertiesView::IndexParam2Changed(double param2) { mitk::DataStorage::SetOfObjects::Pointer set = ActiveSet("QBallImage"); SetFloatProp(set,"IndexParam2", param2); set = ActiveSet("TensorImage"); SetFloatProp(set,"IndexParam2", param2); if(m_MultiWidget) m_MultiWidget->RequestUpdate(); } void QmitkControlVisualizationPropertiesView::OpacityChanged(double l, double u) { mitk::LevelWindow olw; olw.SetRangeMinMax(l*255, u*255); mitk::DataStorage::SetOfObjects::Pointer set = ActiveSet("QBallImage"); SetLevelWindowProp(set,"opaclevelwindow", olw); set = ActiveSet("TensorImage"); SetLevelWindowProp(set,"opaclevelwindow", olw); set = ActiveSet("Image"); SetLevelWindowProp(set,"opaclevelwindow", olw); m_Controls->m_OpacityMinFaLabel->setText(QString::number(l,'f',2) + " : " + QString::number(u,'f',2)); if(m_MultiWidget) m_MultiWidget->RequestUpdate(); } void QmitkControlVisualizationPropertiesView::ScalingCheckbox() { m_Controls->m_ScalingFrame->setVisible( m_Controls->m_ScalingCheckbox->isChecked()); if(!m_Controls->m_ScalingCheckbox->isChecked()) { m_Controls->m_AdditionalScaling->setCurrentIndex(0); m_Controls->m_ScalingFactor->setValue(1.0); } } void QmitkControlVisualizationPropertiesView::Fiber2DfadingEFX() { if (m_SelectedNode) { bool currentMode; m_SelectedNode->GetBoolProperty("Fiber2DfadeEFX", currentMode); m_SelectedNode->SetProperty("Fiber2DfadeEFX", mitk::BoolProperty::New(!currentMode)); mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); } } void QmitkControlVisualizationPropertiesView::FiberSlicingThickness2D() { if (m_SelectedNode) { float fibThickness = m_Controls->m_FiberThicknessSlider->value() * 0.1; m_SelectedNode->SetProperty("Fiber2DSliceThickness", mitk::FloatProperty::New(fibThickness)); mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); } } void QmitkControlVisualizationPropertiesView::FiberSlicingUpdateLabel(int value) { QString label = "Range %1"; label = label.arg(value * 0.1); m_Controls->label_range->setText(label); } void QmitkControlVisualizationPropertiesView::BundleRepresentationWire() { if(m_SelectedNode) { int width = m_Controls->m_LineWidth->value(); m_SelectedNode->SetProperty("LineWidth",mitk::IntProperty::New(width)); m_SelectedNode->SetProperty("ColorCoding",mitk::IntProperty::New(15)); mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); m_SelectedNode->SetProperty("ColorCoding",mitk::IntProperty::New(18)); mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); m_SelectedNode->SetProperty("ColorCoding",mitk::IntProperty::New(1)); mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); m_SelectedNode->SetProperty("ColorCoding",mitk::IntProperty::New(2)); mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); m_SelectedNode->SetProperty("ColorCoding",mitk::IntProperty::New(3)); mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); m_SelectedNode->SetProperty("ColorCoding",mitk::IntProperty::New(4)); mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); m_SelectedNode->SetProperty("ColorCoding",mitk::IntProperty::New(0)); mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); } } void QmitkControlVisualizationPropertiesView::BundleRepresentationTube() { if(m_SelectedNode) { float radius = m_Controls->m_TubeRadius->value() / 100.0; m_SelectedNode->SetProperty("TubeRadius",mitk::FloatProperty::New(radius)); m_SelectedNode->SetProperty("ColorCoding",mitk::IntProperty::New(17)); mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); m_SelectedNode->SetProperty("ColorCoding",mitk::IntProperty::New(13)); mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); m_SelectedNode->SetProperty("ColorCoding",mitk::IntProperty::New(16)); mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); m_SelectedNode->SetProperty("ColorCoding",mitk::IntProperty::New(0)); mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); } } void QmitkControlVisualizationPropertiesView::SetFiberBundleCustomColor(const itk::EventObject& /*e*/) { float color[3]; m_SelectedNode->GetColor(color); m_Controls->m_Color->setAutoFillBackground(true); QString styleSheet = "background-color:rgb("; styleSheet.append(QString::number(color[0]*255.0)); styleSheet.append(","); styleSheet.append(QString::number(color[1]*255.0)); styleSheet.append(","); styleSheet.append(QString::number(color[2]*255.0)); styleSheet.append(")"); m_Controls->m_Color->setStyleSheet(styleSheet); m_SelectedNode->SetProperty("color",mitk::ColorProperty::New(color[0], color[1], color[2])); mitk::FiberBundleX::Pointer fib = dynamic_cast(m_SelectedNode->GetData()); fib->SetColorCoding(mitk::FiberBundleX::COLORCODING_CUSTOM); m_SelectedNode->Modified(); mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); } void QmitkControlVisualizationPropertiesView::BundleRepresentationColor() { if(m_SelectedNode) { QColor color = QColorDialog::getColor(); if (!color.isValid()) return; m_Controls->m_Color->setAutoFillBackground(true); QString styleSheet = "background-color:rgb("; styleSheet.append(QString::number(color.red())); styleSheet.append(","); styleSheet.append(QString::number(color.green())); styleSheet.append(","); styleSheet.append(QString::number(color.blue())); styleSheet.append(")"); m_Controls->m_Color->setStyleSheet(styleSheet); m_SelectedNode->SetProperty("color",mitk::ColorProperty::New(color.red()/255.0, color.green()/255.0, color.blue()/255.0)); mitk::FiberBundleX::Pointer fib = dynamic_cast(m_SelectedNode->GetData()); fib->SetColorCoding(mitk::FiberBundleX::COLORCODING_CUSTOM); m_SelectedNode->Modified(); mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); } } void QmitkControlVisualizationPropertiesView::BundleRepresentationResetColoring() { if(m_SelectedNode) { MITK_INFO << "reset colorcoding to oBased"; m_Controls->m_Color->setAutoFillBackground(true); QString styleSheet = "background-color:rgb(255,255,255)"; m_Controls->m_Color->setStyleSheet(styleSheet); // m_SelectedNode->SetProperty("color",NULL); m_SelectedNode->SetProperty("color",mitk::ColorProperty::New(1.0, 1.0, 1.0)); mitk::FiberBundleX::Pointer fib = dynamic_cast(m_SelectedNode->GetData()); fib->SetColorCoding(mitk::FiberBundleX::COLORCODING_ORIENTATION_BASED); fib->DoColorCodingOrientationBased(); m_SelectedNode->Modified(); mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); } } void QmitkControlVisualizationPropertiesView::PlanarFigureFocus() { if(m_SelectedNode) { mitk::PlanarFigure* _PlanarFigure = 0; _PlanarFigure = dynamic_cast (m_SelectedNode->GetData()); if (_PlanarFigure) { QmitkRenderWindow* selectedRenderWindow = 0; bool PlanarFigureInitializedWindow = false; QmitkRenderWindow* RenderWindow1 = this->GetActiveStdMultiWidget()->GetRenderWindow1(); if (m_SelectedNode->GetBoolProperty("PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, RenderWindow1->GetRenderer())) { selectedRenderWindow = RenderWindow1; } QmitkRenderWindow* RenderWindow2 = this->GetActiveStdMultiWidget()->GetRenderWindow2(); if (!selectedRenderWindow && m_SelectedNode->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, RenderWindow2->GetRenderer())) { selectedRenderWindow = RenderWindow2; } QmitkRenderWindow* RenderWindow3 = this->GetActiveStdMultiWidget()->GetRenderWindow3(); if (!selectedRenderWindow && m_SelectedNode->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, RenderWindow3->GetRenderer())) { selectedRenderWindow = RenderWindow3; } QmitkRenderWindow* RenderWindow4 = this->GetActiveStdMultiWidget()->GetRenderWindow4(); if (!selectedRenderWindow && m_SelectedNode->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, RenderWindow4->GetRenderer())) { selectedRenderWindow = RenderWindow4; } const mitk::PlaneGeometry * _PlaneGeometry = dynamic_cast (_PlanarFigure->GetGeometry2D()); mitk::VnlVector normal = _PlaneGeometry->GetNormalVnl(); mitk::Geometry2D::ConstPointer worldGeometry1 = RenderWindow1->GetRenderer()->GetCurrentWorldGeometry2D(); mitk::PlaneGeometry::ConstPointer _Plane1 = dynamic_cast( worldGeometry1.GetPointer() ); mitk::VnlVector normal1 = _Plane1->GetNormalVnl(); mitk::Geometry2D::ConstPointer worldGeometry2 = RenderWindow2->GetRenderer()->GetCurrentWorldGeometry2D(); mitk::PlaneGeometry::ConstPointer _Plane2 = dynamic_cast( worldGeometry2.GetPointer() ); mitk::VnlVector normal2 = _Plane2->GetNormalVnl(); mitk::Geometry2D::ConstPointer worldGeometry3 = RenderWindow3->GetRenderer()->GetCurrentWorldGeometry2D(); mitk::PlaneGeometry::ConstPointer _Plane3 = dynamic_cast( worldGeometry3.GetPointer() ); mitk::VnlVector normal3 = _Plane3->GetNormalVnl(); normal[0] = fabs(normal[0]); normal[1] = fabs(normal[1]); normal[2] = fabs(normal[2]); normal1[0] = fabs(normal1[0]); normal1[1] = fabs(normal1[1]); normal1[2] = fabs(normal1[2]); normal2[0] = fabs(normal2[0]); normal2[1] = fabs(normal2[1]); normal2[2] = fabs(normal2[2]); normal3[0] = fabs(normal3[0]); normal3[1] = fabs(normal3[1]); normal3[2] = fabs(normal3[2]); double ang1 = angle(normal, normal1); double ang2 = angle(normal, normal2); double ang3 = angle(normal, normal3); if(ang1 < ang2 && ang1 < ang3) { selectedRenderWindow = RenderWindow1; } else { if(ang2 < ang3) { selectedRenderWindow = RenderWindow2; } else { selectedRenderWindow = RenderWindow3; } } // make node visible if (selectedRenderWindow) { mitk::Point3D centerP = _PlaneGeometry->GetOrigin(); selectedRenderWindow->GetSliceNavigationController()->ReorientSlices( centerP, _PlaneGeometry->GetNormal()); selectedRenderWindow->GetSliceNavigationController()->SelectSliceByPoint( centerP); } } // set interactor for new node (if not already set) mitk::PlanarFigureInteractor::Pointer figureInteractor = dynamic_cast(m_SelectedNode->GetInteractor()); if(figureInteractor.IsNull()) figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", m_SelectedNode); mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); m_SelectedNode->SetProperty("planarfigure.iseditable",mitk::BoolProperty::New(true)); } } void QmitkControlVisualizationPropertiesView::SetInteractor() { typedef std::vector Container; Container _NodeSet = this->GetDataManagerSelection(); mitk::DataNode* node = 0; mitk::FiberBundleX* bundle = 0; mitk::FiberBundleInteractor::Pointer bundleInteractor = 0; // finally add all nodes to the model for(Container::const_iterator it=_NodeSet.begin(); it!=_NodeSet.end() ; it++) { node = const_cast(*it); bundle = dynamic_cast(node->GetData()); if(bundle) { bundleInteractor = dynamic_cast(node->GetInteractor()); if(bundleInteractor.IsNotNull()) mitk::GlobalInteraction::GetInstance()->RemoveInteractor(bundleInteractor); if(!m_Controls->m_Crosshair->isChecked()) { m_Controls->m_Crosshair->setChecked(false); this->GetActiveStdMultiWidget()->GetRenderWindow4()->setCursor(Qt::ArrowCursor); m_CurrentPickingNode = 0; } else { m_Controls->m_Crosshair->setChecked(true); bundleInteractor = mitk::FiberBundleInteractor::New("FiberBundleInteractor", node); mitk::GlobalInteraction::GetInstance()->AddInteractor(bundleInteractor); this->GetActiveStdMultiWidget()->GetRenderWindow4()->setCursor(Qt::CrossCursor); m_CurrentPickingNode = node; } } } } void QmitkControlVisualizationPropertiesView::PFWidth(int w) { double width = w/10.0; m_SelectedNode->SetProperty("planarfigure.line.width", mitk::FloatProperty::New(width) ); m_SelectedNode->SetProperty("planarfigure.shadow.widthmodifier", mitk::FloatProperty::New(width) ); m_SelectedNode->SetProperty("planarfigure.outline.width", mitk::FloatProperty::New(width) ); m_SelectedNode->SetProperty("planarfigure.helperline.width", mitk::FloatProperty::New(width) ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QString label = "Width %1"; label = label.arg(width); m_Controls->label_pfwidth->setText(label); } void QmitkControlVisualizationPropertiesView::PFColor() { QColor color = QColorDialog::getColor(); if (!color.isValid()) return; m_Controls->m_PFColor->setAutoFillBackground(true); QString styleSheet = "background-color:rgb("; styleSheet.append(QString::number(color.red())); styleSheet.append(","); styleSheet.append(QString::number(color.green())); styleSheet.append(","); styleSheet.append(QString::number(color.blue())); styleSheet.append(")"); m_Controls->m_PFColor->setStyleSheet(styleSheet); m_SelectedNode->SetProperty( "planarfigure.default.line.color", mitk::ColorProperty::New(color.red()/255.0, color.green()/255.0, color.blue()/255.0)); m_SelectedNode->SetProperty( "planarfigure.default.outline.color", mitk::ColorProperty::New(color.red()/255.0, color.green()/255.0, color.blue()/255.0)); m_SelectedNode->SetProperty( "planarfigure.default.helperline.color", mitk::ColorProperty::New(color.red()/255.0, color.green()/255.0, color.blue()/255.0)); m_SelectedNode->SetProperty( "planarfigure.default.markerline.color", mitk::ColorProperty::New(color.red()/255.0, color.green()/255.0, color.blue()/255.0)); m_SelectedNode->SetProperty( "planarfigure.default.marker.color", mitk::ColorProperty::New(color.red()/255.0, color.green()/255.0, color.blue()/255.0)); m_SelectedNode->SetProperty( "planarfigure.hover.line.color", mitk::ColorProperty::New(color.red()/255.0, color.green()/255.0, color.blue()/255.0) ); m_SelectedNode->SetProperty( "planarfigure.hover.outline.color", mitk::ColorProperty::New(color.red()/255.0, color.green()/255.0, color.blue()/255.0) ); m_SelectedNode->SetProperty( "planarfigure.hover.helperline.color", mitk::ColorProperty::New(color.red()/255.0, color.green()/255.0, color.blue()/255.0) ); m_SelectedNode->SetProperty( "color", mitk::ColorProperty::New(color.red()/255.0, color.green()/255.0, color.blue()/255.0)); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::GenerateTdi() { if(m_SelectedNode) { mitk::FiberBundleX* bundle = dynamic_cast(m_SelectedNode->GetData()); if(!bundle) return; typedef float OutPixType; typedef itk::Image OutImageType; // run generator itk::TractDensityImageFilter< OutImageType >::Pointer generator = itk::TractDensityImageFilter< OutImageType >::New(); generator->SetFiberBundle(bundle); generator->SetOutputAbsoluteValues(true); generator->SetUpsamplingFactor(1); generator->Update(); // get result OutImageType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // to datastorage mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); QString name(m_SelectedNode->GetName().c_str()); name += "_TDI"; node->SetName(name.toStdString()); node->SetVisibility(true); GetDataStorage()->Add(node); } } void QmitkControlVisualizationPropertiesView::LineWidthChanged(int w) { QString label = "Width %1"; label = label.arg(w); m_Controls->label_linewidth->setText(label); BundleRepresentationWire(); } void QmitkControlVisualizationPropertiesView::TubeRadiusChanged(int r) { QString label = "Radius %1"; label = label.arg(r / 100.0); m_Controls->label_tuberadius->setText(label); this->BundleRepresentationTube(); } void QmitkControlVisualizationPropertiesView::Welcome() { berry::PlatformUI::GetWorkbench()->GetIntroManager()->ShowIntro( GetSite()->GetWorkbenchWindow(), false); } 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 94dd852334..a47730cd18 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui @@ -1,912 +1,912 @@ QmitkFiberProcessingViewControls 0 0 665 683 Form 0 9 3 9 3 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 Extract fibers passing through selected ROI or composite ROI. Select ROI and fiber bundle to execute. Extract 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 Merge selected fiber bundles. Select at least two fiber bundles to execute. Join Qt::Horizontal 40 20 false 0 0 200 16777215 11 Extract fibers passing through selected surface mesh. Select surface mesh and fiber bundle to execute. Extract 3D 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 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 0 0 Tract Density Image Tract Density Image (normalize image values) Binary Envelope Fiber Bundle Image Fiber Endings Image Fiber Endings Pointset false 0 0 200 16777215 11 Perform selected operation on all selected fiber bundles. Generate If selected operation generates an image, the inverse image is returned. Invert 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 false 0 0 200 16777215 11 Mirror fibers around specified axis. Mirror Fibers false 0 0 200 16777215 11 Apply float image values (0-1) as color coding to the selected fiber bundle. Color By Scalar Map 0 3 3 Sagittal Coronal - Transversal + Axial Upsampling factor 1 0.100000000000000 10.000000000000000 0.100000000000000 1.000000000000000 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 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 Fiber Statistics Courier 10 Pitch false true Qt::Vertical 20 40 diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkPartialVolumeAnalysisView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkPartialVolumeAnalysisView.cpp index a1c109e4b0..9bde8497bf 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkPartialVolumeAnalysisView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkPartialVolumeAnalysisView.cpp @@ -1,2138 +1,2138 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "QmitkPartialVolumeAnalysisView.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "QmitkStdMultiWidget.h" #include "QmitkStdMultiWidgetEditor.h" #include "QmitkSliderNavigatorWidget.h" #include #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateOr.h" #include "mitkImageTimeSelector.h" #include "mitkProperties.h" #include "mitkProgressBar.h" #include "mitkImageCast.h" #include "mitkImageToItk.h" #include "mitkITKImageImport.h" #include "mitkDataNodeObject.h" #include "mitkNodePredicateData.h" #include "mitkPlanarFigureInteractor.h" #include "mitkGlobalInteraction.h" #include "mitkTensorImage.h" #include "mitkPlanarCircle.h" #include "mitkPlanarRectangle.h" #include "mitkPlanarPolygon.h" #include "mitkPartialVolumeAnalysisClusteringCalculator.h" #include "mitkDiffusionImage.h" #include #include "itkTensorDerivedMeasurementsFilter.h" #include "itkDiffusionTensor3D.h" #include "itkCartesianToPolarVectorImageFilter.h" #include "itkPolarToCartesianVectorImageFilter.h" #include "itkBinaryThresholdImageFilter.h" #include "itkMaskImageFilter.h" #include "itkCastImageFilter.h" #include "itkImageMomentsCalculator.h" #include #include #include #include #define _USE_MATH_DEFINES #include #define PVA_PI M_PI const std::string QmitkPartialVolumeAnalysisView::VIEW_ID = "org.mitk.views.partialvolumeanalysisview"; class QmitkRequestStatisticsUpdateEvent : public QEvent { public: enum Type { StatisticsUpdateRequest = QEvent::MaxUser - 1025 }; QmitkRequestStatisticsUpdateEvent() : QEvent( (QEvent::Type) StatisticsUpdateRequest ) {}; }; typedef itk::Image ImageType; typedef itk::Image FloatImageType; typedef itk::Image, 3> VectorImageType; inline bool my_isnan(float x) { volatile float d = x; if(d!=d) return true; if(d==d) return false; return d != d; } QmitkPartialVolumeAnalysisView::QmitkPartialVolumeAnalysisView(QObject * /*parent*/, const char * /*name*/) : //QmitkFunctionality(), m_Controls( NULL ), m_TimeStepperAdapter( NULL ), m_MeasurementInfoRenderer(0), m_MeasurementInfoAnnotation(0), m_SelectedImageNodes( ), m_SelectedImage( NULL ), m_SelectedMaskNode( NULL ), m_SelectedImageMask( NULL ), m_SelectedPlanarFigureNodes(0), m_SelectedPlanarFigure( NULL ), m_IsTensorImage(false), m_FAImage(0), m_RDImage(0), m_ADImage(0), m_MDImage(0), m_CAImage(0), // m_DirectionImage(0), m_DirectionComp1Image(0), m_DirectionComp2Image(0), m_AngularErrorImage(0), m_SelectedRenderWindow(NULL), m_LastRenderWindow(NULL), m_ImageObserverTag( -1 ), m_ImageMaskObserverTag( -1 ), m_PlanarFigureObserverTag( -1 ), m_CurrentStatisticsValid( false ), m_StatisticsUpdatePending( false ), m_GaussianSigmaChangedSliding(false), m_NumberBinsSliding(false), m_UpsamplingChangedSliding(false), m_ClusteringResult(NULL), m_EllipseCounter(0), m_RectangleCounter(0), m_PolygonCounter(0), m_CurrentFigureNodeInitialized(false), m_QuantifyClass(2), m_IconTexOFF(new QIcon(":/QmitkPartialVolumeAnalysisView/texIntOFFIcon.png")), m_IconTexON(new QIcon(":/QmitkPartialVolumeAnalysisView/texIntONIcon.png")), m_TexIsOn(true), m_Visible(false) { } QmitkPartialVolumeAnalysisView::~QmitkPartialVolumeAnalysisView() { if ( m_SelectedImage.IsNotNull() ) m_SelectedImage->RemoveObserver( m_ImageObserverTag ); if ( m_SelectedImageMask.IsNotNull() ) m_SelectedImageMask->RemoveObserver( m_ImageMaskObserverTag ); if ( m_SelectedPlanarFigure.IsNotNull() ) { m_SelectedPlanarFigure->RemoveObserver( m_PlanarFigureObserverTag ); m_SelectedPlanarFigure->RemoveObserver( m_InitializedObserverTag ); } this->GetDataStorage()->AddNodeEvent -= mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeAddedInDataStorage ); m_SelectedPlanarFigureNodes->NodeChanged.RemoveListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeChanged ) ); m_SelectedPlanarFigureNodes->NodeRemoved.RemoveListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeRemoved ) ); m_SelectedPlanarFigureNodes->PropertyChanged.RemoveListener( mitk::MessageDelegate2( this, &QmitkPartialVolumeAnalysisView::PropertyChanged ) ); m_SelectedImageNodes->NodeChanged.RemoveListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeChanged ) ); m_SelectedImageNodes->NodeRemoved.RemoveListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeRemoved ) ); m_SelectedImageNodes->PropertyChanged.RemoveListener( mitk::MessageDelegate2( this, &QmitkPartialVolumeAnalysisView::PropertyChanged ) ); } void QmitkPartialVolumeAnalysisView::CreateQtPartControl(QWidget *parent) { if (m_Controls == NULL) { m_Controls = new Ui::QmitkPartialVolumeAnalysisViewControls; m_Controls->setupUi(parent); this->CreateConnections(); } SetHistogramVisibility(); m_Controls->m_TextureIntON->setIcon(*m_IconTexON); m_Controls->m_SimilarAnglesFrame->setVisible(false); m_Controls->m_SimilarAnglesLabel->setVisible(false); vtkTextProperty *textProp = vtkTextProperty::New(); textProp->SetColor(1.0, 1.0, 1.0); m_MeasurementInfoAnnotation = vtkCornerAnnotation::New(); m_MeasurementInfoAnnotation->SetMaximumFontSize(12); m_MeasurementInfoAnnotation->SetTextProperty(textProp); m_MeasurementInfoRenderer = vtkRenderer::New(); m_MeasurementInfoRenderer->AddActor(m_MeasurementInfoAnnotation); m_SelectedPlanarFigureNodes = mitk::DataStorageSelection::New(this->GetDataStorage(), false); m_SelectedPlanarFigureNodes->NodeChanged.AddListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeChanged ) ); m_SelectedPlanarFigureNodes->NodeRemoved.AddListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeRemoved ) ); m_SelectedPlanarFigureNodes->PropertyChanged.AddListener( mitk::MessageDelegate2( this, &QmitkPartialVolumeAnalysisView::PropertyChanged ) ); m_SelectedImageNodes = mitk::DataStorageSelection::New(this->GetDataStorage(), false); m_SelectedImageNodes->PropertyChanged.AddListener( mitk::MessageDelegate2( this, &QmitkPartialVolumeAnalysisView::PropertyChanged ) ); m_SelectedImageNodes->NodeChanged.AddListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeChanged ) ); m_SelectedImageNodes->NodeRemoved.AddListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeRemoved ) ); this->GetDataStorage()->AddNodeEvent.AddListener( mitk::MessageDelegate1( this, &QmitkPartialVolumeAnalysisView::NodeAddedInDataStorage ) ); Select(NULL,true,true); SetAdvancedVisibility(); } void QmitkPartialVolumeAnalysisView::SetHistogramVisibility() { m_Controls->m_HistogramWidget->setVisible(m_Controls->m_DisplayHistogramCheckbox->isChecked()); } void QmitkPartialVolumeAnalysisView::SetAdvancedVisibility() { m_Controls->frame_7->setVisible(m_Controls->m_AdvancedCheckbox->isChecked()); } void QmitkPartialVolumeAnalysisView::CreateConnections() { if ( m_Controls ) { connect( m_Controls->m_DisplayHistogramCheckbox, SIGNAL( clicked() ) , this, SLOT( SetHistogramVisibility() ) ); connect( m_Controls->m_AdvancedCheckbox, SIGNAL( clicked() ) , this, SLOT( SetAdvancedVisibility() ) ); connect( m_Controls->m_NumberBinsSlider, SIGNAL( sliderReleased () ), this, SLOT( NumberBinsReleasedSlider( ) ) ); connect( m_Controls->m_UpsamplingSlider, SIGNAL( sliderReleased( ) ), this, SLOT( UpsamplingReleasedSlider( ) ) ); connect( m_Controls->m_GaussianSigmaSlider, SIGNAL( sliderReleased( ) ), this, SLOT( GaussianSigmaReleasedSlider( ) ) ); connect( m_Controls->m_SimilarAnglesSlider, SIGNAL( sliderReleased( ) ), this, SLOT( SimilarAnglesReleasedSlider( ) ) ); connect( m_Controls->m_NumberBinsSlider, SIGNAL( valueChanged (int) ), this, SLOT( NumberBinsChangedSlider( int ) ) ); connect( m_Controls->m_UpsamplingSlider, SIGNAL( valueChanged( int ) ), this, SLOT( UpsamplingChangedSlider( int ) ) ); connect( m_Controls->m_GaussianSigmaSlider, SIGNAL( valueChanged( int ) ), this, SLOT( GaussianSigmaChangedSlider( int ) ) ); connect( m_Controls->m_SimilarAnglesSlider, SIGNAL( valueChanged( int ) ), this, SLOT( SimilarAnglesChangedSlider(int) ) ); connect( m_Controls->m_OpacitySlider, SIGNAL( valueChanged( int ) ), this, SLOT( OpacityChangedSlider(int) ) ); connect( (QObject*)(m_Controls->m_ButtonCopyHistogramToClipboard), SIGNAL(clicked()),(QObject*) this, SLOT(ToClipBoard())); connect( m_Controls->m_CircleButton, SIGNAL( clicked() ) , this, SLOT( ActionDrawEllipseTriggered() ) ); connect( m_Controls->m_RectangleButton, SIGNAL( clicked() ) , this, SLOT( ActionDrawRectangleTriggered() ) ); connect( m_Controls->m_PolygonButton, SIGNAL( clicked() ) , this, SLOT( ActionDrawPolygonTriggered() ) ); connect( m_Controls->m_GreenRadio, SIGNAL( clicked(bool) ) , this, SLOT( GreenRadio(bool) ) ); connect( m_Controls->m_PartialVolumeRadio, SIGNAL( clicked(bool) ) , this, SLOT( PartialVolumeRadio(bool) ) ); connect( m_Controls->m_BlueRadio, SIGNAL( clicked(bool) ) , this, SLOT( BlueRadio(bool) ) ); connect( m_Controls->m_AllRadio, SIGNAL( clicked(bool) ) , this, SLOT( AllRadio(bool) ) ); connect( m_Controls->m_EstimateCircle, SIGNAL( clicked() ) , this, SLOT( EstimateCircle() ) ); connect( (QObject*)(m_Controls->m_TextureIntON), SIGNAL(clicked()), this, SLOT(TextIntON()) ); connect( m_Controls->m_ExportClusteringResultsButton, SIGNAL(clicked()), this, SLOT(ExportClusteringResults())); } } void QmitkPartialVolumeAnalysisView::ExportClusteringResults() { if (m_ClusteringResult.IsNull() || m_SelectedImage.IsNull()) return; mitk::Geometry3D* geometry = m_SelectedImage->GetGeometry(); itk::Image< short, 3>::Pointer referenceImage = itk::Image< short, 3>::New(); mitk::Vector3D newSpacing = geometry->GetSpacing(); 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 newDirection; itk::ImageRegion<3> imageRegion; for (int i=0; i<3; i++) for (int j=0; j<3; j++) newDirection[j][i] = geometry->GetMatrixColumn(i)[j]/newSpacing[j]; imageRegion.SetSize(0, geometry->GetExtent(0)); imageRegion.SetSize(1, geometry->GetExtent(1)); imageRegion.SetSize(2, geometry->GetExtent(2)); // apply new image parameters referenceImage->SetSpacing( newSpacing ); referenceImage->SetOrigin( newOrigin ); referenceImage->SetDirection( newDirection ); referenceImage->SetRegions( imageRegion ); referenceImage->Allocate(); typedef itk::Image< float, 3 > OutType; mitk::Image::Pointer mitkInImage = dynamic_cast(m_ClusteringResult->GetData()); typedef itk::Image< itk::RGBAPixel, 3 > ItkRgbaImageType; typedef mitk::ImageToItk< ItkRgbaImageType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(mitkInImage); caster->Update(); ItkRgbaImageType::Pointer itkInImage = caster->GetOutput(); typedef itk::ExtractChannelFromRgbaImageFilter< itk::Image< short, 3>, OutType > ExtractionFilterType; ExtractionFilterType::Pointer filter = ExtractionFilterType::New(); filter->SetInput(itkInImage); filter->SetChannel(ExtractionFilterType::ALPHA); filter->SetReferenceImage(referenceImage); filter->Update(); OutType::Pointer outImg = filter->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); node->SetName("Clustering Result"); GetDataStorage()->Add(node); } void QmitkPartialVolumeAnalysisView::EstimateCircle() { typedef itk::Image SegImageType; SegImageType::Pointer mask_itk = SegImageType::New(); typedef mitk::ImageToItk CastType; CastType::Pointer caster = CastType::New(); caster->SetInput(m_SelectedImageMask); caster->Update(); typedef itk::ImageMomentsCalculator< SegImageType > MomentsType; MomentsType::Pointer momentsCalc = MomentsType::New(); momentsCalc->SetImage(caster->GetOutput()); momentsCalc->Compute(); MomentsType::VectorType cog = momentsCalc->GetCenterOfGravity(); MomentsType::MatrixType axes = momentsCalc->GetPrincipalAxes(); MomentsType::VectorType moments = momentsCalc->GetPrincipalMoments(); // moments-coord conversion // third coordinate min oder max? // max-min = extent MomentsType::AffineTransformPointer trafo = momentsCalc->GetPhysicalAxesToPrincipalAxesTransform(); itk::ImageRegionIterator itimage(caster->GetOutput(), caster->GetOutput()->GetLargestPossibleRegion()); itimage = itimage.Begin(); double max = -9999999999.0; double min = 9999999999.0; while( !itimage.IsAtEnd() ) { if(itimage.Get()) { ImageType::IndexType index = itimage.GetIndex(); itk::Point point; caster->GetOutput()->TransformIndexToPhysicalPoint(index,point); itk::Point newPoint; newPoint = trafo->TransformPoint(point); if(newPoint[2]max) max = newPoint[2]; } ++itimage; } double extent = max - min; MITK_INFO << "EXTENT = " << extent; mitk::Point3D origin; mitk::Vector3D right, bottom, normal; double factor = 1000.0; mitk::FillVector3D(origin, cog[0]-factor*axes[1][0]-factor*axes[2][0], cog[1]-factor*axes[1][1]-factor*axes[2][1], cog[2]-factor*axes[1][2]-factor*axes[2][2]); // mitk::FillVector3D(normal, axis[0][0],axis[0][1],axis[0][2]); mitk::FillVector3D(bottom, 2*factor*axes[1][0], 2*factor*axes[1][1], 2*factor*axes[1][2]); mitk::FillVector3D(right, 2*factor*axes[2][0], 2*factor*axes[2][1], 2*factor*axes[2][2]); mitk::PlaneGeometry::Pointer planegeometry = mitk::PlaneGeometry::New(); planegeometry->InitializeStandardPlane(right.Get_vnl_vector(), bottom.Get_vnl_vector()); planegeometry->SetOrigin(origin); double len1 = sqrt(axes[1][0]*axes[1][0] + axes[1][1]*axes[1][1] + axes[1][2]*axes[1][2]); double len2 = sqrt(axes[2][0]*axes[2][0] + axes[2][1]*axes[2][1] + axes[2][2]*axes[2][2]); mitk::Point2D point1; point1[0] = factor*len1; point1[1] = factor*len2; mitk::Point2D point2; point2[0] = factor*len1+extent*.5; point2[1] = factor*len2; mitk::PlanarCircle::Pointer circle = mitk::PlanarCircle::New(); circle->SetGeometry2D(planegeometry); circle->PlaceFigure( point1 ); circle->SetControlPoint(0,point1); circle->SetControlPoint(1,point2); //circle->SetCurrentControlPoint( point2 ); mitk::PlanarFigure::PolyLineType polyline = circle->GetPolyLine( 0 ); MITK_INFO << "SIZE of planar figure polyline: " << polyline.size(); AddFigureToDataStorage(circle, "Circle"); } bool QmitkPartialVolumeAnalysisView::AssertDrawingIsPossible(bool checked) { if (m_SelectedImageNodes->GetNode().IsNull()) { checked = false; this->HandleException("Please select an image!", dynamic_cast(this->parent()), true); return false; } //this->GetActiveStdMultiWidget()->SetWidgetPlanesVisibility(false); return checked; } void QmitkPartialVolumeAnalysisView::ActionDrawEllipseTriggered() { bool checked = m_Controls->m_CircleButton->isChecked(); if(!this->AssertDrawingIsPossible(checked)) return; mitk::PlanarCircle::Pointer figure = mitk::PlanarCircle::New(); this->AddFigureToDataStorage(figure, QString("Circle%1").arg(++m_EllipseCounter)); MITK_INFO << "PlanarCircle created ..."; } void QmitkPartialVolumeAnalysisView::ActionDrawRectangleTriggered() { bool checked = m_Controls->m_RectangleButton->isChecked(); if(!this->AssertDrawingIsPossible(checked)) return; mitk::PlanarRectangle::Pointer figure = mitk::PlanarRectangle::New(); this->AddFigureToDataStorage(figure, QString("Rectangle%1").arg(++m_RectangleCounter)); MITK_INFO << "PlanarRectangle created ..."; } void QmitkPartialVolumeAnalysisView::ActionDrawPolygonTriggered() { 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_INFO << "PlanarPolygon created ..."; } void QmitkPartialVolumeAnalysisView::AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *propertyKey, mitk::BaseProperty *property ) { mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetName(name.toStdString()); newNode->SetData(figure); // Add custom property, if available if ( (propertyKey != NULL) && (property != NULL) ) { newNode->AddProperty( propertyKey, property ); } // figure drawn on the topmost layer / image this->GetDataStorage()->Add(newNode, m_SelectedImageNodes->GetNode() ); QList selectedNodes = this->GetDataManagerSelection(); for(unsigned int i = 0; i < selectedNodes.size(); i++) { selectedNodes[i]->SetSelected(false); } std::vector selectedPFNodes = m_SelectedPlanarFigureNodes->GetNodes(); for(unsigned int i = 0; i < selectedPFNodes.size(); i++) { selectedPFNodes[i]->SetSelected(false); } newNode->SetSelected(true); Select(newNode); } void QmitkPartialVolumeAnalysisView::PlanarFigureInitialized() { if(m_SelectedPlanarFigureNodes->GetNode().IsNull()) return; m_CurrentFigureNodeInitialized = true; this->Select(m_SelectedPlanarFigureNodes->GetNode()); m_Controls->m_CircleButton->setChecked(false); m_Controls->m_RectangleButton->setChecked(false); m_Controls->m_PolygonButton->setChecked(false); //this->GetActiveStdMultiWidget()->SetWidgetPlanesVisibility(true); this->RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::PlanarFigureFocus(mitk::DataNode* node) { mitk::PlanarFigure* _PlanarFigure = 0; _PlanarFigure = dynamic_cast (node->GetData()); if (_PlanarFigure) { FindRenderWindow(node); const mitk::PlaneGeometry * _PlaneGeometry = dynamic_cast (_PlanarFigure->GetGeometry2D()); // make node visible if (m_SelectedRenderWindow) { mitk::Point3D centerP = _PlaneGeometry->GetOrigin(); m_SelectedRenderWindow->GetSliceNavigationController()->ReorientSlices( centerP, _PlaneGeometry->GetNormal()); m_SelectedRenderWindow->GetSliceNavigationController()->SelectSliceByPoint( centerP); } } } void QmitkPartialVolumeAnalysisView::FindRenderWindow(mitk::DataNode* node) { if (node && dynamic_cast (node->GetData())) { m_SelectedRenderWindow = 0; bool PlanarFigureInitializedWindow = false; - foreach(QmitkRenderWindow * window, this->GetRenderWindowPart()->GetRenderWindows().values()) + foreach(QmitkRenderWindow * window, this->GetRenderWindowPart()->GetQmitkRenderWindows().values()) { if (!m_SelectedRenderWindow && node->GetBoolProperty("PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, window->GetRenderer())) { m_SelectedRenderWindow = window; } } } } void QmitkPartialVolumeAnalysisView::OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &nodes) { if ( !m_Visible ) { return; } if ( nodes.empty() || nodes.size() > 1 ) { // Nothing to do: invalidate image, clear statistics, histogram, and GUI return; } Select(nodes.front()); } void QmitkPartialVolumeAnalysisView::Select( mitk::DataNode::Pointer node, bool clearMaskOnFirstArgNULL, bool clearImageOnFirstArgNULL ) { // Clear any unreferenced images this->RemoveOrphanImages(); bool somethingChanged = false; if(node.IsNull()) { somethingChanged = true; if(clearMaskOnFirstArgNULL) { if ( (m_SelectedImageMask.IsNotNull()) && (m_ImageMaskObserverTag >= 0) ) { m_SelectedImageMask->RemoveObserver( m_ImageMaskObserverTag ); m_ImageMaskObserverTag = -1; } if ( (m_SelectedPlanarFigure.IsNotNull()) && (m_PlanarFigureObserverTag >= 0) ) { m_SelectedPlanarFigure->RemoveObserver( m_PlanarFigureObserverTag ); m_PlanarFigureObserverTag = -1; } if ( (m_SelectedPlanarFigure.IsNotNull()) && (m_InitializedObserverTag >= 0) ) { m_SelectedPlanarFigure->RemoveObserver( m_InitializedObserverTag ); m_InitializedObserverTag = -1; } m_SelectedPlanarFigure = NULL; m_SelectedPlanarFigureNodes->RemoveAllNodes(); m_CurrentFigureNodeInitialized = false; m_SelectedRenderWindow = 0; m_SelectedMaskNode = NULL; m_SelectedImageMask = NULL; } if(clearImageOnFirstArgNULL) { if ( (m_SelectedImage.IsNotNull()) && (m_ImageObserverTag >= 0) ) { m_SelectedImage->RemoveObserver( m_ImageObserverTag ); m_ImageObserverTag = -1; } m_SelectedImageNodes->RemoveAllNodes(); m_SelectedImage = NULL; m_IsTensorImage = false; m_FAImage = NULL; m_RDImage = NULL; m_ADImage = NULL; m_MDImage = NULL; m_CAImage = NULL; m_DirectionComp1Image = NULL; m_DirectionComp2Image = NULL; m_AngularErrorImage = NULL; m_Controls->m_SimilarAnglesFrame->setVisible(false); m_Controls->m_SimilarAnglesLabel->setVisible(false); } } else { typedef itk::SimpleMemberCommand< QmitkPartialVolumeAnalysisView > ITKCommandType; ITKCommandType::Pointer changeListener; changeListener = ITKCommandType::New(); changeListener->SetCallbackFunction( this, &QmitkPartialVolumeAnalysisView::RequestStatisticsUpdate ); // Get selected element mitk::TensorImage *selectedTensorImage = dynamic_cast< mitk::TensorImage * >( node->GetData() ); mitk::Image *selectedImage = dynamic_cast< mitk::Image * >( node->GetData() ); mitk::PlanarFigure *selectedPlanar = dynamic_cast< mitk::PlanarFigure * >( node->GetData() ); bool isMask = false; bool isImage = false; bool isPlanar = false; bool isTensorImage = false; if (selectedTensorImage != NULL) { isTensorImage = true; } else if(selectedImage != NULL) { node->GetPropertyValue("binary", isMask); isImage = !isMask; } else if ( (selectedPlanar != NULL) ) { isPlanar = true; } // image if(isImage && selectedImage->GetDimension()==3) { if(selectedImage != m_SelectedImage.GetPointer()) { somethingChanged = true; if ( (m_SelectedImage.IsNotNull()) && (m_ImageObserverTag >= 0) ) { m_SelectedImage->RemoveObserver( m_ImageObserverTag ); m_ImageObserverTag = -1; } *m_SelectedImageNodes = node; m_SelectedImage = selectedImage; m_IsTensorImage = false; m_FAImage = NULL; m_RDImage = NULL; m_ADImage = NULL; m_MDImage = NULL; m_CAImage = NULL; m_DirectionComp1Image = NULL; m_DirectionComp2Image = NULL; m_AngularErrorImage = NULL; // Add change listeners to selected objects m_ImageObserverTag = m_SelectedImage->AddObserver( itk::ModifiedEvent(), changeListener ); m_Controls->m_SimilarAnglesFrame->setVisible(false); m_Controls->m_SimilarAnglesLabel->setVisible(false); m_Controls->m_SelectedImageLabel->setText( m_SelectedImageNodes->GetNode()->GetName().c_str() ); } } //planar if(isPlanar) { if(selectedPlanar != m_SelectedPlanarFigure.GetPointer()) { MITK_INFO << "Planar selection changed"; somethingChanged = true; // Possibly previous change listeners if ( (m_SelectedPlanarFigure.IsNotNull()) && (m_PlanarFigureObserverTag >= 0) ) { m_SelectedPlanarFigure->RemoveObserver( m_PlanarFigureObserverTag ); m_PlanarFigureObserverTag = -1; } if ( (m_SelectedPlanarFigure.IsNotNull()) && (m_InitializedObserverTag >= 0) ) { m_SelectedPlanarFigure->RemoveObserver( m_InitializedObserverTag ); m_InitializedObserverTag = -1; } m_SelectedPlanarFigure = selectedPlanar; *m_SelectedPlanarFigureNodes = node; m_CurrentFigureNodeInitialized = selectedPlanar->IsPlaced(); m_SelectedMaskNode = NULL; m_SelectedImageMask = NULL; m_PlanarFigureObserverTag = m_SelectedPlanarFigure->AddObserver( mitk::EndInteractionPlanarFigureEvent(), changeListener ); if(!m_CurrentFigureNodeInitialized) { typedef itk::SimpleMemberCommand< QmitkPartialVolumeAnalysisView > ITKCommandType; ITKCommandType::Pointer initializationCommand; initializationCommand = ITKCommandType::New(); // set the callback function of the member command initializationCommand->SetCallbackFunction( this, &QmitkPartialVolumeAnalysisView::PlanarFigureInitialized ); // add an observer m_InitializedObserverTag = selectedPlanar->AddObserver( mitk::EndPlacementPlanarFigureEvent(), initializationCommand ); } m_Controls->m_SelectedMaskLabel->setText( m_SelectedPlanarFigureNodes->GetNode()->GetName().c_str() ); PlanarFigureFocus(node); } } //mask if(isMask && selectedImage->GetDimension()==3) { if(selectedImage != m_SelectedImage.GetPointer()) { somethingChanged = true; if ( (m_SelectedImageMask.IsNotNull()) && (m_ImageMaskObserverTag >= 0) ) { m_SelectedImageMask->RemoveObserver( m_ImageMaskObserverTag ); m_ImageMaskObserverTag = -1; } m_SelectedMaskNode = node; m_SelectedImageMask = selectedImage; m_SelectedPlanarFigure = NULL; m_SelectedPlanarFigureNodes->RemoveAllNodes(); m_ImageMaskObserverTag = m_SelectedImageMask->AddObserver( itk::ModifiedEvent(), changeListener ); m_Controls->m_SelectedMaskLabel->setText( m_SelectedMaskNode->GetName().c_str() ); } } //tensor image if(isTensorImage && selectedTensorImage->GetDimension()==3) { if(selectedImage != m_SelectedImage.GetPointer()) { somethingChanged = true; if ( (m_SelectedImage.IsNotNull()) && (m_ImageObserverTag >= 0) ) { m_SelectedImage->RemoveObserver( m_ImageObserverTag ); m_ImageObserverTag = -1; } *m_SelectedImageNodes = node; m_SelectedImage = selectedImage; m_IsTensorImage = true; ExtractTensorImages(selectedImage); // Add change listeners to selected objects m_ImageObserverTag = m_SelectedImage->AddObserver( itk::ModifiedEvent(), changeListener ); m_Controls->m_SimilarAnglesFrame->setVisible(true); m_Controls->m_SimilarAnglesLabel->setVisible(true); m_Controls->m_SelectedImageLabel->setText( m_SelectedImageNodes->GetNode()->GetName().c_str() ); } } } if(somethingChanged) { this->SetMeasurementInfoToRenderWindow(""); if(m_SelectedPlanarFigure.IsNull() && m_SelectedImageMask.IsNull() ) { m_Controls->m_SelectedMaskLabel->setText( "-" ); m_Controls->m_ResampleOptionsFrame->setEnabled(false); m_Controls->m_HistogramWidget->setEnabled(false); m_Controls->m_ClassSelector->setEnabled(false); m_Controls->m_DisplayHistogramCheckbox->setEnabled(false); m_Controls->m_AdvancedCheckbox->setEnabled(false); m_Controls->frame_7->setEnabled(false); } else { m_Controls->m_ResampleOptionsFrame->setEnabled(true); m_Controls->m_HistogramWidget->setEnabled(true); m_Controls->m_ClassSelector->setEnabled(true); m_Controls->m_DisplayHistogramCheckbox->setEnabled(true); m_Controls->m_AdvancedCheckbox->setEnabled(true); m_Controls->frame_7->setEnabled(true); } // Clear statistics / histogram GUI if nothing is selected if ( m_SelectedImage.IsNull() ) { m_Controls->m_PlanarFigureButtonsFrame->setEnabled(false); m_Controls->m_OpacityFrame->setEnabled(false); m_Controls->m_SelectedImageLabel->setText( "-" ); } else { m_Controls->m_PlanarFigureButtonsFrame->setEnabled(true); m_Controls->m_OpacityFrame->setEnabled(true); } if( m_SelectedImage.IsNull() || (m_SelectedPlanarFigure.IsNull() && m_SelectedImageMask.IsNull()) ) { m_Controls->m_HistogramWidget->ClearItemModel(); m_CurrentStatisticsValid = false; } else { this->RequestStatisticsUpdate(); } } } void QmitkPartialVolumeAnalysisView::ShowClusteringResults() { typedef itk::Image MaskImageType; mitk::Image::Pointer mask = 0; MaskImageType::Pointer itkmask = 0; if(m_IsTensorImage && m_Controls->m_SimilarAnglesSlider->value() != 0) { typedef itk::Image AngularErrorImageType; typedef mitk::ImageToItk CastType; CastType::Pointer caster = CastType::New(); caster->SetInput(m_AngularErrorImage); caster->Update(); typedef itk::BinaryThresholdImageFilter< AngularErrorImageType, MaskImageType > ThreshType; ThreshType::Pointer thresh = ThreshType::New(); thresh->SetUpperThreshold((90-m_Controls->m_SimilarAnglesSlider->value())*(PVA_PI/180.0)); thresh->SetInsideValue(1.0); thresh->SetInput(caster->GetOutput()); thresh->Update(); itkmask = thresh->GetOutput(); mask = mitk::Image::New(); mask->InitializeByItk(itkmask.GetPointer()); mask->SetVolume(itkmask->GetBufferPointer()); // GetDefaultDataStorage()->Remove(m_newnode); // m_newnode = mitk::DataNode::New(); // m_newnode->SetData(mask); // m_newnode->SetName("masking node"); // m_newnode->SetIntProperty( "layer", 1002 ); // GetDefaultDataStorage()->Add(m_newnode, m_SelectedImageNodes->GetNode()); } mitk::Image::Pointer clusteredImage; ClusteringType::Pointer clusterer = ClusteringType::New(); if(m_QuantifyClass==3) { if(m_IsTensorImage) { double *green_fa, *green_rd, *green_ad, *green_md; //double *greengray_fa, *greengray_rd, *greengray_ad, *greengray_md; double *gray_fa, *gray_rd, *gray_ad, *gray_md; //double *redgray_fa, *redgray_rd, *redgray_ad, *redgray_md; double *red_fa, *red_rd, *red_ad, *red_md; mitk::Image* tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(0); mitk::Image::ConstPointer imgToCluster = tmpImg; red_fa = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->r, mask); green_fa = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->g, mask); gray_fa = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->b, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(3); mitk::Image::ConstPointer imgToCluster3 = tmpImg; red_rd = clusterer->PerformQuantification(imgToCluster3, m_CurrentRGBClusteringResults->rgbChannels->r, mask); green_rd = clusterer->PerformQuantification(imgToCluster3, m_CurrentRGBClusteringResults->rgbChannels->g, mask); gray_rd = clusterer->PerformQuantification(imgToCluster3, m_CurrentRGBClusteringResults->rgbChannels->b, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(4); mitk::Image::ConstPointer imgToCluster4 = tmpImg; red_ad = clusterer->PerformQuantification(imgToCluster4, m_CurrentRGBClusteringResults->rgbChannels->r, mask); green_ad = clusterer->PerformQuantification(imgToCluster4, m_CurrentRGBClusteringResults->rgbChannels->g, mask); gray_ad = clusterer->PerformQuantification(imgToCluster4, m_CurrentRGBClusteringResults->rgbChannels->b, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(5); mitk::Image::ConstPointer imgToCluster5 = tmpImg; red_md = clusterer->PerformQuantification(imgToCluster5, m_CurrentRGBClusteringResults->rgbChannels->r, mask); green_md = clusterer->PerformQuantification(imgToCluster5, m_CurrentRGBClusteringResults->rgbChannels->g, mask); gray_md = clusterer->PerformQuantification(imgToCluster5, m_CurrentRGBClusteringResults->rgbChannels->b, mask); // clipboard QString clipboardText("FA\t%1\t%2\t\t%3\t%4\t\t%5\t%6\t"); clipboardText = clipboardText .arg(red_fa[0]).arg(red_fa[1]) .arg(gray_fa[0]).arg(gray_fa[1]) .arg(green_fa[0]).arg(green_fa[1]); QString clipboardText3("RD\t%1\t%2\t\t%3\t%4\t\t%5\t%6\t"); clipboardText3 = clipboardText3 .arg(red_rd[0]).arg(red_rd[1]) .arg(gray_rd[0]).arg(gray_rd[1]) .arg(green_rd[0]).arg(green_rd[1]); QString clipboardText4("AD\t%1\t%2\t\t%3\t%4\t\t%5\t%6\t"); clipboardText4 = clipboardText4 .arg(red_ad[0]).arg(red_ad[1]) .arg(gray_ad[0]).arg(gray_ad[1]) .arg(green_ad[0]).arg(green_ad[1]); QString clipboardText5("MD\t%1\t%2\t\t%3\t%4\t\t%5\t%6"); clipboardText5 = clipboardText5 .arg(red_md[0]).arg(red_md[1]) .arg(gray_md[0]).arg(gray_md[1]) .arg(green_md[0]).arg(green_md[1]); QApplication::clipboard()->setText(clipboardText+clipboardText3+clipboardText4+clipboardText5, QClipboard::Clipboard); // now paint infos also on renderwindow QString plainInfoText("%1 %2 %3 \n"); plainInfoText = plainInfoText .arg("Red ", 20) .arg("Gray ", 20) .arg("Green", 20); QString plainInfoText0("FA:%1 ± %2%3 ± %4%5 ± %6\n"); plainInfoText0 = plainInfoText0 .arg(red_fa[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(red_fa[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(gray_fa[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(gray_fa[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(green_fa[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(green_fa[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText3("RDx10³:%1 ± %2%3 ± %4%5 ± %6\n"); plainInfoText3 = plainInfoText3 .arg(1000.0 * red_rd[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_rd[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * gray_rd[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * gray_rd[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * green_rd[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * green_rd[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText4("ADx10³:%1 ± %2%3 ± %4%5 ± %6\n"); plainInfoText4 = plainInfoText4 .arg(1000.0 * red_ad[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_ad[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * gray_ad[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * gray_ad[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * green_ad[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * green_ad[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText5("MDx10³:%1 ± %2%3 ± %4%5 ± %6"); plainInfoText5 = plainInfoText5 .arg(1000.0 * red_md[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_md[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * gray_md[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * gray_md[1], -10, 'g', 2, QLatin1Char( ' ' )) .arg(1000.0 * green_md[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * green_md[1], -10, 'g', 2, QLatin1Char( ' ' )); this->SetMeasurementInfoToRenderWindow(plainInfoText+plainInfoText0+plainInfoText3+plainInfoText4+plainInfoText5); } else { double* green; double* gray; double* red; mitk::Image* tmpImg = m_CurrentStatisticsCalculator->GetInternalImage(); mitk::Image::ConstPointer imgToCluster = tmpImg; red = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->r); green = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->g); gray = clusterer->PerformQuantification(imgToCluster, m_CurrentRGBClusteringResults->rgbChannels->b); // clipboard QString clipboardText("%1\t%2\t\t%3\t%4\t\t%5\t%6"); clipboardText = clipboardText.arg(red[0]).arg(red[1]) .arg(gray[0]).arg(gray[1]) .arg(green[0]).arg(green[1]); QApplication::clipboard()->setText(clipboardText, QClipboard::Clipboard); // now paint infos also on renderwindow QString plainInfoText("Red: %1 ± %2\nGray: %3 ± %4\nGreen: %5 ± %6"); plainInfoText = plainInfoText.arg(red[0]).arg(red[1]) .arg(gray[0]).arg(gray[1]) .arg(green[0]).arg(green[1]); this->SetMeasurementInfoToRenderWindow(plainInfoText); } clusteredImage = m_CurrentRGBClusteringResults->rgb; } else { if(m_IsTensorImage) { double *red_fa, *red_rd, *red_ad, *red_md; mitk::Image* tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(0); mitk::Image::ConstPointer imgToCluster = tmpImg; red_fa = clusterer->PerformQuantification(imgToCluster, m_CurrentPerformClusteringResults->clusteredImage, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(3); mitk::Image::ConstPointer imgToCluster3 = tmpImg; red_rd = clusterer->PerformQuantification(imgToCluster3, m_CurrentPerformClusteringResults->clusteredImage, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(4); mitk::Image::ConstPointer imgToCluster4 = tmpImg; red_ad = clusterer->PerformQuantification(imgToCluster4, m_CurrentPerformClusteringResults->clusteredImage, mask); tmpImg = m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(5); mitk::Image::ConstPointer imgToCluster5 = tmpImg; red_md = clusterer->PerformQuantification(imgToCluster5, m_CurrentPerformClusteringResults->clusteredImage, mask); // clipboard QString clipboardText("FA\t%1\t%2\t"); clipboardText = clipboardText .arg(red_fa[0]).arg(red_fa[1]); QString clipboardText3("RD\t%1\t%2\t"); clipboardText3 = clipboardText3 .arg(red_rd[0]).arg(red_rd[1]); QString clipboardText4("AD\t%1\t%2\t"); clipboardText4 = clipboardText4 .arg(red_ad[0]).arg(red_ad[1]); QString clipboardText5("MD\t%1\t%2\t"); clipboardText5 = clipboardText5 .arg(red_md[0]).arg(red_md[1]); QApplication::clipboard()->setText(clipboardText+clipboardText3+clipboardText4+clipboardText5, QClipboard::Clipboard); // now paint infos also on renderwindow QString plainInfoText("%1 \n"); plainInfoText = plainInfoText .arg("Red ", 20); QString plainInfoText0("FA:%1 ± %2\n"); plainInfoText0 = plainInfoText0 .arg(red_fa[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(red_fa[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText3("RDx10³:%1 ± %2\n"); plainInfoText3 = plainInfoText3 .arg(1000.0 * red_rd[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_rd[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText4("ADx10³:%1 ± %2\n"); plainInfoText4 = plainInfoText4 .arg(1000.0 * red_ad[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_ad[1], -10, 'g', 2, QLatin1Char( ' ' )); QString plainInfoText5("MDx10³:%1 ± %2"); plainInfoText5 = plainInfoText5 .arg(1000.0 * red_md[0], 10, 'g', 2, QLatin1Char( ' ' )).arg(1000.0 * red_md[1], -10, 'g', 2, QLatin1Char( ' ' )); this->SetMeasurementInfoToRenderWindow(plainInfoText+plainInfoText0+plainInfoText3+plainInfoText4+plainInfoText5); } else { double* quant; mitk::Image* tmpImg = m_CurrentStatisticsCalculator->GetInternalImage(); mitk::Image::ConstPointer imgToCluster = tmpImg; quant = clusterer->PerformQuantification(imgToCluster, m_CurrentPerformClusteringResults->clusteredImage); // clipboard QString clipboardText("%1\t%2"); clipboardText = clipboardText.arg(quant[0]).arg(quant[1]); QApplication::clipboard()->setText(clipboardText, QClipboard::Clipboard); // now paint infos also on renderwindow QString plainInfoText("Measurement: %1 ± %2"); plainInfoText = plainInfoText.arg(quant[0]).arg(quant[1]); this->SetMeasurementInfoToRenderWindow(plainInfoText); } clusteredImage = m_CurrentPerformClusteringResults->displayImage; } if(mask.IsNotNull()) { typedef itk::Image,3> RGBImageType; typedef mitk::ImageToItk ClusterCasterType; ClusterCasterType::Pointer clCaster = ClusterCasterType::New(); clCaster->SetInput(clusteredImage); clCaster->Update(); clCaster->GetOutput(); typedef itk::MaskImageFilter< RGBImageType, MaskImageType, RGBImageType > MaskType; MaskType::Pointer masker = MaskType::New(); masker->SetInput1(clCaster->GetOutput()); masker->SetInput2(itkmask); masker->Update(); clusteredImage = mitk::Image::New(); clusteredImage->InitializeByItk(masker->GetOutput()); clusteredImage->SetVolume(masker->GetOutput()->GetBufferPointer()); } if(m_ClusteringResult.IsNotNull()) { this->GetDataStorage()->Remove(m_ClusteringResult); } m_ClusteringResult = mitk::DataNode::New(); m_ClusteringResult->SetBoolProperty("helper object", true); m_ClusteringResult->SetIntProperty( "layer", 1000 ); m_ClusteringResult->SetBoolProperty("texture interpolation", m_TexIsOn); m_ClusteringResult->SetData(clusteredImage); m_ClusteringResult->SetName("Clusterprobs"); this->GetDataStorage()->Add(m_ClusteringResult, m_SelectedImageNodes->GetNode()); if(m_SelectedPlanarFigure.IsNotNull() && m_SelectedPlanarFigureNodes->GetNode().IsNotNull()) { m_SelectedPlanarFigureNodes->GetNode()->SetIntProperty( "layer", 1001 ); } this->RequestRenderWindowUpdate(); } void QmitkPartialVolumeAnalysisView::UpdateStatistics() { MITK_INFO << "UpdateStatistics()"; if(!m_CurrentFigureNodeInitialized && m_SelectedPlanarFigure.IsNotNull()) { MITK_INFO << "Selected planar figure not initialized. No stats calculation performed."; return; } // Remove any cached images that are no longer referenced elsewhere this->RemoveOrphanImages(); QmitkStdMultiWidget *multiWidget = 0; QmitkStdMultiWidgetEditor * multiWidgetEdit = 0; multiWidgetEdit = dynamic_cast(this->GetRenderWindowPart()); if(multiWidgetEdit){ multiWidget = multiWidgetEdit->GetStdMultiWidget(); } if ( multiWidget == NULL ) { return; } if ( m_SelectedImage.IsNotNull() ) { // Check if a the selected image is a multi-channel image. If yes, statistics // cannot be calculated currently. if ( !m_IsTensorImage && m_SelectedImage->GetPixelType().GetNumberOfComponents() > 1 ) { QMessageBox::information( NULL, "Warning", "Non-tensor multi-component images not supported."); m_Controls->m_HistogramWidget->ClearItemModel(); m_CurrentStatisticsValid = false; return; } // Retrieve HistogramStatisticsCalculator from has map (or create a new one // for this image if non-existant) PartialVolumeAnalysisMapType::iterator it = m_PartialVolumeAnalysisMap.find( m_SelectedImage ); if ( it != m_PartialVolumeAnalysisMap.end() ) { m_CurrentStatisticsCalculator = it->second; MITK_INFO << "Retrieving StatisticsCalculator"; } else { m_CurrentStatisticsCalculator = mitk::PartialVolumeAnalysisHistogramCalculator::New(); m_CurrentStatisticsCalculator->SetPlanarFigureThickness(m_Controls->m_PlanarFiguresThickness->value()); if(m_IsTensorImage) { m_CurrentStatisticsCalculator->SetImage( m_CAImage ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_FAImage ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_DirectionComp1Image ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_DirectionComp2Image ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_RDImage ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_ADImage ); m_CurrentStatisticsCalculator->AddAdditionalResamplingImage( m_MDImage ); } else { m_CurrentStatisticsCalculator->SetImage( m_SelectedImage ); } m_PartialVolumeAnalysisMap[m_SelectedImage] = m_CurrentStatisticsCalculator; MITK_INFO << "Creating StatisticsCalculator"; } std::string maskName; std::string maskType; unsigned int maskDimension; if ( m_SelectedImageMask.IsNotNull() ) { mitk::PixelType pixelType = m_SelectedImageMask->GetPixelType(); std::cout << pixelType.GetItkTypeAsString() << std::endl; if(pixelType.GetBitsPerComponent() == 16) { //convert from short to uchar typedef itk::Image ShortImageType; typedef itk::Image CharImageType; CharImageType::Pointer charImage; ShortImageType::Pointer shortImage; mitk::CastToItkImage(m_SelectedImageMask, shortImage); typedef itk::CastImageFilter ImageCasterType; ImageCasterType::Pointer caster = ImageCasterType::New(); caster->SetInput( shortImage ); caster->Update(); charImage = caster->GetOutput(); mitk::CastToMitkImage(charImage, m_SelectedImageMask); } m_CurrentStatisticsCalculator->SetImageMask( m_SelectedImageMask ); m_CurrentStatisticsCalculator->SetMaskingModeToImage(); maskName = m_SelectedMaskNode->GetName(); maskType = m_SelectedImageMask->GetNameOfClass(); maskDimension = 3; std::stringstream maskLabel; maskLabel << maskName; if ( maskDimension > 0 ) { maskLabel << " [" << maskDimension << "D " << maskType << "]"; } m_Controls->m_SelectedMaskLabel->setText( maskLabel.str().c_str() ); } else if ( m_SelectedPlanarFigure.IsNotNull() && m_SelectedPlanarFigureNodes->GetNode().IsNotNull()) { m_CurrentStatisticsCalculator->SetPlanarFigure( m_SelectedPlanarFigure ); m_CurrentStatisticsCalculator->SetMaskingModeToPlanarFigure(); maskName = m_SelectedPlanarFigureNodes->GetNode()->GetName(); maskType = m_SelectedPlanarFigure->GetNameOfClass(); maskDimension = 2; } else { m_CurrentStatisticsCalculator->SetMaskingModeToNone(); maskName = "-"; maskType = ""; maskDimension = 0; } bool statisticsChanged = false; bool statisticsCalculationSuccessful = false; // Initialize progress bar mitk::ProgressBar::GetInstance()->AddStepsToDo( 100 ); // Install listener for progress events and initialize progress bar typedef itk::SimpleMemberCommand< QmitkPartialVolumeAnalysisView > ITKCommandType; ITKCommandType::Pointer progressListener; progressListener = ITKCommandType::New(); progressListener->SetCallbackFunction( this, &QmitkPartialVolumeAnalysisView::UpdateProgressBar ); unsigned long progressObserverTag = m_CurrentStatisticsCalculator ->AddObserver( itk::ProgressEvent(), progressListener ); ClusteringType::ParamsType *cparams = 0; ClusteringType::ClusterResultType *cresult = 0; ClusteringType::HistType *chist = 0; try { m_CurrentStatisticsCalculator->SetNumberOfBins(m_Controls->m_NumberBins->text().toInt()); m_CurrentStatisticsCalculator->SetUpsamplingFactor(m_Controls->m_Upsampling->text().toDouble()); m_CurrentStatisticsCalculator->SetGaussianSigma(m_Controls->m_GaussianSigma->text().toDouble()); // Compute statistics statisticsChanged = m_CurrentStatisticsCalculator->ComputeStatistics( ); mitk::Image* tmpImg = m_CurrentStatisticsCalculator->GetInternalImage(); mitk::Image::ConstPointer imgToCluster = tmpImg; if(imgToCluster.IsNotNull()) { // perform clustering const HistogramType *histogram = m_CurrentStatisticsCalculator->GetHistogram( ); if(histogram != NULL) { ClusteringType::Pointer clusterer = ClusteringType::New(); clusterer->SetStepsNumIntegration(200); clusterer->SetMaxIt(1000); mitk::Image::Pointer pFiberImg; if(m_QuantifyClass==3) { if(m_Controls->m_Quantiles->isChecked()) { m_CurrentRGBClusteringResults = clusterer->PerformRGBQuantiles(imgToCluster, histogram, m_Controls->m_q1->value(),m_Controls->m_q2->value()); } else { m_CurrentRGBClusteringResults = clusterer->PerformRGBClustering(imgToCluster, histogram); } pFiberImg = m_CurrentRGBClusteringResults->rgbChannels->r; cparams = m_CurrentRGBClusteringResults->params; cresult = m_CurrentRGBClusteringResults->result; chist = m_CurrentRGBClusteringResults->hist; } else { if(m_Controls->m_Quantiles->isChecked()) { m_CurrentPerformClusteringResults = clusterer->PerformQuantiles(imgToCluster, histogram, m_Controls->m_q1->value(),m_Controls->m_q2->value()); } else { m_CurrentPerformClusteringResults = clusterer->PerformClustering(imgToCluster, histogram, m_QuantifyClass); } pFiberImg = m_CurrentPerformClusteringResults->clusteredImage; cparams = m_CurrentPerformClusteringResults->params; cresult = m_CurrentPerformClusteringResults->result; chist = m_CurrentPerformClusteringResults->hist; } if(m_IsTensorImage) { m_AngularErrorImage = clusterer->CaculateAngularErrorImage( m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(1), m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(2), pFiberImg); // GetDefaultDataStorage()->Remove(m_newnode2); // m_newnode2 = mitk::DataNode::New(); // m_newnode2->SetData(m_AngularErrorImage); // m_newnode2->SetName(("AngularError")); // m_newnode2->SetIntProperty( "layer", 1003 ); // GetDefaultDataStorage()->Add(m_newnode2, m_SelectedImageNodes->GetNode()); // newnode = mitk::DataNode::New(); // newnode->SetData(m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(1)); // newnode->SetName(("Comp1")); // GetDefaultDataStorage()->Add(newnode, m_SelectedImageNodes->GetNode()); // newnode = mitk::DataNode::New(); // newnode->SetData(m_CurrentStatisticsCalculator->GetInternalAdditionalResampledImage(2)); // newnode->SetName(("Comp2")); // GetDefaultDataStorage()->Add(newnode, m_SelectedImageNodes->GetNode()); } ShowClusteringResults(); } } statisticsCalculationSuccessful = true; } catch ( const std::runtime_error &e ) { QMessageBox::information( NULL, "Warning", e.what()); } catch ( const std::exception &e ) { MITK_ERROR << "Caught exception: " << e.what(); QMessageBox::information( NULL, "Warning", e.what()); } m_CurrentStatisticsCalculator->RemoveObserver( progressObserverTag ); // Make sure that progress bar closes mitk::ProgressBar::GetInstance()->Progress( 100 ); if ( statisticsCalculationSuccessful ) { if ( statisticsChanged ) { // Do not show any error messages m_CurrentStatisticsValid = true; } // m_Controls->m_HistogramWidget->SetHistogramModeToDirectHistogram(); m_Controls->m_HistogramWidget->SetParameters( cparams, cresult, chist ); // m_Controls->m_HistogramWidget->UpdateItemModelFromHistogram(); } else { m_Controls->m_SelectedMaskLabel->setText( "-" ); // Clear statistics and histogram m_Controls->m_HistogramWidget->ClearItemModel(); m_CurrentStatisticsValid = false; // If a (non-closed) PlanarFigure is selected, display a line profile widget if ( m_SelectedPlanarFigure.IsNotNull() ) { // TODO: enable line profile widget //m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 1 ); //m_Controls->m_LineProfileWidget->SetImage( m_SelectedImage ); //m_Controls->m_LineProfileWidget->SetPlanarFigure( m_SelectedPlanarFigure ); //m_Controls->m_LineProfileWidget->UpdateItemModelFromPath(); } } } } void QmitkPartialVolumeAnalysisView::SetMeasurementInfoToRenderWindow(const QString& text) { FindRenderWindow(m_SelectedPlanarFigureNodes->GetNode()); if(m_LastRenderWindow != m_SelectedRenderWindow) { if(m_LastRenderWindow) { QObject::disconnect( m_LastRenderWindow, SIGNAL( destroyed(QObject*) ) , this, SLOT( OnRenderWindowDelete(QObject*) ) ); } m_LastRenderWindow = m_SelectedRenderWindow; if(m_LastRenderWindow) { QObject::connect( m_LastRenderWindow, SIGNAL( destroyed(QObject*) ) , this, SLOT( OnRenderWindowDelete(QObject*) ) ); } } if(m_LastRenderWindow && m_SelectedPlanarFigureNodes->GetNode().IsNotNull()) { if (!text.isEmpty()) { m_MeasurementInfoAnnotation->SetText(1, text.toLatin1().data()); mitk::VtkLayerController::GetInstance(m_LastRenderWindow->GetRenderWindow())->InsertForegroundRenderer( m_MeasurementInfoRenderer, true); } else { if (mitk::VtkLayerController::GetInstance( m_LastRenderWindow->GetRenderWindow()) ->IsRendererInserted( m_MeasurementInfoRenderer)) mitk::VtkLayerController::GetInstance(m_LastRenderWindow->GetRenderWindow())->RemoveRenderer( m_MeasurementInfoRenderer); } } else { QmitkStdMultiWidget *multiWidget = 0; QmitkStdMultiWidgetEditor * multiWidgetEdit = 0; multiWidgetEdit = dynamic_cast(this->GetRenderWindowPart()); if(multiWidgetEdit){ multiWidget = multiWidgetEdit->GetStdMultiWidget(); } if ( multiWidget == NULL ) { return; } if (!text.isEmpty()) { m_MeasurementInfoAnnotation->SetText(1, text.toLatin1().data()); mitk::VtkLayerController::GetInstance(multiWidget->GetRenderWindow1()->GetRenderWindow())->InsertForegroundRenderer( m_MeasurementInfoRenderer, true); } else { if (mitk::VtkLayerController::GetInstance( multiWidget->GetRenderWindow1()->GetRenderWindow()) ->IsRendererInserted( m_MeasurementInfoRenderer)) mitk::VtkLayerController::GetInstance(multiWidget->GetRenderWindow1()->GetRenderWindow())->RemoveRenderer( m_MeasurementInfoRenderer); } } } void QmitkPartialVolumeAnalysisView::UpdateProgressBar() { mitk::ProgressBar::GetInstance()->Progress(); } void QmitkPartialVolumeAnalysisView::RequestStatisticsUpdate() { if ( !m_StatisticsUpdatePending ) { QApplication::postEvent( this, new QmitkRequestStatisticsUpdateEvent ); m_StatisticsUpdatePending = true; } } void QmitkPartialVolumeAnalysisView::RemoveOrphanImages() { PartialVolumeAnalysisMapType::iterator it = m_PartialVolumeAnalysisMap.begin(); while ( it != m_PartialVolumeAnalysisMap.end() ) { mitk::Image *image = it->first; mitk::PartialVolumeAnalysisHistogramCalculator *calculator = it->second; ++it; mitk::NodePredicateData::Pointer hasImage = mitk::NodePredicateData::New( image ); if ( this->GetDataStorage()->GetNode( hasImage ) == NULL ) { if ( m_SelectedImage == image ) { m_SelectedImage = NULL; m_SelectedImageNodes->RemoveAllNodes(); } if ( m_CurrentStatisticsCalculator == calculator ) { m_CurrentStatisticsCalculator = NULL; } m_PartialVolumeAnalysisMap.erase( image ); it = m_PartialVolumeAnalysisMap.begin(); } } } void QmitkPartialVolumeAnalysisView::ExtractTensorImages( mitk::Image::ConstPointer tensorimage) { typedef itk::Image< itk::DiffusionTensor3D, 3> TensorImageType; typedef mitk::ImageToItk CastType; CastType::Pointer caster = CastType::New(); caster->SetInput(tensorimage); caster->Update(); TensorImageType::Pointer image = caster->GetOutput(); typedef itk::TensorDerivedMeasurementsFilter MeasurementsType; MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(image ); measurementsCalculator->SetMeasure(MeasurementsType::FA); measurementsCalculator->Update(); MeasurementsType::OutputImageType::Pointer fa = measurementsCalculator->GetOutput(); m_FAImage = mitk::Image::New(); m_FAImage->InitializeByItk(fa.GetPointer()); m_FAImage->SetVolume(fa->GetBufferPointer()); // mitk::DataNode::Pointer node = mitk::DataNode::New(); // node->SetData(m_FAImage); // GetDefaultDataStorage()->Add(node); measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(image ); measurementsCalculator->SetMeasure(MeasurementsType::CA); measurementsCalculator->Update(); MeasurementsType::OutputImageType::Pointer ca = measurementsCalculator->GetOutput(); m_CAImage = mitk::Image::New(); m_CAImage->InitializeByItk(ca.GetPointer()); m_CAImage->SetVolume(ca->GetBufferPointer()); // node = mitk::DataNode::New(); // node->SetData(m_CAImage); // GetDefaultDataStorage()->Add(node); measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(image ); measurementsCalculator->SetMeasure(MeasurementsType::RD); measurementsCalculator->Update(); MeasurementsType::OutputImageType::Pointer rd = measurementsCalculator->GetOutput(); m_RDImage = mitk::Image::New(); m_RDImage->InitializeByItk(rd.GetPointer()); m_RDImage->SetVolume(rd->GetBufferPointer()); // node = mitk::DataNode::New(); // node->SetData(m_CAImage); // GetDefaultDataStorage()->Add(node); measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(image ); measurementsCalculator->SetMeasure(MeasurementsType::AD); measurementsCalculator->Update(); MeasurementsType::OutputImageType::Pointer ad = measurementsCalculator->GetOutput(); m_ADImage = mitk::Image::New(); m_ADImage->InitializeByItk(ad.GetPointer()); m_ADImage->SetVolume(ad->GetBufferPointer()); // node = mitk::DataNode::New(); // node->SetData(m_CAImage); // GetDefaultDataStorage()->Add(node); measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(image ); measurementsCalculator->SetMeasure(MeasurementsType::RA); measurementsCalculator->Update(); MeasurementsType::OutputImageType::Pointer md = measurementsCalculator->GetOutput(); m_MDImage = mitk::Image::New(); m_MDImage->InitializeByItk(md.GetPointer()); m_MDImage->SetVolume(md->GetBufferPointer()); // node = mitk::DataNode::New(); // node->SetData(m_CAImage); // GetDefaultDataStorage()->Add(node); typedef DirectionsFilterType::OutputImageType DirImageType; DirectionsFilterType::Pointer dirFilter = DirectionsFilterType::New(); dirFilter->SetInput(image ); dirFilter->Update(); itk::ImageRegionIterator itd(dirFilter->GetOutput(), dirFilter->GetOutput()->GetLargestPossibleRegion()); itd = itd.Begin(); while( !itd.IsAtEnd() ) { DirImageType::PixelType direction = itd.Get(); direction[0] = fabs(direction[0]); direction[1] = fabs(direction[1]); direction[2] = fabs(direction[2]); itd.Set(direction); ++itd; } typedef itk::CartesianToPolarVectorImageFilter< DirImageType, DirImageType, true> C2PFilterType; C2PFilterType::Pointer cpFilter = C2PFilterType::New(); cpFilter->SetInput(dirFilter->GetOutput()); cpFilter->Update(); DirImageType::Pointer dir = cpFilter->GetOutput(); typedef itk::Image CompImageType; CompImageType::Pointer comp1 = CompImageType::New(); comp1->SetSpacing( dir->GetSpacing() ); // Set the image spacing comp1->SetOrigin( dir->GetOrigin() ); // Set the image origin comp1->SetDirection( dir->GetDirection() ); // Set the image direction comp1->SetRegions( dir->GetLargestPossibleRegion() ); comp1->Allocate(); CompImageType::Pointer comp2 = CompImageType::New(); comp2->SetSpacing( dir->GetSpacing() ); // Set the image spacing comp2->SetOrigin( dir->GetOrigin() ); // Set the image origin comp2->SetDirection( dir->GetDirection() ); // Set the image direction comp2->SetRegions( dir->GetLargestPossibleRegion() ); comp2->Allocate(); itk::ImageRegionConstIterator it(dir, dir->GetLargestPossibleRegion()); itk::ImageRegionIterator it1(comp1, comp1->GetLargestPossibleRegion()); itk::ImageRegionIterator it2(comp2, comp2->GetLargestPossibleRegion()); it = it.Begin(); it1 = it1.Begin(); it2 = it2.Begin(); while( !it.IsAtEnd() ) { it1.Set(it.Get()[1]); it2.Set(it.Get()[2]); ++it; ++it1; ++it2; } m_DirectionComp1Image = mitk::Image::New(); m_DirectionComp1Image->InitializeByItk(comp1.GetPointer()); m_DirectionComp1Image->SetVolume(comp1->GetBufferPointer()); m_DirectionComp2Image = mitk::Image::New(); m_DirectionComp2Image->InitializeByItk(comp2.GetPointer()); m_DirectionComp2Image->SetVolume(comp2->GetBufferPointer()); } void QmitkPartialVolumeAnalysisView::OnRenderWindowDelete(QObject * obj) { if(obj == m_LastRenderWindow) m_LastRenderWindow = 0; if(obj == m_SelectedRenderWindow) m_SelectedRenderWindow = 0; } bool QmitkPartialVolumeAnalysisView::event( QEvent *event ) { if ( event->type() == (QEvent::Type) QmitkRequestStatisticsUpdateEvent::StatisticsUpdateRequest ) { // Update statistics m_StatisticsUpdatePending = false; this->UpdateStatistics(); return true; } return false; } bool QmitkPartialVolumeAnalysisView::IsExclusiveFunctionality() const { return true; } void QmitkPartialVolumeAnalysisView::Activated() { MITK_INFO << "QmitkPartialVolumeAnalysisView:Activated"; //this->GetActiveStdMultiWidget()->SetWidgetPlanesVisibility(false); //this->GetActiveStdMultiWidget()->GetRenderWindow1()->FullScreenMode(true); mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDataStorage()->GetAll(); mitk::DataNode* node = 0; mitk::PlanarFigure* figure = 0; mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; // finally add all nodes to the model for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() ; it++) { node = const_cast(it->Value().GetPointer()); figure = dynamic_cast(node->GetData()); if(figure) { figureInteractor = dynamic_cast(node->GetInteractor()); if(figureInteractor.IsNull()) figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", node); mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); } } m_Visible = true; } void QmitkPartialVolumeAnalysisView::Deactivated() { MITK_INFO << "QmitkPartialVolumeAnalysisView:Deactivated"; } void QmitkPartialVolumeAnalysisView::ActivatedZombieView(berry::IWorkbenchPartReference::Pointer reference) { MITK_INFO << "QmitkPartialVolumeAnalysisView:ActivatedZombieView"; //this->GetActiveStdMultiWidget()->SetWidgetPlanesVisibility(true); this->SetMeasurementInfoToRenderWindow(""); mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDataStorage()->GetAll(); mitk::DataNode* node = 0; mitk::PlanarFigure* figure = 0; mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; // finally add all nodes to the model for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() ; it++) { node = const_cast(it->Value().GetPointer()); figure = dynamic_cast(node->GetData()); if(figure) { figureInteractor = dynamic_cast(node->GetInteractor()); if(figureInteractor) mitk::GlobalInteraction::GetInstance()->RemoveInteractor(figureInteractor); } } m_Visible = false; } void QmitkPartialVolumeAnalysisView::Hidden() { } void QmitkPartialVolumeAnalysisView::Visible() { //this->OnSelectionChanged( this->Get, this->GetDataManagerSelection() ); } void QmitkPartialVolumeAnalysisView::SetFocus() { } void QmitkPartialVolumeAnalysisView::GreenRadio(bool checked) { if(checked) { m_Controls->m_PartialVolumeRadio->setChecked(false); m_Controls->m_BlueRadio->setChecked(false); m_Controls->m_AllRadio->setChecked(false); m_Controls->m_ExportClusteringResultsButton->setEnabled(true); } m_QuantifyClass = 0; RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::PartialVolumeRadio(bool checked) { if(checked) { m_Controls->m_GreenRadio->setChecked(false); m_Controls->m_BlueRadio->setChecked(false); m_Controls->m_AllRadio->setChecked(false); m_Controls->m_ExportClusteringResultsButton->setEnabled(true); } m_QuantifyClass = 1; RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::BlueRadio(bool checked) { if(checked) { m_Controls->m_PartialVolumeRadio->setChecked(false); m_Controls->m_GreenRadio->setChecked(false); m_Controls->m_AllRadio->setChecked(false); m_Controls->m_ExportClusteringResultsButton->setEnabled(true); } m_QuantifyClass = 2; RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::AllRadio(bool checked) { if(checked) { m_Controls->m_BlueRadio->setChecked(false); m_Controls->m_PartialVolumeRadio->setChecked(false); m_Controls->m_GreenRadio->setChecked(false); m_Controls->m_ExportClusteringResultsButton->setEnabled(false); } m_QuantifyClass = 3; RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::NumberBinsChangedSlider(int v ) { m_Controls->m_NumberBins->setText(QString("%1").arg(m_Controls->m_NumberBinsSlider->value()*5.0)); } void QmitkPartialVolumeAnalysisView::UpsamplingChangedSlider( int v) { m_Controls->m_Upsampling->setText(QString("%1").arg(m_Controls->m_UpsamplingSlider->value()/10.0)); } void QmitkPartialVolumeAnalysisView::GaussianSigmaChangedSlider(int v ) { m_Controls->m_GaussianSigma->setText(QString("%1").arg(m_Controls->m_GaussianSigmaSlider->value()/100.0)); } void QmitkPartialVolumeAnalysisView::SimilarAnglesChangedSlider(int v ) { m_Controls->m_SimilarAngles->setText(QString("%1°").arg(90-m_Controls->m_SimilarAnglesSlider->value())); ShowClusteringResults(); } void QmitkPartialVolumeAnalysisView::OpacityChangedSlider(int v ) { if(m_SelectedImageNodes->GetNode().IsNotNull()) { float opacImag = 1.0f-(v-5)/5.0f; opacImag = opacImag < 0 ? 0 : opacImag; m_SelectedImageNodes->GetNode()->SetFloatProperty("opacity", opacImag); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } if(m_ClusteringResult.IsNotNull()) { float opacClust = v/5.0f; opacClust = opacClust > 1 ? 1 : opacClust; m_ClusteringResult->SetFloatProperty("opacity", opacClust); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkPartialVolumeAnalysisView::NumberBinsReleasedSlider( ) { RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::UpsamplingReleasedSlider( ) { RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::GaussianSigmaReleasedSlider( ) { RequestStatisticsUpdate(); } void QmitkPartialVolumeAnalysisView::SimilarAnglesReleasedSlider( ) { } void QmitkPartialVolumeAnalysisView::ToClipBoard() { std::vector* > vals = m_Controls->m_HistogramWidget->m_Vals; QString clipboardText; for (std::vector* >::iterator it = vals.begin(); it != vals.end(); ++it) { for (std::vector::iterator it2 = (**it).begin(); it2 != (**it).end(); ++it2) { clipboardText.append(QString("%1 \t").arg(*it2)); } clipboardText.append(QString("\n")); } QApplication::clipboard()->setText(clipboardText, QClipboard::Clipboard); } void QmitkPartialVolumeAnalysisView::PropertyChanged(const mitk::DataNode* /*node*/, const mitk::BaseProperty* /*prop*/) { } void QmitkPartialVolumeAnalysisView::NodeChanged(const mitk::DataNode* /*node*/) { } void QmitkPartialVolumeAnalysisView::NodeRemoved(const mitk::DataNode* node) { if (dynamic_cast(node->GetData())) this->GetDataStorage()->Remove(m_ClusteringResult); if( node == m_SelectedPlanarFigureNodes->GetNode().GetPointer() || node == m_SelectedMaskNode.GetPointer() ) { this->Select(NULL,true,false); SetMeasurementInfoToRenderWindow(""); } if( node == m_SelectedImageNodes->GetNode().GetPointer() ) { this->Select(NULL,false,true); SetMeasurementInfoToRenderWindow(""); } } void QmitkPartialVolumeAnalysisView::NodeAddedInDataStorage(const mitk::DataNode* node) { if(!m_Visible) return; mitk::DataNode* nonConstNode = const_cast(node); mitk::PlanarFigure* figure = dynamic_cast(nonConstNode->GetData()); if(figure) { // set interactor for new node (if not already set) mitk::PlanarFigureInteractor::Pointer figureInteractor = dynamic_cast(node->GetInteractor()); if(figureInteractor.IsNull()) figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", nonConstNode); mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); // remove uninitialized old planars if( m_SelectedPlanarFigureNodes->GetNode().IsNotNull() && m_CurrentFigureNodeInitialized == false ) { mitk::Interactor::Pointer oldInteractor = m_SelectedPlanarFigureNodes->GetNode()->GetInteractor(); if(oldInteractor.IsNotNull()) mitk::GlobalInteraction::GetInstance()->RemoveInteractor(oldInteractor); this->GetDataStorage()->Remove(m_SelectedPlanarFigureNodes->GetNode()); } } } void QmitkPartialVolumeAnalysisView::TextIntON() { if(m_ClusteringResult.IsNotNull()) { if(m_TexIsOn) { m_Controls->m_TextureIntON->setIcon(*m_IconTexOFF); } else { m_Controls->m_TextureIntON->setIcon(*m_IconTexON); } m_ClusteringResult->SetBoolProperty("texture interpolation", !m_TexIsOn); m_TexIsOn = !m_TexIsOn; this->RequestRenderWindowUpdate(); } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimagingapp/documentation/UserManual/QmitkDiffusionImagingAppUserManual.dox b/Plugins/org.mitk.gui.qt.diffusionimagingapp/documentation/UserManual/QmitkDiffusionImagingAppUserManual.dox index d08667e22f..9f679c8296 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimagingapp/documentation/UserManual/QmitkDiffusionImagingAppUserManual.dox +++ b/Plugins/org.mitk.gui.qt.diffusionimagingapp/documentation/UserManual/QmitkDiffusionImagingAppUserManual.dox @@ -1,12 +1,10 @@ /** -\bundlemainpage{org_diffusionapplication} Using The Diffusion Imaging Application +\page org_mitk_gui_qt_diffusionimagingapp Using The Diffusion Imaging Application \section QMitkDiffusionApplicationManualOverview What is the Diffusion Imaging Application The Diffusion Imaging Application contains selected views for the analysis of images of the human brain. These encompass the views developed by the Neuroimaging Group of the Division Medical and Biological Informatics as well as basic image processing views such as segmentation and volumevisualization. -\isHtml For a basic guide to MITK see \ref MITKUserManualPage . -\isHtmlend */ diff --git a/Plugins/org.mitk.gui.qt.dtiatlasapp/documentation/UserManual/QmitkDTIAtlasAppUserManual.dox b/Plugins/org.mitk.gui.qt.dtiatlasapp/documentation/UserManual/QmitkDTIAtlasAppUserManual.dox index 487a8af86b..28b4536cc5 100644 --- a/Plugins/org.mitk.gui.qt.dtiatlasapp/documentation/UserManual/QmitkDTIAtlasAppUserManual.dox +++ b/Plugins/org.mitk.gui.qt.dtiatlasapp/documentation/UserManual/QmitkDTIAtlasAppUserManual.dox @@ -1,12 +1,10 @@ /** -\bundlemainpage{org_dti_atlas_application} Using The DTI Atlas Application +\page org_dti_atlas_application Using The DTI Atlas Application \section QMitkDTIAtlasApplicationManualOverview What is the DTI Atlas Application The DTI Atlas Application is a viewer for MR, diffusion tensor and fibre images and contains no additional functionality. The welcome page allows the selection of which example data to examine. -\isHtml For a basic guide to MITK see \ref MITKUserManualPage . -\isHtmlend */ diff --git a/Plugins/org.mitk.gui.qt.examples/documentation/Manual/MITKExamples.dox b/Plugins/org.mitk.gui.qt.examples/documentation/Manual/MITKExamples.dox index 537b98603f..bf7631f9a6 100644 --- a/Plugins/org.mitk.gui.qt.examples/documentation/Manual/MITKExamples.dox +++ b/Plugins/org.mitk.gui.qt.examples/documentation/Manual/MITKExamples.dox @@ -1,18 +1,18 @@ /** -\bundlemainpage{org_mitkexamples} Examples for the use of MITK +\page org_mitk_gui_qt_examples Examples for the use of MITK \section QmitkExamplesUserManualSummary Summary This module is a collection of examples for developing with mitk. The following examples are included:
    -
  • \subpage org_simpleexample -
  • \subpage org_simplemeasurement -
  • \subpage org_regiongrowing -
  • \subpage org_isosurface -
  • \subpage org_colourimageprocessing -
  • \subpage org_viewinitialitzation +
  • \subpage org_mitk_views_simpleexample +
  • \subpage org_mitk_views_simplemeasurement +
  • \subpage org_mitk_views_regiongrowing +
  • \subpage org_mitk_views_isosurface +
  • \subpage org_mitk_views_colourimageprocessing +
  • \subpage org_mitk_views_viewinitialitzation
  • The Volumetry Module
*/ diff --git a/Plugins/org.mitk.gui.qt.examples/documentation/Manual/QmitkColourImageProcessing.dox b/Plugins/org.mitk.gui.qt.examples/documentation/Manual/QmitkColourImageProcessing.dox index 4ba970890f..dea970f477 100644 --- a/Plugins/org.mitk.gui.qt.examples/documentation/Manual/QmitkColourImageProcessing.dox +++ b/Plugins/org.mitk.gui.qt.examples/documentation/Manual/QmitkColourImageProcessing.dox @@ -1,34 +1,34 @@ /** -\page org_colourimageprocessing The Colour Image Processing Module +\page org_mitk_views_colourimageprocessing The Colour Image Processing Module \image html ColorImageProcessing.png "Icon of the Module" \section QmitkColourImageProcessingUserManualSummary Summary This module allows the user to create coloured images from medical images. Generally, these coloured images would be used in presentations, research papers, or as a teaching aide. \section QmitkColourImageProcessingUserManualOverview Overview The purpose of this module is to create coloured images, which can then be later used in presentations, research papers, or anything else the user desires. Furthermore, different body sections can be assigned a different colour. These images are not particularly useful for further image processing, but provide nice, clear, diagrams. Please note that ultrasound images cannot be coloured. \section QmitkColourImageProcessingUserManualFilters Creating Coloured Images Open an image in mitk, then click on the colour wheel button. Make sure the image you loaded is selected.

\ Image -> RGBAimage

Clicking on this button creates an RGBA image from your medical image, which should appear in your data manager.

\ Image + mask -> RGBAimage

Before clicking on this button, a mask is needed. A mask is generally created using the segmentation tool. Make sure both the mask and image are selected, then click on the image + mask -> RGBA image button. This creates an RGBA image that is coloured only in section defined by the mask.

\ Image + mask + color-> RGBAimage

This functions the same way as the Image + mask -> RGBAimage. The difference is that the user can select the colour of the section represented by the mask. This is done by clicking on the colour next to the Image + mask + color-> RGBAimage button If multiple RGBA images are created with different colours, they can be combined into one image. Ensure that the desired coloured images are selected, then click on the combine RGBA images button. */ diff --git a/Plugins/org.mitk.gui.qt.examples/documentation/Manual/QmitkIsoSurfaceUserManual.dox b/Plugins/org.mitk.gui.qt.examples/documentation/Manual/QmitkIsoSurfaceUserManual.dox index 214e858245..1e8bb8c1f5 100644 --- a/Plugins/org.mitk.gui.qt.examples/documentation/Manual/QmitkIsoSurfaceUserManual.dox +++ b/Plugins/org.mitk.gui.qt.examples/documentation/Manual/QmitkIsoSurfaceUserManual.dox @@ -1,37 +1,37 @@ /** -\page org_isosurface The Iso Surface Module +\page org_mitk_views_isosurface The Iso Surface Module \image html IsoSurfaceIcon.png "Icon of the Module" Available sections: - \ref QmitkIsoSurfaceUserManualOverview - \ref QmitkIsoSurfaceUserManualFeatures - \ref QmitkIsoSurfaceUserManualUsage - \ref QmitkIsoSurfaceUserManualTroubleshooting \section QmitkIsoSurfaceUserManualOverview Overview IsoSurface is a program module for creating surfaces (e.g. polygon structures) out of images. The user defines a threshold that seperates object and background inside the image. Pixels that belong to the object need grey values below the threshold. Pixles with grey values above the threshold will be ignored. The result is a polygon object that can be saved as an *.stl-object. \section QmitkIsoSurfaceUserManualFeatures Features - Creates a surface by thresholding an image \section QmitkIsoSurfaceUserManualUsage Usage How to create a surface: - Load an image into the program, for example by drag & drop - Look for a meaningful threshold. All pixel grey values of the image that are lower than the threshold will be used to create the surface. All grey values that are higher than the surface will be ignored. You can find the best threshold by using the Volumetry-Functionality or by reading the grey value while clicking on a pixel (see picture 2). - Insert the threshold into the GUI - Press the Button "Create Surface" \image html IsoSurfaceGUI.png "Graphical User Interface of Iso Surface" \section QmitkIsoSurfaceUserManualTroubleshooting Troubleshooting */ diff --git a/Plugins/org.mitk.gui.qt.examples/documentation/Manual/QmitkRegionGrowingUserManual.dox b/Plugins/org.mitk.gui.qt.examples/documentation/Manual/QmitkRegionGrowingUserManual.dox index 81c517db55..97360b23ea 100644 --- a/Plugins/org.mitk.gui.qt.examples/documentation/Manual/QmitkRegionGrowingUserManual.dox +++ b/Plugins/org.mitk.gui.qt.examples/documentation/Manual/QmitkRegionGrowingUserManual.dox @@ -1,29 +1,29 @@ /** -\page org_regiongrowing The Region Growing Module +\page org_mitk_views_regiongrowing The Region Growing Module \image html regiongrowing.png "Icon of the Module" Available documentation sections: - \ref QmitkRegionGrowingUserManualOverview - \ref QmitkRegionGrowingUserManualUsage \section QmitkRegionGrowingUserManualOverview Overview The Region growing module provides a programming example, showing developers how to create new bundles for MITK with a graphical user interface (GUI) that also uses some ITK image filters. For the programmers: this functionality is the result of tutorial step 9 \section QmitkRegionGrowingUserManualUsage Usage
  • you can set a number of seed points by clicking into the render windows while holding down the shift key.
  • when clicking "Start region growing", a region growing algorithm starts. This algorithm is gray values based. The gray values are determined from the gray values at all point positions plus/minus a safety margin of 30 (Hounsfield units).
*/ diff --git a/Plugins/org.mitk.gui.qt.examples/documentation/Manual/QmitkSimpleExampleUserManual.dox b/Plugins/org.mitk.gui.qt.examples/documentation/Manual/QmitkSimpleExampleUserManual.dox index 26a06b496b..12df11bc6d 100644 --- a/Plugins/org.mitk.gui.qt.examples/documentation/Manual/QmitkSimpleExampleUserManual.dox +++ b/Plugins/org.mitk.gui.qt.examples/documentation/Manual/QmitkSimpleExampleUserManual.dox @@ -1,21 +1,21 @@ /** -\page org_simpleexample The Simple Example module +\page org_mitk_views_simpleexample The Simple Example module \image html SimpleExample.png "Icon of the Module" \section QmitkSimpleExampleViewUserManualSummary Summary This module is namely a simple example for simple image interaction. It offers:
    -
  • Sliders to navigate through the different slice stacks (Transversal, Sagittal, Coronal) and the time steps +
  • Sliders to navigate through the different slice stacks (Axial, Sagittal, Coronal) and the time steps
  • A "player" for image time series. It automatically steps through all time series with a speed defined by the slider on the right.
  • A button "Re-Initialize Navigators" to reinitialize those sliders to their initial position (Slice and time position 0)
  • A button "Take Screenshot" to take a screenshot of the chosen window (1=Transveral, 2=Sagittal, 3=Coronal, 4=3D View)
  • A button "Take HighDef 3D Screenshot" to take an high resolution screenshot of the 3D scene -
  • A button "Generate Movie" whichs takes a movie of the chosen window by scrolling either through all slices (Transversal, Sagittal, Coronal) +
  • A button "Generate Movie" whichs takes a movie of the chosen window by scrolling either through all slices (Axial, Sagittal, Coronal) or rotating the 3D scene
  • A selection box where the 3D view can be transformed into either a red-blue stereo or a D4D stereo view
*/ diff --git a/Plugins/org.mitk.gui.qt.examples/documentation/Manual/QmitkSimpleMeasurementUserManual.dox b/Plugins/org.mitk.gui.qt.examples/documentation/Manual/QmitkSimpleMeasurementUserManual.dox index 72d0a53688..f3aadf2c81 100644 --- a/Plugins/org.mitk.gui.qt.examples/documentation/Manual/QmitkSimpleMeasurementUserManual.dox +++ b/Plugins/org.mitk.gui.qt.examples/documentation/Manual/QmitkSimpleMeasurementUserManual.dox @@ -1,44 +1,44 @@ /** -\page org_simplemeasurement The Simple Measurement Module +\page org_mitk_views_simplemeasurement The Simple Measurement Module \image html SimpleMeasurementIcon.png "Icon of the Module" Available sections: - \ref QmitkSimpleMeasurementUserManualOverview - \ref QmitkSimpleMeasurementUserManualFeatures - \ref QmitkSimpleMeasurementUserManualUsage \section QmitkSimpleMeasurementUserManualOverview Overview SimpleMeasurement is a program module that allows to measure distances, angles and paths on a dataset. \section QmitkSimpleMeasurementUserManualFeatures Features
  • The SimpleMeasurement Module is able to measure:
    • Distances between two points
    • Angles between two lines (defined by three points)
    • Distances along a path
\section QmitkSimpleMeasurementUserManualUsage Usage To use the SimpleMeasurement Module, a data set must first be loaded. This can be done by drag & drop. Choose the simplemeasurement method you need by pressing the according button.
  • Points can be set by "shift-clicking" on the place in the data set.
  • Remove points by pressing the del-button on your keyboard.
  • You can mark a point by clicking on it with the cursor and moving it while the mouse button is still pressed.
What the different modes mean and how to use them:
  • Distances(a): To measure the distance between two points, you have to set two points. The distance will be displayed on the line between the points.
  • Angles(b): Angles can be measured between two lines. For that you have to set three points. The angle will be displayed between the two lines.
  • Path(c): Distances and angles along a path can be measured by setting at least two (for distance) or three (for angles) or more (for longer paths) points. The distance and the angles for each part will be displayed next to the path.
\image html SimpleMeasurementGUI.png Graphical User Interface of SimpleMeasurement */ diff --git a/Plugins/org.mitk.gui.qt.examples/documentation/Manual/org_mitk_gui_qt_viewinitialization.dox b/Plugins/org.mitk.gui.qt.examples/documentation/Manual/org_mitk_gui_qt_viewinitialization.dox index 6e1fad0a76..f192b11dd4 100644 --- a/Plugins/org.mitk.gui.qt.examples/documentation/Manual/org_mitk_gui_qt_viewinitialization.dox +++ b/Plugins/org.mitk.gui.qt.examples/documentation/Manual/org_mitk_gui_qt_viewinitialization.dox @@ -1,8 +1,8 @@ /** -\page org_viewinitialitzation The View Initialization Module +\page org_mitk_views_viewinitialitzation The View Initialization Module \image html viewInitializationIcon.png "Icon of the Module" -This view serves as a sandbox for understanding and experimenting with the geometry initialization parameters. For example, to view the transversal slices from above instead of from below. It is not intended for end users, but for developers. +This view serves as a sandbox for understanding and experimenting with the geometry initialization parameters. For example, to view the axial slices from above instead of from below. It is not intended for end users, but for developers. */ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.examples/src/internal/simpleexample/QmitkSimpleExampleView.cpp b/Plugins/org.mitk.gui.qt.examples/src/internal/simpleexample/QmitkSimpleExampleView.cpp index c94108fdef..ccddffa2b0 100644 --- a/Plugins/org.mitk.gui.qt.examples/src/internal/simpleexample/QmitkSimpleExampleView.cpp +++ b/Plugins/org.mitk.gui.qt.examples/src/internal/simpleexample/QmitkSimpleExampleView.cpp @@ -1,305 +1,305 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "QmitkSimpleExampleView.h" #include "mitkNodePredicateDataType.h" #include "QmitkDataStorageComboBox.h" #include "QmitkStdMultiWidget.h" #include #include #include "mitkNodePredicateProperty.h" #include "mitkNodePredicateNot.h" #include "mitkProperties.h" #include #include #include #include #include #include "vtkImageWriter.h" #include "vtkPNGWriter.h" #include "vtkJPEGWriter.h" #include "vtkRenderLargeImage.h" const std::string QmitkSimpleExampleView::VIEW_ID = "org.mitk.views.simpleexample"; QmitkSimpleExampleView::QmitkSimpleExampleView() : QmitkFunctionality(), m_Controls(NULL), m_MultiWidget(NULL), m_NavigatorsInitialized(false) { } QmitkSimpleExampleView::QmitkSimpleExampleView(const QmitkSimpleExampleView& other) { Q_UNUSED(other) throw std::runtime_error("Copy constructor not implemented"); } QmitkSimpleExampleView::~QmitkSimpleExampleView() { } void QmitkSimpleExampleView::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkSimpleExampleViewControls; m_Controls->setupUi(parent); this->CreateConnections(); } } void QmitkSimpleExampleView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; - new QmitkStepperAdapter(m_Controls->sliceNavigatorTransversal, m_MultiWidget->mitkWidget1->GetSliceNavigationController()->GetSlice(), "sliceNavigatorTransversalFromSimpleExample"); + new QmitkStepperAdapter(m_Controls->sliceNavigatorAxial, m_MultiWidget->mitkWidget1->GetSliceNavigationController()->GetSlice(), "sliceNavigatorAxialFromSimpleExample"); new QmitkStepperAdapter(m_Controls->sliceNavigatorSagittal, m_MultiWidget->mitkWidget2->GetSliceNavigationController()->GetSlice(), "sliceNavigatorSagittalFromSimpleExample"); new QmitkStepperAdapter(m_Controls->sliceNavigatorFrontal, m_MultiWidget->mitkWidget3->GetSliceNavigationController()->GetSlice(), "sliceNavigatorFrontalFromSimpleExample"); new QmitkStepperAdapter(m_Controls->sliceNavigatorTime, m_MultiWidget->GetTimeNavigationController()->GetTime(), "sliceNavigatorTimeFromSimpleExample"); new QmitkStepperAdapter(m_Controls->movieNavigatorTime, m_MultiWidget->GetTimeNavigationController()->GetTime(), "movieNavigatorTimeFromSimpleExample"); } void QmitkSimpleExampleView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } void QmitkSimpleExampleView::CreateConnections() { if ( m_Controls ) { connect(m_Controls->stereoSelect, SIGNAL(activated(int)), this, SLOT(stereoSelectionChanged(int)) ); connect(m_Controls->reInitializeNavigatorsButton, SIGNAL(clicked()), this, SLOT(initNavigators()) ); connect(m_Controls->genMovieButton, SIGNAL(clicked()), this, SLOT(generateMovie()) ); connect(m_Controls->m_RenderWindow1Button, SIGNAL(clicked()), this, SLOT(OnRenderWindow1Clicked()) ); connect(m_Controls->m_RenderWindow2Button, SIGNAL(clicked()), this, SLOT(OnRenderWindow2Clicked()) ); connect(m_Controls->m_RenderWindow3Button, SIGNAL(clicked()), this, SLOT(OnRenderWindow3Clicked()) ); connect(m_Controls->m_RenderWindow4Button, SIGNAL(clicked()), this, SLOT(OnRenderWindow4Clicked()) ); connect(m_Controls->m_TakeScreenshotBtn, SIGNAL(clicked()), this, SLOT(OnTakeScreenshot()) ); connect(m_Controls->m_TakeHighResScreenShotBtn, SIGNAL(clicked()), this, SLOT(OnTakeHighResolutionScreenshot()) ); } } void QmitkSimpleExampleView::Activated() { QmitkFunctionality::Activated(); } void QmitkSimpleExampleView::Deactivated() { QmitkFunctionality::Deactivated(); } void QmitkSimpleExampleView::initNavigators() { /* get all nodes that have not set "includeInBoundingBox" to false */ mitk::NodePredicateNot::Pointer pred = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("includeInBoundingBox", mitk::BoolProperty::New(false))); mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetDataStorage()->GetSubset(pred); /* calculate bounding geometry of these nodes */ mitk::TimeSlicedGeometry::Pointer bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(rs); /* initialize the views to the bounding geometry */ m_NavigatorsInitialized = mitk::RenderingManager::GetInstance()->InitializeViews(bounds); //m_NavigatorsInitialized = mitk::RenderingManager::GetInstance()->InitializeViews(GetDefaultDataStorage()); } void QmitkSimpleExampleView::generateMovie() { QmitkRenderWindow* movieRenderWindow = GetMovieRenderWindow(); //mitk::Stepper::Pointer stepper = multiWidget->mitkWidget1->GetSliceNavigationController()->GetSlice(); mitk::Stepper::Pointer stepper = movieRenderWindow->GetSliceNavigationController()->GetSlice(); mitk::MovieGenerator::Pointer movieGenerator = mitk::MovieGenerator::New(); if (movieGenerator.IsNotNull()) { movieGenerator->SetStepper( stepper ); movieGenerator->SetRenderer( mitk::BaseRenderer::GetInstance(movieRenderWindow->GetRenderWindow()) ); QString movieFileName = QFileDialog::getSaveFileName(0, "Choose a file name", QString(), "Movie (*.avi)"); if (!movieFileName.isEmpty()) { movieGenerator->SetFileName( movieFileName.toStdString().c_str() ); movieGenerator->WriteMovie(); } } } void QmitkSimpleExampleView::stereoSelectionChanged( int id ) { /* From vtkRenderWindow.h tells us about stereo rendering: Set/Get what type of stereo rendering to use. CrystalEyes mode uses frame-sequential capabilities available in OpenGL to drive LCD shutter glasses and stereo projectors. RedBlue mode is a simple type of stereo for use with red-blue glasses. Anaglyph mode is a superset of RedBlue mode, but the color output channels can be configured using the AnaglyphColorMask and the color of the original image can be (somewhat maintained using AnaglyphColorSaturation; the default colors for Anaglyph mode is red-cyan. Interlaced stereo mode produces a composite image where horizontal lines alternate between left and right views. StereoLeft and StereoRight modes choose one or the other stereo view. Dresden mode is yet another stereoscopic interleaving. */ vtkRenderWindow * vtkrenderwindow = m_MultiWidget->mitkWidget4->GetRenderWindow(); // note: foreground vtkRenderers (at least the department logo renderer) produce errors in stereoscopic visualization. // Therefore, we disable the logo visualization during stereo rendering. switch(id) { case 0: vtkrenderwindow->StereoRenderOff(); break; case 1: vtkrenderwindow->SetStereoTypeToRedBlue(); vtkrenderwindow->StereoRenderOn(); m_MultiWidget->DisableDepartmentLogo(); break; case 2: vtkrenderwindow->SetStereoTypeToDresden(); vtkrenderwindow->StereoRenderOn(); m_MultiWidget->DisableDepartmentLogo(); break; } mitk::BaseRenderer::GetInstance(m_MultiWidget->mitkWidget4->GetRenderWindow())->SetMapperID(2); m_MultiWidget->RequestUpdate(); } QmitkRenderWindow* QmitkSimpleExampleView::GetMovieRenderWindow() { //check which RenderWindow should be used to generate the movie, e.g. which button is toggled if(m_Controls->m_RenderWindow1Button->isChecked()) { return m_MultiWidget->mitkWidget1; } else if(m_Controls->m_RenderWindow2Button->isChecked()) { return m_MultiWidget->mitkWidget2; } else if(m_Controls->m_RenderWindow3Button->isChecked()) { return m_MultiWidget->mitkWidget3; } else if(m_Controls->m_RenderWindow4Button->isChecked()) { return m_MultiWidget->mitkWidget4; } else //as default take widget1 { return m_MultiWidget->mitkWidget1; } } void QmitkSimpleExampleView::OnRenderWindow1Clicked() { m_Controls->m_RenderWindow2Button->setChecked(false); m_Controls->m_RenderWindow3Button->setChecked(false); m_Controls->m_RenderWindow4Button->setChecked(false); } void QmitkSimpleExampleView::OnRenderWindow2Clicked() { m_Controls->m_RenderWindow1Button->setChecked(false); m_Controls->m_RenderWindow3Button->setChecked(false); m_Controls->m_RenderWindow4Button->setChecked(false); } void QmitkSimpleExampleView::OnRenderWindow3Clicked() { m_Controls->m_RenderWindow2Button->setChecked(false); m_Controls->m_RenderWindow1Button->setChecked(false); m_Controls->m_RenderWindow4Button->setChecked(false); } void QmitkSimpleExampleView::OnRenderWindow4Clicked() { m_Controls->m_RenderWindow2Button->setChecked(false); m_Controls->m_RenderWindow3Button->setChecked(false); m_Controls->m_RenderWindow1Button->setChecked(false); } void QmitkSimpleExampleView::OnTakeHighResolutionScreenshot() { QString fileName = QFileDialog::getSaveFileName(NULL, "Save screenshot to...", QDir::currentPath(), "JPEG file (*.jpg);;PNG file (*.png)"); // only works correctly for 3D RenderWindow vtkRenderer* renderer = m_MultiWidget->mitkWidget4->GetRenderer()->GetVtkRenderer(); if (renderer == NULL) return; this->TakeScreenshot(renderer, 4, fileName); } void QmitkSimpleExampleView::OnTakeScreenshot() { QString fileName = QFileDialog::getSaveFileName(NULL, "Save screenshot to...", QDir::currentPath(), "JPEG file (*.jpg);;PNG file (*.png)"); QmitkRenderWindow* renWin = this->GetMovieRenderWindow(); if (renWin == NULL) return; vtkRenderer* renderer = renWin->GetRenderer()->GetVtkRenderer(); if (renderer == NULL) return; this->TakeScreenshot(renderer, 1, fileName); } void QmitkSimpleExampleView::TakeScreenshot(vtkRenderer* renderer, unsigned int magnificationFactor, QString fileName) { if ((renderer == NULL) ||(magnificationFactor < 1) || fileName.isEmpty()) return; bool doubleBuffering( renderer->GetRenderWindow()->GetDoubleBuffer() ); renderer->GetRenderWindow()->DoubleBufferOff(); vtkImageWriter* fileWriter; QFileInfo fi(fileName); QString suffix = fi.suffix(); if (suffix.compare("png", Qt::CaseInsensitive) == 0) { fileWriter = vtkPNGWriter::New(); } else // default is jpeg { vtkJPEGWriter* w = vtkJPEGWriter::New(); w->SetQuality(100); w->ProgressiveOff(); fileWriter = w; } vtkRenderLargeImage* magnifier = vtkRenderLargeImage::New(); magnifier->SetInput(renderer); magnifier->SetMagnification(magnificationFactor); //magnifier->Update(); fileWriter->SetInput(magnifier->GetOutput()); fileWriter->SetFileName(fileName.toLatin1()); // vtkRenderLargeImage has problems with different layers, therefore we have to // temporarily deactivate all other layers. // we set the background to white, because it is nicer than black... double oldBackground[3]; renderer->GetBackground(oldBackground); double white[] = {1.0, 1.0, 1.0}; renderer->SetBackground(white); m_MultiWidget->DisableColoredRectangles(); m_MultiWidget->DisableDepartmentLogo(); m_MultiWidget->DisableGradientBackground(); fileWriter->Write(); fileWriter->Delete(); m_MultiWidget->EnableColoredRectangles(); m_MultiWidget->EnableDepartmentLogo(); m_MultiWidget->EnableGradientBackground(); renderer->SetBackground(oldBackground); renderer->GetRenderWindow()->SetDoubleBuffer(doubleBuffering); } diff --git a/Plugins/org.mitk.gui.qt.examples/src/internal/simpleexample/QmitkSimpleExampleView.h b/Plugins/org.mitk.gui.qt.examples/src/internal/simpleexample/QmitkSimpleExampleView.h index 06c1c114b0..6ed5f3ae04 100644 --- a/Plugins/org.mitk.gui.qt.examples/src/internal/simpleexample/QmitkSimpleExampleView.h +++ b/Plugins/org.mitk.gui.qt.examples/src/internal/simpleexample/QmitkSimpleExampleView.h @@ -1,103 +1,103 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 _QMITKSIMPLEEXAMPLEVIEW_H_INCLUDED #define _QMITKSIMPLEEXAMPLEVIEW_H_INCLUDED #include #include #include "ui_QmitkSimpleExampleViewControls.h" #include /*! * \ingroup org_mitk_gui_qt_simpleexample_internal * * \brief QmitkSimpleExampleView * * Document your class here. * * \sa QmitkFunctionality */ class QmitkSimpleExampleView : public QmitkFunctionality { // 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; QmitkSimpleExampleView(); QmitkSimpleExampleView(const QmitkSimpleExampleView& other); virtual ~QmitkSimpleExampleView(); virtual void CreateQtPartControl(QWidget *parent); /// \brief Creation of the connections of main and control widget virtual void CreateConnections(); /// \brief Called when the functionality is activated virtual void Activated(); virtual void Deactivated(); virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget); virtual void StdMultiWidgetNotAvailable(); protected slots: /*! qt slot for event processing from a qt widget defining the stereo mode of widget 4 */ void stereoSelectionChanged(int id); /*! - initialize the transversal, sagittal, coronal and temporal slider according to the image dimensions + initialize the axial, sagittal, coronal and temporal slider according to the image dimensions */ void initNavigators(); /*! generate a movie as *.avi from the active render window */ void generateMovie(); /*! return the renderwindow of which the movie shall be created, what depends on the toggled button */ QmitkRenderWindow* GetMovieRenderWindow(); void OnRenderWindow1Clicked(); void OnRenderWindow2Clicked(); void OnRenderWindow3Clicked(); void OnRenderWindow4Clicked(); void OnTakeHighResolutionScreenshot(); ///< takes screenshot of the 3D window in 4x resolution of the render window void OnTakeScreenshot(); ///< takes screenshot of the selected render window protected: Ui::QmitkSimpleExampleViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; void TakeScreenshot(vtkRenderer* renderer, unsigned int magnificationFactor, QString fileName); ///< writes a screenshot in JPEG or PNG format to the file fileName bool m_NavigatorsInitialized; }; #endif // _QMITKSIMPLEEXAMPLEVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.examples/src/internal/simpleexample/QmitkSimpleExampleViewControls.ui b/Plugins/org.mitk.gui.qt.examples/src/internal/simpleexample/QmitkSimpleExampleViewControls.ui index 285de033b2..ed5d70daca 100644 --- a/Plugins/org.mitk.gui.qt.examples/src/internal/simpleexample/QmitkSimpleExampleViewControls.ui +++ b/Plugins/org.mitk.gui.qt.examples/src/internal/simpleexample/QmitkSimpleExampleViewControls.ui @@ -1,237 +1,237 @@ QmitkSimpleExampleViewControls 0 0 231 610 0 0 false Form1 4 4 - + 0 0 Re-initialize Navigators 30 32767 1 true true 30 32767 4 true false 30 32767 2 true 30 32767 3 true Take Screenshot Screenshot will be 4 times larger than current render window size Take HighDef 3D Screenshot 32767 23 Generate Movie 200 0 stereo off red-blue stereo D4D stereo Qt::Vertical QSizePolicy::Expanding 20 230 QmitkPrimitiveMovieNavigatorWidget QWidget
QmitkPrimitiveMovieNavigatorWidget.h
1
QmitkSliderNavigatorWidget QWidget
QmitkSliderNavigatorWidget.h
1
reInitializeNavigatorsButton stereoSelect
diff --git a/Plugins/org.mitk.gui.qt.examples/src/internal/viewinitialization/QmitkViewInitializationView.cpp b/Plugins/org.mitk.gui.qt.examples/src/internal/viewinitialization/QmitkViewInitializationView.cpp index 2ecbce01aa..e592e15419 100644 --- a/Plugins/org.mitk.gui.qt.examples/src/internal/viewinitialization/QmitkViewInitializationView.cpp +++ b/Plugins/org.mitk.gui.qt.examples/src/internal/viewinitialization/QmitkViewInitializationView.cpp @@ -1,193 +1,193 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "QmitkViewInitializationView.h" #include "mitkNodePredicateDataType.h" #include "QmitkDataStorageComboBox.h" #include "QmitkStdMultiWidget.h" #include "mitkFocusManager.h" #include "mitkGlobalInteraction.h" #include "itkCommand.h" #include const std::string QmitkViewInitializationView::VIEW_ID = "org.mitk.views.viewinitialization"; QmitkViewInitializationView::QmitkViewInitializationView() : QmitkFunctionality(), m_Controls(NULL), m_MultiWidget(NULL) { m_CommandTag = 0; } QmitkViewInitializationView::~QmitkViewInitializationView() { } void QmitkViewInitializationView::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkViewInitializationViewControls; m_Controls->setupUi(parent); this->CreateConnections(); } } void QmitkViewInitializationView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } void QmitkViewInitializationView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } void QmitkViewInitializationView::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->pbApply), SIGNAL(clicked()),(QObject*) this, SLOT(OnApply()) ); connect( (QObject*)(m_Controls->pbReset), SIGNAL(clicked()),(QObject*) this, SLOT(OnResetAll()) ); } } void QmitkViewInitializationView::Activated() { //init render window selector (List Widget) this->InitRenderWindowSelector(); QmitkFunctionality::Activated(); } void QmitkViewInitializationView::Deactivated() { mitk::FocusManager* fm = mitk::GlobalInteraction::GetInstance()->GetFocusManager(); fm->RemoveObserver(m_CommandTag); QmitkFunctionality::Deactivated(); } void QmitkViewInitializationView::OnApply() { - mitk::SliceNavigationController::ViewDirection viewDirection( mitk::SliceNavigationController::Transversal ); - if( m_Controls->rbTransversal->isChecked() ) - viewDirection = mitk::SliceNavigationController::Transversal; + mitk::SliceNavigationController::ViewDirection viewDirection( mitk::SliceNavigationController::Axial ); + if( m_Controls->rbAxial->isChecked() ) + viewDirection = mitk::SliceNavigationController::Axial; else if( m_Controls->rbFrontal->isChecked()) viewDirection = mitk::SliceNavigationController::Frontal; else if( m_Controls->rbSagittal->isChecked() ) viewDirection = mitk::SliceNavigationController::Sagittal; vtkRenderWindow* renderwindow = this->GetSelectedRenderWindow(); if(renderwindow != NULL) { mitk::BaseRenderer::GetInstance(renderwindow)->GetSliceNavigationController()->Update(viewDirection, m_Controls->cbTop->isChecked(), m_Controls->cbFrontSide->isChecked(), m_Controls->cbRotated->isChecked() ); mitk::BaseRenderer::GetInstance(renderwindow)->GetDisplayGeometry()->Fit(); } } void QmitkViewInitializationView::OnResetAll() { /* calculate bounding geometry of these nodes */ mitk::TimeSlicedGeometry::Pointer bounds = this->GetDefaultDataStorage()->ComputeBoundingGeometry3D(); /* initialize the views to the bounding geometry */ mitk::RenderingManager::GetInstance()->InitializeViews(bounds); } vtkRenderWindow* QmitkViewInitializationView::GetSelectedRenderWindow() { int selectedItem = m_Controls->m_lbRenderWindows->currentRow(); int itemNumber = 0; mitk::BaseRenderer::BaseRendererMapType::iterator mapit; for(mapit = mitk::BaseRenderer::baseRendererMap.begin(); mapit != mitk::BaseRenderer::baseRendererMap.end(); mapit++, itemNumber++) { if(itemNumber==selectedItem) break; } if(itemNumber==selectedItem) { return (*mapit).first; } return NULL; } void QmitkViewInitializationView::InitRenderWindowSelector() { itk::SimpleMemberCommand::Pointer updateRendererListCommand = itk::SimpleMemberCommand::New(); updateRendererListCommand->SetCallbackFunction( this, &QmitkViewInitializationView::UpdateRendererList ); mitk::FocusManager* fm = mitk::GlobalInteraction::GetInstance()->GetFocusManager(); m_CommandTag = fm->AddObserver(mitk::FocusEvent(), updateRendererListCommand); this->UpdateRendererList(); } void QmitkViewInitializationView::UpdateRendererList() { vtkRenderWindow* focusedRenderWindow = NULL; mitk::FocusManager* fm = mitk::GlobalInteraction::GetInstance()->GetFocusManager(); mitk::BaseRenderer::ConstPointer br = fm->GetFocused(); if (br.IsNotNull()) { focusedRenderWindow = br->GetRenderWindow(); } int selectedItem = -1; int itemNumber = 0; m_Controls->m_lbRenderWindows->clear(); for(mitk::BaseRenderer::BaseRendererMapType::iterator mapit = mitk::BaseRenderer::baseRendererMap.begin(); mapit != mitk::BaseRenderer::baseRendererMap.end(); mapit++, itemNumber++) { if( (*mapit).second->GetName()) { m_Controls->m_lbRenderWindows->addItem(QString((*mapit).second->GetName())); if(focusedRenderWindow==(*mapit).first) selectedItem = itemNumber; } } if (selectedItem>=0) { m_Controls->m_lbRenderWindows->setCurrentRow(selectedItem); } else { m_Controls->m_lbRenderWindows->clearSelection(); } } diff --git a/Plugins/org.mitk.gui.qt.examples/src/internal/viewinitialization/QmitkViewInitializationViewControls.ui b/Plugins/org.mitk.gui.qt.examples/src/internal/viewinitialization/QmitkViewInitializationViewControls.ui index bdd3007bc2..599028bd2b 100644 --- a/Plugins/org.mitk.gui.qt.examples/src/internal/viewinitialization/QmitkViewInitializationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.examples/src/internal/viewinitialization/QmitkViewInitializationViewControls.ui @@ -1,161 +1,161 @@ QmitkViewInitializationViewControls 0 0 285 741 0 0 QmitkTemplate Change view initialization of false 0 0 200 0 Change view initialization to false orientation - + - transversal + axial true frontal sagittal rotation first is top true front view true rotated Apply Reset all Qt::Vertical 20 322 QmitkDataStorageComboBox.h diff --git a/Plugins/org.mitk.gui.qt.examplesopencv/documentation/UserManual/MITKExamplesOpenCV.dox b/Plugins/org.mitk.gui.qt.examplesopencv/documentation/UserManual/MITKExamplesOpenCV.dox index 74e11968eb..68f2398d23 100644 --- a/Plugins/org.mitk.gui.qt.examplesopencv/documentation/UserManual/MITKExamplesOpenCV.dox +++ b/Plugins/org.mitk.gui.qt.examplesopencv/documentation/UserManual/MITKExamplesOpenCV.dox @@ -1,12 +1,12 @@ /** -\bundlemainpage{org_mitkexamplesopencv} OpenCV Examples for the use of MITK +\page org_mitkexamplesopencv OpenCV Examples for the use of MITK \section QmitkExamplesOpenCVUserManualSummary Summary This module is a collection of examples for developing with mitk and openCV. The following examples are included:
  • \subpage org_videoplayer
*/ diff --git a/Plugins/org.mitk.gui.qt.ext/documentation/UserManual/MITKUserManual.dox b/Plugins/org.mitk.gui.qt.ext/documentation/UserManual/MITKUserManual.dox index 65f6223227..20f6d10a85 100644 --- a/Plugins/org.mitk.gui.qt.ext/documentation/UserManual/MITKUserManual.dox +++ b/Plugins/org.mitk.gui.qt.ext/documentation/UserManual/MITKUserManual.dox @@ -1,118 +1,118 @@ /** -\bundlemainpage{MITKUserManualPage} The MITK User Manual +\page MITKUserManualPage The MITK User Manual Welcome to the basic MITK user manual. This document tries to give a concise overview of the basic functions of MITK and be an comprehensible guide on using them. Available sections: - \ref MITKUserManualPageOverview - \ref MITKUserManualPageUserInterface - \ref MITKUserManualPagePerspectives \section MITKUserManualPageOverview About MITK MITK is an open-source framework that was originally developed as a common framework for Ph.D. students in the Division of Medical and Biological Informatics (MBI) at the German Cancer Research Center. MITK aims at supporting the development of leading-edge medical imaging software with a high degree of interaction. MITK re-uses virtually anything from VTK and ITK. Thus, it is not at all a competitor to VTK or ITK, but an extension, which tries to ease the combination of both and to add features not supported by VTK or ITK. Research institutes, medical professionals and companies alike can use MITK as a basic framework for their research and even commercial (thorough code research needed) software due to the BSD-like software license. Research institutes will profit from the high level of integration of ITK and VTK enhanced with data management, advanced visualization and interaction functionality in a single framework that is supported by a wide variety of researchers and developers. You will not have to reinvent the wheel over and over and can concentrate on your work. Medical Professionals will profit from MITK and the MITK applications by using its basic functionalities for research projects. But nonetheless they will be better off, unless they are programmers themselves, to cooperate with a research institute developing with MITK to get the functionalitiy they need. MITK and the MITK applications are not certified medical products and may be used in a research setting only. They must not be used in patient care. \section MITKUserManualPageUserInterface The User Interface The layout of the MITK applications is designed to give a clear distinction between the different work areas. The following figure gives an overview of the main sections of the user interface. \image html GUI_Commented.png "The Common MITK Application Graphical User Interface" The datamanager and the \ref MITKUserManualPagePerspectives have their own help sections. This document explains the use of: - The \ref MITKUserManualPageMultiWidget - The \ref MITKUserManualPageMenu - The \ref MITKUserManualPageLevelWindow - The \ref MITKUserManualPageMemoryUsage - The \ref MITKUserManualPageViews \section MITKUserManualPageMultiWidget Four Window View \subsection MITKUserManualPageMultiWidgetOverview Overview -The four window view is the heart of the MITK image viewing. The standard layout is three 2D windows and one 3D window, with the transversal window in the top left quarter, the sagittal window in the top right quarter, the coronal window in the lower left quarter and the 3D window in the lower right quarter. The different planes form a crosshair that can be seen in the 3D window. +The four window view is the heart of the MITK image viewing. The standard layout is three 2D windows and one 3D window, with the axial window in the top left quarter, the sagittal window in the top right quarter, the coronal window in the lower left quarter and the 3D window in the lower right quarter. The different planes form a crosshair that can be seen in the 3D window. Once you select a point within the picture, informations about it are displayed at the bottom of the screen. \subsection MITKUserManualPageMultiWidgetNavigation Navigation Left click in any of the 2D windows centers the crosshair on that point. Pressing the right mouse button and moving the mouse zooms in and out. By scrolling with the mouse wheel you can navigate through the slices of the active window and pressing the mouse wheel while moving the mouse pans the image section. In the 3D window you can rotate the object by pressing the left mouse button and moving the mouse, zoom either with the right mouse button as in 2D or with the mouse wheel, and pan the object by moving the mouse while the mouse wheel is pressed. Placing the cursor within the 3D window and holding the "F" key allows free flight into the 3D view. \subsection MITKUserManualPageMultiWidgetCustomizingViews Customizing By moving the cursor to the upper right corner of any window you can activate the window menu. It consists of three buttons. \image html Crosshair_Modes.png "Crosshair" The crosshair button allows you toggle the crosshair, reset the view and change the behaviour of the planes. Activating either of the rotation modes allows you to rotate the planes visible in a 2D window by moving the mouse cursor close to them and click and dragging once it changes to indicate that rotation can be done. The swivel mode is recommended only for advanced users as the planes can be moved freely by clicking and dragging anywhere within a 2D window. The middle button expands the corresponding window to fullscreen within the four window view. \image html Views_Choices.png "Layout Choices" The right button allows you to choose between many different layouts of the four window view to use the one most suited to your task. \section MITKUserManualPageMenu Menu \subsection MITKUserManualPageFile File This dialog allows you to save, load and clear entire projects, this includes any nodes in the data manager. \subsection MITKUserManualPageEdit Edit This dialog supports undo and redo operations as well as the image navigator, which gives you sliders to navigate through the data quickly. \subsection MITKUserManualPageWindow Window This dialog allows you to open a new window, change between perspectives and reset your current one to default settings. If you want to use an operation of a certain perspective within another perspective the "Show View" menu allows to select a specific function that is opened and can be moved within the working areas according to your wishes. Be aware that not every function works with every perspective in a meaningful way. The Preferences dialog allows you to adjust and save your custom settings. \image html Window_Dropdown.png "Preferences" \subsection MITKUserManualPageHelp Help This dialog contains this help, the welcome screen and information about MITK. \section MITKUserManualPageLevelWindow Levelwindow Once an image is loaded the levelwindow appears to the right hand side of the four window view. With this tool you can adjust the range of grey values displayed and the gradient between them. Moving the lower boundary up results in any pixels having a value lower than that boundary to be displayed as black. Lowering the upper boundary causes all pixels having a value higher than it to be displayed as white. The pixels with a value between the lower and upper boundary are displayed in different shades of grey. This way a smaller levelwindow results in higher contrasts while cutting of the information outside its range whereas a larger levelwindow displays more information at the cost of contrast and detail. You can pick the levelwindow with the mouse to move it up and down, while moving the mouse cursor to the left or right to change its size. Picking one of the boundaries with a left click allows you to change the size symmetrically. Holding CTRL and clicking a boundary adjusts only that value. \section MITKUserManualPageMemoryUsage System Load Indicator The System Load Indicator in the lower right hand corner of the screen gives information about the memory currently required by the MITK application. Keep in mind that image processing is a highly memory intensive task and monitor the indicator to avoid your system freezing while constantly swapping to the hard drive. \section MITKUserManualPageViews Views Each solution for a specific problem that is self contained is realized as a single view. Thus you can create a workflow for your problem by combining the capabilities of different views to suit your needs. One elegant way to do this is by combining views in \ref MITKUserManualPagePerspectives. By pressing and holding the left mouse button on a views tab you can move it around to suit your needs, even out of the application window. \section MITKUserManualPagePerspectives Perspectives The different tasks that arise in medical imaging need very different approaches. To acknowledge this circumstance MITK supplies a framework that can be build uppon by very different solutions to those tasks. These solutions are called perspectives, each of them works independently of others although they might be used in sequence to achieve the solution of more difficult problems. It is possible to switch between the perspectives using the "Window"->"Open Perspective" dialog. See \ref MITKUserManualPageMenu for more information about switching perspectives. */ diff --git a/Plugins/org.mitk.gui.qt.ext/resources/index.html b/Plugins/org.mitk.gui.qt.ext/resources/index.html index 0973a2e318..f26a4fa569 100644 --- a/Plugins/org.mitk.gui.qt.ext/resources/index.html +++ b/Plugins/org.mitk.gui.qt.ext/resources/index.html @@ -1,12 +1,12 @@ -Welcome to MITK ExtApp +Welcome to MITK -Welcome to MITK - ExtApp +Welcome to MITK

The content of this message box can be changed in the org.mitk.gui.qt.ext/index.html file in the resource folder! \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.cpp b/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.cpp index 734c11a634..24e66118cc 100644 --- a/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.cpp +++ b/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.cpp @@ -1,1190 +1,1190 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "QmitkExtWorkbenchWindowAdvisor.h" #include "QmitkExtActionBarAdvisor.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 #include #include #include #include #include #include #include #include #include #include #include // UGLYYY #include "internal/QmitkExtWorkbenchWindowAdvisorHack.h" #include "internal/QmitkCommonExtPlugin.h" #include "mitkUndoController.h" #include "mitkVerboseLimitedLinearUndo.h" #include #include #include #include QmitkExtWorkbenchWindowAdvisorHack * QmitkExtWorkbenchWindowAdvisorHack::undohack = new QmitkExtWorkbenchWindowAdvisorHack(); QString QmitkExtWorkbenchWindowAdvisor::QT_SETTINGS_FILENAME = "QtSettings.ini"; class PartListenerForTitle: public berry::IPartListener { public: PartListenerForTitle(QmitkExtWorkbenchWindowAdvisor* wa) : windowAdvisor(wa) { } Events::Types GetPartEventTypes() const { return Events::ACTIVATED | Events::BROUGHT_TO_TOP | Events::CLOSED | Events::HIDDEN | Events::VISIBLE; } void PartActivated(berry::IWorkbenchPartReference::Pointer ref) { if (ref.Cast ()) { windowAdvisor->UpdateTitle(false); } } void PartBroughtToTop(berry::IWorkbenchPartReference::Pointer ref) { if (ref.Cast ()) { windowAdvisor->UpdateTitle(false); } } void PartClosed(berry::IWorkbenchPartReference::Pointer /*ref*/) { windowAdvisor->UpdateTitle(false); } void PartHidden(berry::IWorkbenchPartReference::Pointer ref) { if (!windowAdvisor->lastActiveEditor.Expired() && ref->GetPart(false) == windowAdvisor->lastActiveEditor.Lock()) { windowAdvisor->UpdateTitle(true); } } void PartVisible(berry::IWorkbenchPartReference::Pointer ref) { if (!windowAdvisor->lastActiveEditor.Expired() && ref->GetPart(false) == windowAdvisor->lastActiveEditor.Lock()) { windowAdvisor->UpdateTitle(false); } } private: QmitkExtWorkbenchWindowAdvisor* windowAdvisor; }; class PartListenerForImageNavigator: public berry::IPartListener { public: PartListenerForImageNavigator(QAction* act) : imageNavigatorAction(act) { } Events::Types GetPartEventTypes() const { return Events::OPENED | Events::CLOSED | Events::HIDDEN | Events::VISIBLE; } void PartOpened(berry::IWorkbenchPartReference::Pointer ref) { if (ref->GetId()=="org.mitk.views.imagenavigator") { imageNavigatorAction->setChecked(true); } } void PartClosed(berry::IWorkbenchPartReference::Pointer ref) { if (ref->GetId()=="org.mitk.views.imagenavigator") { imageNavigatorAction->setChecked(false); } } void PartVisible(berry::IWorkbenchPartReference::Pointer ref) { if (ref->GetId()=="org.mitk.views.imagenavigator") { imageNavigatorAction->setChecked(true); } } void PartHidden(berry::IWorkbenchPartReference::Pointer ref) { if (ref->GetId()=="org.mitk.views.imagenavigator") { imageNavigatorAction->setChecked(false); } } private: QAction* imageNavigatorAction; }; class PerspectiveListenerForTitle: public berry::IPerspectiveListener { public: PerspectiveListenerForTitle(QmitkExtWorkbenchWindowAdvisor* wa) : windowAdvisor(wa), perspectivesClosed(false) { } Events::Types GetPerspectiveEventTypes() const { return Events::ACTIVATED | Events::SAVED_AS | Events::DEACTIVATED // remove the following line when command framework is finished | Events::CLOSED | Events::OPENED; } void PerspectiveActivated(berry::IWorkbenchPage::Pointer /*page*/, berry::IPerspectiveDescriptor::Pointer /*perspective*/) { windowAdvisor->UpdateTitle(false); } void PerspectiveSavedAs(berry::IWorkbenchPage::Pointer /*page*/, berry::IPerspectiveDescriptor::Pointer /*oldPerspective*/, berry::IPerspectiveDescriptor::Pointer /*newPerspective*/) { windowAdvisor->UpdateTitle(false); } void PerspectiveDeactivated(berry::IWorkbenchPage::Pointer /*page*/, berry::IPerspectiveDescriptor::Pointer /*perspective*/) { windowAdvisor->UpdateTitle(false); } void PerspectiveOpened(berry::IWorkbenchPage::Pointer /*page*/, berry::IPerspectiveDescriptor::Pointer /*perspective*/) { if (perspectivesClosed) { QListIterator i(windowAdvisor->viewActions); while (i.hasNext()) { i.next()->setEnabled(true); } //GetViewRegistry()->Find("org.mitk.views.imagenavigator"); if(windowAdvisor->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.dicomeditor")) { windowAdvisor->openDicomEditorAction->setEnabled(true); } windowAdvisor->fileSaveProjectAction->setEnabled(true); windowAdvisor->closeProjectAction->setEnabled(true); windowAdvisor->undoAction->setEnabled(true); windowAdvisor->redoAction->setEnabled(true); windowAdvisor->imageNavigatorAction->setEnabled(true); windowAdvisor->resetPerspAction->setEnabled(true); if( windowAdvisor->GetShowClosePerspectiveMenuItem() ) { windowAdvisor->closePerspAction->setEnabled(true); } } perspectivesClosed = false; } void PerspectiveClosed(berry::IWorkbenchPage::Pointer /*page*/, berry::IPerspectiveDescriptor::Pointer /*perspective*/) { berry::IWorkbenchWindow::Pointer wnd = windowAdvisor->GetWindowConfigurer()->GetWindow(); bool allClosed = true; if (wnd->GetActivePage()) { std::vector perspectives(wnd->GetActivePage()->GetOpenPerspectives()); allClosed = perspectives.empty(); } if (allClosed) { perspectivesClosed = true; QListIterator i(windowAdvisor->viewActions); while (i.hasNext()) { i.next()->setEnabled(false); } if(windowAdvisor->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.dicomeditor")) { windowAdvisor->openDicomEditorAction->setEnabled(false); } windowAdvisor->fileSaveProjectAction->setEnabled(false); windowAdvisor->closeProjectAction->setEnabled(false); windowAdvisor->undoAction->setEnabled(false); windowAdvisor->redoAction->setEnabled(false); windowAdvisor->imageNavigatorAction->setEnabled(false); windowAdvisor->resetPerspAction->setEnabled(false); if( windowAdvisor->GetShowClosePerspectiveMenuItem() ) { windowAdvisor->closePerspAction->setEnabled(false); } } } private: QmitkExtWorkbenchWindowAdvisor* windowAdvisor; bool perspectivesClosed; }; class PerspectiveListenerForMenu: public berry::IPerspectiveListener { public: PerspectiveListenerForMenu(QmitkExtWorkbenchWindowAdvisor* wa) : windowAdvisor(wa) { } Events::Types GetPerspectiveEventTypes() const { return Events::ACTIVATED | Events::DEACTIVATED; } void PerspectiveActivated(berry::IWorkbenchPage::Pointer /*page*/, berry::IPerspectiveDescriptor::Pointer perspective) { QAction* action = windowAdvisor->mapPerspIdToAction[perspective->GetId()]; if (action) { action->setChecked(true); } } void PerspectiveDeactivated(berry::IWorkbenchPage::Pointer /*page*/, berry::IPerspectiveDescriptor::Pointer perspective) { QAction* action = windowAdvisor->mapPerspIdToAction[perspective->GetId()]; if (action) { action->setChecked(false); } } private: QmitkExtWorkbenchWindowAdvisor* windowAdvisor; }; QmitkExtWorkbenchWindowAdvisor::QmitkExtWorkbenchWindowAdvisor(berry::WorkbenchAdvisor* wbAdvisor, berry::IWorkbenchWindowConfigurer::Pointer configurer) : berry::WorkbenchWindowAdvisor(configurer), lastInput(0), wbAdvisor(wbAdvisor), showViewToolbar(true), showPerspectiveToolbar(false), showVersionInfo(true), showMitkVersionInfo(true), showViewMenuItem(true), showNewWindowMenuItem(false), showClosePerspectiveMenuItem(true), dropTargetListener(new QmitkDefaultDropTargetListener) { productName = berry::Platform::GetConfiguration().getString("application.baseName"); } berry::ActionBarAdvisor::Pointer QmitkExtWorkbenchWindowAdvisor::CreateActionBarAdvisor( berry::IActionBarConfigurer::Pointer configurer) { berry::ActionBarAdvisor::Pointer actionBarAdvisor( new QmitkExtActionBarAdvisor(configurer)); return actionBarAdvisor; } void* QmitkExtWorkbenchWindowAdvisor::CreateEmptyWindowContents(void* parent) { QWidget* parentWidget = static_cast(parent); QLabel* label = new QLabel(parentWidget); label->setText("No perspectives are open. Open a perspective in the Window->Open Perspective menu."); label->setContentsMargins(10,10,10,10); label->setAlignment(Qt::AlignTop); label->setEnabled(false); parentWidget->layout()->addWidget(label); return label; } void QmitkExtWorkbenchWindowAdvisor::ShowClosePerspectiveMenuItem(bool show) { showClosePerspectiveMenuItem = show; } bool QmitkExtWorkbenchWindowAdvisor::GetShowClosePerspectiveMenuItem() { return showClosePerspectiveMenuItem; } void QmitkExtWorkbenchWindowAdvisor::ShowNewWindowMenuItem(bool show) { showNewWindowMenuItem = show; } void QmitkExtWorkbenchWindowAdvisor::ShowViewToolbar(bool show) { showViewToolbar = show; } void QmitkExtWorkbenchWindowAdvisor::ShowViewMenuItem(bool show) { showViewMenuItem = show; } void QmitkExtWorkbenchWindowAdvisor::ShowPerspectiveToolbar(bool show) { showPerspectiveToolbar = show; } void QmitkExtWorkbenchWindowAdvisor::ShowVersionInfo(bool show) { showVersionInfo = show; } void QmitkExtWorkbenchWindowAdvisor::ShowMitkVersionInfo(bool show) { showMitkVersionInfo = show; } void QmitkExtWorkbenchWindowAdvisor::SetProductName(const std::string& product) { productName = product; } void QmitkExtWorkbenchWindowAdvisor::SetWindowIcon(const std::string& wndIcon) { windowIcon = wndIcon; } void QmitkExtWorkbenchWindowAdvisor::PostWindowCreate() { // very bad hack... berry::IWorkbenchWindow::Pointer window = this->GetWindowConfigurer()->GetWindow(); QMainWindow* mainWindow = static_cast (window->GetShell()->GetControl()); if (!windowIcon.empty()) { mainWindow->setWindowIcon(QIcon(QString::fromStdString(windowIcon))); } mainWindow->setContextMenuPolicy(Qt::PreventContextMenu); /*mainWindow->setStyleSheet("color: white;" "background-color: #808080;" "selection-color: #659EC7;" "selection-background-color: #808080;" " QMenuBar {" "background-color: #808080; }");*/ // ==== Application menu ============================ QMenuBar* menuBar = mainWindow->menuBar(); menuBar->setContextMenuPolicy(Qt::PreventContextMenu); QMenu* fileMenu = menuBar->addMenu("&File"); fileMenu->setObjectName("FileMenu"); QAction* fileOpenAction = new QmitkFileOpenAction(QIcon(":/org.mitk.gui.qt.ext/Load_48.png"), window); fileMenu->addAction(fileOpenAction); fileSaveProjectAction = new QmitkExtFileSaveProjectAction(window); fileSaveProjectAction->setIcon(QIcon(":/org.mitk.gui.qt.ext/Save_48.png")); fileMenu->addAction(fileSaveProjectAction); closeProjectAction = new QmitkCloseProjectAction(window); closeProjectAction->setIcon(QIcon(":/org.mitk.gui.qt.ext/Remove_48.png")); fileMenu->addAction(closeProjectAction); fileMenu->addSeparator(); QAction* fileExitAction = new QmitkFileExitAction(window); fileExitAction->setObjectName("QmitkFileExitAction"); fileMenu->addAction(fileExitAction); if(this->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.dicomeditor")) { openDicomEditorAction = new QmitkOpenDicomEditorAction(window); } berry::IViewRegistry* viewRegistry = berry::PlatformUI::GetWorkbench()->GetViewRegistry(); const std::vector& viewDescriptors = viewRegistry->GetViews(); // another bad hack to get an edit/undo menu... QMenu* editMenu = menuBar->addMenu("&Edit"); undoAction = editMenu->addAction(QIcon(":/org.mitk.gui.qt.ext/Undo_48.png"), "&Undo", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onUndo()), QKeySequence("CTRL+Z")); undoAction->setToolTip("Undo the last action (not supported by all modules)"); redoAction = editMenu->addAction(QIcon(":/org.mitk.gui.qt.ext/Redo_48.png") , "&Redo", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onRedo()), QKeySequence("CTRL+Y")); redoAction->setToolTip("execute the last action that was undone again (not supported by all modules)"); imageNavigatorAction = new QAction(QIcon(":/org.mitk.gui.qt.ext/Slider.png"), "&Image Navigator", NULL); bool imageNavigatorViewFound = window->GetWorkbench()->GetViewRegistry()->Find("org.mitk.views.imagenavigator"); if (imageNavigatorViewFound) { QObject::connect(imageNavigatorAction, SIGNAL(triggered(bool)), QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onImageNavigator())); imageNavigatorAction->setCheckable(true); // add part listener for image navigator imageNavigatorPartListener = new PartListenerForImageNavigator(imageNavigatorAction); window->GetPartService()->AddPartListener(imageNavigatorPartListener); berry::IViewPart::Pointer imageNavigatorView = window->GetActivePage()->FindView("org.mitk.views.imagenavigator"); imageNavigatorAction->setChecked(false); if (imageNavigatorView) { bool isImageNavigatorVisible = window->GetActivePage()->IsPartVisible(imageNavigatorView); if (isImageNavigatorVisible) imageNavigatorAction->setChecked(true); } imageNavigatorAction->setToolTip("Open image navigator for navigating through image"); } // toolbar for showing file open, undo, redo and other main actions QToolBar* mainActionsToolBar = new QToolBar; mainActionsToolBar->setContextMenuPolicy(Qt::PreventContextMenu); #ifdef __APPLE__ mainActionsToolBar->setToolButtonStyle ( Qt::ToolButtonTextUnderIcon ); #else mainActionsToolBar->setToolButtonStyle ( Qt::ToolButtonTextBesideIcon ); #endif mainActionsToolBar->addAction(fileOpenAction); mainActionsToolBar->addAction(fileSaveProjectAction); mainActionsToolBar->addAction(closeProjectAction); mainActionsToolBar->addAction(undoAction); mainActionsToolBar->addAction(redoAction); if(this->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.dicomeditor")) { mainActionsToolBar->addAction(openDicomEditorAction); } if (imageNavigatorViewFound) { mainActionsToolBar->addAction(imageNavigatorAction); } mainWindow->addToolBar(mainActionsToolBar); #ifdef __APPLE__ mainWindow->setUnifiedTitleAndToolBarOnMac(true); #endif // ==== Window Menu ========================== QMenu* windowMenu = menuBar->addMenu("Window"); if (showNewWindowMenuItem) { windowMenu->addAction("&New Window", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onNewWindow())); windowMenu->addSeparator(); } QMenu* perspMenu = windowMenu->addMenu("&Open Perspective"); QMenu* viewMenu; if (showViewMenuItem) { viewMenu = windowMenu->addMenu("Show &View"); viewMenu->setObjectName("Show View"); } windowMenu->addSeparator(); resetPerspAction = windowMenu->addAction("&Reset Perspective", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onResetPerspective())); if(showClosePerspectiveMenuItem) closePerspAction = windowMenu->addAction("&Close Perspective", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onClosePerspective())); windowMenu->addSeparator(); windowMenu->addAction("&Preferences...", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onEditPreferences()), QKeySequence("CTRL+P")); // fill perspective menu berry::IPerspectiveRegistry* perspRegistry = window->GetWorkbench()->GetPerspectiveRegistry(); QActionGroup* perspGroup = new QActionGroup(menuBar); std::vector perspectives( perspRegistry->GetPerspectives()); bool skip = false; for (std::vector::iterator perspIt = perspectives.begin(); perspIt != perspectives.end(); ++perspIt) { // if perspectiveExcludeList is set, it contains the id-strings of perspectives, which // should not appear as an menu-entry in the perspective menu if (perspectiveExcludeList.size() > 0) { for (unsigned int i=0; iGetId()) { skip = true; break; } } if (skip) { skip = false; continue; } } QAction* perspAction = new berry::QtOpenPerspectiveAction(window, *perspIt, perspGroup); mapPerspIdToAction.insert(std::make_pair((*perspIt)->GetId(), perspAction)); } perspMenu->addActions(perspGroup->actions()); // sort elements (converting vector to map...) std::vector::const_iterator iter; std::map VDMap; skip = false; for (iter = viewDescriptors.begin(); iter != viewDescriptors.end(); ++iter) { // if viewExcludeList is set, it contains the id-strings of view, which // should not appear as an menu-entry in the menu if (viewExcludeList.size() > 0) { for (unsigned int i=0; iGetId()) { skip = true; break; } } if (skip) { skip = false; continue; } } if ((*iter)->GetId() == "org.blueberry.ui.internal.introview") continue; if ((*iter)->GetId() == "org.mitk.views.imagenavigator") continue; std::pair p( (*iter)->GetLabel(), (*iter)); VDMap.insert(p); } // ================================================== // ==== Perspective Toolbar ================================== QToolBar* qPerspectiveToolbar = new QToolBar; if (showPerspectiveToolbar) { qPerspectiveToolbar->addActions(perspGroup->actions()); mainWindow->addToolBar(qPerspectiveToolbar); } else delete qPerspectiveToolbar; // ==== View Toolbar ================================== QToolBar* qToolbar = new QToolBar; std::map::const_iterator MapIter; for (MapIter = VDMap.begin(); MapIter != VDMap.end(); ++MapIter) { berry::QtShowViewAction* viewAction = new berry::QtShowViewAction(window, (*MapIter).second); viewActions.push_back(viewAction); if(showViewMenuItem) viewMenu->addAction(viewAction); if (showViewToolbar) { qToolbar->addAction(viewAction); } } if (showViewToolbar) { mainWindow->addToolBar(qToolbar); } else delete qToolbar; QSettings settings(GetQSettingsFile(), QSettings::IniFormat); mainWindow->restoreState(settings.value("ToolbarPosition").toByteArray()); // ==================================================== // ===== Help menu ==================================== - QMenu* helpMenu = menuBar->addMenu("Help"); + QMenu* helpMenu = menuBar->addMenu("&Help"); helpMenu->addAction("&Welcome",this, SLOT(onIntro())); - helpMenu->addAction("&Contents", this, SLOT(onHelpContents())); - helpMenu->addAction("Context &Help",this, SLOT(onHelp()), QKeySequence("F1")); + helpMenu->addAction("&Open Help Perspective", this, SLOT(onHelpOpenHelpPerspective())); + helpMenu->addAction("&Context Help",this, SLOT(onHelp()), QKeySequence("F1")); helpMenu->addAction("&About",this, SLOT(onAbout())); // ===================================================== QStatusBar* qStatusBar = new QStatusBar(); //creating a QmitkStatusBar for Output on the QStatusBar and connecting it with the MainStatusBar QmitkStatusBar *statusBar = new QmitkStatusBar(qStatusBar); //disabling the SizeGrip in the lower right corner statusBar->SetSizeGripEnabled(false); QmitkProgressBar *progBar = new QmitkProgressBar(); qStatusBar->addPermanentWidget(progBar, 0); progBar->hide(); // progBar->AddStepsToDo(2); // progBar->Progress(1); mainWindow->setStatusBar(qStatusBar); QmitkMemoryUsageIndicatorView* memoryIndicator = new QmitkMemoryUsageIndicatorView(); qStatusBar->addPermanentWidget(memoryIndicator, 0); } void QmitkExtWorkbenchWindowAdvisor::PreWindowOpen() { berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); // show the shortcut bar and progress indicator, which are hidden by // default //configurer->SetShowPerspectiveBar(true); //configurer->SetShowFastViewBars(true); //configurer->SetShowProgressIndicator(true); // // add the drag and drop support for the editor area // configurer.addEditorAreaTransfer(EditorInputTransfer.getInstance()); // configurer.addEditorAreaTransfer(ResourceTransfer.getInstance()); // configurer.addEditorAreaTransfer(FileTransfer.getInstance()); // configurer.addEditorAreaTransfer(MarkerTransfer.getInstance()); // configurer.configureEditorAreaDropListener(new EditorAreaDropAdapter( // configurer.getWindow())); this->HookTitleUpdateListeners(configurer); menuPerspectiveListener = new PerspectiveListenerForMenu(this); configurer->GetWindow()->AddPerspectiveListener(menuPerspectiveListener); configurer->AddEditorAreaTransfer(QStringList("text/uri-list")); configurer->ConfigureEditorAreaDropListener(dropTargetListener); } void QmitkExtWorkbenchWindowAdvisor::PostWindowOpen() { // Force Rendering Window Creation on startup. berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); ctkPluginContext* context = QmitkCommonExtPlugin::getContext(); ctkServiceReference serviceRef = context->getServiceReference(); if (serviceRef) { mitk::IDataStorageService *dsService = context->getService(serviceRef); if (dsService) { mitk::IDataStorageReference::Pointer dsRef = dsService->GetDataStorage(); mitk::DataStorageEditorInput::Pointer dsInput(new mitk::DataStorageEditorInput(dsRef)); mitk::WorkbenchUtil::OpenEditor(configurer->GetWindow()->GetActivePage(),dsInput); } } } void QmitkExtWorkbenchWindowAdvisor::onIntro() { QmitkExtWorkbenchWindowAdvisorHack::undohack->onIntro(); } void QmitkExtWorkbenchWindowAdvisor::onHelp() { QmitkExtWorkbenchWindowAdvisorHack::undohack->onHelp(); } -void QmitkExtWorkbenchWindowAdvisor::onHelpContents() +void QmitkExtWorkbenchWindowAdvisor::onHelpOpenHelpPerspective() { - QmitkExtWorkbenchWindowAdvisorHack::undohack->onHelpContents(); + QmitkExtWorkbenchWindowAdvisorHack::undohack->onHelpOpenHelpPerspective(); } void QmitkExtWorkbenchWindowAdvisor::onAbout() { QmitkExtWorkbenchWindowAdvisorHack::undohack->onAbout(); } //-------------------------------------------------------------------------------- // Ugly hack from here on. Feel free to delete when command framework // and undo buttons are done. //-------------------------------------------------------------------------------- QmitkExtWorkbenchWindowAdvisorHack::QmitkExtWorkbenchWindowAdvisorHack() : QObject() { } QmitkExtWorkbenchWindowAdvisorHack::~QmitkExtWorkbenchWindowAdvisorHack() { } void QmitkExtWorkbenchWindowAdvisorHack::onUndo() { mitk::UndoModel* model = mitk::UndoController::GetCurrentUndoModel(); if (model) { if (mitk::VerboseLimitedLinearUndo* verboseundo = dynamic_cast( model )) { mitk::VerboseLimitedLinearUndo::StackDescription descriptions = verboseundo->GetUndoDescriptions(); if (descriptions.size() >= 1) { MITK_INFO << "Undo " << descriptions.front().second; } } model->Undo(); } else { MITK_ERROR << "No undo model instantiated"; } } void QmitkExtWorkbenchWindowAdvisorHack::onRedo() { mitk::UndoModel* model = mitk::UndoController::GetCurrentUndoModel(); if (model) { if (mitk::VerboseLimitedLinearUndo* verboseundo = dynamic_cast( model )) { mitk::VerboseLimitedLinearUndo::StackDescription descriptions = verboseundo->GetRedoDescriptions(); if (descriptions.size() >= 1) { MITK_INFO << "Redo " << descriptions.front().second; } } model->Redo(); } else { MITK_ERROR << "No undo model instantiated"; } } void QmitkExtWorkbenchWindowAdvisorHack::onImageNavigator() { // get ImageNavigatorView berry::IViewPart::Pointer imageNavigatorView = berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage()->FindView("org.mitk.views.imagenavigator"); if (imageNavigatorView) { bool isImageNavigatorVisible = berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage()->IsPartVisible(imageNavigatorView); if (isImageNavigatorVisible) { berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage()->HideView(imageNavigatorView); return; } } berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage()->ShowView("org.mitk.views.imagenavigator"); //berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage()->ResetPerspective(); } void QmitkExtWorkbenchWindowAdvisorHack::onEditPreferences() { QmitkPreferencesDialog _PreferencesDialog(QApplication::activeWindow()); _PreferencesDialog.exec(); } void QmitkExtWorkbenchWindowAdvisorHack::onQuit() { berry::PlatformUI::GetWorkbench()->Close(); } void QmitkExtWorkbenchWindowAdvisorHack::onResetPerspective() { berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage()->ResetPerspective(); } void QmitkExtWorkbenchWindowAdvisorHack::onClosePerspective() { berry::IWorkbenchPage::Pointer page = berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage(); page->ClosePerspective(page->GetPerspective(), true, true); } void QmitkExtWorkbenchWindowAdvisorHack::onNewWindow() { berry::PlatformUI::GetWorkbench()->OpenWorkbenchWindow(0); } void QmitkExtWorkbenchWindowAdvisorHack::onIntro() { bool hasIntro = berry::PlatformUI::GetWorkbench()->GetIntroManager()->HasIntro(); if (!hasIntro) { QRegExp reg("(.*)(\\n)*"); QRegExp reg2("(\\n)*(.*)"); QFile file(":/org.mitk.gui.qt.ext/index.html"); file.open(QIODevice::ReadOnly | QIODevice::Text); // Als Text-Datei nur zum Lesen öffnen QString text = QString(file.readAll()); file.close(); QString title = text; title.replace(reg, ""); title.replace(reg2, ""); std::cout << title.toStdString() << std::endl; QMessageBox::information(NULL, title, text, "Close"); } else { berry::PlatformUI::GetWorkbench()->GetIntroManager()->ShowIntro( berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow(), false); } } void QmitkExtWorkbenchWindowAdvisorHack::onHelp() { ctkPluginContext* context = QmitkCommonExtPlugin::getContext(); if (context == 0) { MITK_WARN << "Plugin context not set, unable to open context help"; return; } // Check if the org.blueberry.ui.qt.help plug-in is installed and started QList > plugins = context->getPlugins(); foreach(QSharedPointer p, plugins) { if (p->getSymbolicName() == "org.blueberry.ui.qt.help") { if (p->getState() != ctkPlugin::ACTIVE) { // try to activate the plug-in explicitly try { p->start(ctkPlugin::START_TRANSIENT); } catch (const ctkPluginException& pe) { MITK_ERROR << "Activating org.blueberry.ui.qt.help failed: " << pe.what(); return; } } } } ctkServiceReference eventAdminRef = context->getServiceReference(); ctkEventAdmin* eventAdmin = 0; if (eventAdminRef) { eventAdmin = context->getService(eventAdminRef); } if (eventAdmin == 0) { MITK_WARN << "ctkEventAdmin service not found. Unable to open context help"; } else { ctkEvent ev("org/blueberry/ui/help/CONTEXTHELP_REQUESTED"); eventAdmin->postEvent(ev); } } -void QmitkExtWorkbenchWindowAdvisorHack::onHelpContents() +void QmitkExtWorkbenchWindowAdvisorHack::onHelpOpenHelpPerspective() { berry::PlatformUI::GetWorkbench()->ShowPerspective("org.blueberry.perspectives.help", berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()); } void QmitkExtWorkbenchWindowAdvisorHack::onAbout() { QmitkAboutDialog* aboutDialog = new QmitkAboutDialog(QApplication::activeWindow(),NULL); aboutDialog->open(); } void QmitkExtWorkbenchWindowAdvisor::HookTitleUpdateListeners( berry::IWorkbenchWindowConfigurer::Pointer configurer) { // hook up the listeners to update the window title titlePartListener = new PartListenerForTitle(this); titlePerspectiveListener = new PerspectiveListenerForTitle(this); editorPropertyListener = new berry::PropertyChangeIntAdapter< QmitkExtWorkbenchWindowAdvisor>(this, &QmitkExtWorkbenchWindowAdvisor::PropertyChange); // configurer.getWindow().addPageListener(new IPageListener() { // public void pageActivated(IWorkbenchPage page) { // updateTitle(false); // } // // public void pageClosed(IWorkbenchPage page) { // updateTitle(false); // } // // public void pageOpened(IWorkbenchPage page) { // // do nothing // } // }); configurer->GetWindow()->AddPerspectiveListener(titlePerspectiveListener); configurer->GetWindow()->GetPartService()->AddPartListener(titlePartListener); } std::string QmitkExtWorkbenchWindowAdvisor::ComputeTitle() { berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); berry::IWorkbenchPage::Pointer currentPage = configurer->GetWindow()->GetActivePage(); berry::IEditorPart::Pointer activeEditor; if (currentPage) { activeEditor = lastActiveEditor.Lock(); } std::string title; //TODO Product // IProduct product = Platform.getProduct(); // if (product != null) { // title = product.getName(); // } // instead of the product name, we use a custom variable for now title = productName; if(showMitkVersionInfo) { title += std::string(" ") + MITK_VERSION_STRING; } if (showVersionInfo) { // add version informatioin QString versions = QString(" (ITK %1.%2.%3 VTK %4.%5.%6 Qt %7 MITK %8)") .arg(ITK_VERSION_MAJOR).arg(ITK_VERSION_MINOR).arg(ITK_VERSION_PATCH) .arg(VTK_MAJOR_VERSION).arg(VTK_MINOR_VERSION).arg(VTK_BUILD_VERSION) .arg(QT_VERSION_STR) .arg(MITK_VERSION_STRING); title += versions.toStdString(); } if (currentPage) { if (activeEditor) { lastEditorTitle = activeEditor->GetTitleToolTip(); if (!lastEditorTitle.empty()) title = lastEditorTitle + " - " + title; } berry::IPerspectiveDescriptor::Pointer persp = currentPage->GetPerspective(); std::string label = ""; if (persp) { label = persp->GetLabel(); } berry::IAdaptable* input = currentPage->GetInput(); if (input && input != wbAdvisor->GetDefaultPageInput()) { label = currentPage->GetLabel(); } if (!label.empty()) { title = label + " - " + title; } } title += " (Not for use in diagnosis or treatment of patients)"; return title; } void QmitkExtWorkbenchWindowAdvisor::RecomputeTitle() { berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); std::string oldTitle = configurer->GetTitle(); std::string newTitle = ComputeTitle(); if (newTitle != oldTitle) { configurer->SetTitle(newTitle); } } void QmitkExtWorkbenchWindowAdvisor::UpdateTitle(bool editorHidden) { berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); berry::IWorkbenchWindow::Pointer window = configurer->GetWindow(); berry::IEditorPart::Pointer activeEditor; berry::IWorkbenchPage::Pointer currentPage = window->GetActivePage(); berry::IPerspectiveDescriptor::Pointer persp; berry::IAdaptable* input = 0; if (currentPage) { activeEditor = currentPage->GetActiveEditor(); persp = currentPage->GetPerspective(); input = currentPage->GetInput(); } if (editorHidden) { activeEditor = 0; } // Nothing to do if the editor hasn't changed if (activeEditor == lastActiveEditor.Lock() && currentPage == lastActivePage.Lock() && persp == lastPerspective.Lock() && input == lastInput) { return; } if (!lastActiveEditor.Expired()) { lastActiveEditor.Lock()->RemovePropertyListener(editorPropertyListener); } lastActiveEditor = activeEditor; lastActivePage = currentPage; lastPerspective = persp; lastInput = input; if (activeEditor) { activeEditor->AddPropertyListener(editorPropertyListener); } RecomputeTitle(); } void QmitkExtWorkbenchWindowAdvisor::PropertyChange(berry::Object::Pointer /*source*/, int propId) { if (propId == berry::IWorkbenchPartConstants::PROP_TITLE) { if (!lastActiveEditor.Expired()) { std::string newTitle = lastActiveEditor.Lock()->GetPartName(); if (lastEditorTitle != newTitle) { RecomputeTitle(); } } } } void QmitkExtWorkbenchWindowAdvisor::SetPerspectiveExcludeList(std::vector v) { this->perspectiveExcludeList = v; } std::vector QmitkExtWorkbenchWindowAdvisor::GetPerspectiveExcludeList() { return this->perspectiveExcludeList; } void QmitkExtWorkbenchWindowAdvisor::SetViewExcludeList(std::vector v) { this->viewExcludeList = v; } std::vector QmitkExtWorkbenchWindowAdvisor::GetViewExcludeList() { return this->viewExcludeList; } void QmitkExtWorkbenchWindowAdvisor::PostWindowClose() { berry::IWorkbenchWindow::Pointer window = this->GetWindowConfigurer()->GetWindow(); QMainWindow* mainWindow = static_cast (window->GetShell()->GetControl()); QSettings settings(GetQSettingsFile(), QSettings::IniFormat); settings.setValue("ToolbarPosition", mainWindow->saveState()); } QString QmitkExtWorkbenchWindowAdvisor::GetQSettingsFile() const { QFileInfo settingsInfo = QmitkCommonExtPlugin::getContext()->getDataFile(QT_SETTINGS_FILENAME); return settingsInfo.canonicalFilePath(); } diff --git a/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.h b/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.h index c2c8d9ee64..75642fa30c 100644 --- a/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.h +++ b/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.h @@ -1,168 +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. ===================================================================*/ #ifndef QMITKEXTWORKBENCHWINDOWADVISOR_H_ #define QMITKEXTWORKBENCHWINDOWADVISOR_H_ #include #include #include #include #include #include #include #include class QAction; class QMenu; class MITK_QT_COMMON_EXT_EXPORT QmitkExtWorkbenchWindowAdvisor : public QObject, public berry::WorkbenchWindowAdvisor { Q_OBJECT public: QmitkExtWorkbenchWindowAdvisor(berry::WorkbenchAdvisor* wbAdvisor, berry::IWorkbenchWindowConfigurer::Pointer configurer); berry::ActionBarAdvisor::Pointer CreateActionBarAdvisor( berry::IActionBarConfigurer::Pointer configurer); void* CreateEmptyWindowContents(void* parent); void PostWindowCreate(); void PreWindowOpen(); void PostWindowOpen(); void PostWindowClose(); void ShowViewToolbar(bool show); void ShowPerspectiveToolbar(bool show); void ShowVersionInfo(bool show); void ShowMitkVersionInfo(bool show); void ShowViewMenuItem(bool show); void ShowNewWindowMenuItem(bool show); void ShowClosePerspectiveMenuItem(bool show); bool GetShowClosePerspectiveMenuItem(); //TODO should be removed when product support is here void SetProductName(const std::string& product); void SetWindowIcon(const std::string& wndIcon); void SetPerspectiveExcludeList(std::vector v); std::vector GetPerspectiveExcludeList(); void SetViewExcludeList(std::vector v); std::vector GetViewExcludeList(); protected slots: virtual void onIntro(); virtual void onHelp(); - virtual void onHelpContents(); + virtual void onHelpOpenHelpPerspective(); virtual void onAbout(); private: /** * Hooks the listeners needed on the window * * @param configurer */ void HookTitleUpdateListeners(berry::IWorkbenchWindowConfigurer::Pointer configurer); std::string ComputeTitle(); void RecomputeTitle(); QString GetQSettingsFile() const; /** * Updates the window title. Format will be: [pageInput -] * [currentPerspective -] [editorInput -] [workspaceLocation -] productName * @param editorHidden TODO */ void UpdateTitle(bool editorHidden); void PropertyChange(berry::Object::Pointer /*source*/, int propId); static QString QT_SETTINGS_FILENAME; berry::IPartListener::Pointer titlePartListener; berry::IPerspectiveListener::Pointer titlePerspectiveListener; berry::IPerspectiveListener::Pointer menuPerspectiveListener; berry::IPartListener::Pointer imageNavigatorPartListener; berry::IPropertyChangeListener::Pointer editorPropertyListener; friend struct berry::PropertyChangeIntAdapter; friend class PartListenerForTitle; friend class PerspectiveListenerForTitle; friend class PerspectiveListenerForMenu; friend class PartListenerForImageNavigator; berry::IEditorPart::WeakPtr lastActiveEditor; berry::IPerspectiveDescriptor::WeakPtr lastPerspective; berry::IWorkbenchPage::WeakPtr lastActivePage; std::string lastEditorTitle; berry::IAdaptable* lastInput; berry::WorkbenchAdvisor* wbAdvisor; bool showViewToolbar; bool showPerspectiveToolbar; bool showVersionInfo; bool showMitkVersionInfo; bool showViewMenuItem; bool showNewWindowMenuItem; bool showClosePerspectiveMenuItem; std::string productName; std::string windowIcon; // enables DnD on the editor area berry::IDropTargetListener::Pointer dropTargetListener; // stringlist for excluding perspectives from the perspective menu entry (e.g. Welcome Perspective) std::vector perspectiveExcludeList; // stringlist for excluding views from the menu entry std::vector viewExcludeList; // maps perspective ids to QAction objects std::map mapPerspIdToAction; // actions which will be enabled/disabled depending on the application state QList viewActions; QAction* fileSaveProjectAction; QAction* closeProjectAction; QAction* undoAction; QAction* redoAction; QAction* imageNavigatorAction; QAction* resetPerspAction; QAction* closePerspAction; QAction* openDicomEditorAction; }; #endif /*QMITKEXTWORKBENCHWINDOWADVISOR_H_*/ diff --git a/Plugins/org.mitk.gui.qt.ext/src/internal/QmitkExtWorkbenchWindowAdvisorHack.h b/Plugins/org.mitk.gui.qt.ext/src/internal/QmitkExtWorkbenchWindowAdvisorHack.h index c594cc84bd..e81302d99e 100644 --- a/Plugins/org.mitk.gui.qt.ext/src/internal/QmitkExtWorkbenchWindowAdvisorHack.h +++ b/Plugins/org.mitk.gui.qt.ext/src/internal/QmitkExtWorkbenchWindowAdvisorHack.h @@ -1,58 +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. ===================================================================*/ #include class ctkPluginContext; class QmitkPreferencesDialog; class QmitkExtWorkbenchWindowAdvisorHack : public QObject { Q_OBJECT public slots: void onUndo(); void onRedo(); void onImageNavigator(); void onEditPreferences(); void onQuit(); void onResetPerspective(); void onClosePerspective(); void onNewWindow(); void onIntro(); /** * @brief This slot is called if the user klicks the menu item "help->context help" or presses F1. * The help page is shown in a workbench editor. */ void onHelp(); - void onHelpContents(); + void onHelpOpenHelpPerspective(); /** * @brief This slot is called if the user clicks in help menu the about button */ void onAbout(); public: QmitkExtWorkbenchWindowAdvisorHack(); ~QmitkExtWorkbenchWindowAdvisorHack(); static QmitkExtWorkbenchWindowAdvisorHack* undohack; }; diff --git a/Plugins/org.mitk.gui.qt.extapplication/CMakeLists.txt b/Plugins/org.mitk.gui.qt.extapplication/CMakeLists.txt index 64a92f7cab..50c9d87cc7 100644 --- a/Plugins/org.mitk.gui.qt.extapplication/CMakeLists.txt +++ b/Plugins/org.mitk.gui.qt.extapplication/CMakeLists.txt @@ -1,6 +1,13 @@ +set(QT_USE_QTWEBKIT TRUE) +include(${QT_USE_FILE}) + +if(QT_QTWEBKIT_FOUND) + add_definitions(-DQT_WEBKIT) +endif(QT_QTWEBKIT_FOUND) + project(org_mitk_gui_qt_extapplication) MACRO_CREATE_MITK_CTK_PLUGIN( EXPORT_DIRECTIVE MITK_QT_EXTAPP EXPORTED_INCLUDE_SUFFIXES src ) diff --git a/Plugins/org.mitk.gui.qt.extapplication/documentation/UserManual/QmitkExtapplicationUserManual.dox b/Plugins/org.mitk.gui.qt.extapplication/documentation/UserManual/QmitkExtapplicationUserManual.dox deleted file mode 100644 index dc03786879..0000000000 --- a/Plugins/org.mitk.gui.qt.extapplication/documentation/UserManual/QmitkExtapplicationUserManual.dox +++ /dev/null @@ -1,19 +0,0 @@ -/** -\bundlemainpage{org_extapplication} Using The Ext Application - -\section QMitkExtApplicationManualOverview What is the Ext App - -The MITK Ext Application is used by developers. As such the kind and number of views it contains is highly variable and dependent on the specific build. Typically it contains no special perspectives and whatever views the developer deemed desirable. Be aware, that it may contain views which are work in progress and may behave erratically. - -If you have been given such an executable by someone, please refer to the appropriate section of the online documentation for up to date usage information on any module. -\isHtml -\ref ModuleListPage -\isHtmlend - -If you are using a nightly installer, the Ext Application will contain nearly all views available in MITK and as such most likely will seem confusing. Again the list of modules might be a good starting point if you want to have a rough idea of what could be of interest to you. - -\isHtml -For a basic guide to MITK see \ref MITKUserManualPage . -\isHtmlend - -*/ diff --git a/Plugins/org.mitk.gui.qt.extapplication/documentation/UserManual/QmitkMITKWorkbenchUserManual.dox b/Plugins/org.mitk.gui.qt.extapplication/documentation/UserManual/QmitkMITKWorkbenchUserManual.dox new file mode 100644 index 0000000000..f941fe82be --- /dev/null +++ b/Plugins/org.mitk.gui.qt.extapplication/documentation/UserManual/QmitkMITKWorkbenchUserManual.dox @@ -0,0 +1,17 @@ +/** +\page org_mitkworkbench Using The MITK Workbench + +\section QMitkMitkWorkbenchManualOverview What is the MITK Workbench + +The MITK Workbench is used by developers. As such the kind and number of views it contains is highly variable and dependent on the specific build. Typically it contains no special perspectives and whatever views the developer deemed desirable. Be aware, that it may contain views which are work in progress and may behave erratically. + +If you have been given such an executable by someone, please refer to the appropriate section of the online documentation for up to date usage information on any module. + +Nightly online documentation + + +If you are using a nightly installer, the MITK Workbench will contain nearly all views available in MITK and as such most likely will seem confusing. Again the list of modules might be a good starting point if you want to have a rough idea of what could be of interest to you. + +For a basic guide to MITK see \ref MITKUserManualPage . + +*/ diff --git a/Plugins/org.mitk.gui.qt.extapplication/documentation/doxygen/modules.dox b/Plugins/org.mitk.gui.qt.extapplication/documentation/doxygen/modules.dox index 468fe60327..4172a9d45b 100644 --- a/Plugins/org.mitk.gui.qt.extapplication/documentation/doxygen/modules.dox +++ b/Plugins/org.mitk.gui.qt.extapplication/documentation/doxygen/modules.dox @@ -1,16 +1,16 @@ /** - \defgroup org_mitk_gui_qt_extapplication org.mitk.gui.qt.extapplication + \defgroup org_mitk_gui_qt_mitkworkbench org.mitk.gui.qt.mitkworkbench \ingroup MITKPlugins - \brief This plug-in is responsible for initializing the "ExtApp". + \brief This plug-in is responsible for initializing the MITK Workbench. */ /** - \defgroup org_mitk_gui_qt_extapplication_internal Internal - \ingroup org_mitk_gui_qt_extapplication + \defgroup org_mitk_gui_qt_mitkworkbench_internal Internal + \ingroup org_mitk_gui_qt_mitkworkbench - \brief This subcategory includes the internal classes of the org.mitk.gui.qt.extapplication plugin. Other + \brief This subcategory includes the internal classes of the org.mitk.gui.qt.mitkworkbench 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.extapplication/files.cmake b/Plugins/org.mitk.gui.qt.extapplication/files.cmake index 77328988e7..e7bcaae435 100644 --- a/Plugins/org.mitk.gui.qt.extapplication/files.cmake +++ b/Plugins/org.mitk.gui.qt.extapplication/files.cmake @@ -1,40 +1,49 @@ set(SRC_CPP_FILES ) set(INTERNAL_CPP_FILES QmitkExtApplication.cpp QmitkExtApplicationPlugin.cpp QmitkExtAppWorkbenchAdvisor.cpp - QmitkExtDefaultPerspective.cpp + QmitkMitkWorkbenchIntroPart.cpp + perspectives/QmitkEditorPerspective.cpp + perspectives/QmitkExtDefaultPerspective.cpp ) set(MOC_H_FILES src/internal/QmitkExtApplication.h src/internal/QmitkExtApplicationPlugin.h - src/internal/QmitkExtDefaultPerspective.h + src/internal/QmitkMitkWorkbenchIntroPart.h + src/internal/perspectives/QmitkEditorPerspective.h + src/internal/perspectives/QmitkExtDefaultPerspective.h +) + +set(UI_FILES + src/internal/perspectives/QmitkWelcomeScreenViewControls.ui ) 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_research.xpm ) set(QRC_FILES # uncomment the following line if you want to use Qt resources # resources/QmitkExtApplication.qrc +resources/welcome/QmitkWelcomeScreenView.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.extapplication/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.extapplication/manifest_headers.cmake index 0462ac1ab9..b951506aa9 100644 --- a/Plugins/org.mitk.gui.qt.extapplication/manifest_headers.cmake +++ b/Plugins/org.mitk.gui.qt.extapplication/manifest_headers.cmake @@ -1,5 +1,5 @@ -set(Plugin-Name "MITK Ext Application") +set(Plugin-Name "MITK Workbench") 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.ext) diff --git a/Plugins/org.mitk.gui.qt.extapplication/plugin.xml b/Plugins/org.mitk.gui.qt.extapplication/plugin.xml index a9777eeb61..4cb8e70b51 100644 --- a/Plugins/org.mitk.gui.qt.extapplication/plugin.xml +++ b/Plugins/org.mitk.gui.qt.extapplication/plugin.xml @@ -1,18 +1,33 @@ + + + + + + icon="resources/icon_research.xpm"> + + \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/QmitkWelcomeScreenView.qrc b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/QmitkWelcomeScreenView.qrc new file mode 100644 index 0000000000..c24d388671 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/QmitkWelcomeScreenView.qrc @@ -0,0 +1,12 @@ + + + style.css + function.js + pics/background.jpg + pics/popup_bttn_close.png + pics/experimental.png + pics/button_mitka.png + pics/button_mitk.png + mitkworkbenchwelcomeview.html + + diff --git a/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/function.js b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/function.js new file mode 100644 index 0000000000..513330f719 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/function.js @@ -0,0 +1,257 @@ +// 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("MITK Downloads & News"); + +// add the MITK-link to your module +var moduleLinks = new Array("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("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("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); + +// add the description for your module. The description is displayed in a PopUp-window. +var moduleDescriptions = new Array("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.extapplication/resources/welcome/mitkworkbenchwelcomeview.html b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/mitkworkbenchwelcomeview.html new file mode 100644 index 0000000000..eb16e88264 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/mitkworkbenchwelcomeview.html @@ -0,0 +1,37 @@ + + + + + + MITK Workbench + + + + + + +
+ + +
+ +

Welcome to MITK Workbench!

+ + +
+ +
+ This application was developed at the German Cancer Research Center (DKFZ). The software is developed on the basis of the well established, free open source software toolkit The Medical Imaging Interaction Toolkit (MITK). For additional information check the help pages or our website www.mitk.org. +

Instructions:

+
+ +
+ + +
+ +
+ +
+ + diff --git a/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/background.jpg b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/background.jpg new file mode 100644 index 0000000000..c93f36df92 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/background.jpg differ diff --git a/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/button_mitk.png b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/button_mitk.png new file mode 100644 index 0000000000..821e041d36 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/button_mitk.png differ diff --git a/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/button_mitka.png b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/button_mitka.png new file mode 100644 index 0000000000..baf4f14a46 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/button_mitka.png differ diff --git a/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/experimental.png b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/experimental.png new file mode 100644 index 0000000000..b05093ea2e Binary files /dev/null and b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/experimental.png differ diff --git a/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/popup_bg.png b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/popup_bg.png new file mode 100644 index 0000000000..9fef73a742 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/popup_bg.png differ diff --git a/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/popup_bg_bottom.png b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/popup_bg_bottom.png new file mode 100644 index 0000000000..f181fb97e2 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/popup_bg_bottom.png differ diff --git a/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/popup_bg_middle.png b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/popup_bg_middle.png new file mode 100644 index 0000000000..fd477da298 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/popup_bg_middle.png differ diff --git a/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/popup_bg_top.png b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/popup_bg_top.png new file mode 100644 index 0000000000..99424cbbb7 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/popup_bg_top.png differ diff --git a/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/popup_bttn_close.png b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/popup_bttn_close.png new file mode 100644 index 0000000000..279e340beb Binary files /dev/null and b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/popup_bttn_close.png differ diff --git a/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/shadow.png b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/shadow.png new file mode 100644 index 0000000000..83eda7b89e Binary files /dev/null and b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/pics/shadow.png differ diff --git a/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/style.css b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/style.css new file mode 100644 index 0000000000..55dc94a56b --- /dev/null +++ b/Plugins/org.mitk.gui.qt.extapplication/resources/welcome/style.css @@ -0,0 +1,174 @@ +@charset "utf-8"; + +body{ + margin:0px 0px; + padding: 0px 0px; +} + +h1{ + margin:0px 0px; + padding: 0px 0px; + font-family:"Times New Roman", Times, serif; + color:#333; +} + +img{border:none;} + +#screen{ + width:100%; + min-height:1060px; + height:100%; + padding-top:15px; + background-color:#888888; + background-image:url(pics/background.jpg); + background-repeat:repeat-x; +} + +#welcome{ + min-width:150px; + max-width:690px; + margin: 0 auto; + padding-left:5px; + font-family:"Times New Roman", Times, serif; + color:#333; +} + +#welcomeText{ + margin-top:15px; + margin-bottom:15px; + z-index:1; +} + +#bttnField{ + min-width:150px; + max-width:690px; + margin: 0 auto; + padding-left:5px; +} + +.bttnWrap{ + position:relative; + float:left; + width:140px; + height:190px; + margin-right:32px; + margin-top:5px; + z-index:2; +} + +.modBttn{ + margin-bottom:8px; + border: solid 2px #000; + -webkit-box-shadow: 5px 5px 6px rgba(0,0,0,0.6); +} + +.modBttn:hover{ + border: solid 2px #FFF; + cursor:pointer; + -webkit-box-shadow: none; +} + +.modBttnHover{ + margin-bottom:8px; + border: solid 2px #FFF; + cursor:pointer; + -webkit-box-shadow: none; +} + +.txtLink{ + font-family:"Times New Roman", Times, serif; + font-size:16px; + font-weight:bold; + text-decoration:none; + cursor:pointer; + color:#333; +} + +.txtLink:hover{ + text-decoration:underline; +} + +.popUpLink{ + font-family:"Times New Roman", Times, serif; + font-size:14px; + font-weight:normal; + line-height:16px; + color:#333; +} + +.popUpLink:hover{ + text-decoration:underline; + cursor:pointer; +} + +#popup{ + position:fixed; + max-width:690px; + min-width:150px; + background-color:#000000; + opacity: 0.8; + -webkit-border-radius: 1em; + z-index:3; + font-family:Arial, Helvetica, sans-serif; + color:#FFF; +} + +#bttnClose{ + position:relative; + right:10px; + top:10px; + cursor:pointer; +} + +#contHeadline{ + max-width:690px; + min-width:150px; + margin-left:10px; + margin-right:10px; + font-weight:bold; + font-size:14px; + text-align:left; +} + +#contDescription{ + max-width:690px; + min-width:150px; + margin-top:15px; + margin-bottom:15px; + margin-left:10px; + margin-right:10px; + line-height:21px; + font-family:Arial, Helvetica, sans-serif; + font-weight:normal; + font-size:14px; + text-align:left; +} + +#contModLink{ + max-width:690px; + min-width:150px; + height:50px; + margin-left:10px; + margin-right:10px; + text-align:left; +} + +.moduleLink{ + font-family:Arial, Helvetica, sans-serif; + color:#FFF; +} + +.expPic{ + margin-top:-126px; +} + +.clearfloat{clear:both;} + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkExtApplicationPlugin.cpp b/Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkExtApplicationPlugin.cpp index 47786d687d..c2411123d7 100644 --- a/Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkExtApplicationPlugin.cpp +++ b/Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkExtApplicationPlugin.cpp @@ -1,84 +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 "QmitkExtApplicationPlugin.h" -#include "QmitkExtDefaultPerspective.h" +#include "perspectives/QmitkExtDefaultPerspective.h" +#include "perspectives/QmitkEditorPerspective.h" +#include "QmitkMitkWorkbenchIntroPart.h" #include "QmitkExtApplication.h" #include #include #include #include #include #include #include QmitkExtApplicationPlugin* QmitkExtApplicationPlugin::inst = 0; QmitkExtApplicationPlugin::QmitkExtApplicationPlugin() { inst = this; } QmitkExtApplicationPlugin::~QmitkExtApplicationPlugin() { } QmitkExtApplicationPlugin* QmitkExtApplicationPlugin::GetDefault() { return inst; } void QmitkExtApplicationPlugin::start(ctkPluginContext* context) { berry::AbstractUICTKPlugin::start(context); this->context = context; BERRY_REGISTER_EXTENSION_CLASS(QmitkExtDefaultPerspective, context); + BERRY_REGISTER_EXTENSION_CLASS(QmitkEditorPerspective, context); + BERRY_REGISTER_EXTENSION_CLASS(QmitkMitkWorkbenchIntroPart, context); BERRY_REGISTER_EXTENSION_CLASS(QmitkExtApplication, context); ctkServiceReference cmRef = context->getServiceReference(); ctkConfigurationAdmin* configAdmin = 0; if (cmRef) { configAdmin = context->getService(cmRef); } // Use the CTK Configuration Admin service to configure the BlueBerry help system if (configAdmin) { ctkConfigurationPtr conf = configAdmin->getConfiguration("org.blueberry.services.help", QString()); ctkDictionary helpProps; helpProps.insert("homePage", "qthelp://org.mitk.gui.qt.extapplication/bundle/index.html"); conf->update(helpProps); context->ungetService(cmRef); } else { MITK_WARN << "Configuration Admin service unavailable, cannot set home page url."; } } ctkPluginContext* QmitkExtApplicationPlugin::GetPluginContext() const { return context; } Q_EXPORT_PLUGIN2(org_mitk_gui_qt_extapplication, QmitkExtApplicationPlugin) diff --git a/Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkMitkWorkbenchIntroPart.cpp b/Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkMitkWorkbenchIntroPart.cpp new file mode 100644 index 0000000000..8e90bca52e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkMitkWorkbenchIntroPart.cpp @@ -0,0 +1,203 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY 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 "QmitkMitkWorkbenchIntroPart.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#ifdef QT_WEBKIT +#include +#include +#endif +#include +#include +#include +#include +#include +#include + +#include "QmitkExtApplicationPlugin.h" +#include "mitkDataStorageEditorInput.h" +#include + +QmitkMitkWorkbenchIntroPart::QmitkMitkWorkbenchIntroPart() + : m_Controls(NULL) +{ + berry::IPreferences::Pointer workbenchPrefs = QmitkExtApplicationPlugin::GetDefault()->GetPreferencesService()->GetSystemPreferences(); + workbenchPrefs->PutBool(berry::WorkbenchPreferenceConstants::SHOW_INTRO, true); + workbenchPrefs->Flush(); +} + +QmitkMitkWorkbenchIntroPart::~QmitkMitkWorkbenchIntroPart() +{ + // if the workbench is not closing (that means, welcome screen was closed explicitly), set "Show_intro" false + if (!this->GetIntroSite()->GetPage()->GetWorkbenchWindow()->GetWorkbench()->IsClosing()) + { + berry::IPreferences::Pointer workbenchPrefs = QmitkExtApplicationPlugin::GetDefault()->GetPreferencesService()->GetSystemPreferences(); + workbenchPrefs->PutBool(berry::WorkbenchPreferenceConstants::SHOW_INTRO, false); + workbenchPrefs->Flush(); + } + else + { + berry::IPreferences::Pointer workbenchPrefs = QmitkExtApplicationPlugin::GetDefault()->GetPreferencesService()->GetSystemPreferences(); + workbenchPrefs->PutBool(berry::WorkbenchPreferenceConstants::SHOW_INTRO, true); + workbenchPrefs->Flush(); + } + + // if workbench is not closing (Just welcome screen closing), open last used perspective + if (this->GetIntroSite()->GetPage()->GetPerspective()->GetId() + == "org.mitk.mitkworkbench.perspectives.editor" && !this->GetIntroSite()->GetPage()->GetWorkbenchWindow()->GetWorkbench()->IsClosing()) + { + berry::IPerspectiveDescriptor::Pointer perspective = this->GetIntroSite()->GetWorkbenchWindow()->GetWorkbench()->GetPerspectiveRegistry()->FindPerspectiveWithId("org.mitk.mitkworkbench.perspectives.editor"); + if (perspective) + { + this->GetIntroSite()->GetPage()->SetPerspective(perspective); + } + } + +} + + +void QmitkMitkWorkbenchIntroPart::CreateQtPartControl(QWidget* parent) +{ + if (!m_Controls) + { + // create GUI widgets + m_Controls = new Ui::QmitkWelcomeScreenViewControls; + m_Controls->setupUi(parent); +#ifdef QT_WEBKIT + + // create a QWebView as well as a QWebPage and QWebFrame within the QWebview + m_view = new QWebView(parent); + m_view->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); + + QUrl urlQtResource(QString("qrc:/org.mitk.gui.qt.welcomescreen/mitkworkbenchwelcomeview.html"), QUrl::TolerantMode ); + m_view->load( urlQtResource ); + + // adds the webview as a widget + parent->layout()->addWidget(m_view); + this->CreateConnections(); +#else + parent->layout()->addWidget(new QLabel("

Please install Qt with the WebKit option to see cool pictures!

")); +#endif + } +} + +#ifdef QT_WEBKIT +void QmitkMitkWorkbenchIntroPart::CreateConnections() +{ + if ( m_Controls ) + { + connect( (QObject*)(m_view->page()), SIGNAL(linkClicked(const QUrl& )), this, SLOT(DelegateMeTo(const QUrl& )) ); + } +} + + +void QmitkMitkWorkbenchIntroPart::DelegateMeTo(const QUrl& showMeNext) +{ + QString scheme = showMeNext.scheme(); + QByteArray urlHostname = showMeNext.encodedHost(); + QByteArray urlPath = showMeNext.encodedPath(); + QByteArray dataset = showMeNext.encodedQueryItemValue("dataset"); + QByteArray clear = showMeNext.encodedQueryItemValue("clear"); + + if (scheme.isEmpty()) MITK_INFO << " empty scheme of the to be delegated link" ; + + // if the scheme is set to mitk, it is to be tested which action should be applied + if (scheme.contains(QString("mitk")) ) + { + if(urlPath.isEmpty() ) MITK_INFO << " mitk path is empty " ; + + // searching for the perspective keyword within the host name + if(urlHostname.contains(QByteArray("perspectives")) ) + { + // the simplified method removes every whitespace + // ( whitespace means any character for which the standard C++ isspace() method returns true) + urlPath = urlPath.simplified(); + QString tmpPerspectiveId(urlPath.data()); + tmpPerspectiveId.replace(QString("/"), QString("") ); + std::string perspectiveId = tmpPerspectiveId.toStdString(); + + // is working fine as long as the perspective id is valid, if not the application crashes + GetIntroSite()->GetWorkbenchWindow()->GetWorkbench()->ShowPerspective(perspectiveId, GetIntroSite()->GetWorkbenchWindow() ); + + // search the Workbench for opened StdMultiWidgets to ensure the focus does not stay on the welcome screen and is switched to + // an StdMultiWidget if one available + mitk::IDataStorageService::Pointer service = + berry::Platform::GetServiceRegistry().GetServiceById(mitk::IDataStorageService::ID); + berry::IEditorInput::Pointer editorInput; + editorInput = new mitk::DataStorageEditorInput( service->GetActiveDataStorage() ); + + // the solution is not clean, but the dependency to the StdMultiWidget was removed in order to fix a crash problem + // as described in Bug #11715 + // This is the correct way : use the static string ID variable + // berry::IEditorPart::Pointer editor = GetIntroSite()->GetPage()->FindEditors( editorInput, QmitkStdMultiWidgetEditor::EDITOR_ID ); + // QuickFix: we use the same string for an local variable + const std::string stdEditorID = "org.mitk.editors.stdmultiwidget"; + + // search for opened StdMultiWidgetEditors + std::vector editorList = GetIntroSite()->GetPage()->FindEditors( editorInput, stdEditorID, 1 ); + + // if an StdMultiWidgetEditor open was found, give focus to it + if(editorList.size()) + { + GetIntroSite()->GetPage()->Activate( editorList[0]->GetPart(true) ); + } + + } + } + // if the scheme is set to http, by default no action is performed, if an external webpage needs to be + // shown it should be implemented below + else if (scheme.contains(QString("http")) ) + { + QDesktopServices::openUrl(showMeNext); +// m_view->load( ) ; + } + else if(scheme.contains("qrc")) + { + m_view->load(showMeNext); + } + +} + +#endif + +void QmitkMitkWorkbenchIntroPart::StandbyStateChanged(bool standby) +{ + +} + + +void QmitkMitkWorkbenchIntroPart::SetFocus() +{ + +} diff --git a/Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkMitkWorkbenchIntroPart.h b/Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkMitkWorkbenchIntroPart.h new file mode 100644 index 0000000000..06db8a2e27 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkMitkWorkbenchIntroPart.h @@ -0,0 +1,93 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#ifndef QMITKWORKBENCHINTROPART_H_ +#define QMITKWORKBENCHINTROPART_H_ + +#include + +#include +#include + + +/** + * \ingroup org_mitk_gui_qt_welcomescreen_internal + * \brief QmitkMitkWorkbenchIntroPart + * The WelcomeView Module is an helpful feature to people new to MITK. The main idea is to provide first + * information about the MITK Workbench. + * The WelcomeView is realized by making use of the QTWebKit Module. The Qt WebKit module + * provides an HTML browser engine that makes it easy to embed web content into native applications, and to enhance + * web content with native controls. + * For the welcome view of the application the QWebView, QWebPage classes have been used. The shown WelcomeView + * html start page is styled by an external css stylesheet. The required resources as well as the html pages are integrated + * into the QtResource system. The QT resource system allows the storage of files like html pages, css pages, jpgs etc. + * as binaries within the executable. + * This minimizes the risk of loosing resource files as well as the risk of getting files deleted. In order to use the Qt + * resource system the resource files have to be added to the associated qrt resource file list. + * + * The foundation is set to design more complex html pages. The Q::WebPage gives options to set a + * LinkDelegationPolicy. The used policy defines how links to external or internal resources are handled. To fit our needs + * the delegate all links policy is used. This requires all external as well as internal links of the html pages to be handle + * explicitly. In order to change mitk working modes (perspectives) a mitk url scheme has been designed. The url scheme + * is set to mitk. The url host provides information about what's next to do. In our case, the case of switching to a + * particular working mode the host is set to perspectives. The followed path provides information about the perspective id. + * (e.g. mitk//::mitk.perspectives/org.mitk.qt.defaultperspective) The the generic design of the mitk url scheme allows to + * execute other task depending on the mitk url host. + * \sa QmitkWelcomePage Editor + */ + +class QWebView ; + +class QmitkMitkWorkbenchIntroPart : public berry::QtIntroPart +{ + +// this is needed for all Qt objects that should have a MOC object (everything that derives from QObject) + Q_OBJECT + +public: + + QmitkMitkWorkbenchIntroPart(); + QmitkMitkWorkbenchIntroPart(const QmitkMitkWorkbenchIntroPart& other) + { + Q_UNUSED(other) + throw std::runtime_error("Copy constructor not implemented"); + } + ~QmitkMitkWorkbenchIntroPart(); + + + virtual void CreateQtPartControl(QWidget *parent); + + void StandbyStateChanged(bool standby); + + void SetFocus(); +#ifdef QT_WEBKIT + + virtual void CreateConnections(); + + +protected slots: + + + void DelegateMeTo(const QUrl& ShowMeNext); +#endif +protected: + + Ui::QmitkWelcomeScreenViewControls* m_Controls; + QWebView* m_view; +}; + +#endif /* QMITKWORKBENCHINTROPART_H_ */ diff --git a/Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkExtDefaultPerspective.h b/Plugins/org.mitk.gui.qt.extapplication/src/internal/perspectives/QmitkEditorPerspective.cpp old mode 100755 new mode 100644 similarity index 55% copy from Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkExtDefaultPerspective.h copy to Plugins/org.mitk.gui.qt.extapplication/src/internal/perspectives/QmitkEditorPerspective.cpp index 48e98aae9f..6c787290a9 --- a/Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkExtDefaultPerspective.h +++ b/Plugins/org.mitk.gui.qt.extapplication/src/internal/perspectives/QmitkEditorPerspective.cpp @@ -1,36 +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. ===================================================================*/ +#include "QmitkEditorPerspective.h" -#ifndef QMITKEXTDEFAULTPERSPECTIVE_H_ -#define QMITKEXTDEFAULTPERSPECTIVE_H_ - -#include - -class QmitkExtDefaultPerspective : public QObject, public berry::IPerspectiveFactory +void QmitkEditorPerspective::CreateInitialLayout(berry::IPageLayout::Pointer /*layout*/) { - Q_OBJECT - Q_INTERFACES(berry::IPerspectiveFactory) - -public: - - QmitkExtDefaultPerspective(); - - void CreateInitialLayout(berry::IPageLayout::Pointer layout); - -}; - -#endif /* QMITKEXTDEFAULTPERSPECTIVE_H_ */ +} diff --git a/Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkExtDefaultPerspective.h b/Plugins/org.mitk.gui.qt.extapplication/src/internal/perspectives/QmitkEditorPerspective.h old mode 100755 new mode 100644 similarity index 56% copy from Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkExtDefaultPerspective.h copy to Plugins/org.mitk.gui.qt.extapplication/src/internal/perspectives/QmitkEditorPerspective.h index 48e98aae9f..83496d942f --- a/Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkExtDefaultPerspective.h +++ b/Plugins/org.mitk.gui.qt.extapplication/src/internal/perspectives/QmitkEditorPerspective.h @@ -1,36 +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. ===================================================================*/ -#ifndef QMITKEXTDEFAULTPERSPECTIVE_H_ -#define QMITKEXTDEFAULTPERSPECTIVE_H_ +#ifndef QMITKEDITORPERSPECTIVE_H_ +#define QMITKEDITORPERSPECTIVE_H_ #include -class QmitkExtDefaultPerspective : public QObject, public berry::IPerspectiveFactory +class QmitkEditorPerspective : public QObject, public berry::IPerspectiveFactory { Q_OBJECT Q_INTERFACES(berry::IPerspectiveFactory) - -public: - QmitkExtDefaultPerspective(); +public: - void CreateInitialLayout(berry::IPageLayout::Pointer layout); + QmitkEditorPerspective() {} + QmitkEditorPerspective(const QmitkEditorPerspective& other) + { + Q_UNUSED(other) + throw std::runtime_error("Copy constructor not implemented"); + } + ~QmitkEditorPerspective() {} + void CreateInitialLayout(berry::IPageLayout::Pointer /*layout*/); }; -#endif /* QMITKEXTDEFAULTPERSPECTIVE_H_ */ +#endif /* QMITKEDITORPERSPECTIVE_H_ */ diff --git a/Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkExtDefaultPerspective.cpp b/Plugins/org.mitk.gui.qt.extapplication/src/internal/perspectives/QmitkExtDefaultPerspective.cpp old mode 100755 new mode 100644 similarity index 100% rename from Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkExtDefaultPerspective.cpp rename to Plugins/org.mitk.gui.qt.extapplication/src/internal/perspectives/QmitkExtDefaultPerspective.cpp diff --git a/Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkExtDefaultPerspective.h b/Plugins/org.mitk.gui.qt.extapplication/src/internal/perspectives/QmitkExtDefaultPerspective.h old mode 100755 new mode 100644 similarity index 100% rename from Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkExtDefaultPerspective.h rename to Plugins/org.mitk.gui.qt.extapplication/src/internal/perspectives/QmitkExtDefaultPerspective.h diff --git a/Modules/USUI/Qmitk/QmitkUSDeviceListWidgetControls.ui b/Plugins/org.mitk.gui.qt.extapplication/src/internal/perspectives/QmitkWelcomeScreenViewControls.ui similarity index 61% rename from Modules/USUI/Qmitk/QmitkUSDeviceListWidgetControls.ui rename to Plugins/org.mitk.gui.qt.extapplication/src/internal/perspectives/QmitkWelcomeScreenViewControls.ui index 4d36c2bb5e..4a7cda1314 100644 --- a/Modules/USUI/Qmitk/QmitkUSDeviceListWidgetControls.ui +++ b/Plugins/org.mitk.gui.qt.extapplication/src/internal/perspectives/QmitkWelcomeScreenViewControls.ui @@ -1,31 +1,34 @@ - QmitkUSDeviceListWidgetControls - + QmitkWelcomeScreenViewControls + 0 0 - 323 - 231 + 458 + 398 0 0 - QmitkUSDeviceListWidget + QmitkTemplate + + 0 + - + diff --git a/Plugins/org.mitk.gui.qt.igtexamples/documentation/UserManual/Manual.dox b/Plugins/org.mitk.gui.qt.igtexamples/documentation/UserManual/Manual.dox index 13d7f57fd2..116b47b88d 100644 --- a/Plugins/org.mitk.gui.qt.igtexamples/documentation/UserManual/Manual.dox +++ b/Plugins/org.mitk.gui.qt.igtexamples/documentation/UserManual/Manual.dox @@ -1,12 +1,12 @@ /** -\bundlemainpage{org_mitk_gui_qt_igtexample} IGT Examples +\page org_mitk_gui_qt_igtexample IGT Examples This bundle includes views with examples and help applications for IGT. The different views are described on the pages below:
  • \subpage org_igttrackinglab
  • \subpage org_imageguidedtherapytutorial
*/ diff --git a/Plugins/org.mitk.gui.qt.igttracking/documentation/UserManual/Manual.dox b/Plugins/org.mitk.gui.qt.igttracking/documentation/UserManual/Manual.dox index fe5b5c39b4..6ac68844cb 100644 --- a/Plugins/org.mitk.gui.qt.igttracking/documentation/UserManual/Manual.dox +++ b/Plugins/org.mitk.gui.qt.igttracking/documentation/UserManual/Manual.dox @@ -1,15 +1,15 @@ /** -\bundlemainpage{org_mitk_gui_qt_igttracking} IGT Tracking +\page org_mitk_gui_qt_igttracking IGT Tracking This bundle offers basic tracking functionalities. This includes connecting to a tracking system, logging and recording of tracking data, managing tracking tools and playing recorded tracking data. The bundle includes different views, which are described in different pages in detail:
    -
  • \subpage org_igttrackingtoolbox : Allows for connecting to a tracking system and logging/recording of the tracked data. -
  • \subpage org_igtnavigationtoolmanager : Navigation Tool Manager: This view offers functionality to manage tool storages. Each tool storage holds a preconfigured tool collection. Once saved you can load a tool storage in the Tracking Toolbox and don't need to add every tool seperately. -
  • \subpage org_navigationdataplayer : Navigation Data Player: Plays navigation data which was recorded with the Tracking Toolbox for example. +
  • \subpage org_mitk_views_igttrackingtoolbox : Allows for connecting to a tracking system and logging/recording of the tracked data. +
  • \subpage org_mitk_views_igtnavigationtoolmanager : Navigation Tool Manager: This view offers functionality to manage tool storages. Each tool storage holds a preconfigured tool collection. Once saved you can load a tool storage in the Tracking Toolbox and don't need to add every tool seperately. +
  • \subpage org_mitk_views_navigationdataplayer : Navigation Data Player: Plays navigation data which was recorded with the Tracking Toolbox for example.
*/ diff --git a/Plugins/org.mitk.gui.qt.igttracking/documentation/UserManual/QmitkMITKIGTNavigationToolManager.dox b/Plugins/org.mitk.gui.qt.igttracking/documentation/UserManual/QmitkMITKIGTNavigationToolManager.dox index 1fee58aeee..2253f1917f 100644 --- a/Plugins/org.mitk.gui.qt.igttracking/documentation/UserManual/QmitkMITKIGTNavigationToolManager.dox +++ b/Plugins/org.mitk.gui.qt.igttracking/documentation/UserManual/QmitkMITKIGTNavigationToolManager.dox @@ -1,47 +1,47 @@ /** -\page org_igtnavigationtoolmanager The MITK-IGT Navigation Tool Manager +\page org_mitk_views_igtnavigationtoolmanager The MITK-IGT Navigation Tool Manager \image html iconNavigationToolManager.png "Icon of the Module" \section QmitkMITKIGTNavigationToolManager Introduction This bundle allows for creating and editing NavigationToolStorages. These storages contains naviagtion tools of a tracking device, can be saved permanently and used later for any other IGT application. Available sections: - \ref QmitkMITKIGTNavigationToolManager - \ref QmitkMITKIGTNavigationToolManagerToolOverview - \ref QmitkMITKIGTNavigationToolManagerManagingNavigationToolStorage - \ref QmitkMITKIGTNavigationToolManagerAddingEditingNavigationTools \section QmitkMITKIGTNavigationToolManagerToolOverview Navigation Tools Overview A navigation tool of MITK-IGT represents a tracking tool (e.g. an emt sensor or an optically tracked tool) and it's corresponding data, like it's name and it's surface. A navigation tool is a generalized container for any trackable object in combination with it's additional information. Every navigation tool has different properties which are:
  • Name
  • Unique identifier
  • Tool definition file
  • Serial number
  • Surface for visualization
  • Type of tracking device
  • Type of the tool
Note that not all properties are needed for all types of tools. A tool definition file, for example, is only needed by optical tracking tools (e.g. a .rom file for Polaris or a toolfile for the MicronTracker). A tool associated with the aurora system is alwalys identified by it's serial number. You can also detect Aurora tools automatically with the TrackingToolbox bundle and edit the automatically detected tool storage later with this bundle. \section QmitkMITKIGTNavigationToolManagerManagingNavigationToolStorage Managing Navigation Tool Storage In order to create a new storage container, or edit an existing one, you can use the buttons "add", "edit" and "delete" to manage the contained navigation tools. If you click "edit" or "delete" the operation is applied on the currently selected tool, as shown in the screenshot below. If you want to create a new storage container, just start adding tools when you start the program and save the storage container. To edit an existing tool storage container click "load" and add/edit/delete tools. \image html NavigationToolManagemantStartScreen.png "Screenshot of the main view of NavigationToolManagent" \section QmitkMITKIGTNavigationToolManagerAddingEditingNavigationTools Adding / Editing Navigation Tools If you add or edit a navigation tool, an input mask, as shown in the screenshot below, appears. The tool identifier is filled automatically, if you change it, remember that it is unique in the current storage. Also, choose a valid surface for every tool, this is nessesary for correct tool visualization. The other information depends on the tracking system type. So choose a tool file for the Polaris or the MicronTracker system and type in a serial number for the Aurora system. Two identical tools with the same serial number are also possible, they are assigned by the order in which they are attached to the device. As long as they also have the same surface, this should not be a problem. The tool type is additional information which is not needed by the tracking device but might be needed by further IGT applications. \image html NavigationToolManagementAddTool.png "Screenshot of add/edit navigation tool screen" */ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.igttracking/documentation/UserManual/QmitkMITKIGTTrackingToolbox.dox b/Plugins/org.mitk.gui.qt.igttracking/documentation/UserManual/QmitkMITKIGTTrackingToolbox.dox index 82a85e61fa..c6d911fe51 100644 --- a/Plugins/org.mitk.gui.qt.igttracking/documentation/UserManual/QmitkMITKIGTTrackingToolbox.dox +++ b/Plugins/org.mitk.gui.qt.igttracking/documentation/UserManual/QmitkMITKIGTTrackingToolbox.dox @@ -1,64 +1,64 @@ /** -\page org_igttrackingtoolbox The MITK-IGT Tracking Toolbox +\page org_mitk_views_igttrackingtoolbox The MITK-IGT Tracking Toolbox \image html iconTrackingToolbox.png "Icon of the module" Available sections: - \ref QmitkMITKIGTTrackingToolboxIntroduction - \ref QmitkMITKIGTTrackingToolboxWorkflow - \ref QmitkMITKIGTTrackingToolboxConnecting - \ref QmitkMITKIGTTrackingToolboxLoadingTools - \ref QmitkMITKIGTTrackingToolboxAutoDetection - \ref QmitkMITKIGTTrackingToolboxStartTracking - \ref QmitkMITKIGTTrackingToolboxLogging - \ref QmitkMITKIGTTrackingOptions \section QmitkMITKIGTTrackingToolboxIntroduction Introduction The MITK-IGT Tracking Toolbox is a bundle which allows you to connect to a tracking device, track and visualize navigation tools and write the tracked data into a log file. Currently the devices Polaris, Aurora (both Northern Digital Inc. (NDI); Waterloo, Ontario, Canada) and MicronTracker (Claron Technology, Inc.; Toronto, Ontario, Canada) are supported. The MicroBird family (Ascension Technology Corporation, Inc.; Burlington, USA) will hopefully follow soon since it is already supported by the tracking layer of IGT. The logging feature of the Tracking Toolbox supports logging in XML or CSV format. \image html screenshot_mitk.png "MITK Screenshot with the TrackingToolbox activated" \section QmitkMITKIGTTrackingToolboxWorkflow General workflow Introduction A general Workflow with the Tracking Toolbox may be:
  • Configuration of a tracking device
  • Loading a toolfile which holds tool definitions
  • Start tracking
  • Logging tracked data
\section QmitkMITKIGTTrackingToolboxConnecting Tracking Device Configuration The tracking device can be specified in the tracking device configuration section located in the upper area of the tracking tab. As shown in the screenshot below, you choose your tracking device in the drop down menu. If you use a tracking system connected to a serial port, like Aurora or Polaris, you then need to specifiy the serial port. In case of the MicronTracker you only need to ensure that all drivers are installed correctly and integrated into MITK. If you want to check the connection, press "test connection". The results are displayed in the small black box on the right. \image html configurationWidget.png "Tracking Device Configuration" \section QmitkMITKIGTTrackingToolboxLoadingTools Loading tools To load tools which can be tracked you need a predefined tracking tool storage. If you use the Aurora system you also have the possibility to automatically detect the connected tools. In this case a tracking tool storage is created by the software (see section below). Otherwise you can use the MITK bundle NavigationToolManager to define a navigation tool storage. There you can create navigation tools with the corresponding toolfiles, visualization surfaces and so on. Please see NavigationToolManager manual for more details. Navigation tool storages can be loaded by pressing the button "Load Tools". Please ensure that the tracking device type of the tools matches the chosen tracking device, otherwise you will get an error message if you try to start tracking. All loaded tools will then be displayed in grey as shown in the screenshot below. If you start tracking they will become green if the tools were found and red if they were not found inside the tracking volume. \image html trackingToolsWidget.png "Tracking Tools" \section QmitkMITKIGTTrackingToolboxAutoDetection Auto detection of tools (only Aurora) If the Aurora tracking system is used, a button "Auto Detection" appears. If you press this button the software connects to the system and automatically detects all connected tools. You will then be asked whether you want to save the detected tools as a tool storage to the hard drive. You might want to do this if you want to use or modify this tool storage later. In the automatically detected tool storage the tools are named AutoDetectedTools1, AutoDetectedTools2, and so on. Small spheres are used as tool surfaces. After autodetection the detected tools are loaded automatically even if you did not save them. \section QmitkMITKIGTTrackingToolboxStartTracking Start/stop tracking Tracking can simply be started by pressing "Start Tracking". Note that options may not be changed during tracking. Once tracking has started the tracking volume (only if the option is on) and the tools are visualized in the 3D view of MITK. \section QmitkMITKIGTTrackingToolboxLogging Logging features If your device is tracking, you are able to log the tracking data by using the logging tab. You first must define a file name. You can then choose whether you want comma seperated (csv) or xml format. Press "Start Logging" to start logging. You can also limit the number of logged frames, which will cause the logging to stop automatically after the given number. \section QmitkMITKIGTTrackingOptions Options In the options tab you can enable or disable the visualization of the tracking volume and of the tool quaternions. If enabled, the tool quaternions are shown in the tool information. You can also define the update rate of the tracking data. The update rate should not be set higher than the update rate of the tracking system. */ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.igttracking/documentation/UserManual/QmitkNavigationDataPlayer.dox b/Plugins/org.mitk.gui.qt.igttracking/documentation/UserManual/QmitkNavigationDataPlayer.dox index 667946ac47..c6dec7930e 100644 --- a/Plugins/org.mitk.gui.qt.igttracking/documentation/UserManual/QmitkNavigationDataPlayer.dox +++ b/Plugins/org.mitk.gui.qt.igttracking/documentation/UserManual/QmitkNavigationDataPlayer.dox @@ -1,18 +1,18 @@ /** -\page org_navigationdataplayer NavigationData Player +\page org_mitk_views_navigationdataplayer NavigationData Player \image html iconNavigationDataPlayer.png "Icon of NavigationData Player" Available sections: - \ref NavigationDataPlayerOverview \section NavigationDataPlayerOverview The navigation data player plays recorded or artificial navigation data of one ore more tracking tools and visualizes their trajectory. For that purpose select an input file (*.xml only) and select which tracking tool's trajectory should be visualized. If you additionally activate the checkbox "Splines" the trajectory curve will be smoothed via spline interpolation. Press the button "start" for starting the player and the visualization. If "Sequential Mode" is checked, the navigation data are played sequentially without regarding the recorded time steps. You can use the resolution field to define which part of the samples you want to use. E.g. 1 = every sample; 2 = every second sample; 3 = every third sample, ... \image html screenshotNavigationDataPlayer.png "Screenshot of the NavigationData Player" */ diff --git a/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/QmitkImageCropperUserManual.dox b/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/QmitkImageCropperUserManual.dox index dfaf6256e0..58b7015c0e 100644 --- a/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/QmitkImageCropperUserManual.dox +++ b/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/QmitkImageCropperUserManual.dox @@ -1,41 +1,41 @@ /** -\bundlemainpage{org_imagecropper} The Image Cropper Module +\page org_mitk_views_imagecropper The Image Cropper Module \image html icon.png "Icon of the Module" Available sections: - \ref QmitkImageCropperUserManualOverview - \ref QmitkImageCropperUserManualFeatures - \ref QmitkImageCropperUserManualUsage - \ref QmitkImageCropperUserManualTroubleshooting \section QmitkImageCropperUserManualOverview Overview ImageCropper is a functionality which allows the user to manually crop an image by means of a bounding box. The functionality does not create a new image, it only hides parts of the original image. \section QmitkImageCropperUserManualFeatures Features - Crop a selected image using a bounding box. - Set the border voxels to a specific user defined value after cropping. \section QmitkImageCropperUserManualUsage Usage -First select from the drop down menu the image to crop. The three 2D widgets show yellow rectangles representing the bounding box in each plane (transversal, sagital, coronal ), the lower right 3D widget shows the entire volume of the bounding box.\n +First select from the drop down menu the image to crop. The three 2D widgets show yellow rectangles representing the bounding box in each plane (axial, sagital, coronal), the lower right 3D widget shows the entire volume of the bounding box.\n - To change the size of bounding box press control + right click and move the cursor up/down or left/right in one of the three 2D views.\n - To change the orientation of the bounding box press control + middle click and move the cursor up/down or left/right in one of the three 2D views.\n - To move the bounding box press control + left click and move the cursor to the wanted position in one of the three 2D views.\n To show the result press the [crop] button.\n To crop the image again press the [New bounding box!] button.\n\n All actions can be undone by using the global undo function (Ctrl+Z).\n To set the border voxels to a specific value after cropping the image, activate the corresponding checkbox and choose a gray value. \section QmitkImageCropperUserManualTroubleshooting Troubleshooting */ diff --git a/Plugins/org.mitk.gui.qt.imagenavigator/documentation/UserManual/QmtikImageNavigator.dox b/Plugins/org.mitk.gui.qt.imagenavigator/documentation/UserManual/QmtikImageNavigator.dox index c8070d7594..86ed33d160 100644 --- a/Plugins/org.mitk.gui.qt.imagenavigator/documentation/UserManual/QmtikImageNavigator.dox +++ b/Plugins/org.mitk.gui.qt.imagenavigator/documentation/UserManual/QmtikImageNavigator.dox @@ -1,15 +1,15 @@ /** -\bundlemainpage{org_imagenavigator} The Image Navigator +\page org_mitk_views_imagenavigator The Image Navigator \image html Slider.png "Icon of the Module" \image html ImageNavigator.png "Image Navigator" Fast movement through the available data can be achieved by using the Image Navigator. By moving the sliders around you can scroll quickly through the slides and timesteps. By entering numbers in the relevant fields you can jump directly to your point of interest. The "Show detail" checkbox enables you to see the world coordinates in millimetres and the index/voxel coordinates. These may be edited to jump to a specific location. */ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.imagenavigator/src/internal/QmitkImageNavigatorView.cpp b/Plugins/org.mitk.gui.qt.imagenavigator/src/internal/QmitkImageNavigatorView.cpp index 8572e6c006..fcfec0e161 100644 --- a/Plugins/org.mitk.gui.qt.imagenavigator/src/internal/QmitkImageNavigatorView.cpp +++ b/Plugins/org.mitk.gui.qt.imagenavigator/src/internal/QmitkImageNavigatorView.cpp @@ -1,398 +1,398 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "QmitkImageNavigatorView.h" #include #include #include const std::string QmitkImageNavigatorView::VIEW_ID = "org.mitk.views.imagenavigator"; QmitkImageNavigatorView::QmitkImageNavigatorView() - : m_TransversalStepper(0) + : m_AxialStepper(0) , m_SagittalStepper(0) , m_FrontalStepper(0) , m_TimeStepper(0) , m_Parent(0) , m_IRenderWindowPart(0) { } QmitkImageNavigatorView::~QmitkImageNavigatorView() { } void QmitkImageNavigatorView::CreateQtPartControl(QWidget *parent) { // create GUI widgets m_Parent = parent; m_Controls.setupUi(parent); - m_Controls.m_SliceNavigatorTransversal->SetInverseDirection(true); + m_Controls.m_SliceNavigatorAxial->SetInverseDirection(true); connect(m_Controls.m_XWorldCoordinateSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnMillimetreCoordinateValueChanged())); connect(m_Controls.m_YWorldCoordinateSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnMillimetreCoordinateValueChanged())); connect(m_Controls.m_ZWorldCoordinateSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnMillimetreCoordinateValueChanged())); m_Parent->setEnabled(false); mitk::IRenderWindowPart* renderPart = this->GetRenderWindowPart(); this->RenderWindowPartActivated(renderPart); } void QmitkImageNavigatorView::SetFocus () { m_Controls.m_XWorldCoordinateSpinBox->setFocus(); } void QmitkImageNavigatorView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { if (this->m_IRenderWindowPart != renderWindowPart) { this->m_IRenderWindowPart = renderWindowPart; this->m_Parent->setEnabled(true); - QmitkRenderWindow* renderWindow = renderWindowPart->GetRenderWindow("transversal"); + QmitkRenderWindow* renderWindow = renderWindowPart->GetRenderWindow("axial"); if (renderWindow) { - if (m_TransversalStepper) m_TransversalStepper->deleteLater(); - m_TransversalStepper = new QmitkStepperAdapter(m_Controls.m_SliceNavigatorTransversal, + if (m_AxialStepper) m_AxialStepper->deleteLater(); + m_AxialStepper = new QmitkStepperAdapter(m_Controls.m_SliceNavigatorAxial, renderWindow->GetSliceNavigationController()->GetSlice(), - "sliceNavigatorTransversalFromSimpleExample"); - m_Controls.m_SliceNavigatorTransversal->setEnabled(true); - m_Controls.m_TransversalLabel->setEnabled(true); + "sliceNavigatorAxialFromSimpleExample"); + m_Controls.m_SliceNavigatorAxial->setEnabled(true); + m_Controls.m_AxialLabel->setEnabled(true); m_Controls.m_ZWorldCoordinateSpinBox->setEnabled(true); - connect(m_TransversalStepper, SIGNAL(Refetch()), this, SLOT(OnRefetch())); + connect(m_AxialStepper, SIGNAL(Refetch()), this, SLOT(OnRefetch())); } else { - m_Controls.m_SliceNavigatorTransversal->setEnabled(false); - m_Controls.m_TransversalLabel->setEnabled(false); + m_Controls.m_SliceNavigatorAxial->setEnabled(false); + m_Controls.m_AxialLabel->setEnabled(false); m_Controls.m_ZWorldCoordinateSpinBox->setEnabled(false); } renderWindow = renderWindowPart->GetRenderWindow("sagittal"); if (renderWindow) { if (m_SagittalStepper) m_SagittalStepper->deleteLater(); m_SagittalStepper = new QmitkStepperAdapter(m_Controls.m_SliceNavigatorSagittal, renderWindow->GetSliceNavigationController()->GetSlice(), "sliceNavigatorSagittalFromSimpleExample"); m_Controls.m_SliceNavigatorSagittal->setEnabled(true); m_Controls.m_SagittalLabel->setEnabled(true); m_Controls.m_YWorldCoordinateSpinBox->setEnabled(true); connect(m_SagittalStepper, SIGNAL(Refetch()), this, SLOT(OnRefetch())); } else { m_Controls.m_SliceNavigatorSagittal->setEnabled(false); m_Controls.m_SagittalLabel->setEnabled(false); m_Controls.m_YWorldCoordinateSpinBox->setEnabled(false); } renderWindow = renderWindowPart->GetRenderWindow("coronal"); if (renderWindow) { if (m_FrontalStepper) m_FrontalStepper->deleteLater(); m_FrontalStepper = new QmitkStepperAdapter(m_Controls.m_SliceNavigatorFrontal, renderWindow->GetSliceNavigationController()->GetSlice(), "sliceNavigatorFrontalFromSimpleExample"); m_Controls.m_SliceNavigatorFrontal->setEnabled(true); m_Controls.m_CoronalLabel->setEnabled(true); m_Controls.m_XWorldCoordinateSpinBox->setEnabled(true); connect(m_FrontalStepper, SIGNAL(Refetch()), this, SLOT(OnRefetch())); } else { m_Controls.m_SliceNavigatorFrontal->setEnabled(false); m_Controls.m_CoronalLabel->setEnabled(false); m_Controls.m_XWorldCoordinateSpinBox->setEnabled(false); } mitk::SliceNavigationController* timeController = renderWindowPart->GetTimeNavigationController(); if (timeController) { if (m_TimeStepper) m_TimeStepper->deleteLater(); m_TimeStepper = new QmitkStepperAdapter(m_Controls.m_SliceNavigatorTime, timeController->GetTime(), "sliceNavigatorTimeFromSimpleExample"); m_Controls.m_SliceNavigatorTime->setEnabled(true); m_Controls.m_TimeLabel->setEnabled(true); } else { m_Controls.m_SliceNavigatorTime->setEnabled(false); m_Controls.m_TimeLabel->setEnabled(false); } } } void QmitkImageNavigatorView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* /*renderWindowPart*/) { m_IRenderWindowPart = 0; m_Parent->setEnabled(false); } int QmitkImageNavigatorView::GetSizeFlags(bool width) { if(!width) { return berry::Constants::MIN | berry::Constants::MAX | berry::Constants::FILL; } else { return 0; } } int QmitkImageNavigatorView::ComputePreferredSize(bool width, int /*availableParallel*/, int /*availablePerpendicular*/, int preferredResult) { if(width==false) { return 200; } else { return preferredResult; } } int QmitkImageNavigatorView::GetClosestAxisIndex(mitk::Vector3D normal) { // cos(theta) = normal . axis // cos(theta) = (a, b, c) . (d, e, f) // cos(theta) = (a, b, c) . (1, 0, 0) = a // cos(theta) = (a, b, c) . (0, 1, 0) = b // cos(theta) = (a, b, c) . (0, 0, 1) = c double absCosThetaWithAxis[3]; for (int i = 0; i < 3; i++) { absCosThetaWithAxis[i] = fabs(normal[i]); } int largestIndex = 0; double largestValue = absCosThetaWithAxis[0]; for (int i = 1; i < 3; i++) { if (absCosThetaWithAxis[i] > largestValue) { largestValue = absCosThetaWithAxis[i]; largestIndex = i; } } return largestIndex; } void QmitkImageNavigatorView::SetBorderColors() { if (m_IRenderWindowPart) { - QmitkRenderWindow* renderWindow = m_IRenderWindowPart->GetRenderWindow("transversal"); + QmitkRenderWindow* renderWindow = m_IRenderWindowPart->GetRenderWindow("axial"); if (renderWindow) { mitk::PlaneGeometry::ConstPointer geometry = renderWindow->GetSliceNavigationController()->GetCurrentPlaneGeometry(); if (geometry.IsNotNull()) { mitk::Vector3D normal = geometry->GetNormal(); int axis = this->GetClosestAxisIndex(normal); this->SetBorderColor(axis, QString("red")); } } renderWindow = m_IRenderWindowPart->GetRenderWindow("sagittal"); if (renderWindow) { mitk::PlaneGeometry::ConstPointer geometry = renderWindow->GetSliceNavigationController()->GetCurrentPlaneGeometry(); if (geometry.IsNotNull()) { mitk::Vector3D normal = geometry->GetNormal(); int axis = this->GetClosestAxisIndex(normal); this->SetBorderColor(axis, QString("green")); } } renderWindow = m_IRenderWindowPart->GetRenderWindow("coronal"); if (renderWindow) { mitk::PlaneGeometry::ConstPointer geometry = renderWindow->GetSliceNavigationController()->GetCurrentPlaneGeometry(); if (geometry.IsNotNull()) { mitk::Vector3D normal = geometry->GetNormal(); int axis = this->GetClosestAxisIndex(normal); this->SetBorderColor(axis, QString("blue")); } } } } void QmitkImageNavigatorView::SetBorderColor(int axis, QString colorAsStyleSheetString) { if (axis == 0) { this->SetBorderColor(m_Controls.m_XWorldCoordinateSpinBox, colorAsStyleSheetString); } else if (axis == 1) { this->SetBorderColor(m_Controls.m_YWorldCoordinateSpinBox, colorAsStyleSheetString); } else if (axis == 2) { this->SetBorderColor(m_Controls.m_ZWorldCoordinateSpinBox, colorAsStyleSheetString); } } void QmitkImageNavigatorView::SetBorderColor(QDoubleSpinBox *spinBox, QString colorAsStyleSheetString) { assert(spinBox); spinBox->setStyleSheet(QString("border: 2px solid ") + colorAsStyleSheetString + ";"); } void QmitkImageNavigatorView::SetStepSizes() { this->SetStepSize(0); this->SetStepSize(1); this->SetStepSize(2); } void QmitkImageNavigatorView::SetStepSize(int axis) { if (m_IRenderWindowPart) { - mitk::Geometry3D::ConstPointer geometry = m_IRenderWindowPart->GetActiveRenderWindow()->GetSliceNavigationController()->GetInputWorldGeometry(); + mitk::Geometry3D::ConstPointer geometry = m_IRenderWindowPart->GetActiveQmitkRenderWindow()->GetSliceNavigationController()->GetInputWorldGeometry(); if (geometry.IsNotNull()) { mitk::Point3D crossPositionInIndexCoordinates; mitk::Point3D crossPositionInIndexCoordinatesPlus1; mitk::Point3D crossPositionInMillimetresPlus1; mitk::Vector3D transformedAxisDirection; mitk::Point3D crossPositionInMillimetres = m_IRenderWindowPart->GetSelectedPosition(); geometry->WorldToIndex(crossPositionInMillimetres, crossPositionInIndexCoordinates); crossPositionInIndexCoordinatesPlus1 = crossPositionInIndexCoordinates; crossPositionInIndexCoordinatesPlus1[axis] += 1; geometry->IndexToWorld(crossPositionInIndexCoordinatesPlus1, crossPositionInMillimetresPlus1); transformedAxisDirection = crossPositionInMillimetresPlus1 - crossPositionInMillimetres; int closestAxisInMillimetreSpace = this->GetClosestAxisIndex(transformedAxisDirection); double stepSize = transformedAxisDirection.GetNorm(); this->SetStepSize(closestAxisInMillimetreSpace, stepSize); } } } void QmitkImageNavigatorView::SetStepSize(int axis, double stepSize) { if (axis == 0) { m_Controls.m_XWorldCoordinateSpinBox->setSingleStep(stepSize); } else if (axis == 1) { m_Controls.m_YWorldCoordinateSpinBox->setSingleStep(stepSize); } else if (axis == 2) { m_Controls.m_ZWorldCoordinateSpinBox->setSingleStep(stepSize); } } void QmitkImageNavigatorView::OnMillimetreCoordinateValueChanged() { if (m_IRenderWindowPart) { - mitk::Geometry3D::ConstPointer geometry = m_IRenderWindowPart->GetActiveRenderWindow()->GetSliceNavigationController()->GetInputWorldGeometry(); + mitk::Geometry3D::ConstPointer geometry = m_IRenderWindowPart->GetActiveQmitkRenderWindow()->GetSliceNavigationController()->GetInputWorldGeometry(); if (geometry.IsNotNull()) { mitk::Point3D positionInWorldCoordinates; positionInWorldCoordinates[0] = m_Controls.m_XWorldCoordinateSpinBox->value(); positionInWorldCoordinates[1] = m_Controls.m_YWorldCoordinateSpinBox->value(); positionInWorldCoordinates[2] = m_Controls.m_ZWorldCoordinateSpinBox->value(); m_IRenderWindowPart->SetSelectedPosition(positionInWorldCoordinates); } } } void QmitkImageNavigatorView::OnRefetch() { if (m_IRenderWindowPart) { - mitk::Geometry3D::ConstPointer geometry = m_IRenderWindowPart->GetActiveRenderWindow()->GetSliceNavigationController()->GetInputWorldGeometry(); + mitk::Geometry3D::ConstPointer geometry = m_IRenderWindowPart->GetActiveQmitkRenderWindow()->GetSliceNavigationController()->GetInputWorldGeometry(); if (geometry.IsNotNull()) { mitk::Geometry3D::BoundsArrayType bounds = geometry->GetBounds(); mitk::Point3D cornerPoint1InIndexCoordinates; cornerPoint1InIndexCoordinates[0] = bounds[0]; cornerPoint1InIndexCoordinates[1] = bounds[2]; cornerPoint1InIndexCoordinates[2] = bounds[4]; mitk::Point3D cornerPoint2InIndexCoordinates; cornerPoint2InIndexCoordinates[0] = bounds[1]; cornerPoint2InIndexCoordinates[1] = bounds[3]; cornerPoint2InIndexCoordinates[2] = bounds[5]; if (!geometry->GetImageGeometry()) { cornerPoint1InIndexCoordinates[0] += 0.5; cornerPoint1InIndexCoordinates[1] += 0.5; cornerPoint1InIndexCoordinates[2] += 0.5; cornerPoint2InIndexCoordinates[0] -= 0.5; cornerPoint2InIndexCoordinates[1] -= 0.5; cornerPoint2InIndexCoordinates[2] -= 0.5; } mitk::Point3D crossPositionInWorldCoordinates = m_IRenderWindowPart->GetSelectedPosition(); mitk::Point3D cornerPoint1InWorldCoordinates; mitk::Point3D cornerPoint2InWorldCoordinates; geometry->IndexToWorld(cornerPoint1InIndexCoordinates, cornerPoint1InWorldCoordinates); geometry->IndexToWorld(cornerPoint2InIndexCoordinates, cornerPoint2InWorldCoordinates); m_Controls.m_XWorldCoordinateSpinBox->blockSignals(true); m_Controls.m_YWorldCoordinateSpinBox->blockSignals(true); m_Controls.m_ZWorldCoordinateSpinBox->blockSignals(true); m_Controls.m_XWorldCoordinateSpinBox->setMinimum(std::min(cornerPoint1InWorldCoordinates[0], cornerPoint2InWorldCoordinates[0])); m_Controls.m_YWorldCoordinateSpinBox->setMinimum(std::min(cornerPoint1InWorldCoordinates[1], cornerPoint2InWorldCoordinates[1])); m_Controls.m_ZWorldCoordinateSpinBox->setMinimum(std::min(cornerPoint1InWorldCoordinates[2], cornerPoint2InWorldCoordinates[2])); m_Controls.m_XWorldCoordinateSpinBox->setMaximum(std::max(cornerPoint1InWorldCoordinates[0], cornerPoint2InWorldCoordinates[0])); m_Controls.m_YWorldCoordinateSpinBox->setMaximum(std::max(cornerPoint1InWorldCoordinates[1], cornerPoint2InWorldCoordinates[1])); m_Controls.m_ZWorldCoordinateSpinBox->setMaximum(std::max(cornerPoint1InWorldCoordinates[2], cornerPoint2InWorldCoordinates[2])); m_Controls.m_XWorldCoordinateSpinBox->setValue(crossPositionInWorldCoordinates[0]); m_Controls.m_YWorldCoordinateSpinBox->setValue(crossPositionInWorldCoordinates[1]); m_Controls.m_ZWorldCoordinateSpinBox->setValue(crossPositionInWorldCoordinates[2]); m_Controls.m_XWorldCoordinateSpinBox->blockSignals(false); m_Controls.m_YWorldCoordinateSpinBox->blockSignals(false); m_Controls.m_ZWorldCoordinateSpinBox->blockSignals(false); } this->SetBorderColors(); } } diff --git a/Plugins/org.mitk.gui.qt.imagenavigator/src/internal/QmitkImageNavigatorView.h b/Plugins/org.mitk.gui.qt.imagenavigator/src/internal/QmitkImageNavigatorView.h index d81cad83a1..402ade547d 100644 --- a/Plugins/org.mitk.gui.qt.imagenavigator/src/internal/QmitkImageNavigatorView.h +++ b/Plugins/org.mitk.gui.qt.imagenavigator/src/internal/QmitkImageNavigatorView.h @@ -1,96 +1,96 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 _QMITKIMAGENAVIGATORVIEW_H_INCLUDED #define _QMITKIMAGENAVIGATORVIEW_H_INCLUDED #include #include #include #include "ui_QmitkImageNavigatorViewControls.h" class QmitkStepperAdapter; /*! * \ingroup org_mitk_gui_qt_imagenavigator_internal * * \class QmitkImageNavigatorView * - * \brief Provides a means to scan quickly through a dataset via Transversal, + * \brief Provides a means to scan quickly through a dataset via Axial, * Coronal and Sagittal sliders, displaying millimetre location and stepper position. * * For images, the stepper position corresponds to a voxel index. For other datasets * such as a surface, it corresponds to a sub-division of the bounding box. * * \sa QmitkAbstractView */ class QmitkImageNavigatorView : public QmitkAbstractView, public mitk::IRenderWindowPartListener, 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; QmitkImageNavigatorView(); virtual ~QmitkImageNavigatorView(); virtual void CreateQtPartControl(QWidget *parent); virtual int GetSizeFlags(bool width); virtual int ComputePreferredSize(bool width, int /*availableParallel*/, int /*availablePerpendicular*/, int preferredResult); protected slots: void OnMillimetreCoordinateValueChanged(); void OnRefetch(); protected: void SetFocus(); void RenderWindowPartActivated(mitk::IRenderWindowPart *renderWindowPart); void RenderWindowPartDeactivated(mitk::IRenderWindowPart *renderWindowPart); void SetBorderColors(); void SetBorderColor(QDoubleSpinBox *spinBox, QString colorAsStyleSheetString); void SetBorderColor(int axis, QString colorAsStyleSheetString); void SetStepSizes(); void SetStepSize(int axis); void SetStepSize(int axis, double stepSize); int GetClosestAxisIndex(mitk::Vector3D normal); Ui::QmitkImageNavigatorViewControls m_Controls; - QmitkStepperAdapter* m_TransversalStepper; + QmitkStepperAdapter* m_AxialStepper; QmitkStepperAdapter* m_SagittalStepper; QmitkStepperAdapter* m_FrontalStepper; QmitkStepperAdapter* m_TimeStepper; QWidget* m_Parent; mitk::IRenderWindowPart* m_IRenderWindowPart; }; #endif // _QMITKIMAGENAVIGATORVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.imagenavigator/src/internal/QmitkImageNavigatorViewControls.ui b/Plugins/org.mitk.gui.qt.imagenavigator/src/internal/QmitkImageNavigatorViewControls.ui index 92c069b87d..65e4d0d94b 100644 --- a/Plugins/org.mitk.gui.qt.imagenavigator/src/internal/QmitkImageNavigatorViewControls.ui +++ b/Plugins/org.mitk.gui.qt.imagenavigator/src/internal/QmitkImageNavigatorViewControls.ui @@ -1,223 +1,223 @@ QmitkImageNavigatorViewControls 0 0 399 440 0 0 QmitkTemplate Location (mm) 0 0 false 2 -100000.000000000000000 100000.000000000000000 0 0 false 2 -100000.000000000000000 100000.000000000000000 0 0 false 2 -100000.000000000000000 100000.000000000000000 - + 0 0 - Transversal + Axial - + 0 0 0 0 0 0 Sagittal 0 0 0 0 Coronal 0 0 0 0 Time 0 0 Qt::Vertical 20 413 QmitkSliderNavigatorWidget QWidget
QmitkSliderNavigatorWidget.h
1
QmitkDataStorageComboBox.h
diff --git a/Plugins/org.mitk.gui.qt.materialeditor/documentation/UserManual/QmitkSurfaceMaterialEditor.dox b/Plugins/org.mitk.gui.qt.materialeditor/documentation/UserManual/QmitkSurfaceMaterialEditor.dox index c1ad65b3ea..95e01b1d88 100644 --- a/Plugins/org.mitk.gui.qt.materialeditor/documentation/UserManual/QmitkSurfaceMaterialEditor.dox +++ b/Plugins/org.mitk.gui.qt.materialeditor/documentation/UserManual/QmitkSurfaceMaterialEditor.dox @@ -1,10 +1,10 @@ /** -\bundlemainpage{org_surfacematerialeditor} The Surface Material Editor +\page org_surfacematerialeditor The Surface Material Editor \image html SurfaceMaterialEditorIcon.png "Icon of the Module" The Surface Material Editor shows the properties of the selected data that are relevant for the selected shader. These properties can be filtered to find a specific property. The preview window shows the representation of a neutral 3D object with the currently selected settings. \image html QmitkSurfaceMaterialEditorGui.png "The Surface Material Editor" */ \ No newline at end of file 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 d8b1a02745..95b83862ae 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,44 @@ /** -\page org_imagestatistics The Image Statistics Module +\page org_mitk_views_imagestatistics The Image Statistics Module \image html ImageStatistic_48.png "Icon of the Module" \section QmitkImageStatisticsUserManualSummary Summary This module 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 module, 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 module, please have a look at the \ref QmitkImageStatisticsUserManualTrouble page. \section QmitkImageStatisticsUserManualDetails Details Manual sections: - \ref QmitkImageStatisticsUserManualOverview - \ref QmitkImageStatisticsUserManualUsage - \ref QmitkImageStatisticsUserManualTrouble \section QmitkImageStatisticsUserManualOverview Overview This module 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 module 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. At the bottom of the module are two buttons. 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/QmitkMeasurement.dox b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkMeasurement.dox index 91cc3bd5c4..ad3e18a4d6 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkMeasurement.dox +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkMeasurement.dox @@ -1,134 +1,134 @@ /** -\page org_measurement The Measurement Module +\page org_mitk_views_measurement The Measurement Module \image html Measurement_48.png "Icon of the Module" \section QmitkMeasurementUserManualOverview Overview The Measurement module enables the user to interact with 2D images or single slices of 3D image stacks and planar figure data types. It allows to measure distances, angels, pathes and several geometric figures on a dataset. Available Sections: - \ref QmitkMeasurementUserManualOverview - \ref QmitkMeasurementUserManualFeatures - - \ref SubOne - - \ref SubTwo - - \ref SubThree - - \ref SubFour - - \ref SubFive - - \ref SubSix - - \ref SubSeven + - \ref SubOne + - \ref SubTwo + - \ref SubThree + - \ref SubFour + - \ref SubFive + - \ref SubSix + - \ref SubSeven - \ref QmitkMeasurementUserManualUsage - - \ref One - - \ref Two - - \ref Three - - \ref Four + - \ref One + - \ref Two + - \ref Three + - \ref Four The workflow to use this module is: \image html Workflow.png The workflow is repeatedly useable with the same or different measurement figures, which are correlated to the choosen image and can be saved together with it for future use. On pressing the Measurement icon (see picture below the page title) in the view button line the basic appearance of the bundle is as follws. \image html Basic_Screen_edited.JPG -The standard working plane is "Transversal" but the other standard viewplanes ("Saggital" and "Coronal") are also valid for measurements. To swap between the view planes refer to 3M Application Bundle User Manual. +The standard working plane is "Axial" but the other standard viewplanes ("Saggital" and "Coronal") are also valid for measurements. To swap between the view planes refer to 3M Application Bundle User Manual. \section QmitkMeasurementUserManualFeatures Features The bundle as it is depicted below offers the following features in the order of apperance on the image from top to bottom: \image html Measurement_View.JPG The first information is the selected image's name (here: DICOM-MRI-Image) followed by the measurement figures button line with the seven measurement figures. From left to right the buttons are connected with the following functions: \subsection SubOne Draw Line Draws a line between two set points and returns the distance between these points. \subsection SubTwo Draw Path Draws a path between several set points (two and more) and calculates the circumference, that is all line's length summed up. Add the final point by double left click. \subsection SubThree Draw Angle Draws two lines from three set points connected in the second set point and returns the inner angle at the second point. \subsection SubFour Draw Four Point Angle Draws two lines that may but must not intersect from four set points. The returned angle is the one depicted in the icon. \subsection SubFive Draw Circle Draws a circle by setting two points, whereas the first set point is the center and the second the radius of the circle. The measured values are the radius and the included area. \subsection SubSix Draw Rectangle Draws a rectangle by setting two points at the opposing edges of the rectangle starting with the upper left edge. The measured values are the circumference and the included area. \subsection SubSeven Draw Polygon Draws a polygon by setting three or more points. The measured values are the circumference and the included area. Add the final point by double left click. Below the buttonline the statistics window is situated, it displays the results of the actual measurements from the selected measurement figures. The content of the statistics window can be copied to the clipboard with the correspondig button for further use in a table calculation programm (e.g. Open Office Calc etc.). \image html Image_processed.JPG The last row contains again a button line to swap from the measurement bundle (activated in the image) to other supported MITK 3M3 bundles. \section QmitkMeasurementUserManualUsage Usage This Section is subdivided into four subsections:
  1. Add an image
  2. Work with measurement figures
  3. Save the image with measurement information -
  4. Remove measurement figures or image +
  5. Remove measurement figures or image
Let's start with subsection 1 -\subsection One Add an image +\subsection One Add an image There are two possible ways to add an image to the programm. One is to grap the image with left mouse click from your prefered file browser and simply drag&drop it to the View Plane field. The other way is to use the \image html OpenButton.png button in the upper left corner of the application. A dialog window appears showing the file tree of the computer. Navigate to the wanted file and select it with the left mouse click. Afterwards just use the dialog's open button. The wanted image appears in the View Plane and in the Data Manager the images name appears as a new tree node. Now the image is loaded it can be adjusted in the usual way ( zoom in/out: right mouse button + moving the mouse up and down, moving the image: press mouse wheel and move the mouse to the wished direction, scroll through the slices( only on 3D images): scroll mouse wheel up and down). \image html Image_Loaded_Screen.JPG After the image is loaded the image's name appears in the Data Manager. By left-clicking on the image name the buttonline becomes activated. \subsection Two Work with measurement figures The measurement module comes with seven measurement figures(see picture below), that can be applied to the images. \image html MeasurementFigureButtonline.jpg The results of the measurement with each of these figures is shown in the statistics window and in the lower right corner of the view plane. \image html Image_processed_Screen.JPG When applying more then one measurement figure to the image the actual measurement figure is depicted in red and the displayed values belong to this measurement figure. All measurement figures become part of the Data Manager as a node of the image tree. \subsection Three Save the image with measurement information After applying the wanted measurement figures the entire scene consisting of the image and the measurement figures can be saved for future use. Therefore just click the right mouse button when over the image item in the Data Manager and choose the item "Save" in the opening item list. Following to that a save dialog appears where the path to the save folder can be set. Afterwards just accept your choice with the save button. \subsection Four Remove measurement figures or image If the single measurement figures or the image is not needed any longer, it can be removed solely or as an entire group. The image can't be removed without simultaneously removing all the dependent measurement figures that belong to the image tree in the Data Manager. To remove just select the wanted items in the data manager list by left-click on it or if several items wanted to be removed left click on all wanted by simultaneously holding the ctrl-button pressed. For more detailed usage of the save/remove functionality refer to the Data Manager User Manual. */ diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkMeasurementToolbox.dox b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkMeasurementToolbox.dox index 127d8f695f..291d8d2334 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkMeasurementToolbox.dox +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkMeasurementToolbox.dox @@ -1,12 +1,12 @@ /** -\bundlemainpage{org_measurementtoolbox} The Measurement Toolbox Bundle +\page org_mitk_gui_qt_measurementtoolbox The Measurement Toolbox Bundle \section QmitkmeasurementToolbox Manual This bundle contains all views that provide measurement and statistics functionality.
    -
  • \subpage org_measurement -
  • \subpage org_imagestatistics +
  • \subpage org_mitk_views_measurement +
  • \subpage org_mitk_views_imagestatistics
*/ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.cpp b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.cpp index c7816e8e91..b00f0c516a 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.cpp +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.cpp @@ -1,718 +1,718 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 MEASUREMENT_DEBUG MITK_DEBUG("QmitkMeasurementView") << __LINE__ << ": " #include "QmitkMeasurementView.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct QmitkPlanarFigureData { QmitkPlanarFigureData() : m_Figure(0), m_EndPlacementObserverTag(0), m_SelectObserverTag(0), m_StartInteractionObserverTag(0), m_EndInteractionObserverTag(0) { } mitk::PlanarFigure* m_Figure; unsigned int m_EndPlacementObserverTag; unsigned int m_SelectObserverTag; unsigned int m_StartInteractionObserverTag; unsigned int m_EndInteractionObserverTag; }; struct QmitkMeasurementViewData { QmitkMeasurementViewData() : m_LineCounter(0), m_PathCounter(0), m_AngleCounter(0), m_FourPointAngleCounter(0), m_EllipseCounter(0), m_RectangleCounter(0), m_PolygonCounter(0), m_UnintializedPlanarFigure(false) { } // internal vars unsigned int m_LineCounter; unsigned int m_PathCounter; unsigned int m_AngleCounter; unsigned int m_FourPointAngleCounter; unsigned int m_EllipseCounter; unsigned int m_RectangleCounter; unsigned int m_PolygonCounter; QList m_CurrentSelection; std::map m_DataNodeToPlanarFigureData; mitk::WeakPointer m_SelectedImageNode; bool m_UnintializedPlanarFigure; // WIDGETS QWidget* m_Parent; QLabel* m_SelectedImageLabel; QAction* m_DrawLine; QAction* m_DrawPath; QAction* m_DrawAngle; QAction* m_DrawFourPointAngle; QAction* m_DrawEllipse; QAction* m_DrawRectangle; QAction* m_DrawPolygon; QToolBar* m_DrawActionsToolBar; QActionGroup* m_DrawActionsGroup; QTextBrowser* m_SelectedPlanarFiguresText; QPushButton* m_CopyToClipboard; QGridLayout* m_Layout; }; const std::string QmitkMeasurementView::VIEW_ID = "org.mitk.views.measurement"; QmitkMeasurementView::QmitkMeasurementView() : d( new QmitkMeasurementViewData ) { } QmitkMeasurementView::~QmitkMeasurementView() { this->RemoveAllInteractors(); delete d; } void QmitkMeasurementView::CreateQtPartControl(QWidget* parent) { d->m_Parent = parent; // image label QLabel* selectedImageLabel = new QLabel("Reference Image: "); d->m_SelectedImageLabel = new QLabel; d->m_SelectedImageLabel->setStyleSheet("font-weight: bold;"); d->m_DrawActionsToolBar = new QToolBar; d->m_DrawActionsGroup = new QActionGroup(this); d->m_DrawActionsGroup->setExclusive(true); //# add actions MEASUREMENT_DEBUG << "Draw Line"; QAction* currentAction = d->m_DrawActionsToolBar->addAction(QIcon( ":/measurement/line.png"), "Draw Line"); currentAction->setCheckable(true); d->m_DrawLine = currentAction; d->m_DrawActionsToolBar->addAction(currentAction); d->m_DrawActionsGroup->addAction(currentAction); MEASUREMENT_DEBUG << "Draw Path"; currentAction = d->m_DrawActionsToolBar->addAction(QIcon( ":/measurement/path.png"), "Draw Path"); currentAction->setCheckable(true); d->m_DrawPath = currentAction; d->m_DrawActionsToolBar->addAction(currentAction); d->m_DrawActionsGroup->addAction(currentAction); MEASUREMENT_DEBUG << "Draw Angle"; currentAction = d->m_DrawActionsToolBar->addAction(QIcon( ":/measurement/angle.png"), "Draw Angle"); currentAction->setCheckable(true); d->m_DrawAngle = currentAction; d->m_DrawActionsToolBar->addAction(currentAction); d->m_DrawActionsGroup->addAction(currentAction); MEASUREMENT_DEBUG << "Draw Four Point Angle"; currentAction = d->m_DrawActionsToolBar->addAction(QIcon( ":/measurement/four-point-angle.png"), "Draw Four Point Angle"); currentAction->setCheckable(true); d->m_DrawFourPointAngle = currentAction; d->m_DrawActionsToolBar->addAction(currentAction); d->m_DrawActionsGroup->addAction(currentAction); MEASUREMENT_DEBUG << "Draw Circle"; currentAction = d->m_DrawActionsToolBar->addAction(QIcon( ":/measurement/circle.png"), "Draw Circle"); currentAction->setCheckable(true); d->m_DrawEllipse = currentAction; d->m_DrawActionsToolBar->addAction(currentAction); d->m_DrawActionsGroup->addAction(currentAction); MEASUREMENT_DEBUG << "Draw Rectangle"; currentAction = d->m_DrawActionsToolBar->addAction(QIcon( ":/measurement/rectangle.png"), "Draw Rectangle"); currentAction->setCheckable(true); d->m_DrawRectangle = currentAction; d->m_DrawActionsToolBar->addAction(currentAction); d->m_DrawActionsGroup->addAction(currentAction); MEASUREMENT_DEBUG << "Draw Polygon"; currentAction = d->m_DrawActionsToolBar->addAction(QIcon( ":/measurement/polygon.png"), "Draw Polygon"); currentAction->setCheckable(true); d->m_DrawPolygon = currentAction; d->m_DrawActionsToolBar->addAction(currentAction); d->m_DrawActionsGroup->addAction(currentAction); // planar figure details text d->m_SelectedPlanarFiguresText = new QTextBrowser; // copy to clipboard button d->m_CopyToClipboard = new QPushButton("Copy to Clipboard"); d->m_Layout = new QGridLayout; d->m_Layout->addWidget(selectedImageLabel, 0, 0, 1, 1); d->m_Layout->addWidget(d->m_SelectedImageLabel, 0, 1, 1, 1); d->m_Layout->addWidget(d->m_DrawActionsToolBar, 1, 0, 1, 2); d->m_Layout->addWidget(d->m_SelectedPlanarFiguresText, 2, 0, 1, 2); d->m_Layout->addWidget(d->m_CopyToClipboard, 3, 0, 1, 2); d->m_Parent->setLayout(d->m_Layout); // create connections this->CreateConnections(); // readd interactors and observers this->AddAllInteractors(); } void QmitkMeasurementView::CreateConnections() { QObject::connect( d->m_DrawLine, SIGNAL( triggered(bool) ) , this, SLOT( ActionDrawLineTriggered(bool) ) ); QObject::connect( d->m_DrawPath, SIGNAL( triggered(bool) ) , this, SLOT( ActionDrawPathTriggered(bool) ) ); QObject::connect( d->m_DrawAngle, SIGNAL( triggered(bool) ) , this, SLOT( ActionDrawAngleTriggered(bool) ) ); QObject::connect( d->m_DrawFourPointAngle, SIGNAL( triggered(bool) ) , this, SLOT( ActionDrawFourPointAngleTriggered(bool) ) ); QObject::connect( d->m_DrawEllipse, SIGNAL( triggered(bool) ) , this, SLOT( ActionDrawEllipseTriggered(bool) ) ); QObject::connect( d->m_DrawRectangle, SIGNAL( triggered(bool) ) , this, SLOT( ActionDrawRectangleTriggered(bool) ) ); QObject::connect( d->m_DrawPolygon, SIGNAL( triggered(bool) ) , this, SLOT( ActionDrawPolygonTriggered(bool) ) ); QObject::connect( d->m_CopyToClipboard, SIGNAL( clicked(bool) ) , this, SLOT( CopyToClipboard(bool) ) ); } void QmitkMeasurementView::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 ) { MEASUREMENT_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); } MEASUREMENT_DEBUG << "adding interactor to globalinteraction"; mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); MEASUREMENT_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< QmitkMeasurementView > SimpleCommandType; SimpleCommandType::Pointer initializationCommand = SimpleCommandType::New(); initializationCommand->SetCallbackFunction( this, &QmitkMeasurementView::PlanarFigureInitialized ); data.m_EndPlacementObserverTag = figure->AddObserver( mitk::EndPlacementPlanarFigureEvent(), initializationCommand ); // add observer for event when figure is picked (selected) typedef itk::MemberCommand< QmitkMeasurementView > MemberCommandType; MemberCommandType::Pointer selectCommand = MemberCommandType::New(); selectCommand->SetCallbackFunction( this, &QmitkMeasurementView::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, &QmitkMeasurementView::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, &QmitkMeasurementView::EnableCrosshairNavigation); data.m_EndInteractionObserverTag = figure->AddObserver( mitk::EndInteractionPlanarFigureEvent(), endInteractionCommand ); // adding to the map of tracked planarfigures d->m_DataNodeToPlanarFigureData[nonConstNode] = data; } this->CheckForTopMostVisibleImage(); } void QmitkMeasurementView::NodeChanged(const mitk::DataNode* node) { // DETERMINE IF WE HAVE TO RENEW OUR DETAILS TEXT (ANY NODE CHANGED IN OUR SELECTION?) bool renewText = false; for( int i=0; i < d->m_CurrentSelection.size(); ++i ) { if( node == d->m_CurrentSelection.at(i) ) { renewText = true; break; } } if(renewText) { MEASUREMENT_DEBUG << "Selected nodes changed. Refreshing text."; this->UpdateMeasurementText(); } this->CheckForTopMostVisibleImage(); } void QmitkMeasurementView::CheckForTopMostVisibleImage(mitk::DataNode* _NodeToNeglect) { d->m_SelectedImageNode = this->DetectTopMostVisibleImage().GetPointer(); if( d->m_SelectedImageNode.GetPointer() == _NodeToNeglect ) d->m_SelectedImageNode = 0; if( d->m_SelectedImageNode.IsNotNull() && d->m_UnintializedPlanarFigure == false ) { MEASUREMENT_DEBUG << "Reference image found"; d->m_SelectedImageLabel->setText( QString::fromStdString( d->m_SelectedImageNode->GetName() ) ); d->m_DrawActionsToolBar->setEnabled(true); MEASUREMENT_DEBUG << "Updating Measurement text"; } else { MEASUREMENT_DEBUG << "No reference image available. Will disable actions for creating new planarfigures"; if( d->m_UnintializedPlanarFigure == false ) d->m_SelectedImageLabel->setText( "No visible image available." ); d->m_DrawActionsToolBar->setEnabled(false); } } void QmitkMeasurementView::NodeRemoved(const mitk::DataNode* node) { MEASUREMENT_DEBUG << "node removed from data storage"; mitk::DataNode* nonConstNode = const_cast(node); std::map::iterator it = d->m_DataNodeToPlanarFigureData.find(nonConstNode); if( it != d->m_DataNodeToPlanarFigureData.end() ) { QmitkPlanarFigureData& data = it->second; MEASUREMENT_DEBUG << "removing figure interactor to globalinteraction"; mitk::Interactor::Pointer oldInteractor = node->GetInteractor(); // if(oldInteractor.IsNotNull()) // mitk::GlobalInteraction::GetInstance()->RemoveInteractor(oldInteractor); // 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 ); MEASUREMENT_DEBUG << "removing from the list of tracked planar figures"; d->m_DataNodeToPlanarFigureData.erase( it ); } this->CheckForTopMostVisibleImage(nonConstNode); } void QmitkMeasurementView::PlanarFigureSelected( itk::Object* object, const itk::EventObject& ) { MEASUREMENT_DEBUG << "planar figure " << object << " selected"; std::map::iterator it = d->m_DataNodeToPlanarFigureData.begin(); d->m_CurrentSelection.clear(); while( it != d->m_DataNodeToPlanarFigureData.end()) { mitk::DataNode* node = it->first; QmitkPlanarFigureData& data = it->second; if( data.m_Figure == object ) { MITK_DEBUG << "selected node found. enabling selection"; node->SetSelected(true); d->m_CurrentSelection.push_back( node ); } else { node->SetSelected(false); } ++it; } this->UpdateMeasurementText(); this->RequestRenderWindowUpdate(); } void QmitkMeasurementView::PlanarFigureInitialized() { MEASUREMENT_DEBUG << "planar figure initialized"; d->m_UnintializedPlanarFigure = false; d->m_DrawActionsToolBar->setEnabled(true); d->m_DrawLine->setChecked(false); d->m_DrawPath->setChecked(false); d->m_DrawAngle->setChecked(false); d->m_DrawFourPointAngle->setChecked(false); d->m_DrawEllipse->setChecked(false); d->m_DrawRectangle->setChecked(false); d->m_DrawPolygon->setChecked(false); } void QmitkMeasurementView::SetFocus() { d->m_SelectedImageLabel->setFocus(); } void QmitkMeasurementView::OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &nodes) { MEASUREMENT_DEBUG << "Determine the top most visible image"; MEASUREMENT_DEBUG << "The PlanarFigure interactor will take the currently visible PlaneGeometry from the slice navigation controller"; this->CheckForTopMostVisibleImage(); MEASUREMENT_DEBUG << "refreshing selection and detailed text"; d->m_CurrentSelection = nodes; this->UpdateMeasurementText(); for( int i=d->m_CurrentSelection.size()-1; i>= 0; --i) { mitk::DataNode* node = d->m_CurrentSelection.at(i); mitk::PlanarFigure* _PlanarFigure = _PlanarFigure = dynamic_cast (node->GetData()); // the last selected planar figure if( _PlanarFigure ) { mitk::ILinkedRenderWindowPart* linkedRenderWindow = dynamic_cast(this->GetRenderWindowPart()); if( linkedRenderWindow ) { mitk::Point3D centerP = _PlanarFigure->GetGeometry()->GetOrigin(); - linkedRenderWindow->GetRenderWindow("transversal")->GetSliceNavigationController()->SelectSliceByPoint(centerP); + linkedRenderWindow->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SelectSliceByPoint(centerP); } break; } } this->RequestRenderWindowUpdate(); } void QmitkMeasurementView::ActionDrawLineTriggered(bool checked) { Q_UNUSED(checked) mitk::PlanarLine::Pointer figure = mitk::PlanarLine::New(); QString qString = QString("Line%1").arg(++d->m_LineCounter); this->AddFigureToDataStorage(figure, qString); MEASUREMENT_DEBUG << "PlanarLine initialized..."; } void QmitkMeasurementView::ActionDrawPathTriggered(bool checked) { Q_UNUSED(checked) mitk::PlanarPolygon::Pointer figure = mitk::PlanarPolygon::New(); figure->ClosedOff(); QString qString = QString("Path%1").arg(++d->m_PathCounter); mitk::DataNode::Pointer node = this->AddFigureToDataStorage(figure, qString); mitk::BoolProperty::Pointer closedProperty = mitk::BoolProperty::New( false ); node->SetProperty("ClosedPlanarPolygon", closedProperty); MEASUREMENT_DEBUG << "PlanarPath initialized..."; } void QmitkMeasurementView::ActionDrawAngleTriggered(bool checked) { Q_UNUSED(checked) mitk::PlanarAngle::Pointer figure = mitk::PlanarAngle::New(); QString qString = QString("Angle%1").arg(++d->m_AngleCounter); this->AddFigureToDataStorage(figure, qString); MEASUREMENT_DEBUG << "PlanarAngle initialized..."; } void QmitkMeasurementView::ActionDrawFourPointAngleTriggered(bool checked) { Q_UNUSED(checked) mitk::PlanarFourPointAngle::Pointer figure = mitk::PlanarFourPointAngle::New(); QString qString = QString("Four Point Angle%1").arg(++d->m_FourPointAngleCounter); this->AddFigureToDataStorage(figure, qString); MEASUREMENT_DEBUG << "PlanarFourPointAngle initialized..."; } void QmitkMeasurementView::ActionDrawEllipseTriggered(bool checked) { Q_UNUSED(checked) mitk::PlanarCircle::Pointer figure = mitk::PlanarCircle::New(); QString qString = QString("Circle%1").arg(++d->m_EllipseCounter); this->AddFigureToDataStorage(figure, qString); MEASUREMENT_DEBUG << "PlanarCircle initialized..."; } void QmitkMeasurementView::ActionDrawRectangleTriggered(bool checked) { Q_UNUSED(checked) mitk::PlanarRectangle::Pointer figure = mitk::PlanarRectangle::New(); QString qString = QString("Rectangle%1").arg(++d->m_RectangleCounter); this->AddFigureToDataStorage(figure, qString); MEASUREMENT_DEBUG << "PlanarRectangle initialized..."; } void QmitkMeasurementView::ActionDrawPolygonTriggered(bool checked) { Q_UNUSED(checked) mitk::PlanarPolygon::Pointer figure = mitk::PlanarPolygon::New(); figure->ClosedOn(); QString qString = QString("Polygon%1").arg(++d->m_PolygonCounter); this->AddFigureToDataStorage(figure, qString); MEASUREMENT_DEBUG << "PlanarPolygon initialized..."; } void QmitkMeasurementView::CopyToClipboard( bool checked ) { Q_UNUSED(checked) MEASUREMENT_DEBUG << "Copying current Text to clipboard..."; QString clipboardText = d->m_SelectedPlanarFiguresText->toPlainText(); QApplication::clipboard()->setText(clipboardText, QClipboard::Clipboard); } mitk::DataNode::Pointer QmitkMeasurementView::AddFigureToDataStorage( mitk::PlanarFigure* figure, const QString& name) { // add as MEASUREMENT_DEBUG << "Adding new figure to datastorage..."; if( d->m_SelectedImageNode.IsNull() ) { MITK_ERROR << "No reference image available"; return 0; } mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetName(name.toStdString()); newNode->SetData(figure); // set as selected newNode->SetSelected( true ); this->GetDataStorage()->Add(newNode, d->m_SelectedImageNode); // set all others in selection as deselected for( size_t i=0; im_CurrentSelection.size(); ++i) d->m_CurrentSelection.at(i)->SetSelected(false); d->m_CurrentSelection.clear(); d->m_CurrentSelection.push_back( newNode ); this->UpdateMeasurementText(); this->DisableCrosshairNavigation(); d->m_DrawActionsToolBar->setEnabled(false); d->m_UnintializedPlanarFigure = true; return newNode; } void QmitkMeasurementView::UpdateMeasurementText() { d->m_SelectedPlanarFiguresText->clear(); QString infoText; QString plainInfoText; unsigned int j = 1; mitk::PlanarFigure* _PlanarFigure = 0; mitk::PlanarAngle* planarAngle = 0; mitk::PlanarFourPointAngle* planarFourPointAngle = 0; mitk::DataNode::Pointer node = 0; for (unsigned int i=0; im_CurrentSelection.size(); ++i, ++j) { plainInfoText.clear(); node = d->m_CurrentSelection.at(i); _PlanarFigure = dynamic_cast (node->GetData()); if( !_PlanarFigure ) continue; if(j>1) infoText.append("
"); infoText.append(QString("%1
").arg(QString::fromStdString( node->GetName()))); plainInfoText.append(QString("%1").arg(QString::fromStdString( node->GetName()))); planarAngle = dynamic_cast (_PlanarFigure); if(!planarAngle) { planarFourPointAngle = dynamic_cast (_PlanarFigure); } double featureQuantity = 0.0; for (unsigned int k = 0; k < _PlanarFigure->GetNumberOfFeatures(); ++k) { if ( !_PlanarFigure->IsFeatureActive( k ) ) continue; featureQuantity = _PlanarFigure->GetQuantity(k); if ((planarAngle && k == planarAngle->FEATURE_ID_ANGLE) || (planarFourPointAngle && k == planarFourPointAngle->FEATURE_ID_ANGLE)) featureQuantity = featureQuantity * 180 / vnl_math::pi; infoText.append( QString("%1: %2 %3") .arg(QString( _PlanarFigure->GetFeatureName(k))) .arg(featureQuantity, 0, 'f', 2) .arg(QString(_PlanarFigure->GetFeatureUnit(k)))); plainInfoText.append( QString("\n%1: %2 %3") .arg(QString(_PlanarFigure->GetFeatureName(k))) .arg( featureQuantity, 0, 'f', 2) .arg(QString( _PlanarFigure->GetFeatureUnit(k)))); if(k+1 != _PlanarFigure->GetNumberOfFeatures()) infoText.append("
"); } if (j != d->m_CurrentSelection.size()) infoText.append("
"); } d->m_SelectedPlanarFiguresText->setHtml(infoText); } void QmitkMeasurementView::AddAllInteractors() { MEASUREMENT_DEBUG << "Adding interactors to all planar figures"; mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDataStorage()->GetAll(); const mitk::DataNode* node = 0; for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() ; it++) { node = const_cast(it->Value().GetPointer()); this->NodeAdded( node ); } } void QmitkMeasurementView::RemoveAllInteractors() { MEASUREMENT_DEBUG << "Removing interactors and observers from all planar figures"; mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDataStorage()->GetAll(); const mitk::DataNode* node = 0; for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() ; it++) { node = const_cast(it->Value().GetPointer()); this->NodeRemoved( node ); } } mitk::DataNode::Pointer QmitkMeasurementView::DetectTopMostVisibleImage() { // get all images from the data storage which are not a segmentation mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateNot::Pointer isNotBinary = mitk::NodePredicateNot::New( isBinary ); mitk::NodePredicateAnd::Pointer isNormalImage = mitk::NodePredicateAnd::New( isImage, isNotBinary ); mitk::DataStorage::SetOfObjects::ConstPointer Images = this->GetDataStorage()->GetSubset( isNormalImage ); mitk::DataNode::Pointer currentNode; int maxLayer = itk::NumericTraits::min(); // iterate over selection for (mitk::DataStorage::SetOfObjects::ConstIterator sofIt = Images->Begin(); sofIt != Images->End(); ++sofIt) { mitk::DataNode::Pointer node = sofIt->Value(); if ( node.IsNull() ) continue; if (node->IsVisible(NULL) == false) continue; int layer = 0; node->GetIntProperty("layer", layer); if ( layer < maxLayer ) { continue; } else { maxLayer = layer; currentNode = node; } } return currentNode; } void QmitkMeasurementView::EnableCrosshairNavigation() { MEASUREMENT_DEBUG << "EnableCrosshairNavigation"; // enable the crosshair navigation if (mitk::ILinkedRenderWindowPart* linkedRenderWindow = dynamic_cast(this->GetRenderWindowPart())) { MEASUREMENT_DEBUG << "enabling linked navigation"; //linkedRenderWindow->EnableLinkedNavigation(true); linkedRenderWindow->EnableSlicingPlanes(true); } } void QmitkMeasurementView::DisableCrosshairNavigation() { MEASUREMENT_DEBUG << "DisableCrosshairNavigation"; // disable the crosshair navigation during the drawing if (mitk::ILinkedRenderWindowPart* linkedRenderWindow = dynamic_cast(this->GetRenderWindowPart())) { MEASUREMENT_DEBUG << "disabling linked navigation"; //linkedRenderWindow->EnableLinkedNavigation(false); linkedRenderWindow->EnableSlicingPlanes(false); } } diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.h b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.h index 5423827e34..4fa4f5743d 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.h +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.h @@ -1,270 +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. ===================================================================*/ #ifndef QMITK_MEASUREMENT_H__INCLUDED #define QMITK_MEASUREMENT_H__INCLUDED /* #include #include #include #include #include #include #include #include #include #include #include class QmitkPlanarFiguresTableModel; class QGridLayout; class QMainWindow; class QToolBar; class QLabel; class QTableView; class QTextBrowser; class QActionGroup; class QPushButton; class vtkRenderer; class vtkCornerAnnotation; */ #include #include /// forward declarations struct QmitkMeasurementViewData; namespace mitk { class PlanarFigure; } /// /// A view for doing measurements in digital images by means of /// mitk::Planarfigures which can represent drawing primitives (Lines, circles, ...). /// The view consists of only three main elements: /// 1. A toolbar for activating PlanarFigure drawing /// 2. A textbrowser which shows details for the selected PlanarFigures /// 3. A button for copying all details to the clipboard /// class QmitkMeasurementView : public QmitkAbstractView { Q_OBJECT public: static const std::string VIEW_ID; QmitkMeasurementView(); virtual ~QmitkMeasurementView(); void CreateQtPartControl(QWidget* parent); void SetFocus(); virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &nodes); void NodeAdded(const mitk::DataNode* node); void NodeChanged(const mitk::DataNode* node); void NodeRemoved(const mitk::DataNode* node); void PlanarFigureSelected( itk::Object* object, const itk::EventObject& ); protected slots: ///# draw actions void ActionDrawLineTriggered( bool checked = false ); void ActionDrawPathTriggered( bool checked = false ); void ActionDrawAngleTriggered( bool checked = false ); void ActionDrawFourPointAngleTriggered( bool checked = false ); void ActionDrawEllipseTriggered( bool checked = false ); void ActionDrawRectangleTriggered( bool checked = false ); void ActionDrawPolygonTriggered( bool checked = false ); void CopyToClipboard( bool checked = false ); private: void CreateConnections(); mitk::DataNode::Pointer AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name); void UpdateMeasurementText(); void AddAllInteractors(); void RemoveAllInteractors(); mitk::DataNode::Pointer DetectTopMostVisibleImage(); void EnableCrosshairNavigation(); void DisableCrosshairNavigation(); void PlanarFigureInitialized(); void CheckForTopMostVisibleImage(mitk::DataNode* _NodeToNeglect=0); QmitkMeasurementViewData* d; }; /* public: /// /// Just a shortcut /// typedef std::vector DataNodes; /// /// Initialize pointers to 0. The rest is done in CreateQtPartControl() /// QmitkMeasurementView(); /// /// Remove all event listener from DataStorage, DataStorageSelection, Selection Service /// virtual ~QmitkMeasurementView(); public: /// /// Initializes all variables. /// Builds up GUI. /// void CreateQtPartControl(QWidget* parent); /// /// Set widget planes visibility to false. - /// Show only transversal view. + /// Show only axial view. /// Add an interactor to all PlanarFigures in the DataStorage (if they dont have one yet). /// Add their interactor to the global interaction. /// virtual void Activated(); virtual void Deactivated(); virtual void Visible(); virtual void Hidden(); /// /// Show widget planes and all renderwindows again. /// Remove all planar figure interactors from the global interaction. /// virtual void ActivatedZombieView(berry::IWorkbenchPartReference::Pointer zombieView); /// /// Invoked from a DataStorage selection /// virtual void NodeChanged(const mitk::DataNode* node); virtual void PropertyChanged(const mitk::DataNode* node, const mitk::BaseProperty* prop); virtual void NodeRemoved(const mitk::DataNode* node); virtual void NodeAddedInDataStorage(const mitk::DataNode* node); virtual void PlanarFigureInitialized(); virtual void PlanarFigureSelected( itk::Object* object, const itk::EventObject& event ); virtual void AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *propertyKey = NULL, mitk::BaseProperty *property = NULL ); /// /// Invoked when the DataManager selection changed. /// If an image is in the selection it will be set as the selected one for measurement, /// If a planarfigure is in the selection its parent image will be set as the selected one for measurement. /// All selected planarfigures will be added to m_SelectedPlanarFigures. /// Then PlanarFigureSelectionChanged is called /// virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &nodes); public slots: /// /// Called when the renderwindow gets deleted /// void OnRenderWindowDelete(QObject * obj = 0); protected: /// /// Prints all features of the selected PlanarFigures into the TextBrowser. /// For the last figure in the selection list: /// - Go to the corresponding slice and show figure /// - Draw info text on the bottom right side of the corresponding renderwindow /// void PlanarFigureSelectionChanged(); /// Draws a string on the bottom left side of the render window /// void SetMeasurementInfoToRenderWindow(const QString& text, QmitkRenderWindow* _RenderWindow); bool AssertDrawingIsPossible(bool checked); void EnableCrosshairNavigation(); void DisableCrosshairNavigation(); void SetFocus(); protected slots: ///# draw actions void ActionDrawLineTriggered( bool checked = false ); void ActionDrawPathTriggered( bool checked = false ); void ActionDrawAngleTriggered( bool checked = false ); void ActionDrawFourPointAngleTriggered( bool checked = false ); void ActionDrawEllipseTriggered( bool checked = false ); void ActionDrawRectangleTriggered( bool checked = false ); void ActionDrawPolygonTriggered( bool checked = false ); void ActionDrawArrowTriggered( bool checked = false ); void ActionDrawTextTriggered( bool checked = false ); void CopyToClipboard( bool checked = false ); void ReproducePotentialBug(bool); // fields // widgets protected: QAction* m_DrawLine; QAction* m_DrawPath; QAction* m_DrawAngle; QAction* m_DrawFourPointAngle; QAction* m_DrawEllipse; QAction* m_DrawRectangle; QAction* m_DrawPolygon; QToolBar* m_DrawActionsToolBar; QActionGroup* m_DrawActionsGroup; QTextBrowser* m_SelectedPlanarFiguresText; QPushButton* m_CopyToClipboard; vtkRenderer * m_MeasurementInfoRenderer; vtkCornerAnnotation *m_MeasurementInfoAnnotation; // Selection service /// berry::SelectionChangedAdapter must be a friend to call friend struct berry::SelectionChangedAdapter; berry::ISelectionListener::Pointer m_SelectionListener; mitk::DataStorageSelection::Pointer m_SelectedPlanarFigures; /// Selected image on which measurements will be performed /// mitk::DataStorageSelection::Pointer m_SelectedImageNode; mitk::DataNode::Pointer m_CurrentFigureNode; /// Counter variables to give a newly created Figure a unique name. /// unsigned int m_LineCounter; unsigned int m_PathCounter; unsigned int m_AngleCounter; unsigned int m_FourPointAngleCounter; unsigned int m_EllipseCounter; unsigned int m_RectangleCounter; unsigned int m_PolygonCounter; unsigned int m_EndPlacementObserverTag; unsigned int m_SelectObserverTag; unsigned int m_StartInteractionObserverTag; unsigned int m_EndInteractionObserverTag; bool m_Visible; bool m_CurrentFigureNodeInitialized; bool m_Activated; /// /// Saves the last renderwindow any info data was inserted /// QmitkRenderWindow* m_LastRenderWindow; private: void RemoveEndPlacementObserverTag(); mitk::DataNode::Pointer DetectTopMostVisibleImage(); */ #endif // QMITK_MEASUREMENT_H__INCLUDED diff --git a/Plugins/org.mitk.gui.qt.meshdecimation/documentation/Manual/meshdecimation-manual.dox b/Plugins/org.mitk.gui.qt.meshdecimation/documentation/Manual/meshdecimation-manual.dox index 33ead4ba4d..43367b70d1 100644 --- a/Plugins/org.mitk.gui.qt.meshdecimation/documentation/Manual/meshdecimation-manual.dox +++ b/Plugins/org.mitk.gui.qt.meshdecimation/documentation/Manual/meshdecimation-manual.dox @@ -1,33 +1,33 @@ /** -\bundlemainpage{org_meshdecimation} The Mesh Decimation Module +\page org_mitk_views_meshdecimation The Mesh Decimation Module \image html meshdecimation.png "Icon of the Module" Available sections: - \ref meshdecimationOverview - \ref meshdecimationFeatures - \ref meshdecimationUsage \section meshdecimationOverview Overview MeshDecimation is a user friendly tool to decimate a MITK surface. \section meshdecimationFeatures Features The module offers two basic procedures to decimate surfaces: One that reduces a surface with a possible loss of topology (quality), but with a garuanteed reduction rate that is expressed in terms of percent of the original mesh. The other variant preserves the topology and stops decimating when it detects heavy topological changes. \section meshdecimationUsage Usage \image html meshdecimation-ui.png "The user interface of the Mesh Decimation Module" The usage of the module should be straightforward, as shown in the screenshot. To decimate a MITK surface do the following: - Select a surface in the datamanager - Enter a target reduction rate - Select a decimation method (\ref meshdecimationFeatures) - Press the "Decimate" button - Repeat the process until you are satisfied with the decimation - Save the surface to disk */ diff --git a/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMakerUserManual.dox b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMakerUserManual.dox index 2e0780d8b9..24068b877c 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMakerUserManual.dox +++ b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMakerUserManual.dox @@ -1,45 +1,45 @@ /** -\bundlemainpage{org_moviemaker} The Movie Maker Module +\page org_mitk_views_moviemaker The Movie Maker Module \image html icon.png "Icon of the Module" Available sections: - \ref QmitkMovieMakerUserManualOverview - \ref QmitkMovieMakerUserManualFeatures - \ref QmitkMovieMakerUserManualUsage \section QmitkMovieMakerUserManualOverview Overview MovieMaker is a functionality for easily creating fancy movies from scenes displayed in MITK widgets. It is also possible to slide through your data, automatically rotate 3D scenes and take screenshots of widgets. \section QmitkMovieMakerUserManualFeatures Features The Movie Maker allows you to create movies and screenshots from within MITK. It can automatically scroll thorugh timesteps and slices while recording a movie. This way, you can record visualizations like a beating heart or a rotating skull. \section QmitkMovieMakerUserManualUsage Usage \image html QmitkMovieMakerControlArea.png "A view of the command area of QmitkMovieMaker" \subsection QmitkMovieMakerUserManualWindowSelection Window selection With the first two drop down boxes, you can choose which window you want to step through and which window you want to record in. Left clicking inside a window will set both drop down boxes to that window, but you can choose different windows for stepping and recording. The first drop down box defines the window along which slices will be stepped through if stepping is set to spatial (see below). The second denotes the window from which the content will be recorded. \subsection QmitkMovieMakerUserManualRecordingOptions Recording Options The slider can be used to step through the slices manually while not recording. Start and stop control a preview of what a video would look like. The buttons in the bottom part of this section can be used to create movies (windows only) or screenshots. Clicking opens a file %dialog where a name can be selected. After confirmation, a screenshot or movie is created according to the playing options. \subsection QmitkMovieMakerUserManualPlayingOptions Playing Options The first section controls whether the movie steps through slices (if a 2D view is selected), rotate the shown scene (if a 3D view is selected), or step through time steps (if set to temporal and a time resolved dataset is selected). If set to combined, a combination of both above options is used, with their speed relation set via the S/T Relation Spinbox. In the second section the direction of stepping can be set. Options are: Forward, backward and Ping-Pong, which is back-and-forth.The stepping speed can be set via the spinbox(total time in seconds). Although stepping speed is a total time in sec., this can not always be achieved. As a minimal frame rate of 25 fps is assumed to provide smooth movies, a dataset with only 25 slices will always be stepped through in 1 sec or faster. */ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkScreenshotMakerManual.dox b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkScreenshotMakerManual.dox similarity index 94% rename from Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkScreenshotMakerManual.dox rename to Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkScreenshotMakerManual.dox index 9f2e96a063..8536d9f771 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkScreenshotMakerManual.dox +++ b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkScreenshotMakerManual.dox @@ -1,19 +1,19 @@ /** -\page screenshot_maker The Screenshot Maker +\page org_mitk_views_screenshotmaker The Screenshot Maker This module provides the functionality to create and save screenshots of the data. Available sections: - \ref QmitkScreenshotMakerUserManualUse \image html screenshot_maker_interface.png The Screenshot Maker User Interface \section QmitkScreenshotMakerUserManualUse Usage The first section offers the option of creating a screenshot of the last activated render window (thus the one, which was last clicked into). Upon clicking the button, the Screenshot Maker asks for a filename in which the screenshot is to be stored. The multiplanar Screenshot button asks for a folder, where screenshots of the three 2D views will be stored with default names. The high resolution screenshot section works the same as the simple screenshot section, aside from the fact, that the user can choose a magnification factor. In the option section one can rotate the camera in the 3D view by using the buttons. Furthermore one can choose the background colour for the screenshots, default is black. */ diff --git a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkMovieMaker.cpp b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkMovieMaker.cpp index 51f34fc47c..3802de4780 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkMovieMaker.cpp +++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkMovieMaker.cpp @@ -1,771 +1,771 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "QmitkMovieMaker.h" //#include "QmitkMovieMakerControls.h" #include "QmitkStepperAdapter.h" #include "QmitkStdMultiWidget.h" #include "QmitkCommonFunctionality.h" #include "QmitkMovieMaker.h" //#include "QmitkMovieMakerControls.h" #include "QmitkStepperAdapter.h" #include "QmitkStdMultiWidget.h" #include "QmitkCommonFunctionality.h" #include "mitkVtkPropRenderer.h" #include "mitkGlobalInteraction.h" #include #include #include #include #include #include #include #include #include #include "qapplication.h" #include "vtkImageWriter.h" #include "vtkJPEGWriter.h" #include "vtkPNGWriter.h" #include "vtkRenderLargeImage.h" #include "vtkRenderWindowInteractor.h" #include "vtkRenderer.h" #include "vtkTestUtilities.h" #include #include "vtkMitkRenderProp.h" #include #include #include "vtkRenderWindowInteractor.h" #include QmitkMovieMaker::QmitkMovieMaker(QObject *parent, const char * /*name*/) : QmitkFunctionality(), m_Controls(NULL), m_StepperAdapter(NULL), m_FocusManagerCallback(0), m_Looping(true), m_Direction(0), m_Aspect(0) { parentWidget = parent; m_Timer = new QTimer(this); m_Time = new QTime(); m_FocusManagerCallback = MemberCommand::New(); m_FocusManagerCallback->SetCallbackFunction(this, &QmitkMovieMaker::FocusChange); m_movieGenerator = mitk::MovieGenerator::New(); if (m_movieGenerator.IsNull()) { MITK_ERROR << "Either mitk::MovieGenerator is not implemented for your"; MITK_ERROR << " platform or an error occurred during"; MITK_ERROR << " mitk::MovieGenerator::New()" ; } } QmitkMovieMaker::~QmitkMovieMaker() { delete m_StepperAdapter; delete m_Timer; delete m_Time; //delete m_RecordingRenderer; } mitk::BaseController* QmitkMovieMaker::GetSpatialController() { mitk::BaseRenderer* focusedRenderer = mitk::GlobalInteraction::GetInstance()->GetFocus(); if (mitk::BaseRenderer::GetInstance(GetActiveStdMultiWidget()->mitkWidget1->GetRenderWindow()) == focusedRenderer) { return GetActiveStdMultiWidget()->mitkWidget1->GetController(); } else if (mitk::BaseRenderer::GetInstance( GetActiveStdMultiWidget()->mitkWidget2->GetRenderWindow()) == focusedRenderer) { return GetActiveStdMultiWidget()->mitkWidget2->GetController(); } else if (mitk::BaseRenderer::GetInstance( GetActiveStdMultiWidget()->mitkWidget3->GetRenderWindow()) == focusedRenderer) { return GetActiveStdMultiWidget()->mitkWidget3->GetController(); } else if (mitk::BaseRenderer::GetInstance( GetActiveStdMultiWidget()->mitkWidget4->GetRenderWindow()) == focusedRenderer) { return GetActiveStdMultiWidget()->mitkWidget4->GetController(); } return GetActiveStdMultiWidget()->mitkWidget4->GetController(); } mitk::BaseController* QmitkMovieMaker::GetTemporalController() { return GetActiveStdMultiWidget()->GetTimeNavigationController(); } void QmitkMovieMaker::CreateConnections() { if (m_Controls) { // start / pause / stop playing connect((QObject*) m_Controls->btnPlay, SIGNAL(clicked()), (QObject*) this, SLOT(StartPlaying())); connect((QObject*) m_Controls->btnPause, SIGNAL(clicked()), this, SLOT(PausePlaying())); connect((QObject*) m_Controls->btnStop, SIGNAL(clicked()), this, SLOT(StopPlaying())); connect((QObject*) m_Controls->rbtnForward, SIGNAL(clicked()), this, SLOT(RBTNForward())); connect((QObject*) m_Controls->rbtnBackward, SIGNAL(clicked()), this, SLOT(RBTNBackward())); connect((QObject*) m_Controls->rbtnPingPong, SIGNAL(clicked()), this, SLOT(RBTNPingPong())); // radio button group: forward, backward, ping-pong connect( this, SIGNAL(SwitchDirection(int)), this, SLOT(SetDirection(int)) ); // radio button group: spatial, temporal connect((QObject*) m_Controls->rbtnSpatial, SIGNAL(clicked()), this, SLOT(RBTNSpatial())); connect((QObject*) m_Controls->rbtnTemporal, SIGNAL(clicked()), this, SLOT(RBTNTemporal())); connect((QObject*) m_Controls->rbtnCombined, SIGNAL(clicked()), this, SLOT(RBTNCombined())); connect( this, SIGNAL(SwitchAspect(int)), this, SLOT(SetAspect(int)) ); // stepper window selection connect((QObject*) (m_Controls->cmbSelectedStepperWindow), SIGNAL ( activated ( int) ), (QObject*) this, SLOT ( SetStepperWindow (int) ) ); // recording window selection connect((QObject*) (m_Controls->cmbSelectedRecordingWindow), SIGNAL ( activated ( int) ), (QObject*) this, SLOT ( SetRecordingWindow (int) ) ); // advance the animation // every timer tick connect((QObject*) m_Timer, SIGNAL(timeout()), this, SLOT(AdvanceAnimation())); // movie generation // when the movie button is clicked connect((QObject*) m_Controls->btnMovie, SIGNAL(clicked()), this, SLOT(GenerateMovie())); connect((QObject*) m_Controls->btnScreenshot, SIGNAL(clicked()), this, SLOT( GenerateScreenshot())); connect((QObject*) m_Controls->m_HRScreenshot, SIGNAL(clicked()), this, SLOT( GenerateHR3DScreenshot())); // blocking of ui elements during movie generation connect((QObject*) this, SIGNAL(StartBlockControls()), (QObject*) this, SLOT(BlockControls())); connect((QObject*) this, SIGNAL(EndBlockControls()), (QObject*) this, SLOT(UnBlockControls())); connect((QObject*) this, SIGNAL(EndBlockControlsMovieDeactive()), (QObject*) this, SLOT( UnBlockControlsMovieDeactive())); // allow for change of spatialtime relation connect((QObject*) m_Controls->spatialTimeRelation, SIGNAL(valueChanged ( int ) ), this, SLOT( DeleteMStepper() ) ); m_Controls->btnScreenshot->setVisible(false); m_Controls->m_HRScreenshot->setVisible(false); } } void QmitkMovieMaker::Activated() { QmitkFunctionality::Activated(); // create a member command that will be executed from the observer itk::SimpleMemberCommand::Pointer stepperChangedCommand; stepperChangedCommand = itk::SimpleMemberCommand::New(); // set the callback function of the member command stepperChangedCommand->SetCallbackFunction(this, &QmitkMovieMaker::UpdateGUI); // add an observer to the data tree node pointer connected to the above member command MITK_INFO << "Add observer on insertion point node in NavigationPathController::AddObservers"; m_StepperObserverTag = this->GetTemporalController()->GetTime()->AddObserver( itk::ModifiedEvent(), stepperChangedCommand); m_FocusManagerObserverTag = mitk::GlobalInteraction::GetInstance()->GetFocusManager()->AddObserver(mitk::FocusEvent(), m_FocusManagerCallback); this->UpdateGUI(); // Initialize steppers etc. this->FocusChange(); } void QmitkMovieMaker::Deactivated() { QmitkFunctionality::Deactivated(); this->GetTemporalController()->GetTime()->RemoveObserver(m_StepperObserverTag); mitk::GlobalInteraction::GetInstance()->GetFocusManager()->RemoveObserver( m_FocusManagerObserverTag); // remove (if tag is invalid, nothing is removed) } void QmitkMovieMaker::FocusChange() { mitk::Stepper *stepper = this->GetAspectStepper(); m_StepperAdapter->SetStepper(stepper); // Make the stepper movement non-inverted stepper->InverseDirectionOff(); // Set stepping direction and aspect (spatial / temporal) for new stepper this->UpdateLooping(); this->UpdateDirection(); // Set newly focused window as active in "Selected Window" combo box const mitk::RenderingManager::RenderWindowVector rwv = mitk::RenderingManager::GetInstance()->GetAllRegisteredRenderWindows(); int i; mitk::RenderingManager::RenderWindowVector::const_iterator iter; for (iter = rwv.begin(), i = 0; iter != rwv.end(); ++iter, ++i) { mitk::BaseRenderer* focusedRenderer = mitk::GlobalInteraction::GetInstance()->GetFocusManager()->GetFocused(); if (focusedRenderer == mitk::BaseRenderer::GetInstance((*iter))) { m_Controls->cmbSelectedStepperWindow->setCurrentIndex(i); // this->cmbSelectedStepperWindow_activated(i); this->SetStepperWindow(i); m_Controls->cmbSelectedRecordingWindow->setCurrentIndex(i); // this->cmbSelectedRecordWindow_activated(i); this->SetRecordingWindow(i); break; } } } void QmitkMovieMaker::AdvanceAnimation() { // This method is called when a timer timeout occurs. It increases the // stepper value according to the elapsed time and the stepper interval. // Note that a screen refresh is not forced, but merely requested, and may // occur only after more calls to AdvanceAnimation(). mitk::Stepper* stepper = this->GetAspectStepper(); m_StepperAdapter->SetStepper(stepper); int elapsedTime = m_Time->elapsed(); m_Time->restart(); static double increment = 0.0; increment = increment - static_cast (increment); increment += elapsedTime * stepper->GetSteps() / (m_Controls->spnDuration->value() * 1000.0); int i, n = static_cast (increment); for (i = 0; i < n; ++i) { stepper->Next(); } } void QmitkMovieMaker::RenderSlot() { int *i = widget->GetRenderWindow()->GetSize(); m_PropRenderer->Resize(i[0], i[1]); widget->GetRenderWindow()->Render(); } void QmitkMovieMaker::PausePlaying() { m_Controls->slidAngle->setDisabled(false); m_Controls->btnMovie->setEnabled(true); m_Controls->btnPlay->setEnabled(true); m_Controls->btnScreenshot->setEnabled(true); m_Timer->stop(); m_Controls->btnPlay->setHidden(false); m_Controls->btnPause->setHidden(true); if (m_movieGenerator.IsNull()) m_Controls->btnMovie->setEnabled(false); } void QmitkMovieMaker::StopPlaying() { m_Controls->slidAngle->setDisabled(false); m_Controls->btnMovie->setEnabled(true); m_Controls->btnPlay->setEnabled(true); m_Controls->btnScreenshot->setEnabled(true); m_Controls->btnPlay->setHidden(false); m_Controls->btnPause->setHidden(true); m_Timer->stop(); switch (m_Direction) { case 0: case 2: this->GetAspectStepper()->First(); break; case 1: this->GetAspectStepper()->Last(); break; } // Reposition slider GUI element m_StepperAdapter->SetStepper(this->GetAspectStepper()); if (m_movieGenerator.IsNull()) m_Controls->btnMovie->setEnabled(false); } void QmitkMovieMaker::SetLooping(bool looping) { m_Looping = looping; this->UpdateLooping(); } void QmitkMovieMaker::SetDirection(int direction) { m_Direction = direction; this->UpdateDirection(); } void QmitkMovieMaker::SetAspect(int aspect) { m_Aspect = aspect; m_StepperAdapter->SetStepper(this->GetAspectStepper()); this->UpdateLooping(); this->UpdateDirection(); } void QmitkMovieMaker::SetStepperWindow(int window) { // Set newly selected window / renderer as focused const mitk::RenderingManager::RenderWindowVector rwv = mitk::RenderingManager::GetInstance()->GetAllRegisteredRenderWindows(); //Delete MultiStepper DeleteMStepper(); int i; mitk::RenderingManager::RenderWindowVector::const_iterator iter; for (iter = rwv.begin(), i = 0; iter != rwv.end(); ++iter, ++i) { if (i == window) { mitk::GlobalInteraction::GetInstance()->GetFocusManager() ->SetFocused( mitk::BaseRenderer::GetInstance((*iter))); break; } } } void QmitkMovieMaker::SetRecordingWindow(int window) { // Set newly selected window for recording const mitk::RenderingManager::RenderWindowVector rwv = mitk::RenderingManager::GetInstance()->GetAllRegisteredRenderWindows(); //Delete MultiStepper DeleteMStepper(); int i; mitk::RenderingManager::RenderWindowVector::const_iterator iter; for (iter = rwv.begin(), i = 0; iter != rwv.end(); ++iter, ++i) { if (i == window) { m_RecordingRenderer = mitk::BaseRenderer::GetInstance((*iter)); break; } } } void QmitkMovieMaker::UpdateLooping() { this->GetAspectStepper()->SetAutoRepeat(m_Looping); } void QmitkMovieMaker::UpdateDirection() { mitk::Stepper* stepper = this->GetAspectStepper(); switch (m_Direction) { case 0: stepper->InverseDirectionOff(); stepper->PingPongOff(); break; case 1: stepper->InverseDirectionOn(); stepper->PingPongOff(); break; case 2: stepper->PingPongOn(); break; } } mitk::Stepper* QmitkMovieMaker::GetAspectStepper() { if (m_Aspect == 0) { m_Stepper = NULL; return this->GetSpatialController()->GetSlice(); } else if (m_Aspect == 1) { m_Stepper = NULL; return this->GetTemporalController()->GetTime(); } else if (m_Aspect == 2) { if (m_Stepper.IsNull()) { int rel = m_Controls->spatialTimeRelation->value(); int timeRepeat = 1; int sliceRepeat = 1; if (rel < 0) { sliceRepeat = -rel; } else if (rel > 0) { timeRepeat = rel; } m_Stepper = mitk::MultiStepper::New(); m_Stepper->AddStepper(this->GetSpatialController()->GetSlice(), sliceRepeat); m_Stepper->AddStepper(this->GetTemporalController()->GetTime(), timeRepeat); } return m_Stepper.GetPointer(); } else { // should never get here return 0; } } void QmitkMovieMaker::GenerateMovie() { emit StartBlockControls(); // provide the movie generator with the stepper and rotate the camera each step if (m_movieGenerator.IsNotNull()) { m_movieGenerator->SetStepper(this->GetAspectStepper()); m_movieGenerator->SetRenderer(m_RecordingRenderer); m_movieGenerator->SetFrameRate(static_cast (360 / (m_Controls->spnDuration->value()))); // QString movieFileName = QFileDialog::getSaveFileName( QString::null, "Movie (*.avi)", 0, "movie file dialog", "Choose a file name" ); QString movieFileName = QFileDialog::getSaveFileName(0, "Choose a file name", QString::null, "Movie (*.avi)", 0, 0); if (movieFileName.isEmpty() == false) { mitk::RenderingManager::GetInstance()->RequestUpdateAll(); m_movieGenerator->SetFileName(movieFileName.toAscii()); m_movieGenerator->WriteMovie(); } emit EndBlockControls(); } else { MITK_ERROR << "Either mitk::MovieGenerator is not implemented for your"; MITK_ERROR << " platform or an error occurred during"; MITK_ERROR << " mitk::MovieGenerator::New()"; emit EndBlockControlsMovieDeactive(); } } void QmitkMovieMaker::GenerateScreenshot() { emit StartBlockControls(); QString fileName = QFileDialog::getSaveFileName(NULL, "Save screenshot to...", QDir::currentPath(), "JPEG file (*.jpg);;PNG file (*.png)"); vtkRenderer* renderer = mitk::GlobalInteraction::GetInstance()->GetFocus()->GetVtkRenderer(); if (renderer == NULL) return; this->TakeScreenshot(renderer, 1, fileName); if (m_movieGenerator.IsNotNull()) emit EndBlockControls(); else emit EndBlockControlsMovieDeactive(); } void QmitkMovieMaker::GenerateHR3DScreenshot() { emit StartBlockControls(); QString fileName = QFileDialog::getSaveFileName(NULL, "Save screenshot to...", QDir::currentPath(), "JPEG file (*.jpg);;PNG file (*.png)"); // only works correctly for 3D RenderWindow vtkRenderer* renderer = m_MultiWidget->mitkWidget4->GetRenderer()->GetVtkRenderer(); if (renderer == NULL) return; this->TakeScreenshot(renderer, 4, fileName); if (m_movieGenerator.IsNotNull()) emit EndBlockControls(); else emit EndBlockControlsMovieDeactive(); } void QmitkMovieMaker::UpdateGUI() { int bla = this->GetTemporalController()->GetTime()->GetSteps(); if (bla < 2) { m_Controls->rbtnTemporal->setEnabled(false); m_Controls->rbtnCombined->setEnabled(false); m_Controls->spatialTimeRelation->setEnabled(false); } else { m_Controls->rbtnTemporal->setEnabled(true); m_Controls->rbtnCombined->setEnabled(true); m_Controls->spatialTimeRelation->setEnabled(true); } } void QmitkMovieMaker::DataStorageChanged() { // UpdateGUI(); } void QmitkMovieMaker::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { m_Controls = new Ui::QmitkMovieMakerControls; m_Controls->setupUi(parent); m_StepperAdapter = new QmitkStepperAdapter((QObject*) m_Controls->slidAngle, this->GetSpatialController()->GetSlice(), "AngleStepperToMovieMakerFunctionality"); // Initialize "Selected Window" combo box const mitk::RenderingManager::RenderWindowVector rwv = mitk::RenderingManager::GetInstance()->GetAllRegisteredRenderWindows(); mitk::RenderingManager::RenderWindowVector::const_iterator iter; unsigned int i = 0; for (iter = rwv.begin(); iter != rwv.end(); ++iter) { QString name(mitk::BaseRenderer::GetInstance((*iter))->GetName()); if (name=="stdmulti.widget1") { - m_Controls->cmbSelectedStepperWindow->insertItem(i, "Transversal"); - m_Controls->cmbSelectedRecordingWindow->insertItem(i++, "Transversal"); + m_Controls->cmbSelectedStepperWindow->insertItem(i, "Axial"); + m_Controls->cmbSelectedRecordingWindow->insertItem(i++, "Axial"); } else if (name=="stdmulti.widget2") { m_Controls->cmbSelectedStepperWindow->insertItem(i, "Sagittal"); m_Controls->cmbSelectedRecordingWindow->insertItem(i++, "Sagittal"); } else if (name=="stdmulti.widget3") { m_Controls->cmbSelectedStepperWindow->insertItem(i, "Coronal"); m_Controls->cmbSelectedRecordingWindow->insertItem(i++, "Coronal"); } else if (name=="stdmulti.widget4") { m_Controls->cmbSelectedStepperWindow->insertItem(i, "3D Window"); m_Controls->cmbSelectedRecordingWindow->insertItem(i++, "3D Window"); } else { m_Controls->cmbSelectedStepperWindow->insertItem(i, name); m_Controls->cmbSelectedRecordingWindow->insertItem(i++, name); } } m_Controls->btnPause->setHidden(true); if (m_movieGenerator.IsNull()) m_Controls->btnMovie->setEnabled(false); } this->CreateConnections(); } void QmitkMovieMaker::StartPlaying() { m_Controls->slidAngle->setDisabled(true); m_Controls->btnMovie->setEnabled(false); m_Controls->btnPlay->setEnabled(false); m_Controls->btnScreenshot->setEnabled(false); // Restart timer with 5 msec interval - this should be fine-grained enough // even for high display refresh frequencies m_Timer->start(5); m_Time->restart(); m_Controls->btnPlay->setHidden(true); m_Controls->btnPause->setHidden(false); if (m_movieGenerator.IsNull()) m_Controls->btnMovie->setEnabled(false); } void QmitkMovieMaker::RBTNForward() { emit SwitchDirection(0); } void QmitkMovieMaker::RBTNBackward() { emit SwitchDirection(1); } void QmitkMovieMaker::RBTNPingPong() { emit SwitchDirection(2); } void QmitkMovieMaker::RBTNSpatial() { emit SwitchAspect(0); } void QmitkMovieMaker::RBTNTemporal() { emit SwitchAspect(1); } void QmitkMovieMaker::RBTNCombined() { emit SwitchAspect(2); } void QmitkMovieMaker::BlockControls() { BlockControls(true); } void QmitkMovieMaker::UnBlockControls() { BlockControls(false); } void QmitkMovieMaker::UnBlockControlsMovieDeactive() { BlockControls(false); m_Controls->btnMovie->setEnabled(false); } void QmitkMovieMaker::BlockControls(bool blocked) { m_Controls->slidAngle->setDisabled(blocked); m_Controls->spnDuration->setEnabled(!blocked); m_Controls->btnPlay->setEnabled(!blocked); m_Controls->btnMovie->setEnabled(!blocked); m_Controls->btnScreenshot->setEnabled(!blocked); } void QmitkMovieMaker::StdMultiWidgetAvailable(QmitkStdMultiWidget& stdMultiWidget) { m_MultiWidget = &stdMultiWidget; m_Parent->setEnabled(true); } void QmitkMovieMaker::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; m_Parent->setEnabled(false); } void QmitkMovieMaker::TakeScreenshot(vtkRenderer* renderer, unsigned int magnificationFactor, QString fileName) { if ((renderer == NULL) ||(magnificationFactor < 1) || fileName.isEmpty()) return; bool doubleBuffering( renderer->GetRenderWindow()->GetDoubleBuffer() ); renderer->GetRenderWindow()->DoubleBufferOff(); vtkImageWriter* fileWriter; QFileInfo fi(fileName); QString suffix = fi.suffix(); if (suffix.compare("png", Qt::CaseInsensitive) == 0) { fileWriter = vtkPNGWriter::New(); } else // default is jpeg { vtkJPEGWriter* w = vtkJPEGWriter::New(); w->SetQuality(100); w->ProgressiveOff(); fileWriter = w; } vtkRenderLargeImage* magnifier = vtkRenderLargeImage::New(); magnifier->SetInput(renderer); magnifier->SetMagnification(magnificationFactor); //magnifier->Update(); fileWriter->SetInput(magnifier->GetOutput()); fileWriter->SetFileName(fileName.toLatin1()); // vtkRenderLargeImage has problems with different layers, therefore we have to // temporarily deactivate all other layers. // we set the background to white, because it is nicer than black... double oldBackground[3]; renderer->GetBackground(oldBackground); double white[] = {1.0, 1.0, 1.0}; renderer->SetBackground(white); m_MultiWidget->DisableColoredRectangles(); m_MultiWidget->DisableDepartmentLogo(); m_MultiWidget->DisableGradientBackground(); m_MultiWidget->mitkWidget1->ActivateMenuWidget( false ); m_MultiWidget->mitkWidget2->ActivateMenuWidget( false ); m_MultiWidget->mitkWidget3->ActivateMenuWidget( false ); m_MultiWidget->mitkWidget4->ActivateMenuWidget( false ); fileWriter->Write(); fileWriter->Delete(); m_MultiWidget->mitkWidget1->ActivateMenuWidget( true ); m_MultiWidget->mitkWidget2->ActivateMenuWidget( true ); m_MultiWidget->mitkWidget3->ActivateMenuWidget( true ); m_MultiWidget->mitkWidget4->ActivateMenuWidget( true ); m_MultiWidget->EnableColoredRectangles(); m_MultiWidget->EnableDepartmentLogo(); m_MultiWidget->EnableGradientBackground(); renderer->SetBackground(oldBackground); renderer->GetRenderWindow()->SetDoubleBuffer(doubleBuffering); } void QmitkMovieMaker::DeleteMStepper() { m_Stepper = NULL; UpdateLooping(); } diff --git a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMaker.cpp b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMaker.cpp index 61028bad02..ac9ac5a307 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMaker.cpp +++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMaker.cpp @@ -1,380 +1,380 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "QmitkScreenshotMaker.h" //#include "QmitkMovieMakerControls.h" #include "QmitkStepperAdapter.h" #include "QmitkStdMultiWidget.h" #include "QmitkCommonFunctionality.h" #include "mitkVtkPropRenderer.h" #include "mitkGlobalInteraction.h" #include #include #include #include #include #include #include #include #include #include #include #include "qapplication.h" #include "vtkImageWriter.h" #include "vtkJPEGWriter.h" #include "vtkPNGWriter.h" #include "vtkRenderLargeImage.h" #include "vtkRenderWindowInteractor.h" #include "vtkRenderer.h" #include "vtkTestUtilities.h" #include #include "vtkMitkRenderProp.h" #include #include #include "vtkRenderWindowInteractor.h" #include #include "mitkSliceNavigationController.h" #include "mitkPlanarFigure.h" QmitkScreenshotMaker::QmitkScreenshotMaker(QObject *parent, const char * /*name*/) : QmitkFunctionality(), m_Controls(NULL), m_SelectedNode(0), m_BackgroundColor(QColor(0,0,0)) { parentWidget = parent; } QmitkScreenshotMaker::~QmitkScreenshotMaker() { } void QmitkScreenshotMaker::CreateConnections() { if (m_Controls) { connect((QObject*) m_Controls->m_AllViews, SIGNAL(clicked()), (QObject*) this, SLOT(GenerateMultiplanar3DHighresScreenshot())); connect((QObject*) m_Controls->m_View1, SIGNAL(clicked()), (QObject*) this, SLOT(View1())); connect((QObject*) m_Controls->m_View2, SIGNAL(clicked()), (QObject*) this, SLOT(View2())); connect((QObject*) m_Controls->m_View3, SIGNAL(clicked()), (QObject*) this, SLOT(View3())); connect((QObject*) m_Controls->m_Shot, SIGNAL(clicked()), (QObject*) this, SLOT(GenerateMultiplanarScreenshots())); connect((QObject*) m_Controls->m_BackgroundColor, SIGNAL(clicked()), (QObject*) this, SLOT(SelectBackgroundColor())); connect((QObject*) m_Controls->btnScreenshot, SIGNAL(clicked()), this, SLOT(GenerateScreenshot())); connect((QObject*) m_Controls->m_HRScreenshot, SIGNAL(clicked()), this, SLOT(Generate3DHighresScreenshot())); QString styleSheet = "background-color:rgb(0,0,0)"; m_Controls->m_BackgroundColor->setStyleSheet(styleSheet); } } void QmitkScreenshotMaker::Activated() { QmitkFunctionality::Activated(); } void QmitkScreenshotMaker::Deactivated() { QmitkFunctionality::Deactivated(); } void QmitkScreenshotMaker::GenerateScreenshot() { QString fileName = QFileDialog::getSaveFileName(NULL, "Save screenshot to...", QDir::currentPath()+"/screenshot.jpg", "JPEG file (*.jpg);;PNG file (*.png)"); vtkRenderer* renderer = mitk::GlobalInteraction::GetInstance()->GetFocus()->GetVtkRenderer(); if (renderer == NULL) return; this->TakeScreenshot(renderer, 1, fileName); } void QmitkScreenshotMaker::GenerateMultiplanarScreenshots() { QString fileName = QFileDialog::getExistingDirectory(NULL, "Save screenshots to...", QDir::currentPath()); if( fileName.isEmpty() ) { return; } //emit StartBlockControls(); mitk::DataNode* n; n = this->m_MultiWidget->GetWidgetPlane1(); if(n) { n->SetProperty( "color", mitk::ColorProperty::New( 1,1,1 ) ); // n->SetProperty("helper object", mitk::BoolProperty::New(false)); } n = this->m_MultiWidget->GetWidgetPlane2(); if(n) { n->SetProperty( "color", mitk::ColorProperty::New( 1,1,1 ) ); // n->SetProperty("helper object", mitk::BoolProperty::New(false)); } n = this->m_MultiWidget->GetWidgetPlane3(); if(n) { n->SetProperty( "color", mitk::ColorProperty::New( 1,1,1 ) ); // n->SetProperty("helper object", mitk::BoolProperty::New(false)); } // only works correctly for 3D RenderWindow vtkRenderer* renderer = m_MultiWidget->mitkWidget1->GetRenderer()->GetVtkRenderer(); if (renderer != NULL) - this->TakeScreenshot(renderer, 1, fileName+"/transversal.png"); + this->TakeScreenshot(renderer, 1, fileName+"/axial.png"); renderer = m_MultiWidget->mitkWidget2->GetRenderer()->GetVtkRenderer(); if (renderer != NULL) this->TakeScreenshot(renderer, 1, fileName+"/sagittal.png"); renderer = m_MultiWidget->mitkWidget3->GetRenderer()->GetVtkRenderer(); if (renderer != NULL) this->TakeScreenshot(renderer, 1, fileName+"/coronal.png"); n = this->m_MultiWidget->GetWidgetPlane1(); if(n) { n->SetProperty( "color", mitk::ColorProperty::New( 1,0,0 ) ); // n->SetProperty("helper object", mitk::BoolProperty::New(false)); } n = this->m_MultiWidget->GetWidgetPlane2(); if(n) { n->SetProperty( "color", mitk::ColorProperty::New( 0,1,0 ) ); // n->SetProperty("helper object", mitk::BoolProperty::New(false)); } n = this->m_MultiWidget->GetWidgetPlane3(); if(n) { n->SetProperty( "color", mitk::ColorProperty::New( 0,0,1 ) ); // n->SetProperty("helper object", mitk::BoolProperty::New(false)); } } void QmitkScreenshotMaker::Generate3DHighresScreenshot() { QString fileName = QFileDialog::getSaveFileName(NULL, "Save screenshot to...", QDir::currentPath()+"/3D_screenshot.jpg", "JPEG file (*.jpg);;PNG file (*.png)"); GenerateHR3DAtlasScreenshots(fileName); } void QmitkScreenshotMaker::GenerateMultiplanar3DHighresScreenshot() { QString fileName = QFileDialog::getExistingDirectory( NULL, "Save screenshots to...", QDir::currentPath()); if( fileName.isEmpty() ) { return; } GetCam()->Azimuth( -7.5 ); GetCam()->Roll(-4); GenerateHR3DAtlasScreenshots(fileName+"/3D_1.png"); GetCam()->Roll(4); GetCam()->Azimuth( 90 ); GetCam()->Elevation( 4 ); GenerateHR3DAtlasScreenshots(fileName+"/3D_2.png"); GetCam()->Elevation( 90 ); GetCam()->Roll( -2.5 ); GenerateHR3DAtlasScreenshots(fileName+"/3D_3.png"); } void QmitkScreenshotMaker::GenerateHR3DAtlasScreenshots(QString fileName) { // only works correctly for 3D RenderWindow vtkRenderer* renderer = m_MultiWidget->mitkWidget4->GetRenderer()->GetVtkRenderer(); if (renderer == NULL) return; this->TakeScreenshot(renderer, this->m_Controls->m_MagFactor->text().toFloat(), fileName); } vtkCamera* QmitkScreenshotMaker::GetCam() { mitk::BaseRenderer* renderer = mitk::BaseRenderer::GetInstance(GetActiveStdMultiWidget()->mitkWidget4->GetRenderWindow()); vtkCamera* cam = 0; const mitk::VtkPropRenderer *propRenderer = dynamic_cast( renderer ); if (propRenderer) { // get vtk renderer vtkRenderer* vtkrenderer = propRenderer->GetVtkRenderer(); if (vtkrenderer) { // get vtk camera vtkCamera* vtkcam = vtkrenderer->GetActiveCamera(); if (vtkcam) { // vtk smart pointer handling cam = vtkcam; cam->Register( NULL ); } } } return cam; } void QmitkScreenshotMaker::View1() { GetCam()->Elevation( 45 ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkScreenshotMaker::View2() { GetCam()->Azimuth(45); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkScreenshotMaker::View3() { GetCam()->Roll(45); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkScreenshotMaker::OnSelectionChanged( std::vector nodes ) { if(nodes.size()) m_SelectedNode = nodes[0]; } void QmitkScreenshotMaker::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { m_Controls = new Ui::QmitkScreenshotMakerControls; m_Controls->setupUi(parent); // Initialize "Selected Window" combo box const mitk::RenderingManager::RenderWindowVector rwv = mitk::RenderingManager::GetInstance()->GetAllRegisteredRenderWindows(); } this->CreateConnections(); } void QmitkScreenshotMaker::StdMultiWidgetAvailable(QmitkStdMultiWidget& stdMultiWidget) { m_MultiWidget = &stdMultiWidget; m_Parent->setEnabled(true); } void QmitkScreenshotMaker::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; m_Parent->setEnabled(false); } void QmitkScreenshotMaker::TakeScreenshot(vtkRenderer* renderer, unsigned int magnificationFactor, QString fileName) { if ((renderer == NULL) ||(magnificationFactor < 1) || fileName.isEmpty()) return; bool doubleBuffering( renderer->GetRenderWindow()->GetDoubleBuffer() ); renderer->GetRenderWindow()->DoubleBufferOff(); vtkImageWriter* fileWriter; QFileInfo fi(fileName); QString suffix = fi.suffix(); if (suffix.compare("png", Qt::CaseInsensitive) == 0) { fileWriter = vtkPNGWriter::New(); } else // default is jpeg { vtkJPEGWriter* w = vtkJPEGWriter::New(); w->SetQuality(100); w->ProgressiveOff(); fileWriter = w; } vtkRenderLargeImage* magnifier = vtkRenderLargeImage::New(); magnifier->SetInput(renderer); magnifier->SetMagnification(magnificationFactor); //magnifier->Update(); fileWriter->SetInput(magnifier->GetOutput()); fileWriter->SetFileName(fileName.toLatin1()); // vtkRenderLargeImage has problems with different layers, therefore we have to // temporarily deactivate all other layers. // we set the background to white, because it is nicer than black... double oldBackground[3]; renderer->GetBackground(oldBackground); // QColor color = QColorDialog::getColor(); double bgcolor[] = {m_BackgroundColor.red()/255.0, m_BackgroundColor.green()/255.0, m_BackgroundColor.blue()/255.0}; renderer->SetBackground(bgcolor); m_MultiWidget->DisableColoredRectangles(); m_MultiWidget->DisableDepartmentLogo(); m_MultiWidget->DisableGradientBackground(); m_MultiWidget->mitkWidget1->ActivateMenuWidget( false ); m_MultiWidget->mitkWidget2->ActivateMenuWidget( false ); m_MultiWidget->mitkWidget3->ActivateMenuWidget( false ); m_MultiWidget->mitkWidget4->ActivateMenuWidget( false ); fileWriter->Write(); fileWriter->Delete(); m_MultiWidget->mitkWidget1->ActivateMenuWidget( true ); m_MultiWidget->mitkWidget2->ActivateMenuWidget( true ); m_MultiWidget->mitkWidget3->ActivateMenuWidget( true ); m_MultiWidget->mitkWidget4->ActivateMenuWidget( true ); m_MultiWidget->EnableColoredRectangles(); m_MultiWidget->EnableDepartmentLogo(); m_MultiWidget->EnableGradientBackground(); renderer->SetBackground(oldBackground); renderer->GetRenderWindow()->SetDoubleBuffer(doubleBuffering); } void QmitkScreenshotMaker::SelectBackgroundColor() { m_BackgroundColor = QColorDialog::getColor(); m_Controls->m_BackgroundColor->setAutoFillBackground(true); QString styleSheet = "background-color:rgb("; styleSheet.append(QString::number(m_BackgroundColor.red())); styleSheet.append(","); styleSheet.append(QString::number(m_BackgroundColor.green())); styleSheet.append(","); styleSheet.append(QString::number(m_BackgroundColor.blue())); styleSheet.append(")"); m_Controls->m_BackgroundColor->setStyleSheet(styleSheet); } diff --git a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMakerControls.ui b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMakerControls.ui index f1068f8050..b4a55ea0cd 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMakerControls.ui +++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMakerControls.ui @@ -1,308 +1,308 @@ QmitkScreenshotMakerControls 0 0 430 368 ScreenshotMaker 5 0 5 0 QFrame::NoFrame QFrame::Raised 0 QFrame::NoFrame QFrame::Raised 0 QFrame::NoFrame QFrame::Raised 0 QFrame::NoFrame QFrame::Raised 0 QFrame::NoFrame QFrame::Raised 0 2D Screenshots 0 0 Writes a screenshot of the selected (last clicked) render window. Single Screenshot - Writes screenshots of the transversal, sagittal and coronal render window. + Writes screenshots of the axial, sagittal and coronal render window. Multiplanar Screenshot 3D Screenshots 0 0 Writes a high resolution screenshot of the 3D render window. High-res Single Screenshot Writes screenshots of the 3D render window from 3 different angles. High-res Multiplanar Screenshot Upsampling: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 1 5 Options 30 0 10 16777215 Rotate 3D camera 45° around x-axis. x 30 16777215 Rotate 3D camera 45° around y-axis. y 30 16777215 Rotate 3D camera 45° around z-axis. z Qt::Horizontal 308 23 Background Color: Qt::Vertical 20 31 diff --git a/Plugins/org.mitk.gui.qt.pointsetinteraction/documentation/UserManual/QmitkPointSetInteractionUserManual.dox b/Plugins/org.mitk.gui.qt.pointsetinteraction/documentation/UserManual/QmitkPointSetInteractionUserManual.dox index 1846ec2e17..56d10b37a8 100644 --- a/Plugins/org.mitk.gui.qt.pointsetinteraction/documentation/UserManual/QmitkPointSetInteractionUserManual.dox +++ b/Plugins/org.mitk.gui.qt.pointsetinteraction/documentation/UserManual/QmitkPointSetInteractionUserManual.dox @@ -1,38 +1,38 @@ /** -\bundlemainpage{org_pointsetinteraction} The Point Set Interaction Module +\page org_mitk_views_pointsetinteraction The Point Set Interaction Module \image html pointset_interaction.png "Icon of the Module" Available sections: - \ref QmitkPointSetInteractionUserManualOverview - \ref QmitkPointSetInteractionUserManualDetails \section QmitkPointSetInteractionUserManualOverview Overview This functionality allows you to define multiple sets of points, to fill them with points and to save them in so called PointSets. \image html QmitkPointSetInteraction.png "MITK with the QmitkPointSetInteraction functionality" This document will tell you how to use this functionality, but it is assumed that you already know how to navigate through the slices of an image using the four window view. Please read the application manual for more information. \section QmitkPointSetInteractionUserManualDetails Details First of all you have to select a PointSet to use this functionality. Therefore, you have to select the point set in the data manager. If there are currently no point sets in the data tree, you have to first add a new point set to the data tree. This is done by clicking the "Add pointset..." button. \image html AddPointSet.png "The Add pointset... dialog" In the pop-up dialog, you have to specify a name for the new point set. This is also the node for the new data tree item. \image html CurrentPointSetArea.png "The Current pointset area" The "Current pointset" area contains a list of points. Within this area, all points for the current point set node are listed. To set points you have to toggle the "Set Points" button, the leftmost of the four buttons on the bottom of the view. Points can be defined by performing a left mouse button click while holding the "Shift"-key pressed in the four window view. To erase all points from the list press the next button. The user is prompted to confirm the decision. If you want to delete only a single point, left click on it in the list and then press delete on your keyboard. With the third button, a previously saved point set can be loaded and all of its points are shown in the list and the four window view. The user is prompted to select the file to be loaded. The file extension is ".mps". On the right of this button is the save button. With this function the entire point set can be saved to the harddrive. The user is prompted to select a filename. Pointsets are saved in XML fileformat but have to have a ".mps" file extension. You can select points in the render window, if the "Set Points" button is toggled, with a left mouse button click on them. If you keep the mouse button pressed, you can move the points by moving the mouse and then releasing the mouse button. With the delete key you can remove the selected points. */ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.registration/documentation/UserManual/QmitkDeformableRegistrationUserManual.dox b/Plugins/org.mitk.gui.qt.registration/documentation/UserManual/QmitkDeformableRegistrationUserManual.dox index 10a3d0cdb5..9e88fa396e 100644 --- a/Plugins/org.mitk.gui.qt.registration/documentation/UserManual/QmitkDeformableRegistrationUserManual.dox +++ b/Plugins/org.mitk.gui.qt.registration/documentation/UserManual/QmitkDeformableRegistrationUserManual.dox @@ -1,52 +1,52 @@ /** -\page org_deform_registration The Deformable Image Registration Module +\page org_mitk_views_deformableregistration The Deformable Image Registration Module Available sections: - \ref DeformableRegistrationUserManualOverview - \ref DeformableRegistrationUserManualDetails \section DeformableRegistrationUserManualOverview Overview This module allows you to register 2D as well as 3D images in a deformable manner. Register means to align two images, so that they become as similar as possible. Registration results will directly be applied to the Moving Image. \image html QmitkDeformableRegistration_small.png "MITK with the DeformableRegistration module" This document will tell you how to use this module, but it is assumed that you already know how to navigate through the slices of an image using the multi-widget. \section DeformableRegistrationUserManualDetails Details First of all you have to open the data sets which you want to register and select them in the Data Manager. You have to select exactly 2 images for registration. The image which was selected first will become the fixed image, the other one the moving image. The two selected images will remain for registration until exactly two images were selected in the Data Manager again. While there aren't two images for registration a message is viewed on top of the module saying that registration needs two images. If two images are selected the message disappears and the interaction areas for the fixed and moving data appears. On default only the fixed and moving image are shown in the render windows. If you want to have other images visible you have to set the visibility via the Data Manager. Also if you want to perform a reinit on a specific node or a global reinit for all nodes you have to use the Data Manager. \image html ImageSelectionDeformable.png "The Image area" The upper area is the "Image" area, where the selected images are shown. It is used for changing the colour of the images between grey values and red/green as well as for changing the opacity of the moving image. To do so, just use the "Moving Image Opacity:" slider. In the "Show Images Red/Green" you can switch the color from both datasets. If you check the box, the fixed dataset will be displayed in redvalues and the moving dataset in greenvalues to improve visibility of differences in the datasets. If you uncheck the "Show Images Red/Green" checkbox, both datasets will be displayed in greyvalues. \image html RegistrationDeformable.png "The Registration area for Demons based registration" In the "Registration" area you have the choice between different Demonsbased deformable registration algorithms. There are available: \li Demons Registration \li Symmetric Forces Demons Registration For both methods you have to define the same set of parameters. First you have to decide whether you want to perform a histogram matching. This can be done by selecting "Use Histogram Matching". When it is selected the corresponding parameters are enabled and have to be set. These are the "Number of Histogram Levels", "Number of Match Points" and whether to use a "Threshold at Mean Intensity". For the registration method itself you have to specify the "Number of Iterations" and the "Standard Deviation" within the "Demons Registration" area. If all this is done, you can perform the registration by clicking the "Calculate Transformation" button. Finally, you will be asked where you want the result image and the resulting deformation field to be saved. Therefore you have to select the folder and enter a filename. The results will be added in the DataStorage and can be saved in the Data Manager. */ diff --git a/Plugins/org.mitk.gui.qt.registration/documentation/UserManual/QmitkPointBasedRegistrationUserManual.dox b/Plugins/org.mitk.gui.qt.registration/documentation/UserManual/QmitkPointBasedRegistrationUserManual.dox index c10a09068a..ab8841cd4b 100644 --- a/Plugins/org.mitk.gui.qt.registration/documentation/UserManual/QmitkPointBasedRegistrationUserManual.dox +++ b/Plugins/org.mitk.gui.qt.registration/documentation/UserManual/QmitkPointBasedRegistrationUserManual.dox @@ -1,106 +1,106 @@ /** -\page org_pointbased_reg The Point Based Registration Module +\page org_mitk_views_pointbasedregistration The Point Based Registration Module \image html pointBasedIcon.png "Icon of the Module" Available sections: - \ref PointBasedRegistrationUserManualOverview - \ref PointBasedRegistrationUserManualDetails \section PointBasedRegistrationUserManualOverview Overview This module allows you to register two datasets in a rigid and deformable manner via corresponding PointSets. Register means to align two datasets, so that they become as similar as possible. Therefore you have to set corresponding points in both datasets, which will be matched. The movement, which has to be performed on the points to align them, will be performed on the moving data as well. The result is shown in the multi-widget. \image html PointBasedRegistration_small.png "MITK with the PointBasedRegistration module" This document will tell you how to use this module, but it is assumed that you already know how to navigate through the slices of a dataset using the multi-widget. \section PointBasedRegistrationUserManualDetails Details First of all you have to open the data sets which you want to register and select them in the Data Manager. You have to select exactly 2 images for registration. The image which was selected first will become the fixed image, the other one the moving image. The two selected images will remain for registration until exactly two images were selected in the Data Manager again. While there aren't two images for registration a message is viewed on top of the module saying that registration needs two images. If two images are selected the message disappears and the interaction areas for the fixed and moving data appears. The upper area is for interaction with the fixed data. Beneath this area is the interaction area for the moving data. On default only the fixed and moving image with their corresponding pointsets are shown in the render windows. If you want to have other images visible you have to set the visibility via the Data Manager. Also if you want to perform a reinit on a specific node or a global reinit for all nodes you have to use the Data Manager. \image html FixedDataPointBased.png "The Fixed Data area" The "Fixed Data" area contains a QmitkPointListWidget. Within this widget, all points for the fixed data are listed. The label above this list shows the number of points that are already set. To set points you have to toggle the "Set Points" button, the leftmost under the QmitkPointListWidget. The views in the QmitkStdMultiWidget were reinitialized to the fixed data. Points can be defined by performing a left click while holding the "Shift"-key pressed in the QmitkStdMultiWidget. You can remove the interactor which listens for left clicks while holding the "Shift"-key pressed by detoggle the "Set Points" button. The next button, "Clear Point Set", is for deleting all specified points from this dataset. The user is prompted to confirm the decision. With the most right button, a previously saved point set can be loaded and all of its points are shown in the QmitkPointListWidget and in the QmitkStdMultiWidget. The user is prompted to select the file to be loaded. The file extension is ".mps". On the left of this button is the save button. With this function all points specified for this dataset and shown in the QmitkPointListWidget are saved to harddisk. The user is prompted to select a filename. Pointsets were saved in XML fileformat but have to have a ".mps" file extension. You can select landmarks in the render window with a left mouse button click on them. If you keep the mouse button pressed you can move the landmark to an other position by moving the mouse and then release the mouse button. With the delete key you can remove the selected landmarks. You can also select landmarks by a double click on a landmark within the QmitkPointListWidget. Using the "Up-Arrow"-button or the "F2" key you can easily move a landmark upwards and bring it further downwards by pressing "F3" or using the "Down-Arrow"-button. Thus the landmark number can be changed. The QmitkStdMultiWidget changes its view to show the position of the landmark. \image html MovingDataPointBased.png "The Moving Data area" The "Moving Data" area contains a QmitkPointListWidget. Within this widget, all points for the moving data are listed. The label above this list shows the number of points that are already set. To set points you have to toggle the "Set Points" button, the leftmost under the QmitkPointListWidget. The views in the QmitkStdMultiWidget were reinitialized to the moving data. With the "Opacity:" slider you can change the opacity of the moving dataset. If the slider is leftmost the moving dataset is totally transparent, whereas if it is rightmost the moving dataset is totally opaque. Points can be defined by performing a left click while holding the "Shift"-key pressed in the QmitkStdMultiWidget. You can remove the interactor which listens for left mousebutton click while holding the "Shift"-key pressed by detoggle the "Set Points" button. The next button, "Clear Point Set", is for deleting all specified points from this dataset. The user is prompted to confirm the decision. With the button on your right hand side, a previously saved point set can be loaded and all of its points are shown in the QmitkPointListWidget and in the QmitkStdMultiWidget. The user is prompted to select the file to be loaded. The file extension is ".mps". On the left of this button is the save button. With this function all points specified for this dataset and shown in the QmitkPointListWidget are saved to harddisk. The user is prompted to select a filename. Pointsets were saved in XML fileformat but have to have a ".mps" file extension. You can select landmarks in the render window with a left click on them. If you keep the mouse button pressed you can move the landmark to an other position by moving the mouse and then release the mouse button. With the delete key you can remove the selected landmarks. You can also select landmarks by a double click on a landmark within the QmitkPointListWidget. Using the "Up-Arrow"-button or the "F2" key you can easily move a landmark upwards and bring it further downwards by pressing "F3" or using the "Down-Arrow"-button. Thus the landmark number can be changed.The QmitkStdMultiWidget changes its view to show the position of the landmark. \image html DisplayOptionsPointBased.png "The Display Options area" In this area you can find the "Show Images Red/Green" checkbox. Here you can switch the color from both datasets. If you check the box, the fixed dataset will be displayed in redvalues and the moving dataset in greenvalues to improve visibility of differences in the datasets. If you uncheck the "Show Images Red/Green" checkbox, both datasets will be displayed in greyvalues. Before you perform your transformation it is useful to see both images again. Therefore detoggle the "Set Points" button for the fixed data as well as for the moving data. \image html RegistrationPointBased.png "The Registration area" The functions concerning the registration are displayed in the "Registration" area. It not only contains the registration method selection and the registration itself but also offers the possibility to save, undo or redo the results. Furthermore a display is implemented, which shows you how good the landmarks correspond. Those features will be explained in following paragraphs. Using the "Method"-selector, you can pick one of those transformations: Rigid, Similarity, Affine and LandmarkWarping. Depending on which one you chose, an additional specifier, "Use ICP" can be set, which leads to the following possibilities for registration: \li Rigid with ICP means only translation and rotation. The order of your landmarks will not be taken into account. E. g. landmark one in the fixed data can be mapped on landmark three in the moving data. You have to set at least one landmark in each dataset to enable the Register button which performs the transformation. \li Similarity with ICP means only translation, scaling and rotation. The order of your landmarks will not be taken into account. E. g. landmark one in the fixed data can be mapped on landmark three in the moving data. You have to set at least one landmark in each dataset to enable the Register button which performs the transformation. \li Affine with ICP means only translation, scaling, rotation and shearing. The order of your landmarks will not be taken into account. E. g. landmark one in the fixed data can be mapped on landmark three in the moving data. You have to set at least one landmark in each dataset to enable the Register button which performs the transformation. \li Rigid means only translation and rotation. The order of your landmarks will be taken into account. E. g. landmark one in the fixed data will be mapped on landmark one in the moving data. You have to set at least one landmark and the same number of landmarks in each dataset to enable the Register button which performs the transformation. \li Similarity means only translation, scaling and rotation. The order of your landmarks will be taken into account. E. g. landmark one in the fixed data will be mapped on landmark one in the moving data. You have to set at least one landmark and the same number of landmarks in each dataset to enable the Register button which performs the transformation. \li Affine means only translation, scaling, rotation and shearing. The order of your landmarks will be taken into account. E. g. landmark one in the fixed data will be mapped on landmark one in the moving data. You have to set at least one landmark and the same number of landmarks in each dataset to enable the Register button which performs the transformation. \li LandmarkWarping means a freeform deformation of the moving image, so that afterwards the landmarks are exactly aligned. The order of your landmarks will be taken into account. E. g. landmark one in the fixed data will be mapped on landmark one in the moving data. You have to set at least one landmark and the same number of landmarks in each dataset to enable the Register button which performs the transformation. The root mean squares difference between the landmarks will be displayed as number, so that you can check how good the landmarks correspond. The "Undo Transformation" button becomes enabled after performing a transformation and allows you to undo it. After doing this, the "Redo Transformation" button is enabled and lets you redo, the just undone transformation(no calculation needed) Saving of the transformed image can be done via the Data Manager. */ diff --git a/Plugins/org.mitk.gui.qt.registration/documentation/UserManual/QmitkRigidRegistrationUserManual.dox b/Plugins/org.mitk.gui.qt.registration/documentation/UserManual/QmitkRigidRegistrationUserManual.dox index 77afc8ed3e..089cd17e3a 100644 --- a/Plugins/org.mitk.gui.qt.registration/documentation/UserManual/QmitkRigidRegistrationUserManual.dox +++ b/Plugins/org.mitk.gui.qt.registration/documentation/UserManual/QmitkRigidRegistrationUserManual.dox @@ -1,214 +1,214 @@ /** -\page org_rigid_regis The Rigid Registration Module +\page org_mitk_views_rigidregistration The Rigid Registration Module \image html rigidRegistrationIcon.png "Icon of the Module" Available sections: - \ref QmitkRigidRegistrationUserManualOverview - \ref QmitkRigidRegistrationUserManualIssues - \ref QmitkRigidRegistrationUserManualDetails - \ref QmitkRigidRegistrationUserManualReferences \section QmitkRigidRegistrationUserManualOverview Overview This module allows you to register 2D as well as 3D images in a rigid manner. If the Moving Image is an image with multiple timesteps you can select one timestep for registration. Register means to align two images, so that they become as similar as possible. Therefore you can select from different transforms, metrics and optimizers. Registration results will directly be applied to the Moving Image. Also binary images as image masks can be used to restrict the metric evaluation only to the masked area. \image html RigidRegistration_small.png "MITK with the QmitkRigidRegistration module" This document will tell you how to use this module, but it is assumed that you already know how to navigate through the slices of an image using the multi-widget. \section QmitkRigidRegistrationUserManualIssues Known Issues Depending on your system the registration can fail to allocate memory for calculating the gradient image for registration. In this case you can try to select another optimizer which is not based on a gradient image and uncheck the checkbox for "Compute Gradient". \section QmitkRigidRegistrationUserManualDetails Details First of all you have to open the data sets which you want to register and select them in the Data Manager. You have to select exactly 2 images for registration. The image which was selected first will become the fixed image, the other one the moving image. The two selected images will remain for registration until exactly two images were selected in the Data Manager again. \image html ImageArea.png "The Image area" While there aren't two images for registration a message is viewed on top of the module saying that registration needs two images. If two images are selected the message disappears and the interaction areas for the fixed and moving data appears. If both selected images have a binary image as childnode a selection box appears which allows, when checked, to use the binary images as image mask to restrict the registration on this certain area. If an image has more than one binary image as child, the upper one from the DataManager list is used. If the Moving Image is a dynamic images with several timesteps a slider appears to select a specific timestep for registration. On default only the fixed and moving image are shown in the render windows. If you want to have other images visible you have to set the visibility via the Data Manager. Also if you want to perform a reinit on a specific node or a global reinit for all nodes you have to use the Data Manager. The colour of the images can be changed between grey values and red/green and the opacity of the moving image can be changed. With the "Moving Image Opacity:" slider you can change the opacity of the moving dataset. In the "Show Images Red/Green" you can switch the color from both datasets. If you check the box, the fixed dataset will be displayed in red-values and the moving dataset in green-values to improve visibility of differences in the datasets. If you uncheck the "Show Images Red/Green" checkbox, both datasets will be displayed in grey-values. \image html RegistrationArea.png "The Registration area" In the "Register" area you can start the registration by clicking the "Calculate Transform" button. The optimizer value for every iteration step is diplayed as LCD number next to the "Optimizer Value:" label. Many of the registration methods can be canceled during their iteration steps by clicking the "Stop Optimization" button. During the calculation, a progress bar indicates the progress of the registration process. The render widgets are updated for every single iteration step, so that the user has the chance to supervise how good the registration process works with the selected methods and parameters. If the registration process does not lead to a sufficient result, it is possible to undo the transformation and restart the registration process with some changes in parameters. The differences in transformation due to the changed parameters can be seen in every iteration step and help the user understand the parameters. Also the optimizer value is updated for every single iteration step and shown in the GUI. The optimizer value is an indicator for the misalignment between the two images. The real time visualization of the registration as well as the optimizer value provides the user with information to trace the improvement through the optimization process. The "Undo Transformation" button becomes enabled when you have performed an transformation and you can undo the performed transformations. The "Redo Transformation" button becomes enabled when you have performed an undo to redo the transformation without to recalculate it. \image html ManualRegistrationArea.png "The Manual Registration area" In the "Manual Registration" area, shown by checking the checkbox Manual Registration, you can manually allign the images by moving sliders for translation and scaling in x-, y- and z-axis as well as for rotation around the x-, y- and z-Axis. Additionally you can automatically allign the image centers with the button "Automatic Allign Image Centers". \image html Tab2.png "The Advanced Mode tab" In the "Advanced Mode" tab you can choose a transform, a metric, an optimizer and an interpolator and you have to set the corresponding parameters to specify the registration method you want to perform. With the topmost button you can also load testpresets. These presets contain all parametersets which were saved using the "Save as Testpreset" button. The "Save as Preset" button makes the preset available from the "Automatic Registration" tab. This button should be used when a preset is not intended for finding good parameters anymore but can be used as standard preset. To show the current transform and its parameters for the registration process, the Transform checkbox has to be checked. Currently, the following transforms are implemented (for detailed information see [1] and [2]): \li Translation: Transformation by a simple translation for every dimension. \li Scale: Transformation by a certain scale factor for each dimension. \li ScaleLogarithmic: Transformation by a certain scale factor for each dimension. The parameter factors are passed as logarithms. \li Affine: Represents an affine transform composed of rotation, scaling, shearing and translation. \li FixedCenterOfRotationAffine: Represents an affine transform composed of rotation around a user provided center, scaling, shearing and translation. \li Rigid3D: Represents a 3D rotation followed by a 3D translation. \li Euler3D: Represents a rigid rotation in 3D space. That is, a rotation followed by a 3D translation. \li CenteredEuler3D: Represents a rigid rotation in 3D space around a user provided center. That is, a rotation followed by a 3D translation. \li QuaternionRigid: Represents a 3D rotation and a 3D translation. The rotation is specified as a quaternion. \li Versor: Represents a 3D rotation. The rotation is specified by a versor or unit quaternion. \li VersorRigid3D: Represents a 3D rotation and a 3D translation. The rotation is specified by a versor or unit quaternion. \li ScaleSkewVersor3D: Represents a 3D translation, scaling, shearing and rotation. The rotation is specified by a versor or unit quaternion. \li Similarity3D: Represents a 3D rotation, a 3D translation and homogeneous scaling. \li Rigid2D: Represents a 2D rotation followed by a 2D translation. \li CenteredRigid2D: Represents a 2D rotation around a user provided center followed by a 2D translation. \li Euler2D: Represents a 2D rotation and a 2D translation. \li Similarity2D: Represents a 2D rotation, homogeneous scaling and a 2D translation. \li CenteredSimilarity2D: Represents a 2D rotation around a user provided center, homogeneous scaling and a 2D translation. The desired transform can be chosen from a combo box. All parameters defining the selected transform have to be specified within the line edits and checkboxes underneath the transform combo box. To show the current metric and its parameters for the registration process, the Metric checkbox has to be checked. Currently, the following metrics are implemented (for detailed information see [1] and [2]): \li MeanSquares: Computes the mean squared pixel-wise difference in intensity between image A and B. \li NormalizedCorrelation: Computes pixel-wise cross correlation and normalizes it by the square root of the autocorrelation of the images. \li GradientDifference: Evaluates the difference in the derivatives of the moving and fixed images. \li KullbackLeiblerCompareHistogram[3]: Measures the relative entropy between two discrete probability distributions. \li CorrelationCoefficientHistogram: Computes the cross correlation coefficient between the intensities. \li MeanSquaresHistogram: The joint histogram of the fixed and the mapped moving image is built first. Then the mean squared pixel-wise difference in intensity between image A and B is calculated. \li MutualInformationHistogram: Computes the mutual information between image A and image B. \li NormalizedMutualInformationHistogram: Computes the mutual information between image A and image B. \li MattesMutualInformation[4, 5]: The method of Mattes et al. is used to compute the mutual information between two images to be registered. \li MeanReciprocalSquareDifference: Computes pixel-wise differences and adds them after passing them through a bell-shaped function 1 / (1+x^2). \li MutualInformation[6]: Computes the mutual information between image A and image B. \li MatchCardinality: Computes cardinality of the set of pixels that match exactly between the moving and fixed images. \li KappaStatistic[7]: Computes spatial intersection of two binary images. The desired metric can be chosen from a combo box. All parameters defining the selected metric have to be specified within the line edits and checkboxes underneath the metric combo box. To show the current optimizer and its parameters for the registration process, the Optimizer checkbox has to be checked. Currently, the following optimizers are implemented (for detailed information see [1] and [2]): \li Exhaustive: Fully samples a grid on the parametric space. \li GradientDescent: A simple gradient descent optimizer. \li QuaternionRigidTransformGradientDescent: Variant of a gradient descent optimizer. \li LBFGSB[8, 9]: Limited memory Broyden Fletcher Goldfarb Shannon minimization with simple bounds. \li OnePlusOneEvolutionary[10]: 1+1 evolutionary strategy. \li Powell: Implements Powell optimization using Brent line search. \li FRPR: Fletch-Reeves & Polak-Ribiere optimization using dBrent line search. \li RegularStepGradientDescent: Variant of a gradient descent optimizer. \li VersorTransform: Variant of a gradient descent optimizer. \li Amoeba: Implementation of the Nelder-Meade downhill simplex algorithm. \li ConjugateGradient: Used to solve unconstrained optimization problems. \li LBFGS: Limited memory Broyden Fletcher Goldfarb Shannon minimization. \li SPSA[11]: Based on simultaneous perturbation. \li VersorRigid3DTransform: Variant of a gradient descent optimizer for the VersorRigid3DTransform parameter space. The desired optimizer can be chosen from a combo box. All parameters defining the selected optimizer have to be specified within the line edits and checkboxes underneath the optimizer combo box. To show the current interpolator for the registration process, just check the Interpolator checkbox. Currently, the following interpolators are implemented (for detailed information see [1] and [2]): \li Linear: Intensity varies linearly between grid positions. \li NearestNeighbor: Uses the intensity of the nearest grid position. You can show and hide the parameters for the selection by checking or unchecking the corresponding area. You can save the current sets of parameters with the "Save as Testpreset" or "Save as Preset" buttons. \section QmitkRigidRegistrationUserManualReferences References: 1. L. Ibanez, W. Schroeder and K. Ng, The ITK Software Guide, Kitware Inc, New York, 2005. 2. http://www.itk.org/Doxygen/ 3. Albert C.S. Chung, William M. Wells III, Alexander Norbash, and W. Eric L. Grimson, Multi-modal Image Registration by Minimising Kullback-Leibler Distance, In Medical Image Computing and Computer-Assisted Intervention - MICCAI 2002, LNCS 2489, pp. 525 - 532. 4. D. Mattes, D. R. Haynor, H. Vesselle, T. Lewellen and W. Eubank, "Nonrigid multimodality image registration", Medical Imaging 2001: Image Processing, 2001, pp. 1609-1620. 5. D. Mattes, D. R. Haynor, H. Vesselle, T. Lewellen and W. Eubank, "PET-CT Image Registration in the Chest Using Free-form Deformations", IEEE Transactions in Medical Imaging. Vol.22, No.1, January 2003, pp.120-128. 6. Viola, P. and Wells III, W. (1997). "Alignment by Maximization of Mutual Information" International Journal of Computer Vision, 24(2):137-154. 7. AP Zijdenbos, BM Dawant, RA Margolin , AC Palmer, Morphometric analysis of white matter lesions in MR images: Method and validation, IEEE Transactions on Medical Imaging, 13(4):716-724, Dec. 1994. 8. R. H. Byrd, P. Lu and J. Nocedal. A Limited Memory Algorithm for Bound Constrained Optimization, (1995), SIAM Journal on Scientific and Statistical Computing , 16, 5, pp. 1190-1208. 9. C. Zhu, R. H. Byrd and J. Nocedal. L-BFGS-B: Algorithm 778: L-BFGS-B, FORTRAN routines for large scale bound constrained optimization (1997), ACM Transactions on Mathematical Software, Vol 23, Num. 4, pp. 550 - 560. 10. Martin Styner, G. Gerig, Christian Brechbuehler, Gabor Szekely, "Parametric estimate of intensity inhomogeneities applied to MRI", IEEE TRANSACTIONS ON MEDICAL IMAGING; 19(3), pp. 153-165, 2000. 11. Spall, J.C. (1998), "An Overview of the Simultaneous Perturbation Method for Efficient Optimization," Johns Hopkins APL Technical Digest, vol. 19, pp. 482-492. */ diff --git a/Plugins/org.mitk.gui.qt.registration/documentation/UserManual/RegistrationModuleOverview.dox b/Plugins/org.mitk.gui.qt.registration/documentation/UserManual/RegistrationModuleOverview.dox index fea50aadd7..1f43c7a195 100644 --- a/Plugins/org.mitk.gui.qt.registration/documentation/UserManual/RegistrationModuleOverview.dox +++ b/Plugins/org.mitk.gui.qt.registration/documentation/UserManual/RegistrationModuleOverview.dox @@ -1,14 +1,14 @@ /** -\bundlemainpage{RegistrationModuleOverviewPage} The Registration Modules +\page org_mitk_gui_qt_registration The Registration Modules \section RegistrationModuleOverviewPageOverview Overview MITK provides several modules for the registration of images. \section RegistrationModuleOverviewPageList List of Modules - \li \subpage org_deform_registration - \li \subpage org_pointbased_reg - \li \subpage org_rigid_regis + \li \subpage org_mitk_views_deformableregistration + \li \subpage org_mitk_views_pointbasedregistration + \li \subpage org_mitk_views_rigidregistration */ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.registration/src/internal/QmitkRigidRegistrationView.cpp b/Plugins/org.mitk.gui.qt.registration/src/internal/QmitkRigidRegistrationView.cpp index fcc768b10f..7e5de8ae23 100644 --- a/Plugins/org.mitk.gui.qt.registration/src/internal/QmitkRigidRegistrationView.cpp +++ b/Plugins/org.mitk.gui.qt.registration/src/internal/QmitkRigidRegistrationView.cpp @@ -1,1275 +1,1410 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "QmitkRigidRegistrationView.h" #include "QmitkStdMultiWidget.h" #include "QmitkCommonFunctionality.h" #include "qinputdialog.h" #include "qmessagebox.h" #include "qcursor.h" #include "qapplication.h" #include "qradiobutton.h" #include "qslider.h" #include "qtooltip.h" #include #include "mitkDataNodeObject.h" #include "berryIWorkbenchWindow.h" #include "berryISelectionService.h" +#include +#include "mitkManualSegmentationToSurfaceFilter.h" +#include + +#include + + +#include + const std::string QmitkRigidRegistrationView::VIEW_ID = "org.mitk.views.rigidregistration"; using namespace berry; struct SelListenerRigidRegistration : ISelectionListener { berryObjectMacro(SelListenerRigidRegistration); SelListenerRigidRegistration(QmitkRigidRegistrationView* view) { m_View = view; } void DoSelectionChanged(ISelection::ConstPointer selection) { // if (!m_View->IsVisible()) // return; // save current selection in member variable m_View->m_CurrentSelection = selection.Cast(); // do something with the selected items if(m_View->m_CurrentSelection) { if (m_View->m_CurrentSelection->Size() != 2) { if (m_View->m_FixedNode.IsNull() || m_View->m_MovingNode.IsNull()) { m_View->m_Controls.m_StatusLabel->show(); m_View->m_Controls.TextLabelFixed->hide(); m_View->m_Controls.m_FixedLabel->hide(); m_View->m_Controls.TextLabelMoving->hide(); m_View->m_Controls.m_MovingLabel->hide(); m_View->m_Controls.m_OpacityLabel->setEnabled(false); m_View->m_Controls.m_OpacitySlider->setEnabled(false); m_View->m_Controls.label->setEnabled(false); m_View->m_Controls.label_2->setEnabled(false); m_View->m_Controls.m_ShowRedGreenValues->setEnabled(false); m_View->m_Controls.m_SwitchImages->hide(); } } else { m_View->m_Controls.m_StatusLabel->hide(); bool foundFixedImage = false; mitk::DataNode::Pointer fixedNode; // 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(); // only look at interesting types if(QString("Image").compare(node->GetData()->GetNameOfClass())==0) { if (dynamic_cast(node->GetData())->GetDimension() == 4) { m_View->m_Controls.m_StatusLabel->show(); QMessageBox::information( NULL, "RigidRegistration", "Only 2D or 3D images can be processed.", QMessageBox::Ok ); return; } if (foundFixedImage == false) { fixedNode = node; foundFixedImage = true; } else { m_View->SetImagesVisible(selection); m_View->FixedSelected(fixedNode); m_View->MovingSelected(node); m_View->m_Controls.m_StatusLabel->hide(); m_View->m_Controls.TextLabelFixed->show(); m_View->m_Controls.m_FixedLabel->show(); m_View->m_Controls.TextLabelMoving->show(); m_View->m_Controls.m_MovingLabel->show(); m_View->m_Controls.m_OpacityLabel->setEnabled(true); m_View->m_Controls.m_OpacitySlider->setEnabled(true); m_View->m_Controls.label->setEnabled(true); m_View->m_Controls.label_2->setEnabled(true); m_View->m_Controls.m_ShowRedGreenValues->setEnabled(true); } } else { m_View->m_Controls.m_StatusLabel->show(); return; } } } } } else if (m_View->m_FixedNode.IsNull() || m_View->m_MovingNode.IsNull()) { m_View->m_Controls.m_StatusLabel->show(); } } 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); } } } QmitkRigidRegistrationView* m_View; }; QmitkRigidRegistrationView::QmitkRigidRegistrationView(QObject * /*parent*/, const char * /*name*/) : QmitkFunctionality(), m_MultiWidget(NULL), m_MovingNode(NULL), m_MovingMaskNode(NULL), m_FixedNode(NULL), m_FixedMaskNode(NULL), m_ShowRedGreen(false), m_Opacity(0.5), m_OriginalOpacity(1.0), m_Deactivated(false),m_FixedDimension(0), m_MovingDimension(0) { m_TranslateSliderPos[0] = 0; m_TranslateSliderPos[1] = 0; m_TranslateSliderPos[2] = 0; m_RotateSliderPos[0] = 0; m_RotateSliderPos[1] = 0; m_RotateSliderPos[2] = 0; m_ScaleSliderPos[0] = 0; m_ScaleSliderPos[1] = 0; m_ScaleSliderPos[2] = 0; translationParams = new int[3]; rotationParams = new int[3]; scalingParams = new int[3]; m_TimeStepperAdapter = NULL; this->GetDataStorage()->RemoveNodeEvent.AddListener(mitk::MessageDelegate1 ( this, &QmitkRigidRegistrationView::DataNodeHasBeenRemoved )); } QmitkRigidRegistrationView::~QmitkRigidRegistrationView() { if(m_SelListener.IsNotNull()) { berry::ISelectionService* s = GetSite()->GetWorkbenchWindow()->GetSelectionService(); if(s) s->RemovePostSelectionListener(m_SelListener); m_SelListener = NULL; } } void QmitkRigidRegistrationView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); m_Controls.m_ManualFrame->hide(); m_Controls.timeSlider->hide(); m_Controls.TextLabelFixed->hide(); m_Controls.m_FixedLabel->hide(); m_Controls.TextLabelMoving->hide(); m_Controls.m_MovingLabel->hide(); m_Controls.m_UseFixedImageMask->hide(); m_Controls.m_UseMovingImageMask->hide(); m_Controls.m_OpacityLabel->setEnabled(false); m_Controls.m_OpacitySlider->setEnabled(false); m_Controls.label->setEnabled(false); m_Controls.label_2->setEnabled(false); m_Controls.m_ShowRedGreenValues->setEnabled(false); m_Controls.m_SwitchImages->hide(); if (m_Controls.m_RigidTransform->currentIndex() == 1) { m_Controls.frame->show(); } else { m_Controls.frame->hide(); } m_Controls.m_ManualFrame->setEnabled(false); m_Parent->setEnabled(false); this->CreateConnections(); this->CheckCalculateEnabled(); } void QmitkRigidRegistrationView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_Parent->setEnabled(true); m_MultiWidget = &stdMultiWidget; m_MultiWidget->SetWidgetPlanesVisibility(true); } void QmitkRigidRegistrationView::StdMultiWidgetNotAvailable() { m_Parent->setEnabled(false); m_MultiWidget = NULL; } void QmitkRigidRegistrationView::CreateConnections() { connect( m_Controls.m_ManualRegistrationCheckbox, SIGNAL(toggled(bool)), this, SLOT(ShowManualRegistrationFrame(bool))); connect((QObject*)(m_Controls.m_SwitchImages),SIGNAL(clicked()),this,SLOT(SwitchImages())); connect(m_Controls.m_ShowRedGreenValues, SIGNAL(toggled(bool)), this, SLOT(ShowRedGreen(bool))); + connect(m_Controls.m_ShowContour, SIGNAL(toggled(bool)), this, SLOT(EnableContour(bool))); connect(m_Controls.m_UseFixedImageMask, SIGNAL(toggled(bool)), this, SLOT(UseFixedMaskImageChecked(bool))); connect(m_Controls.m_UseMovingImageMask, SIGNAL(toggled(bool)), this, SLOT(UseMovingMaskImageChecked(bool))); connect(m_Controls.m_RigidTransform, SIGNAL(currentChanged(int)), this, SLOT(TabChanged(int))); connect(m_Controls.m_OpacitySlider, SIGNAL(valueChanged(int)), this, SLOT(OpacityUpdate(int))); + connect(m_Controls.m_ContourSlider, SIGNAL(sliderReleased()), this, SLOT(ShowContour())); + connect(m_Controls.m_CalculateTransformation, SIGNAL(clicked()), this, SLOT(Calculate())); connect(m_Controls.m_UndoTransformation,SIGNAL(clicked()),this,SLOT(UndoTransformation())); connect(m_Controls.m_RedoTransformation,SIGNAL(clicked()),this,SLOT(RedoTransformation())); connect(m_Controls.m_AutomaticTranslation,SIGNAL(clicked()),this,SLOT(AlignCenters())); connect(m_Controls.m_StopOptimization,SIGNAL(clicked()), this , SLOT(StopOptimizationClicked())); connect(m_Controls.m_XTransSlider, SIGNAL(valueChanged(int)), this, SLOT(xTrans_valueChanged(int))); connect(m_Controls.m_YTransSlider, SIGNAL(valueChanged(int)), this, SLOT(yTrans_valueChanged(int))); connect(m_Controls.m_ZTransSlider, SIGNAL(valueChanged(int)), this, SLOT(zTrans_valueChanged(int))); connect(m_Controls.m_XRotSlider, SIGNAL(valueChanged(int)), this, SLOT(xRot_valueChanged(int))); connect(m_Controls.m_YRotSlider, SIGNAL(valueChanged(int)), this, SLOT(yRot_valueChanged(int))); connect(m_Controls.m_ZRotSlider, SIGNAL(valueChanged(int)), this, SLOT(zRot_valueChanged(int))); connect(m_Controls.m_XScaleSlider, SIGNAL(valueChanged(int)), this, SLOT(xScale_valueChanged(int))); connect(m_Controls.m_YScaleSlider, SIGNAL(valueChanged(int)), this, SLOT(yScale_valueChanged(int))); connect(m_Controls.m_ZScaleSlider, SIGNAL(valueChanged(int)), this, SLOT(zScale_valueChanged(int))); connect(m_Controls.m_LoadRigidRegistrationParameter, SIGNAL(clicked()), m_Controls.qmitkRigidRegistrationSelector1, SLOT(LoadRigidRegistrationParameter())); connect(m_Controls.m_SaveRigidRegistrationParameter, SIGNAL(clicked()), m_Controls.qmitkRigidRegistrationSelector1, SLOT(SaveRigidRegistrationParameter())); connect(m_Controls.m_LoadRigidRegistrationTestParameter, SIGNAL(clicked()), m_Controls.qmitkRigidRegistrationSelector1, SLOT(LoadRigidRegistrationTestParameter())); connect(m_Controls.m_SaveRigidRegistrationTestParameter, SIGNAL(clicked()), m_Controls.qmitkRigidRegistrationSelector1, SLOT(SaveRigidRegistrationTestParameter())); connect(m_Controls.qmitkRigidRegistrationSelector1,SIGNAL(OptimizerChanged(double)),this,SLOT(SetOptimizerValue( double ))); connect(m_Controls.qmitkRigidRegistrationSelector1,SIGNAL(TransformChanged()),this,SLOT(CheckCalculateEnabled())); connect(m_Controls.qmitkRigidRegistrationSelector1,SIGNAL(AddNewTransformationToUndoList()),this,SLOT(AddNewTransformationToUndoList())); } void QmitkRigidRegistrationView::Activated() { m_Deactivated = false; mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QmitkFunctionality::Activated(); if (m_SelListener.IsNull()) { m_SelListener = berry::ISelectionListener::Pointer(new SelListenerRigidRegistration(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); } this->OpacityUpdate(m_Controls.m_OpacitySlider->value()); this->ShowRedGreen(m_Controls.m_ShowRedGreenValues->isChecked()); this->ClearTransformationLists(); this->CheckCalculateEnabled(); /* m_Deactivated = false; mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QmitkFunctionality::Activated(); if (m_SelListener.IsNull()) { m_SelListener = berry::ISelectionListener::Pointer(new SelListenerRigidRegistration(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); } this->OpacityUpdate(m_Controls.m_OpacitySlider->value()); this->ShowRedGreen(m_Controls.m_ShowRedGreenValues->isChecked()); this->ClearTransformationLists(); this->CheckCalculateEnabled();*/ } void QmitkRigidRegistrationView::Visible() { /* m_Deactivated = false; mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QmitkFunctionality::Activated(); if (m_SelListener.IsNull()) { m_SelListener = berry::ISelectionListener::Pointer(new SelListenerRigidRegistration(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); } this->OpacityUpdate(m_Controls.m_OpacitySlider->value()); this->ShowRedGreen(m_Controls.m_ShowRedGreenValues->isChecked()); this->ClearTransformationLists(); this->CheckCalculateEnabled();*/ } void QmitkRigidRegistrationView::Deactivated() { m_Deactivated = true; this->SetImageColor(false); if (m_FixedNode.IsNotNull()) m_FixedNode->SetOpacity(1.0); m_FixedNode = NULL; m_MovingNode = NULL; this->ClearTransformationLists(); berry::ISelectionService* s = GetSite()->GetWorkbenchWindow()->GetSelectionService(); if(s) s->RemovePostSelectionListener(m_SelListener); m_SelListener = NULL; /* m_Deactivated = true; this->SetImageColor(false); m_FixedNode = NULL; m_MovingNode = NULL; this->ClearTransformationLists(); berry::ISelectionService* s = GetSite()->GetWorkbenchWindow()->GetSelectionService(); if(s) s->RemovePostSelectionListener(m_SelListener); m_SelListener = NULL; mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QmitkFunctionality::Deactivated();*/ } void QmitkRigidRegistrationView::Hidden() { /*m_Deactivated = true; this->SetImageColor(false); m_FixedNode = NULL; m_MovingNode = NULL; this->ClearTransformationLists(); berry::ISelectionService* s = GetSite()->GetWorkbenchWindow()->GetSelectionService(); if(s) s->RemovePostSelectionListener(m_SelListener); m_SelListener = NULL; //mitk::RenderingManager::GetInstance()->RequestUpdateAll(); //QmitkFunctionality::Deactivated();*/ } void QmitkRigidRegistrationView::DataNodeHasBeenRemoved(const mitk::DataNode* node) { if(node == m_FixedNode || node == m_MovingNode) { m_Controls.m_StatusLabel->show(); m_Controls.TextLabelFixed->hide(); m_Controls.m_FixedLabel->hide(); m_Controls.TextLabelMoving->hide(); m_Controls.m_MovingLabel->hide(); m_Controls.m_OpacityLabel->setEnabled(false); m_Controls.m_OpacitySlider->setEnabled(false); m_Controls.label->setEnabled(false); m_Controls.label_2->setEnabled(false); m_Controls.m_ShowRedGreenValues->setEnabled(false); m_Controls.m_SwitchImages->hide(); } + + else if(node == m_ContourHelperNode) + { + // can this cause a memory leak? + m_ContourHelperNode = NULL; + } } void QmitkRigidRegistrationView::FixedSelected(mitk::DataNode::Pointer fixedImage) { if (m_FixedNode.IsNotNull()) { this->SetImageColor(false); m_FixedNode->SetOpacity(1.0); } m_FixedNode = fixedImage; if (m_FixedNode.IsNotNull()) { m_FixedNode->SetOpacity(0.5); m_FixedNode->SetVisibility(true); m_Controls.TextLabelFixed->setText(QString::fromStdString(m_FixedNode->GetName())); m_Controls.m_FixedLabel->show(); m_Controls.TextLabelFixed->show(); m_Controls.m_SwitchImages->show(); mitk::ColorProperty::Pointer colorProperty; colorProperty = dynamic_cast(m_FixedNode->GetProperty("color")); if ( colorProperty.IsNotNull() ) { m_FixedColor = colorProperty->GetColor(); } this->SetImageColor(m_ShowRedGreen); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); if (dynamic_cast(m_FixedNode->GetData())) { m_FixedDimension = dynamic_cast(m_FixedNode->GetData())->GetDimension(); m_Controls.qmitkRigidRegistrationSelector1->SetFixedDimension(m_FixedDimension); m_Controls.qmitkRigidRegistrationSelector1->SetFixedNode(m_FixedNode); } bool hasMask = false; mitk::DataStorage::SetOfObjects::ConstPointer children = this->GetDataStorage()->GetDerivations(m_FixedNode); unsigned long size; size = children->Size(); for (unsigned long i = 0; i < size; ++i) { mitk::BoolProperty::Pointer isMaskProp = dynamic_cast(children->GetElement(i)->GetProperty("binary")); if(isMaskProp.IsNotNull() && isMaskProp->GetValue() == true) { m_FixedMaskNode = children->GetElement(i); hasMask = true; this->CheckForMaskImages(); break; } } if (!hasMask) { this->CheckForMaskImages(); m_FixedMaskNode = NULL; } + + // Modify slider range + mitk::Image::Pointer image = dynamic_cast(m_FixedNode->GetData()); + int min = (int)image->GetStatistics()->GetScalarValueMin(); + int max = (int)image->GetStatistics()->GetScalarValueMax(); + m_Controls.m_ContourSlider->setRange(min, max); + + // Set slider to a default value + int avg = (min+max) / 2; + m_Controls.m_ContourSlider->setSliderPosition(avg); + m_Controls.m_ThresholdLabel->setText(QString::number(avg)); + } else { m_Controls.m_FixedLabel->hide(); m_Controls.TextLabelFixed->hide(); m_Controls.m_SwitchImages->hide(); } this->CheckCalculateEnabled(); if(this->GetActiveStdMultiWidget()) { m_TimeStepperAdapter = new QmitkStepperAdapter((QObject*) m_Controls.timeSlider, m_MultiWidget->GetTimeNavigationController()->GetTime(), "sliceNavigatorTimeFromRigidRegistration"); connect( m_TimeStepperAdapter, SIGNAL( Refetch() ), this, SLOT( UpdateTimestep() ) ); } } void QmitkRigidRegistrationView::MovingSelected(mitk::DataNode::Pointer movingImage) { if (m_MovingNode.IsNotNull()) { m_MovingNode->SetOpacity(m_OriginalOpacity); if (m_FixedNode == m_MovingNode) m_FixedNode->SetOpacity(0.5); this->SetImageColor(false); } m_MovingNode = movingImage; if (m_MovingNode.IsNotNull()) { m_MovingNode->SetVisibility(true); m_Controls.TextLabelMoving->setText(QString::fromStdString(m_MovingNode->GetName())); m_Controls.m_MovingLabel->show(); m_Controls.TextLabelMoving->show(); mitk::ColorProperty::Pointer colorProperty; colorProperty = dynamic_cast(m_MovingNode->GetProperty("color")); if ( colorProperty.IsNotNull() ) { m_MovingColor = colorProperty->GetColor(); } this->SetImageColor(m_ShowRedGreen); m_MovingNode->GetFloatProperty("opacity", m_OriginalOpacity); this->OpacityUpdate(m_Opacity); bool hasMask = false; mitk::DataStorage::SetOfObjects::ConstPointer children = this->GetDataStorage()->GetDerivations(m_MovingNode); m_Controls.qmitkRigidRegistrationSelector1->SetMovingNodeChildren(children); unsigned long size; size = children->Size(); for (unsigned long i = 0; i < size; ++i) { mitk::BoolProperty::Pointer isMaskProp = dynamic_cast(children->GetElement(i)->GetProperty("binary")); if(isMaskProp.IsNotNull() && isMaskProp->GetValue() == true) { m_MovingMaskNode = children->GetElement(i); hasMask = true; this->CheckForMaskImages(); break; } } if (!hasMask) { m_MovingMaskNode = NULL; this->CheckForMaskImages(); } } else { m_Controls.m_MovingLabel->hide(); m_Controls.TextLabelMoving->hide(); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); this->MovingImageChanged(); this->CheckCalculateEnabled(); } bool QmitkRigidRegistrationView::CheckCalculate() { if(m_MovingNode==m_FixedNode) return false; return true; } void QmitkRigidRegistrationView::AddNewTransformationToUndoList() { mitk::BaseData::Pointer movingData = m_MovingNode->GetData(); m_UndoGeometryList.push_back(static_cast(movingData->GetGeometry(0)->Clone().GetPointer())); unsigned long size; mitk::DataStorage::SetOfObjects::ConstPointer children = this->GetDataStorage()->GetDerivations(m_MovingNode); size = children->Size(); std::map childGeometries; for (unsigned long i = 0; i < size; ++i) { childGeometries.insert(std::pair(children->GetElement(i), children->GetElement(i)->GetData()->GetGeometry())); } m_UndoChildGeometryList.push_back(childGeometries); m_RedoGeometryList.clear(); m_RedoChildGeometryList.clear(); this->SetUndoEnabled(true); this->SetRedoEnabled(false); } void QmitkRigidRegistrationView::UndoTransformation() { if(!m_UndoGeometryList.empty()) { mitk::BaseData::Pointer movingData = m_MovingNode->GetData(); m_RedoGeometryList.push_back(static_cast(movingData->GetGeometry(0)->Clone().GetPointer())); unsigned long size; mitk::DataStorage::SetOfObjects::ConstPointer children = this->GetDataStorage()->GetDerivations(m_MovingNode); size = children->Size(); std::map childGeometries; for (unsigned long i = 0; i < size; ++i) { childGeometries.insert(std::pair(children->GetElement(i), children->GetElement(i)->GetData()->GetGeometry())); } m_RedoChildGeometryList.push_back(childGeometries); movingData->SetGeometry(m_UndoGeometryList.back()); m_UndoGeometryList.pop_back(); std::map oldChildGeometries; oldChildGeometries = m_UndoChildGeometryList.back(); m_UndoChildGeometryList.pop_back(); std::map::iterator iter; for (unsigned long j = 0; j < size; ++j) { iter = oldChildGeometries.find(children->GetElement(j)); children->GetElement(j)->GetData()->SetGeometry((*iter).second); } //\FIXME when geometry is substituted the matrix referenced by the actor created by the mapper //is still pointing to the old one. Workaround: delete mapper m_MovingNode->SetMapper(1, NULL); mitk::RenderingManager::GetInstance()->RequestUpdate(m_MultiWidget->mitkWidget4->GetRenderWindow()); movingData->GetTimeSlicedGeometry()->UpdateInformation(); this->SetRedoEnabled(true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } if(!m_UndoGeometryList.empty()) { this->SetUndoEnabled(true); } else { this->SetUndoEnabled(false); } this->CheckCalculateEnabled(); } void QmitkRigidRegistrationView::RedoTransformation() { if(!m_RedoGeometryList.empty()) { mitk::BaseData::Pointer movingData = m_MovingNode->GetData(); m_UndoGeometryList.push_back(static_cast(movingData->GetGeometry(0)->Clone().GetPointer())); unsigned long size; mitk::DataStorage::SetOfObjects::ConstPointer children = this->GetDataStorage()->GetDerivations(m_MovingNode); size = children->Size(); std::map childGeometries; for (unsigned long i = 0; i < size; ++i) { childGeometries.insert(std::pair(children->GetElement(i), children->GetElement(i)->GetData()->GetGeometry())); } m_UndoChildGeometryList.push_back(childGeometries); movingData->SetGeometry(m_RedoGeometryList.back()); m_RedoGeometryList.pop_back(); std::map oldChildGeometries; oldChildGeometries = m_RedoChildGeometryList.back(); m_RedoChildGeometryList.pop_back(); std::map::iterator iter; for (unsigned long j = 0; j < size; ++j) { iter = oldChildGeometries.find(children->GetElement(j)); children->GetElement(j)->GetData()->SetGeometry((*iter).second); } //\FIXME when geometry is substituted the matrix referenced by the actor created by the mapper //is still pointing to the old one. Workaround: delete mapper m_MovingNode->SetMapper(1, NULL); mitk::RenderingManager::GetInstance()->RequestUpdate(m_MultiWidget->mitkWidget4->GetRenderWindow()); movingData->GetTimeSlicedGeometry()->UpdateInformation(); this->SetUndoEnabled(true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } if(!m_RedoGeometryList.empty()) { this->SetRedoEnabled(true); } else { this->SetRedoEnabled(false); } } void QmitkRigidRegistrationView::ShowRedGreen(bool redGreen) { m_ShowRedGreen = redGreen; this->SetImageColor(m_ShowRedGreen); } +void QmitkRigidRegistrationView::EnableContour(bool show) +{ + if(show) + ShowContour(); + + // Can happen when the m_ContourHelperNode was deleted before and now the show contour checkbox is turned off + if(m_ContourHelperNode.IsNull()) + return; + + m_Controls.m_ContourSlider->setEnabled(show); + m_ContourHelperNode->SetProperty("visible", mitk::BoolProperty::New(show)); + + mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); + +} + +void QmitkRigidRegistrationView::ShowContour() +{ + int threshold = m_Controls.m_ContourSlider->value(); + + bool show = m_Controls.m_ShowContour->isChecked(); + + if(m_FixedNode.IsNull() || !show) + return; + + + // Update the label next to the slider + m_Controls.m_ThresholdLabel->setText(QString::number(threshold)); + + mitk::Image::Pointer image = dynamic_cast(m_FixedNode->GetData()); + + typedef itk::Image FloatImageType; + typedef itk::Image ShortImageType; + + // Create a binary image using the given treshold + typedef itk::BinaryThresholdImageFilter ThresholdFilterType; + + FloatImageType::Pointer floatImage = FloatImageType::New(); + mitk::CastToItkImage(image, floatImage); + + + ThresholdFilterType::Pointer thresholdFilter = ThresholdFilterType::New(); + thresholdFilter->SetInput(floatImage); + thresholdFilter->SetLowerThreshold(threshold); + thresholdFilter->SetUpperThreshold((int)image->GetStatistics()->GetScalarValueMax()); + thresholdFilter->SetInsideValue(1); + thresholdFilter->SetOutsideValue(0); + thresholdFilter->Update(); + + ShortImageType::Pointer binaryImage = thresholdFilter->GetOutput(); + mitk::Image::Pointer mitkBinaryImage = mitk::Image::New(); + mitk::CastToMitkImage(binaryImage, mitkBinaryImage); + + + + + // Create a contour from the binary image + mitk::ManualSegmentationToSurfaceFilter::Pointer surfaceFilter = mitk::ManualSegmentationToSurfaceFilter::New(); + surfaceFilter->SetInput( mitkBinaryImage ); + surfaceFilter->SetThreshold( 1 ); //expects binary image with zeros and ones + surfaceFilter->SetUseGaussianImageSmooth(false); // apply gaussian to thresholded image ? + surfaceFilter->SetMedianFilter3D(false); // apply median to segmentation before marching cubes ? + surfaceFilter->SetDecimate( mitk::ImageToSurfaceFilter::NoDecimation ); + + surfaceFilter->UpdateLargestPossibleRegion(); + + // calculate normals for nicer display + mitk::Surface::Pointer surface = surfaceFilter->GetOutput(); + + + if(m_ContourHelperNode.IsNull()) + { + m_ContourHelperNode = mitk::DataNode::New(); + m_ContourHelperNode->SetData(surface); + m_ContourHelperNode->SetProperty("opacity", mitk::FloatProperty::New(1.0) ); + m_ContourHelperNode->SetProperty("line width", mitk::IntProperty::New(2) ); + m_ContourHelperNode->SetProperty("scalar visibility", mitk::BoolProperty::New(false) ); + m_ContourHelperNode->SetProperty( "name", mitk::StringProperty::New("surface") ); + m_ContourHelperNode->SetProperty("color", mitk::ColorProperty::New(1.0, 0.0, 0.0)); + m_ContourHelperNode->SetBoolProperty("helper object", true); + this->GetDataStorage()->Add(m_ContourHelperNode); + + } + else + { + m_ContourHelperNode->SetData(surface); + } + + + mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); + + +} + + void QmitkRigidRegistrationView::SetImageColor(bool redGreen) { if (!redGreen && m_FixedNode.IsNotNull()) { m_FixedNode->SetColor(m_FixedColor); } if (!redGreen && m_MovingNode.IsNotNull()) { m_MovingNode->SetColor(m_MovingColor); } if (redGreen && m_FixedNode.IsNotNull()) { m_FixedNode->SetColor(1.0f, 0.0f, 0.0f); } if (redGreen && m_MovingNode.IsNotNull()) { m_MovingNode->SetColor(0.0f, 1.0f, 0.0f); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkRigidRegistrationView::OpacityUpdate(float opacity) { m_Opacity = opacity; if (m_MovingNode.IsNotNull()) { m_MovingNode->SetOpacity(m_Opacity); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkRigidRegistrationView::OpacityUpdate(int opacity) { float fValue = ((float)opacity)/100.0f; this->OpacityUpdate(fValue); } void QmitkRigidRegistrationView::ClearTransformationLists() { this->SetUndoEnabled(false); this->SetRedoEnabled(false); m_UndoGeometryList.clear(); m_UndoChildGeometryList.clear(); m_RedoGeometryList.clear(); m_RedoChildGeometryList.clear(); } void QmitkRigidRegistrationView::Translate(int* translateVector) { if (m_MovingNode.IsNotNull()) { mitk::Vector3D translateVec; translateVec[0] = translateVector[0] - m_TranslateSliderPos[0]; translateVec[1] = translateVector[1] - m_TranslateSliderPos[1]; translateVec[2] = translateVector[2] - m_TranslateSliderPos[2]; m_TranslateSliderPos[0] = translateVector[0]; m_TranslateSliderPos[1] = translateVector[1]; m_TranslateSliderPos[2] = translateVector[2]; vtkMatrix4x4* translationMatrix = vtkMatrix4x4::New(); translationMatrix->Identity(); double (*transMatrix)[4] = translationMatrix->Element; transMatrix[0][3] = -translateVec[0]; transMatrix[1][3] = -translateVec[1]; transMatrix[2][3] = -translateVec[2]; translationMatrix->Invert(); m_MovingNode->GetData()->GetGeometry()->Compose( translationMatrix ); m_MovingNode->GetData()->Modified(); mitk::DataStorage::SetOfObjects::ConstPointer children = this->GetDataStorage()->GetDerivations(m_MovingNode); unsigned long size; size = children->Size(); mitk::DataNode::Pointer childNode; for (unsigned long i = 0; i < size; ++i) { childNode = children->GetElement(i); childNode->GetData()->GetGeometry()->Compose( translationMatrix ); childNode->GetData()->Modified(); } m_RedoGeometryList.clear(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkRigidRegistrationView::Rotate(int* rotateVector) { if (m_MovingNode.IsNotNull()) { mitk::Vector3D rotateVec; rotateVec[0] = rotateVector[0] - m_RotateSliderPos[0]; rotateVec[1] = rotateVector[1] - m_RotateSliderPos[1]; rotateVec[2] = rotateVector[2] - m_RotateSliderPos[2]; m_RotateSliderPos[0] = rotateVector[0]; m_RotateSliderPos[1] = rotateVector[1]; m_RotateSliderPos[2] = rotateVector[2]; vtkMatrix4x4* rotationMatrix = vtkMatrix4x4::New(); vtkMatrix4x4* translationMatrix = vtkMatrix4x4::New(); rotationMatrix->Identity(); translationMatrix->Identity(); double (*rotMatrix)[4] = rotationMatrix->Element; double (*transMatrix)[4] = translationMatrix->Element; mitk::Point3D centerBB = m_MovingNode->GetData()->GetGeometry()->GetCenter(); transMatrix[0][3] = centerBB[0]; transMatrix[1][3] = centerBB[1]; transMatrix[2][3] = centerBB[2]; translationMatrix->Invert(); m_MovingNode->GetData()->GetGeometry()->Compose( translationMatrix ); mitk::DataStorage::SetOfObjects::ConstPointer children = this->GetDataStorage()->GetDerivations(m_MovingNode); unsigned long size; size = children->Size(); mitk::DataNode::Pointer childNode; for (unsigned long i = 0; i < size; ++i) { childNode = children->GetElement(i); childNode->GetData()->GetGeometry()->Compose( translationMatrix ); childNode->GetData()->Modified(); } double radianX = rotateVec[0] * vnl_math::pi / 180; double radianY = rotateVec[1] * vnl_math::pi / 180; double radianZ = rotateVec[2] * vnl_math::pi / 180; if ( rotateVec[0] != 0 ) { rotMatrix[1][1] = cos( radianX ); rotMatrix[1][2] = -sin( radianX ); rotMatrix[2][1] = sin( radianX ); rotMatrix[2][2] = cos( radianX ); } else if ( rotateVec[1] != 0 ) { rotMatrix[0][0] = cos( radianY ); rotMatrix[0][2] = sin( radianY ); rotMatrix[2][0] = -sin( radianY ); rotMatrix[2][2] = cos( radianY ); } else if ( rotateVec[2] != 0 ) { rotMatrix[0][0] = cos( radianZ ); rotMatrix[0][1] = -sin( radianZ ); rotMatrix[1][0] = sin( radianZ ); rotMatrix[1][1] = cos( radianZ ); } m_MovingNode->GetData()->GetGeometry()->Compose( rotationMatrix ); for (unsigned long i = 0; i < size; ++i) { childNode = children->GetElement(i); childNode->GetData()->GetGeometry()->Compose( rotationMatrix ); childNode->GetData()->Modified(); } translationMatrix->Invert(); m_MovingNode->GetData()->GetGeometry()->Compose( translationMatrix ); for (unsigned long i = 0; i < size; ++i) { childNode = children->GetElement(i); childNode->GetData()->GetGeometry()->Compose( rotationMatrix ); childNode->GetData()->Modified(); } m_MovingNode->GetData()->Modified(); m_RedoGeometryList.clear(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkRigidRegistrationView::Scale(int* scaleVector) { if (m_MovingNode.IsNotNull()) { mitk::Vector3D scaleVec; scaleVec[0] = scaleVector[0] - m_ScaleSliderPos[0]; scaleVec[1] = scaleVector[1] - m_ScaleSliderPos[1]; scaleVec[2] = scaleVector[2] - m_ScaleSliderPos[2]; m_ScaleSliderPos[0] = scaleVector[0]; m_ScaleSliderPos[1] = scaleVector[1]; m_ScaleSliderPos[2] = scaleVector[2]; vtkMatrix4x4* scalingMatrix = vtkMatrix4x4::New(); scalingMatrix->Identity(); double (*scaleMatrix)[4] = scalingMatrix->Element; if (scaleVec[0] >= 0) { for(int i = 0; i= 0) { for(int i = 0; i= 0) { for(int i = 0; iInvert(); m_MovingNode->GetData()->GetGeometry()->Compose( scalingMatrix ); m_MovingNode->GetData()->Modified(); mitk::DataStorage::SetOfObjects::ConstPointer children = this->GetDataStorage()->GetDerivations(m_MovingNode); unsigned long size; size = children->Size(); mitk::DataNode::Pointer childNode; for (unsigned long i = 0; i < size; ++i) { childNode = children->GetElement(i); childNode->GetData()->GetGeometry()->Compose( scalingMatrix ); childNode->GetData()->Modified(); } m_RedoGeometryList.clear(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkRigidRegistrationView::AlignCenters() { if (m_FixedNode.IsNotNull() && m_MovingNode.IsNotNull()) { mitk::Point3D fixedPoint = m_FixedNode->GetData()->GetGeometry()->GetCenter(); mitk::Point3D movingPoint = m_MovingNode->GetData()->GetGeometry()->GetCenter(); mitk::Vector3D translateVec; translateVec = fixedPoint - movingPoint; m_Controls.m_XTransSlider->setValue((int)m_Controls.m_XTransSlider->value() + (int)translateVec[0]); m_Controls.m_YTransSlider->setValue((int)m_Controls.m_YTransSlider->value() + (int)translateVec[1]); m_Controls.m_ZTransSlider->setValue((int)m_Controls.m_ZTransSlider->value() + (int)translateVec[2]); } } void QmitkRigidRegistrationView::SetUndoEnabled( bool enable ) { m_Controls.m_UndoTransformation->setEnabled(enable); } void QmitkRigidRegistrationView::SetRedoEnabled( bool enable ) { m_Controls.m_RedoTransformation->setEnabled(enable); } void QmitkRigidRegistrationView::CheckCalculateEnabled() { if (m_FixedNode.IsNotNull() && m_MovingNode.IsNotNull()) { m_Controls.m_ManualFrame->setEnabled(true); m_Controls.m_CalculateTransformation->setEnabled(true); if ( (m_FixedDimension != m_MovingDimension && std::max(m_FixedDimension, m_MovingDimension) != 4) || m_FixedDimension < 2 /*|| m_FixedDimension > 3*/) { m_Controls.m_CalculateTransformation->setEnabled(false); } else if (m_Controls.qmitkRigidRegistrationSelector1->GetSelectedTransform() < 5 && (m_FixedDimension < 2) /*|| m_FixedDimension > 3)*/) { m_Controls.m_CalculateTransformation->setEnabled(false); } else if ((m_Controls.qmitkRigidRegistrationSelector1->GetSelectedTransform() > 4 && m_Controls.qmitkRigidRegistrationSelector1->GetSelectedTransform() < 13) && !(m_FixedDimension > 2)) { m_Controls.m_CalculateTransformation->setEnabled(false); } else if (m_Controls.qmitkRigidRegistrationSelector1->GetSelectedTransform() > 12 && m_FixedDimension != 2) { m_Controls.m_CalculateTransformation->setEnabled(false); } } else { m_Controls.m_CalculateTransformation->setEnabled(false); m_Controls.m_ManualFrame->setEnabled(false); } } void QmitkRigidRegistrationView::xTrans_valueChanged( int v ) { if (m_MovingNode.IsNotNull()) { translationParams[0]=v; translationParams[1]=m_Controls.m_YTransSlider->value(); translationParams[2]=m_Controls.m_ZTransSlider->value(); Translate(translationParams); } else { MovingImageChanged(); } } void QmitkRigidRegistrationView::yTrans_valueChanged( int v ) { if (m_MovingNode.IsNotNull()) { translationParams[0]=m_Controls.m_XTransSlider->value(); translationParams[1]=v; translationParams[2]=m_Controls.m_ZTransSlider->value(); Translate(translationParams); } else { MovingImageChanged(); } } void QmitkRigidRegistrationView::zTrans_valueChanged( int v ) { if (m_MovingNode.IsNotNull()) { translationParams[0]=m_Controls.m_XTransSlider->value(); translationParams[1]=m_Controls.m_YTransSlider->value(); translationParams[2]=v; Translate(translationParams); } else { MovingImageChanged(); } } void QmitkRigidRegistrationView::xRot_valueChanged( int v ) { if (m_MovingNode.IsNotNull()) { rotationParams[0]=v; rotationParams[1]=m_Controls.m_YRotSlider->value(); rotationParams[2]=m_Controls.m_ZRotSlider->value(); Rotate(rotationParams); } else { MovingImageChanged(); } } void QmitkRigidRegistrationView::yRot_valueChanged( int v ) { if (m_MovingNode.IsNotNull()) { rotationParams[0]=m_Controls.m_XRotSlider->value(); rotationParams[1]=v; rotationParams[2]=m_Controls.m_ZRotSlider->value(); Rotate(rotationParams); } else { MovingImageChanged(); } } void QmitkRigidRegistrationView::zRot_valueChanged( int v ) { if (m_MovingNode.IsNotNull()) { rotationParams[0]=m_Controls.m_XRotSlider->value(); rotationParams[1]=m_Controls.m_YRotSlider->value(); rotationParams[2]=v; Rotate(rotationParams); } else { MovingImageChanged(); } } void QmitkRigidRegistrationView::xScale_valueChanged( int v ) { if (m_MovingNode.IsNotNull()) { scalingParams[0]=v; scalingParams[1]=m_Controls.m_YScaleSlider->value(); scalingParams[2]=m_Controls.m_ZScaleSlider->value(); Scale(scalingParams); } else { MovingImageChanged(); } } void QmitkRigidRegistrationView::yScale_valueChanged( int v ) { if (m_MovingNode.IsNotNull()) { scalingParams[0]=m_Controls.m_XScaleSlider->value(); scalingParams[1]=v; scalingParams[2]=m_Controls.m_ZScaleSlider->value(); Scale(scalingParams); } else { MovingImageChanged(); } } void QmitkRigidRegistrationView::zScale_valueChanged( int v ) { if (m_MovingNode.IsNotNull()) { scalingParams[0]=m_Controls.m_XScaleSlider->value(); scalingParams[1]=m_Controls.m_YScaleSlider->value(); scalingParams[2]=v; Scale(scalingParams); } else { MovingImageChanged(); } } void QmitkRigidRegistrationView::MovingImageChanged() { if (dynamic_cast(m_MovingNode->GetData())) { m_Controls.m_XTransSlider->setValue(0); m_Controls.m_YTransSlider->setValue(0); m_Controls.m_ZTransSlider->setValue(0); translationParams[0]=0; translationParams[1]=0; translationParams[2]=0; m_Controls.m_XRotSlider->setValue(0); m_Controls.m_YRotSlider->setValue(0); m_Controls.m_ZRotSlider->setValue(0); rotationParams[0]=0; rotationParams[1]=0; rotationParams[2]=0; m_Controls.m_XScaleSlider->setValue(0); m_Controls.m_YScaleSlider->setValue(0); m_Controls.m_ZScaleSlider->setValue(0); scalingParams[0]=0; scalingParams[1]=0; scalingParams[2]=0; m_MovingDimension = dynamic_cast(m_MovingNode->GetData())->GetDimension(); m_Controls.qmitkRigidRegistrationSelector1->SetMovingDimension(m_MovingDimension); m_Controls.qmitkRigidRegistrationSelector1->SetMovingNode(m_MovingNode); this->CheckCalculateEnabled(); } } void QmitkRigidRegistrationView::Calculate() { m_Controls.qmitkRigidRegistrationSelector1->SetFixedNode(m_FixedNode); m_Controls.qmitkRigidRegistrationSelector1->SetMovingNode(m_MovingNode); if (m_FixedMaskNode.IsNotNull() && m_Controls.m_UseFixedImageMask->isChecked()) { m_Controls.qmitkRigidRegistrationSelector1->SetFixedMaskNode(m_FixedMaskNode); } else { m_Controls.qmitkRigidRegistrationSelector1->SetFixedMaskNode(NULL); } if (m_MovingMaskNode.IsNotNull() && m_Controls.m_UseMovingImageMask->isChecked()) { m_Controls.qmitkRigidRegistrationSelector1->SetMovingMaskNode(m_MovingMaskNode); } else { m_Controls.qmitkRigidRegistrationSelector1->SetMovingMaskNode(NULL); } m_Controls.frame_2->setEnabled(false); m_Controls.frame_3->setEnabled(false); m_Controls.m_CalculateTransformation->setEnabled(false); m_Controls.m_StopOptimization->setEnabled(true); m_Controls.qmitkRigidRegistrationSelector1->CalculateTransformation(((QmitkSliderNavigatorWidget*)m_Controls.timeSlider)->GetPos()); m_Controls.m_StopOptimization->setEnabled(false); m_Controls.frame_2->setEnabled(true); m_Controls.frame_3->setEnabled(true); m_Controls.m_CalculateTransformation->setEnabled(true); m_Controls.qmitkRigidRegistrationSelector1->StopOptimization(false); } void QmitkRigidRegistrationView::SetOptimizerValue( double value ) { m_Controls.m_OptimizerValueLCD->display(value); } void QmitkRigidRegistrationView::StopOptimizationClicked() { m_Controls.qmitkRigidRegistrationSelector1->StopOptimization(true); } void QmitkRigidRegistrationView::UpdateTimestep() { mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkRigidRegistrationView::ShowManualRegistrationFrame(bool show) { if (show) { m_Controls.m_ManualFrame->show(); } else { m_Controls.m_ManualFrame->hide(); } } void QmitkRigidRegistrationView::SetImagesVisible(berry::ISelection::ConstPointer /*selection*/) { if (this->m_CurrentSelection->Size() == 0) { // show all images mitk::DataStorage::SetOfObjects::ConstPointer setOfObjects = this->GetDataStorage()->GetAll(); for (mitk::DataStorage::SetOfObjects::ConstIterator nodeIt = setOfObjects->Begin() ; nodeIt != setOfObjects->End(); ++nodeIt) // for each node { if ( (nodeIt->Value().IsNotNull()) && (nodeIt->Value()->GetProperty("visible")) && dynamic_cast(nodeIt->Value()->GetData())==NULL) { nodeIt->Value()->SetVisibility(true); } } } else { // hide all images mitk::DataStorage::SetOfObjects::ConstPointer setOfObjects = this->GetDataStorage()->GetAll(); for (mitk::DataStorage::SetOfObjects::ConstIterator nodeIt = setOfObjects->Begin() ; nodeIt != setOfObjects->End(); ++nodeIt) // for each node { if ( (nodeIt->Value().IsNotNull()) && (nodeIt->Value()->GetProperty("visible")) && dynamic_cast(nodeIt->Value()->GetData())==NULL) { nodeIt->Value()->SetVisibility(false); } } } } void QmitkRigidRegistrationView::CheckForMaskImages() { if (m_FixedMaskNode.IsNotNull()) { m_Controls.m_UseFixedImageMask->show(); } else { m_Controls.m_UseFixedImageMask->hide(); } if (m_MovingMaskNode.IsNotNull()) { m_Controls.m_UseMovingImageMask->show(); } else { m_Controls.m_UseMovingImageMask->hide(); } } void QmitkRigidRegistrationView::UseFixedMaskImageChecked(bool checked) { if (checked) { m_FixedMaskNode->SetVisibility(true); } else { m_FixedMaskNode->SetVisibility(false); } } void QmitkRigidRegistrationView::UseMovingMaskImageChecked(bool checked) { if (checked) { m_MovingMaskNode->SetVisibility(true); } else { m_MovingMaskNode->SetVisibility(false); } } void QmitkRigidRegistrationView::TabChanged(int index) { if (index == 0) { m_Controls.frame->hide(); } else { m_Controls.frame->show(); } } void QmitkRigidRegistrationView::SwitchImages() { mitk::DataNode::Pointer newMoving = m_FixedNode; mitk::DataNode::Pointer newFixed = m_MovingNode; this->FixedSelected(newFixed); this->MovingSelected(newMoving); + + if(m_ContourHelperNode.IsNotNull()) + { + + // Update the contour + ShowContour(); + + + } + } diff --git a/Plugins/org.mitk.gui.qt.registration/src/internal/QmitkRigidRegistrationView.h b/Plugins/org.mitk.gui.qt.registration/src/internal/QmitkRigidRegistrationView.h index 55d8f48ef5..5938b9d44d 100644 --- a/Plugins/org.mitk.gui.qt.registration/src/internal/QmitkRigidRegistrationView.h +++ b/Plugins/org.mitk.gui.qt.registration/src/internal/QmitkRigidRegistrationView.h @@ -1,297 +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. ===================================================================*/ #ifndef QMITKRIGIDREGISTRATION_H #define QMITKRIGIDREGISTRATION_H #include "QmitkFunctionality.h" #include "ui_QmitkRigidRegistrationViewControls.h" #include "berryISelectionListener.h" #include "berryIStructuredSelection.h" #include // Time Slider related #include /*! \brief This functionality allows you to register 2D as well as 3D images in a rigid manner. Register means to align two images, so that they become as similar as possible. Therefore you can select from different transforms, metrics and optimizers. Registration results will directly be applied to the Moving Image. \sa QmitkFunctionality \ingroup Functionalities \ingroup RigidRegistration \author Daniel Stein */ class REGISTRATION_EXPORT QmitkRigidRegistrationView : public QmitkFunctionality { friend struct SelListenerRigidRegistration; Q_OBJECT public: static const std::string VIEW_ID; /*! \brief default constructor */ QmitkRigidRegistrationView(QObject *parent=0, const char *name=0); QmitkRigidRegistrationView(const QmitkRigidRegistrationView& other) { Q_UNUSED(other) throw std::runtime_error("Copy constructor not implemented"); } /*! \brief default destructor */ virtual ~QmitkRigidRegistrationView(); /*! \brief method for creating the applications main widget */ virtual void CreateQtPartControl(QWidget *parent); /*! \brief Sets the StdMultiWidget and connects it to the functionality. */ virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget); /*! \brief Removes the StdMultiWidget and disconnects it from the functionality. */ virtual void StdMultiWidgetNotAvailable(); /*! \brief method for creating the connections of main and control widget */ virtual void CreateConnections(); /*! \brief Method which is called when this functionality is selected in MITK */ virtual void Activated(); /*! \brief Method which is called whenever the functionality is deselected in MITK */ virtual void Deactivated(); virtual void Visible(); virtual void Hidden(); void DataNodeHasBeenRemoved(const mitk::DataNode* node); signals: protected slots: /*! * sets the fixed Image according to TreeNodeSelector widget */ void FixedSelected(mitk::DataNode::Pointer fixedImage); /*! * sets the moving Image according to TreeNodeSelector widget */ void MovingSelected(mitk::DataNode::Pointer movingImage); /*! * checks if registration is possible */ bool CheckCalculate(); /*! * \brief Undo the last registration. */ void UndoTransformation(); /*! * \brief Redo the last registration */ void RedoTransformation(); /*! * \brief Adds a new Transformation to the undo list and enables the undo button. */ void AddNewTransformationToUndoList(); /*! * \brief Translates the moving image in x, y and z direction given by translateVector * * @param translateVector Contains the translation in x, y and z direction. */ void Translate(int* translateVector); /*! * \brief Rotates the moving image in x, y and z direction given by rotateVector * * @param rotateVector Contains the rotation around x, y and z axis. */ void Rotate(int* rotateVector); /*! * \brief Scales the moving image in x, y and z direction given by scaleVector * * @param scaleVector Contains the scaling around x, y and z axis. */ void Scale(int* scaleVector); /*! * \brief Automatically aligns the image centers. */ void AlignCenters(); /*! * \brief Stores whether the image will be shown in gray values or in red for fixed image and green for moving image * @param show if true, then images will be shown in red and green */ void ShowRedGreen(bool show); + /*! + * \brief Draws the contour of the fixed image according to a threshold + * @param show if true, then images will be shown in red and green + */ + void ShowContour(); + + /*! + * \brief Stores whether the contour of the fixed image will be shhown + * @param show if true, the contour of the fixed image is shown + */ + void EnableContour(bool show); + /*! * \brief Changes the visibility of the manual registration methods accordingly to the checkbox "Manual Registration" in GUI * @param show if true, then manual registration methods will be shown */ void ShowManualRegistrationFrame(bool show); /*! * \brief Sets the selected opacity for moving image * @param opacity the selected opacity */ void OpacityUpdate(float opacity); /*! \brief Sets the selected opacity for moving image @param opacity the selected opacity */ void OpacityUpdate(int opacity); /*! * \brief Sets the images to grayvalues or fixed image to red and moving image to green * @param redGreen if true, then images will be shown in red and green */ void SetImageColor(bool redGreen); /*! * \brief Clears the undo and redo lists and sets the undo and redo buttons to disabled. */ void ClearTransformationLists(); void SetUndoEnabled( bool enable ); void SetRedoEnabled( bool enable ); void CheckCalculateEnabled(); void xTrans_valueChanged( int v ); void yTrans_valueChanged( int v ); void zTrans_valueChanged( int v ); void xRot_valueChanged( int v ); void yRot_valueChanged( int v ); void zRot_valueChanged( int v ); void xScale_valueChanged( int v ); void yScale_valueChanged( int v ); void zScale_valueChanged( int v ); void MovingImageChanged(); /*! * \brief Starts the registration process. */ void Calculate(); void SetOptimizerValue( double value ); void StopOptimizationClicked(); void UpdateTimestep(); void SetImagesVisible(berry::ISelection::ConstPointer /*selection*/); void CheckForMaskImages(); void UseFixedMaskImageChecked(bool checked); void UseMovingMaskImageChecked(bool checked); void TabChanged(int index); void SwitchImages(); protected: berry::ISelectionListener::Pointer m_SelListener; berry::IStructuredSelection::ConstPointer m_CurrentSelection; /*! * default main widget containing 4 windows showing 3 * orthogonal slices of the volume and a 3d render window */ QmitkStdMultiWidget * m_MultiWidget; /*! * control widget to make all changes for Deformable registration */ Ui::QmitkRigidRegistrationViewControls m_Controls; mitk::DataNode::Pointer m_MovingNode; mitk::DataNode::Pointer m_MovingMaskNode; mitk::DataNode::Pointer m_FixedNode; mitk::DataNode::Pointer m_FixedMaskNode; + + + + // A node to store the contour of the fixed image in + mitk::DataNode::Pointer m_ContourHelperNode; + + + std::list m_UndoGeometryList; std::list > m_UndoChildGeometryList; std::list m_RedoGeometryList; std::list > m_RedoChildGeometryList; bool m_ShowRedGreen; float m_Opacity; float m_OriginalOpacity; bool m_Deactivated; int m_FixedDimension; int m_MovingDimension; int * translationParams; int * rotationParams; int * scalingParams; mitk::Color m_FixedColor; mitk::Color m_MovingColor; int m_TranslateSliderPos[3]; int m_RotateSliderPos[3]; int m_ScaleSliderPos[3]; QmitkStepperAdapter* m_TimeStepperAdapter; }; #endif //QMITKRigidREGISTRATION_H diff --git a/Plugins/org.mitk.gui.qt.registration/src/internal/QmitkRigidRegistrationViewControls.ui b/Plugins/org.mitk.gui.qt.registration/src/internal/QmitkRigidRegistrationViewControls.ui index c9b1bfe88b..6b8aa33205 100644 --- a/Plugins/org.mitk.gui.qt.registration/src/internal/QmitkRigidRegistrationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.registration/src/internal/QmitkRigidRegistrationViewControls.ui @@ -1,1009 +1,1030 @@ QmitkRigidRegistrationViewControls 0 0 - 381 - 720 + 417 + 932 0 0 RigidRegistrationControls 0 0 QTabWidget::South QTabWidget::Triangular 0 Qt::ElideNone Automatic Registration QFrame::StyledPanel QFrame::Raised 0 0 QFrame::StyledPanel QFrame::Raised - - 0 - - - 0 - + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + + 8 + + + + Fixed Image: + + + + + + + + 10 + + + + + + + false + + + + + + + + 8 + + + + Moving Image : + + + + + + + + 10 + + + + + + + false + + + + + + + Switch fixed and moving image + + + + + + + Use Fixed Image Mask + + + + + + + Use Moving Image Mask + + + + + 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 118 116 108 118 116 108 118 116 108 8 You have to select two images from Data Manager using CTRL + left click! - - - QFormLayout::AllNonFixedFieldsGrow - - - - - - 8 - - - - Fixed Image: - - - - - - - - 10 - - - - - - - false - - - - - - - - 8 - - - - Moving Image : - - - - - - - - 10 - - - - - - - false - - - - - - - Switch fixed and moving image - - - - - - - Use Fixed Image Mask - - - - - + + + - Use Moving Image Mask + 0% - - - - Moving Image Opacity: false - - - - 0% - - - 0 0 100 50 Qt::Horizontal 100% + + + + + + Show contour + + + + + + + false + + + Qt::Horizontal + + + + + + + 0 + + + + + 0 0 Show Images Red/Green Load Preset + + + + false + + + Stop + + + false 0 0 0 0 Register :/QmitkRigidRegistrationView/RigidRegistration.xpm:/QmitkRigidRegistrationView/RigidRegistration.xpm false - - - - false - - - Stop - - - QFrame::StyledPanel QFrame::Raised Optimizer Value: false QFrame::Raised 10 QLCDNumber::Flat false 0 0 Undo Transformation :/org.mitk.gui.qt.ext/edit-undo.png:/org.mitk.gui.qt.ext/edit-undo.png false 0 0 Redo Transformation :/org.mitk.gui.qt.ext/edit-redo.png:/org.mitk.gui.qt.ext/edit-redo.png Manual Registration true QFrame::StyledPanel QFrame::Raised 0 50 false Align Image Centers 75 true Interactive Translations true false 6 0 50 false x-Direction (Frontal): false 50 false y-Direction (Sagittal): false 50 false - z-Direction (Transversal): + z-Direction (Axial): false ArrowCursor -256 256 Qt::Horizontal -256 256 Qt::Horizontal -256 256 Qt::Horizontal 75 true Interactive Rotations true 0 50 false x-Axis (Frontal): false 50 false y-Axis (Sagittal): false 50 false - z-Axis (Transversal): + z-Axis (Axial): false ArrowCursor -20 20 Qt::Horizontal -20 20 Qt::Horizontal -20 20 Qt::Horizontal 75 true Interactive Scaling true 0 50 false x-Direction (Frontal): false 50 false y-Direction (Sagittal): false 50 false - z-Direction (Transversal): + z-Direction (Axial): false ArrowCursor -20 20 1 1 Qt::Horizontal false QSlider::NoTicks -20 20 1 Qt::Horizontal -20 20 1 Qt::Horizontal Qt::Vertical 20 40 Advanced Mode Load Testpresets QFrame::StyledPanel QFrame::Raised 10 10 505 712 0 0 Save as Testpreset Save as Preset QmitkRigidRegistrationSelectorView QWidget
src/internal/QmitkRigidRegistrationSelectorView.h
1
QmitkSliderNavigatorWidget QWidget
QmitkSliderNavigatorWidget.h
1
mitkDataNode.h mitkBaseData.h -
diff --git a/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/org_mitk_gui_qt_segmentation.dox b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/org_mitk_gui_qt_segmentation.dox index 2130c5e5f5..463e51d867 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/org_mitk_gui_qt_segmentation.dox +++ b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/org_mitk_gui_qt_segmentation.dox @@ -1,292 +1,292 @@ /** -\bundlemainpage{org_segment} The Segmentation Module +\page org_mitk_views_segmentation The Segmentation Module \image html segmentation.png "Icon of the Module" Some of the features described below are not available in the open-source part of the MITK-3M3-Application. Available sections: - \ref org_mitk_gui_qt_segmentationUserManualOverview - \ref org_mitk_gui_qt_segmentationUserManualTechnical - \ref org_mitk_gui_qt_segmentationUserManualImageSelection - \ref org_mitk_gui_qt_segmentationUserManualManualKringeling - \ref org_mitk_gui_qt_segmentationUserManualManualKringeling1 - \ref org_mitk_gui_qt_segmentationUserManualManualKringeling2 - \ref org_mitk_gui_qt_segmentationUserManualManualKringeling3 - \ref org_mitk_gui_qt_segmentationUserManualManualKringeling4 - \ref org_mitk_gui_qt_segmentationUserManualManualKringeling5 - \ref org_mitk_gui_qt_segmentationUserManualOrganSegmentation - \ref org_mitk_gui_qt_segmentationUserManualOrganSegmentation1 - \ref org_mitk_gui_qt_segmentationUserManualOrganSegmentation2 - \ref org_mitk_gui_qt_segmentationUserManualOrganSegmentation99 - \ref org_mitk_gui_qt_segmentationUserManualLesionSegmentation - \ref org_mitk_gui_qt_segmentationUserManualPostprocessing - \ref org_mitk_gui_qt_segmentationUserManualSurfaceMasking - \ref org_mitk_gui_qt_segmentationUserManualTechnicalDetail \section org_mitk_gui_qt_segmentationUserManualOverview Overview The Segmentation perspective allows you to create segmentations of anatomical and pathological structures in medical images of the human body. The perspective groups a number of tools which can be used for:
  • (semi-)automatic segmentation of organs on CT or MR image volumes
  • semi-automatic segmentation of lesions such as enlarged lymph nodes or tumors
  • manual segmentation of any structures you might want to delineate
\image html org_mitk_gui_qt_segmentationIMGapplication.png Segmentation perspective consisting of the Data Manager view and the Segmentation view If you wonder what segmentations are good for, we shortly revisit the concept of a segmentation here. A CT or MR image is made up of volume of physical measurements (volume elements are called voxels). In CT images, for example, the gray value of each voxel corresponds to the mass absorbtion coefficient for X-rays in this voxel, which is similar in many %parts of the human body. The gray value does not contain any further information, so the computer does not know whether a given voxel is part of the body or the background, nor can it tell a brain from a liver. However, the distinction between a foreground and a background structure is required when:
  • you want to know the volume of a given organ (the computer needs to know which %parts of the image belong to this organ)
  • you want to create 3D polygon visualizations (the computer needs to know the surfaces of structures that should be drawn)
  • as a necessary pre-processing step for therapy planning, therapy support, and therapy monitoring
Creating this distinction between foreground and background is called segmentation. -The Segmentation perspective of the MITK ExtApp uses a voxel based approach to segmentation, i.e. each voxel of an image must be completely assigned to either foreground or background. +The Segmentation perspective of the MITK Workbench uses a voxel based approach to segmentation, i.e. each voxel of an image must be completely assigned to either foreground or background. This is in contrast to some other applications which might use an approach based on contours, where the border of a structure might cut a voxel into two %parts. The remainder of this document will summarize the features of the Segmentation perspective and how they are used. \section org_mitk_gui_qt_segmentationUserManualTechnical Technical Issues The Segmentation perspective makes a number of assumptions. To know what this module can be used for, it will help you to know that:
  • Images must be 2D, 3D, or 3D+t
  • Images must be single-values, i.e. CT, MRI or "normal" ultrasound. Images from color doppler or photographic (RGB) images are not supported
  • Segmentations are handled as binary images of the same extent as the original image
\section org_mitk_gui_qt_segmentationUserManualImageSelection Image Selection The Segmentation perspective makes use of the Data Manager view to give you an overview of all images and segmentations. \image html org_mitk_gui_qt_segmentationIMGselection.png Data Manager is used for selecting the current segmentation. The reference image is selected in the drop down box of the control area. To select the reference image (e.g. the original CT/MR image) use the drop down box in the control area of the Segmentation view. The segmentation image selected in the Data Manager is displayed below the drop down box. If no segmentation image exists or none is selected create a new segmentation image by using the "New segmentation" button. Some items of the graphical user interface might be disabled when no image is selected. In any case, the application will give you hints if a selection is needed. \section org_mitk_gui_qt_segmentationUserManualManualKringeling Manual Contouring With manual contouring you define which voxels are part of the segmentation and which are not. This allows you to create segmentations of any structeres that you may find in an image, even if they are not part of the human body. You might also use manual contouring to correct segmentations that result from sub-optimal automatic methods. The drawback of manual contouring is that you might need to define contours on many 2D slices. However, this is moderated by the interpolation feature, which will make suggestions for a segmentation. \subsection org_mitk_gui_qt_segmentationUserManualManualKringeling1 Creating New Segmentations Unless you want to edit existing segmentations, you have to create a new, empty segmentation before you can edit it. To do so, click the "New manual segmentation" button. Input fields will appear where you can choose a name for the new segmentation and a color for its display. Click the checkmark button to confirm or the X button to cancel the new segmentation. Notice that the input field suggests names once you %start typing and that it also suggests colors for known organ names. If you use names that are not yet known to the application, it will automatically remember these names and consider them the next time you create a new segmentation. Once you created a new segmentation, you can notice a new item with the "binary mask" icon in the Data Manager tree view. This item is automatically selected for you, allowing you to %start editing the new segmentation right away. \subsection org_mitk_gui_qt_segmentationUserManualManualKringeling2 Selecting Segmentations for Editing As you might want to have segmentations of multiple structures in a single patient image, the application needs to know which of them to use for editing. You select a segmenation by clicking it in the tree view of Data Manager. Note that segmentations are usually displayed as sub-items of "their" patient image. In the rare case, where you need to edit a segmentation that is not displayed as a a sub-item, you can click both the original image AND the segmentation while holding down CTRL or for Mac OS X the CMD on the keyboard. When a selection is made, the Segmentation View will hide all but the selected segmentation and the corresponding original image. When there are multiple segmentations, the unselected ones will remain in the Data Manager, you can make them visible at any time by selecting them. \subsection org_mitk_gui_qt_segmentationUserManualManualKringeling3 Selecting Editing Tools -If you are familiar with the MITK ExtApp, you know that clicking and moving the mouse in any of the 2D render windows will move around the crosshair that defines what part of the image is displayed. +If you are familiar with the MITK Workbench, you know that clicking and moving the mouse in any of the 2D render windows will move around the crosshair that defines what part of the image is displayed. This behavior is disabled while any of the manual segmentation tools are active -- otherwise you might have a hard time concentrating on the contour you are drawing. To %start using one of the editing tools, click its button the the displayed toolbox. The selected editing tool will be active and its corresponding button will stay pressed until you click the button again. Selecting a different tool also deactivates the previous one. If you have to delineate a lot of images, you should try using shortcuts to switch tools. Just hit the first letter of each tool to activate it (A for Add, S for Subtract, etc.). \subsection org_mitk_gui_qt_segmentationUserManualManualKringeling4 Using Editing Tools -All of the editing tools work by the same principle: you use the mouse (left button) to click anywhere in a 2D window (any of the orientations transversal, sagittal, or frontal), move the mouse while holding the mouse button and release to finish the editing action. +All of the editing tools work by the same principle: you use the mouse (left button) to click anywhere in a 2D window (any of the orientations axial, sagittal, or frontal), move the mouse while holding the mouse button and release to finish the editing action. Multi-step undo and redo is fully supported by all editing tools. Use the application-wide undo button in the toolbar to revert erroneous %actions. \image html org_mitk_gui_qt_segmentationIMGiconAddSubtract.png Add and Subtract Tools Use the left mouse button to draw a closed contour. When releasing the mouse button, the contour will be added (Add tool) to or removed from (Subtract tool) the current segmentation. Hold down the CTRL / CMD key to invert the operation (this will switch tools temporarily to allow for quick corrections). \image html org_mitk_gui_qt_segmentationIMGiconPaintWipe.png Paint and Wipe Tools Use the slider below the toolbox to change the radius of these round paintbrush tools. Move the mouse in any 2D window and press the left button to draw or erase pixels. As the Add/Subtract tools, holding CTRL / CMD while drawing will invert the current tool's behavior. \image html org_mitk_gui_qt_segmentationIMGiconRegionGrowing.png Region Growing Tool Click at one point in a 2D slice widget to add an image region to the segmentation with the region growing tool. Moving up the cursor while holding the left mouse button widens the range for the included grey values; moving it down narrows it. When working on an image with a high range of grey values, the selection range can be influenced more strongly by moving the cursor at higher velocity. Region Growing selects all pixels around the mouse cursor that have a similar gray value as the pixel below the mouse cursor. This enables you to quickly create segmentations of structures that have a good contrast to surrounding tissue, e.g. the lungs. The tool will select more or less pixels (corresponding to a changing gray value interval width) when you move the mouse up or down while holding down the left mouse button. A common issue with region growing is the so called "leakage" which happens when the structure of interest is connected to other pixels, of similar gray values, through a narrow "bridge" at the border of the structure. The Region Growing tool comes with a "leakage detection/removal" feature. If leakage happens, you can left-click into the leakage region and the tool will try to automatically remove this region (see illustration below). \image html org_mitk_gui_qt_segmentationIMGleakage.png Leakage correction feature of the Region Growing tool
\image html org_mitk_gui_qt_segmentationIMGiconCorrection.png Correction Tool You do not have to draw a closed contour to use the Correction tool and do not need to switch between the Add and Substract tool to perform small corrective changes. The following figure shows the usage of this tool:
  • if the user draws a line which %starts and ends outside the segmenation AND it intersects no other segmentation the endpoints of the line are connected and the resulting contour is filled
  • if the user draws a line which %starts and ends outside the segmenation a part of it is cut off (left image)
  • if the line is drawn fully inside the segmentation the marked region is added to the segmentation (right image)
\image html org_mitk_gui_qt_segmentationIMGcorrectionActions.png %Actions of the Correction tool illustrated.
\image html org_mitk_gui_qt_segmentationIMGiconFill.png Fill Tool Left-click inside a segmentation with holes to completely fill all holes. \image html org_mitk_gui_qt_segmentationIMGiconErase.png Erase Tool This tool removes a connected part of pixels that form a segmentation. You may use it to remove so called islands (see picture) or to clear a whole slice at once (hold CTRL while clicking). \subsection org_mitk_gui_qt_segmentationUserManualManualKringeling5 Interpolation Creating segmentations for modern CT volumes is very time-consuming, because structures of interest can easily cover a range of 50 or more slices. The Manual Segmentation View offers two helpful features for these cases:
  • 3D Interpolation
  • 2D Interpolation

The 3D interpolation is activated by default when using the manual segmentation tools. That means if you start contouring, from the second contour onwards, the surface of the segmented area will be interpolated based on the given contour information. The interpolation works with all available manual tools. Please note that this is currently a pure mathematical interpolation, i.e. image intensity information is not taken into account. With each further contour the interpolation result will be improved, but the more contours you provide the longer the recalculation will take. To achieve an optimal interpolation result and in this way a most accurate segmentation you should try to describe the surface with sparse contours by segmenting in arbitrary oriented planes. The 3D interpolation is not meant to be used for parallel slice-wise segmentation. \image html org_mitk_gui_qt_segmentation3DInterpolationWrongRight.png 3D Interpolation HowTo You can accept the interpolation result by clicking the "Accept" - button below the tool buttons. In this case the 3D interpolation will be deactivated automatically so that the result can be postprocessed without any interpolation running in background. During recalculation the interpolated surface is blinking yellow/white. When the interpolation has finished the surface is shown yellow with a small opacity. Additional to the surface, black contours are shown in the 3D render window. They mark the positions of all the drawn contours which were used for the interpolation. You can navigate between the drawn contours by clicking on the „Position“ - Nodes in the datamanager which are located below the selected segmentation. If you don't want to see these nodes just unckeck the „Show Position Nodes“ Checkbox and these nodes will be hidden. If you want to delete a drawn contour we recommend to use the Erase-Tool since Redo/Undo is not yet working for 3D interpolation.
The 2D Interpolation creates suggestions for a segmentation whenever you have a slice that
  • has got neighboring slices with segmentations (these do not need to be direct neighbors but could also be a couple of slices away) AND
  • is completely clear of a manual segmentation -- i.e. there will be no suggestion if there is even only a single pixel of segmentation in the current slice.
Interpolated suggestions are displayed in a different way than manual segmentations are, until you "accept" them as part of the segmentation. To accept single slices, click the "Accept" button below the toolbox. If you have segmented a whole organ in every-x-slice, you may also review the interpolations and then accept all of them at once by clicking "... all slices". \section org_mitk_gui_qt_segmentationUserManualOrganSegmentation Organ Segmentation \note This feature is only available in our 3M3 Demo Application (http://www.mint-medical.de/productssolutions/mitk3m3/mitk3m3/#downloads) but not in the open source part of MITK The manual contouring described above is a fallback option that will work for any kind of images and structures of interest. However, manual contouring is very time-consuming and tedious. This is why a major part of image analysis research is working towards automatic segmentation methods. The Segmentation View comprises a number of easy-to-use tools for segmentation of CT images (Liver) and MR image (left ventricle and wall, left and right lung). \subsection org_mitk_gui_qt_segmentationUserManualOrganSegmentation1 Liver on CT Images On CT image volumes, preferrably with a contrast agent in the portal venous phase, the Liver tool will fully automatically analyze and segment the image. All you have to do is to load and select the image, then click the "Liver" button. During the process, which takes a minute or two, you will get visual progress feedback by means of a contour that moves closer and closer to the real liver boundaries. \subsection org_mitk_gui_qt_segmentationUserManualOrganSegmentation2 Heart, Lung, and Hippocampus on MRI While liver segmentation is performed fully automatic, the following tools for segmentation of the heart, the lungs, and the hippocampus need a minimum amount of guidance. Click one of the buttons on the "Organ segmentation" page to add an average %model of the respective organ to the image. This %model can be dragged to the right position by using the left mouse button while holding down the CTRL key. You can also use CTRL + middle mouse button to rotate or CTRL + right mouse button to scale the %model. Before starting the automatic segmentation process by clicking the "Start segmentation" button, try placing the %model closely to the organ in the MR image (in most cases, you do not need to rotate or scale the %model). During the segmentation process, a green contour that moves closer and closer to the real liver boundaries will provide you with visual feedback of the segmentation progress. The algorithms used for segmentation of the heart and lung are method which need training by a number of example images. They will not work well with other kind of images, so here is a list of the image types that were used for training:
  • Hippocampus segmentation: T1-weighted MR images, 1.5 Tesla scanner (Magnetom Vision, Siemens Medical Solutions), 1.0 mm isotropic resolution
  • Heart: Left ventricle inner segmentation (LV Model): MRI; velocity encoded cine (VEC-cine) MRI sequence; trained on systole and diastole
  • Heart: Left ventricular wall segmentation (LV Inner Wall, LV Outer Wall): 4D MRI; short axis 12 slice spin lock sequence(SA_12_sl); trained on whole heart cycle
  • Lung segmentation: 3D and 4D MRI; works best on FLASH3D and TWIST4D sequences
\subsection org_mitk_gui_qt_segmentationUserManualOrganSegmentation99 Other Organs As mentioned in the Heart/Lung section, most of the underlying methods are based on "training". The basic algorithm is versatile and can be applied on all kinds of segmentation problems where the structure of interest is topologically like a sphere (and not like a torus etc.). If you are interested in other organs than those offered by the current version of the Segmentation view, please contact our research team. \section org_mitk_gui_qt_segmentationUserManualLesionSegmentation Lesion Segmentation \note This feature is only available in our 3M3 Demo Application (http://www.mint-medical.de/productssolutions/mitk3m3/mitk3m3/#downloads) but not in the open source part of MITK Lesion segmentation is a little different from organ segmentation. Since lesions are not part of the healthy body, they sometimes have a diffused border, and are often found in varying places all over the body. The tools in this section offer efficient ways to create 3D segmentations of such lesions. The Segmentation View currently offers supoprt for enlarged lymph nodes. To segment an enlarged lymph node, find a more or less central slice of it, activate the "Lymph Node" tool and draw a rough contour on the inside of the lymph node. When releaseing the mouse button, a segmentation algorithm is started in a background task. The result will become visible after a couple of seconds, but you do not have to wait for it. If you need to segment several lymph nodes, you can continue to inspect the image right after closing the drawn contour. If the lymph node segmentation is not to your content, you can select the "Lymph Node Correction" tool and drag %parts of the lymph node surface towards the right position (works in 3D, not slice-by-slice). This kind of correction helps in many cases. If nothing else helps, you can still use the pure manual tools as a fallback. \section org_mitk_gui_qt_segmentationUserManualPostprocessing Things you can do with segmentations As mentioned in the introduction, segmentations are never an end in themselves. Consequently, the Segmentation view adds a couple of "post-processing" %actions to the Data Manager. These %actions are accessible through the context-menu of segmentations in Data Manager's list view \image html org_mitk_gui_qt_segmentationIMGDataManagerContextMenu.png Context menu items for segmentations.
  • Create polygon %model applies the marching cubes algorithms to the segmentation. This polygon %model can be used for visualization in 3D or other things such as stereolithography (3D printing).
  • Create smoothed polygon %model uses smoothing in addition to the marching cubes algorithms, which creates models that do not follow the exact outlines of the segmentation, but look smoother.
  • Statistics goes through all the voxels in the patient image that are part of the segmentation and calculates some statistical measures (minumum, maximum, median, histogram, etc.). Note that the statistics are ALWAYS calculated for the parent element of the segmentation as shown in Data Manager.
  • Autocrop can save memory. Manual segmentations have the same extent as the patient image, even if the segmentation comprises only a small sub-volume. This invisible and meaningless margin is removed by autocropping.
\section org_mitk_gui_qt_segmentationUserManualSurfaceMasking Surface Masking You can use the surface masking tool to create binary images from a surface which is used used as a mask on an image. This task is demonstrated below: \image html segmentationFromSurfaceBefore.png Load an image and a surface. Select the image and the surface in the corresponding drop-down boxes (both are selected automatically if there is just one image and one surface) \image html segmentationFromSurfaceAfter.png Create segmentation from surface After clicking "Create segmentation from surface" the newly created binary image is inserted in the DataManager and can be used for further processing \section org_mitk_gui_qt_segmentationUserManualTechnicalDetail Technical Information for Developers For technical specifications see \subpage QmitkSegmentationTechnicalPage and for information on the extensions of the tools system \subpage toolextensions . */ 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 7a7ed06f65..066c4b84a6 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkOtsuAction.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkOtsuAction.cpp @@ -1,202 +1,213 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkOtsuAction.h" // MITK #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()); + 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::AlignmentFlag::AlignHCenter); - //numberOfThresholdsLabel->setAlignment(Qt::AlignmentFlag::AlignVCenter); numberOfThresholdsLabel->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter); layout->addWidget(numberOfThresholdsLabel); - layout->addWidget(m_OtsuSpinBox); - layout->addWidget(m_OtsuPushButton); + 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::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); mitk::LevelWindow levelwindow; levelwindow.SetRangeMinMax(0, numberOfThresholds); 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.segmentation/src/internal/QmitkSegmentationView.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp index f15f2ad731..c4142a51a5 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp @@ -1,1221 +1,1211 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkDataNodeObject.h" #include "mitkProperties.h" #include "mitkSegTool2D.h" #include "mitkGlobalInteraction.h" #include "QmitkStdMultiWidget.h" #include "QmitkNewSegmentationDialog.h" #include #include #include "QmitkSegmentationView.h" #include "QmitkSegmentationPostProcessing.h" #include "QmitkSegmentationOrganNamesHandling.cpp" #include #include //For Segmentation in rotated slices //TODO clean up includes #include "mitkVtkResliceInterpolationProperty.h" #include "mitkPlanarCircle.h" #include "mitkGetModuleContext.h" #include "mitkModule.h" #include "mitkModuleRegistry.h" #include "mitkSegmentationObjectFactory.h" const std::string QmitkSegmentationView::VIEW_ID = "org.mitk.views.segmentation"; // public methods QmitkSegmentationView::QmitkSegmentationView() :m_Parent(NULL) ,m_Controls(NULL) ,m_MultiWidget(NULL) ,m_RenderingManagerObserverTag(0) { RegisterSegmentationObjectFactory(); } QmitkSegmentationView::~QmitkSegmentationView() { // delete m_PostProcessing; delete m_Controls; } void QmitkSegmentationView::NewNodesGenerated() { // ForceDisplayPreferencesUponAllImages(); } void QmitkSegmentationView::NewNodeObjectsGenerated(mitk::ToolManager::DataVectorType* nodes) { if (!nodes) return; mitk::ToolManager* toolManager = m_Controls->m_ManualToolSelectionBox->GetToolManager(); if (!toolManager) return; for (mitk::ToolManager::DataVectorType::iterator iter = nodes->begin(); iter != nodes->end(); ++iter) { this->FireNodeSelected( *iter ); // only last iteration meaningful, multiple generated objects are not taken into account here } } void QmitkSegmentationView::Activated() { // should be moved to ::BecomesVisible() or similar if( m_Controls ) { m_Controls->m_ManualToolSelectionBox->setEnabled( true ); m_Controls->m_OrganToolSelectionBox->setEnabled( true ); m_Controls->m_LesionToolSelectionBox->setEnabled( true ); m_Controls->m_SlicesInterpolator->Enable3DInterpolation( m_Controls->widgetStack->currentWidget() == m_Controls->pageManual ); //TODO Remove Observer itk::ReceptorMemberCommand::Pointer command1 = itk::ReceptorMemberCommand::New(); command1->SetCallbackFunction( this, &QmitkSegmentationView::RenderingManagerReinitialized ); m_RenderingManagerObserverTag = mitk::RenderingManager::GetInstance()->AddObserver( mitk::RenderingManagerViewsInitializedEvent(), command1 ); //Adding observers for node visibility to existing segmentations mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isSegmentation = mitk::NodePredicateAnd::New( isImage, isBinary ); mitk::DataStorage::SetOfObjects::ConstPointer segmentations = this->GetDefaultDataStorage()->GetSubset( isSegmentation ); for ( mitk::DataStorage::SetOfObjects::const_iterator iter = segmentations->begin(); iter != segmentations->end(); ++iter) { mitk::DataNode* node = *iter; itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::OnWorkingNodeVisibilityChanged); m_WorkingDataObserverTags.insert( std::pair( node, node->GetProperty("visible")->AddObserver( itk::ModifiedEvent(), command ) ) ); } if(segmentations->Size() > 0) { FireNodeSelected(segmentations->ElementAt(0)); segmentations->ElementAt(0)->GetProperty("visible")->Modified(); } } } void QmitkSegmentationView::Deactivated() { if( m_Controls ) { mitk::RenderingManager::GetInstance()->RemoveObserver( m_RenderingManagerObserverTag ); m_Controls->m_ManualToolSelectionBox->setEnabled( false ); //deactivate all tools m_Controls->m_ManualToolSelectionBox->GetToolManager()->ActivateTool(-1); m_Controls->m_OrganToolSelectionBox->setEnabled( false ); m_Controls->m_LesionToolSelectionBox->setEnabled( false ); m_Controls->m_SlicesInterpolator->EnableInterpolation( false ); //Removing all observers for ( NodeTagMapType::iterator dataIter = m_WorkingDataObserverTags.begin(); dataIter != m_WorkingDataObserverTags.end(); ++dataIter ) { (*dataIter).first->GetProperty("visible")->RemoveObserver( (*dataIter).second ); } m_WorkingDataObserverTags.clear(); if (m_MultiWidget) { mitk::SlicesCoordinator *coordinator = m_MultiWidget->GetSlicesRotator(); if (coordinator) coordinator->RemoveObserver(m_SlicesRotationObserverTag1); coordinator = m_MultiWidget->GetSlicesSwiveller(); if (coordinator) coordinator->RemoveObserver(m_SlicesRotationObserverTag2); } // gets the context of the "Mitk" (Core) module (always has id 1) // TODO Workaround until CTL plugincontext is available mitk::ModuleContext* context = mitk::ModuleRegistry::GetModule(1)->GetModuleContext(); // Workaround end mitk::ServiceReference serviceRef = context->GetServiceReference(); //mitk::ServiceReference serviceRef = mitk::GetModuleContext()->GetServiceReference(); mitk::PlanePositionManagerService* service = dynamic_cast(context->GetService(serviceRef)); service->RemoveAllPlanePositions(); } } void QmitkSegmentationView::StdMultiWidgetAvailable( QmitkStdMultiWidget& stdMultiWidget ) { SetMultiWidget(&stdMultiWidget); } void QmitkSegmentationView::StdMultiWidgetNotAvailable() { SetMultiWidget(NULL); } void QmitkSegmentationView::StdMultiWidgetClosed( QmitkStdMultiWidget& /*stdMultiWidget*/ ) { SetMultiWidget(NULL); } void QmitkSegmentationView::SetMultiWidget(QmitkStdMultiWidget* multiWidget) { if (m_MultiWidget) { mitk::SlicesCoordinator* coordinator = m_MultiWidget->GetSlicesRotator(); if (coordinator) { coordinator->RemoveObserver( m_SlicesRotationObserverTag1 ); } coordinator = m_MultiWidget->GetSlicesSwiveller(); if (coordinator) { coordinator->RemoveObserver( m_SlicesRotationObserverTag2 ); } } // save the current multiwidget as the working widget m_MultiWidget = multiWidget; //TODO Remove Observers if (m_MultiWidget) { mitk::SlicesCoordinator* coordinator = m_MultiWidget->GetSlicesRotator(); if (coordinator) { itk::ReceptorMemberCommand::Pointer command2 = itk::ReceptorMemberCommand::New(); command2->SetCallbackFunction( this, &QmitkSegmentationView::SliceRotation ); m_SlicesRotationObserverTag1 = coordinator->AddObserver( mitk::SliceRotationEvent(), command2 ); } coordinator = m_MultiWidget->GetSlicesSwiveller(); if (coordinator) { itk::ReceptorMemberCommand::Pointer command2 = itk::ReceptorMemberCommand::New(); command2->SetCallbackFunction( this, &QmitkSegmentationView::SliceRotation ); m_SlicesRotationObserverTag2 = coordinator->AddObserver( mitk::SliceRotationEvent(), command2 ); } } //TODO End Remove Observers if (m_Parent) { m_Parent->setEnabled(m_MultiWidget); } // tell the interpolation about toolmanager and multiwidget (and data storage) if (m_Controls && m_MultiWidget) { mitk::ToolManager* toolManager = m_Controls->m_ManualToolSelectionBox->GetToolManager(); m_Controls->m_SlicesInterpolator->SetDataStorage( *(this->GetDefaultDataStorage())); m_Controls->m_SlicesInterpolator->Initialize( toolManager, m_MultiWidget ); } } void QmitkSegmentationView::OnPreferencesChanged(const berry::IBerryPreferences*) { ForceDisplayPreferencesUponAllImages(); } //TODO remove function void QmitkSegmentationView::RenderingManagerReinitialized(const itk::EventObject&) { CheckImageAlignment(); } //TODO remove function void QmitkSegmentationView::SliceRotation(const itk::EventObject&) { CheckImageAlignment(); } // protected slots void QmitkSegmentationView::CreateNewSegmentation() { mitk::DataNode::Pointer node = m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetReferenceData(0); if (node.IsNotNull()) { mitk::Image::Pointer image = dynamic_cast( node->GetData() ); if (image.IsNotNull()) { if (image->GetDimension()>1) { // ask about the name and organ type of the new segmentation QmitkNewSegmentationDialog* dialog = new QmitkNewSegmentationDialog( m_Parent ); // needs a QWidget as parent, "this" is not QWidget QString storedList = QString::fromStdString( this->GetPreferences()->GetByteArray("Organ-Color-List","") ); QStringList organColors; if (storedList.isEmpty()) { organColors = GetDefaultOrganColorString(); } else { /* a couple of examples of how organ names are stored: a simple item is built up like 'name#AABBCC' where #AABBCC is the hexadecimal notation of a color as known from HTML items are stored separated by ';' this makes it necessary to escape occurrences of ';' in name. otherwise the string "hugo;ypsilon#AABBCC;eugen#AABBCC" could not be parsed as two organs but we would get "hugo" and "ypsilon#AABBCC" and "eugen#AABBCC" so the organ name "hugo;ypsilon" is stored as "hugo\;ypsilon" and must be unescaped after loading the following lines could be one split with Perl's negative lookbehind */ // recover string list from BlueBerry view's preferences QString storedString = QString::fromStdString( this->GetPreferences()->GetByteArray("Organ-Color-List","") ); MITK_DEBUG << "storedString: " << storedString.toStdString(); // match a string consisting of any number of repetitions of either "anything but ;" or "\;". This matches everything until the next unescaped ';' QRegExp onePart("(?:[^;]|\\\\;)*"); MITK_DEBUG << "matching " << onePart.pattern().toStdString(); int count = 0; int pos = 0; while( (pos = onePart.indexIn( storedString, pos )) != -1 ) { ++count; int length = onePart.matchedLength(); if (length == 0) break; QString matchedString = storedString.mid(pos, length); MITK_DEBUG << " Captured length " << length << ": " << matchedString.toStdString(); pos += length + 1; // skip separating ';' // unescape possible occurrences of '\;' in the string matchedString.replace("\\;", ";"); // add matched string part to output list organColors << matchedString; } MITK_DEBUG << "Captured " << count << " organ name/colors"; } dialog->SetSuggestionList( organColors ); int dialogReturnValue = dialog->exec(); if ( dialogReturnValue == QDialog::Rejected ) return; // user clicked cancel or pressed Esc or something similar // ask the user about an organ type and name, add this information to the image's (!) propertylist // create a new image of the same dimensions and smallest possible pixel type mitk::ToolManager* toolManager = m_Controls->m_ManualToolSelectionBox->GetToolManager(); mitk::Tool* firstTool = toolManager->GetToolById(0); if (firstTool) { try { mitk::DataNode::Pointer emptySegmentation = firstTool->CreateEmptySegmentationNode( image, dialog->GetSegmentationName().toStdString(), dialog->GetColor() ); //Here we change the reslice interpolation mode for a segmentation, so that contours in rotated slice can be shown correctly emptySegmentation->SetProperty( "reslice interpolation", mitk::VtkResliceInterpolationProperty::New(VTK_RESLICE_NEAREST) ); // initialize showVolume to false to prevent recalculating the volume while working on the segmentation emptySegmentation->SetProperty( "showVolume", mitk::BoolProperty::New( false ) ); if (!emptySegmentation) return; // could be aborted by user UpdateOrganList( organColors, dialog->GetSegmentationName(), dialog->GetColor() ); /* escape ';' here (replace by '\;'), see longer comment above */ std::string stringForStorage = organColors.replaceInStrings(";","\\;").join(";").toStdString(); MITK_DEBUG << "Will store: " << stringForStorage; this->GetPreferences()->PutByteArray("Organ-Color-List", stringForStorage ); this->GetPreferences()->Flush(); if(m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetWorkingData(0)) { m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetWorkingData(0)->SetSelected(false); } emptySegmentation->SetSelected(true); this->GetDefaultDataStorage()->Add( emptySegmentation, node ); // add as a child, because the segmentation "derives" from the original this->FireNodeSelected( emptySegmentation ); this->OnSelectionChanged( emptySegmentation ); this->SetToolManagerSelection(node, emptySegmentation); } catch (std::bad_alloc) { QMessageBox::warning(NULL,"Create new segmentation","Could not allocate memory for new segmentation"); } } } else { QMessageBox::information(NULL,"Segmentation","Segmentation is currently not supported for 2D images"); } } } else { MITK_ERROR << "'Create new segmentation' button should never be clickable unless a patient image is selected..."; } } void QmitkSegmentationView::OnWorkingNodeVisibilityChanged(/*const itk::Object* caller, const itk::EventObject& e*/) { if (!m_Parent || !m_Parent->isVisible()) return; // The new selection behaviour is: // // When clicking on the checkbox of a segmentation the node will e selected and its reference node either // The previous selected segmentation (if there is one) will be deselected. Additionally a reinit on the // selected segmenation will be performed. // If more than one segmentation is selected the tools will be disabled. if (!m_Controls) return; // might happen on initialization (preferences loaded) mitk::DataNode::Pointer referenceDataNew = mitk::DataNode::New(); mitk::DataNode::Pointer workingData; bool workingNodeIsVisible (true); unsigned int numberOfSelectedSegmentations (0); // iterate all images mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); mitk::DataStorage::SetOfObjects::ConstPointer allImages = this->GetDefaultDataStorage()->GetSubset( isImage ); for ( mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter) { mitk::DataNode* node = *iter; // apply display preferences ApplyDisplayOptions(node); bool isSegmentation(false); node->GetBoolProperty("binary", isSegmentation); if (node->IsSelected() && isSegmentation) { workingNodeIsVisible = node->IsVisible(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1"))); if (!workingNodeIsVisible) return; numberOfSelectedSegmentations++; workingData = node; if (this->GetDefaultDataStorage()->GetSources(node)->Size() != 0) { referenceDataNew = this->GetDefaultDataStorage()->GetSources(node)->ElementAt(0); } bool isBinary(false); //Find topmost source or first source which is no binary image while (referenceDataNew && this->GetDefaultDataStorage()->GetSources(referenceDataNew)->Size() != 0) { referenceDataNew = this->GetDefaultDataStorage()->GetSources(referenceDataNew)->ElementAt(0); referenceDataNew->GetBoolProperty("binary",isBinary); if (!isBinary) break; } if (workingNodeIsVisible && referenceDataNew) { //Since the binary property of a segmentation can be set to false and afterwards you can create a new segmentation out of it //->could lead to a deadloop NodeTagMapType::iterator searchIter = m_WorkingDataObserverTags.find( referenceDataNew ); if ( searchIter != m_WorkingDataObserverTags.end()) { referenceDataNew->GetProperty("visible")->RemoveObserver( (*searchIter).second ); } referenceDataNew->SetVisibility(true); } //set comboBox to reference image disconnect( m_Controls->refImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnComboBoxSelectionChanged( const mitk::DataNode* ) ) ); m_Controls->refImageSelector->setCurrentIndex( m_Controls->refImageSelector->Find(referenceDataNew) ); connect( m_Controls->refImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnComboBoxSelectionChanged( const mitk::DataNode* ) ) ); continue; } if (workingData.IsNull() || (workingNodeIsVisible && node != referenceDataNew)) { node->SetVisibility((false)); } } if(numberOfSelectedSegmentations == 1) SetToolManagerSelection(referenceDataNew, workingData); mitk::DataStorage::SetOfObjects::Pointer temp = mitk::DataStorage::SetOfObjects::New(); temp->InsertElement(0,workingData); mitk::TimeSlicedGeometry::Pointer bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(temp); // initialize the views to the bounding geometry /*mitk::RenderingManager::GetInstance()->InitializeViews(bounds); mitk::RenderingManager::GetInstance()->RequestUpdateAll();*/ } void QmitkSegmentationView::NodeRemoved(const mitk::DataNode* node) { bool isSeg(false); bool isHelperObject(false); node->GetBoolProperty("helper object", isHelperObject); node->GetBoolProperty("binary", isSeg); if(isSeg && !isHelperObject) { mitk::DataStorage::SetOfObjects::ConstPointer allContourMarkers = this->GetDataStorage()->GetDerivations(node, mitk::NodePredicateProperty::New("isContourMarker" , mitk::BoolProperty::New(true))); // gets the context of the "Mitk" (Core) module (always has id 1) // TODO Workaround until CTL plugincontext is available mitk::ModuleContext* context = mitk::ModuleRegistry::GetModule(1)->GetModuleContext(); // Workaround end mitk::ServiceReference serviceRef = context->GetServiceReference(); //mitk::ServiceReference serviceRef = mitk::GetModuleContext()->GetServiceReference(); mitk::PlanePositionManagerService* service = dynamic_cast(context->GetService(serviceRef)); for (mitk::DataStorage::SetOfObjects::ConstIterator it = allContourMarkers->Begin(); it != allContourMarkers->End(); ++it) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t+1).c_str())-1; service->RemovePlanePosition(id); this->GetDataStorage()->Remove(it->Value()); } mitk::DataNode* tempNode = const_cast(node); node->GetProperty("visible")->RemoveObserver( m_WorkingDataObserverTags[tempNode] ); m_WorkingDataObserverTags.erase(tempNode); + } + + if((m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetReferenceData(0) == node)|| + (m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetWorkingData(0) == node)) + { + //as we don't know which node was actually remove e.g. our reference node, disable 'New Segmentation' button. + //consider the case that there is no more image in the datastorage this->SetToolManagerSelection(NULL, NULL); } } void QmitkSegmentationView::CreateSegmentationFromSurface() { mitk::DataNode::Pointer surfaceNode = m_Controls->MaskSurfaces->GetSelectedNode(); mitk::Surface::Pointer surface(0); if(surfaceNode.IsNotNull()) surface = dynamic_cast ( surfaceNode->GetData() ); if(surface.IsNull()) { this->HandleException( "No surface selected.", m_Parent, true); return; } mitk::DataNode::Pointer imageNode = m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetReferenceData(0); mitk::Image::Pointer image(0); if (imageNode.IsNotNull()) image = dynamic_cast( imageNode->GetData() ); if(image.IsNull()) { this->HandleException( "No image selected.", m_Parent, true); return; } mitk::SurfaceToImageFilter::Pointer s2iFilter = mitk::SurfaceToImageFilter::New(); s2iFilter->MakeOutputBinaryOn(); s2iFilter->SetInput(surface); s2iFilter->SetImage(image); s2iFilter->Update(); mitk::DataNode::Pointer resultNode = mitk::DataNode::New(); std::string nameOfResultImage = imageNode->GetName(); nameOfResultImage.append(surfaceNode->GetName()); resultNode->SetProperty("name", mitk::StringProperty::New(nameOfResultImage) ); resultNode->SetProperty("binary", mitk::BoolProperty::New(true) ); resultNode->SetData( s2iFilter->GetOutput() ); this->GetDataStorage()->Add(resultNode, imageNode); } -void QmitkSegmentationView::ManualToolSelected(int id) -{ - // disable crosshair movement when a manual drawing tool is active (otherwise too much visual noise) - if (m_MultiWidget) - { - if (id >= 0) - { - m_MultiWidget->DisableNavigationControllerEventListening(); - } - else - { - m_MultiWidget->EnableNavigationControllerEventListening(); - } - } -} - void QmitkSegmentationView::ToolboxStackPageChanged(int id) { // interpolation only with manual tools visible m_Controls->m_SlicesInterpolator->EnableInterpolation( id == 0 ); if( id == 0 ) { mitk::DataNode::Pointer workingData = m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetWorkingData(0); if( workingData.IsNotNull() ) { m_Controls->lblSegmentation->setText( workingData->GetName().c_str() ); m_Controls->lblSegImage->show(); m_Controls->lblSegmentation->show(); } } else { m_Controls->lblSegImage->hide(); m_Controls->lblSegmentation->hide(); } // this is just a workaround, should be removed when all tools support 3D+t if (id==2) // lesions { mitk::DataNode::Pointer node = m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetReferenceData(0); if (node.IsNotNull()) { mitk::Image::Pointer image = dynamic_cast( node->GetData() ); if (image.IsNotNull()) { if (image->GetDimension()>3) { m_Controls->widgetStack->setCurrentIndex(0); QMessageBox::information(NULL,"Segmentation","Lesion segmentation is currently not supported for 4D images"); } } } } } // protected void QmitkSegmentationView::OnComboBoxSelectionChanged( const mitk::DataNode* node ) { mitk::DataNode* selectedNode = const_cast(node); if( selectedNode != NULL ) { m_Controls->refImageSelector->show(); m_Controls->lblReferenceImageSelectionWarning->hide(); bool isBinary(false); selectedNode->GetBoolProperty("binary", isBinary); if ( isBinary ) { FireNodeSelected(selectedNode); selectedNode->SetVisibility(true); } else if (node != m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetReferenceData(0)) { if (m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetReferenceData(0)) m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetReferenceData(0)->SetVisibility(false); if (m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetWorkingData(0)) { m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetWorkingData(0)->SetVisibility(false); } FireNodeSelected(selectedNode); selectedNode->SetVisibility(true); SetToolManagerSelection(selectedNode, NULL); } } else { m_Controls->refImageSelector->hide(); m_Controls->lblReferenceImageSelectionWarning->show(); } } void QmitkSegmentationView::OnShowMarkerNodes (bool state) { mitk::SegTool2D::Pointer manualSegmentationTool; unsigned int numberOfExistingTools = m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetTools().size(); for(unsigned int i = 0; i < numberOfExistingTools; i++) { manualSegmentationTool = dynamic_cast(m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetToolById(i)); if (manualSegmentationTool) { if(state == true) { manualSegmentationTool->SetShowMarkerNodes( true ); } else { manualSegmentationTool->SetShowMarkerNodes( false ); } } } } void QmitkSegmentationView::OnSelectionChanged(mitk::DataNode* node) { std::vector nodes; nodes.push_back( node ); this->OnSelectionChanged( nodes ); } void QmitkSegmentationView::OnSurfaceSelectionChanged() { // if Image and Surface are selected, enable button if ( (m_Controls->refImageSelector->GetSelectedNode().IsNull()) || (m_Controls->MaskSurfaces->GetSelectedNode().IsNull())) m_Controls->CreateSegmentationFromSurface->setEnabled(false); else m_Controls->CreateSegmentationFromSurface->setEnabled(true); } void QmitkSegmentationView::OnSelectionChanged(std::vector nodes) { // if the selected node is a contourmarker if ( !nodes.empty() ) { std::string markerName = "Position"; unsigned int numberOfNodes = nodes.size(); std::string nodeName = nodes.at( 0 )->GetName(); if ( ( numberOfNodes == 1 ) && ( nodeName.find( markerName ) == 0) ) { this->OnContourMarkerSelected( nodes.at( 0 ) ); } } // if Image and Surface are selected, enable button if ( (m_Controls->refImageSelector->GetSelectedNode().IsNull()) || (m_Controls->MaskSurfaces->GetSelectedNode().IsNull())) m_Controls->CreateSegmentationFromSurface->setEnabled(false); else m_Controls->CreateSegmentationFromSurface->setEnabled(true); if (!m_Parent || !m_Parent->isVisible()) return; // reaction to BlueBerry selection events // this method will try to figure out if a relevant segmentation and its corresponding original image were selected // a warning is issued if the selection is invalid // appropriate reactions are triggered otherwise mitk::DataNode::Pointer referenceData = FindFirstRegularImage( nodes ); //m_Controls->refImageSelector->GetSelectedNode(); //FindFirstRegularImage( nodes ); mitk::DataNode::Pointer workingData = FindFirstSegmentation( nodes ); if(referenceData.IsNull() && workingData.IsNull()) return; bool invalidSelection( !nodes.empty() && ( nodes.size() > 2 || // maximum 2 selected nodes (nodes.size() == 2 && (workingData.IsNull() || referenceData.IsNull()) ) || // with two nodes, one must be the original image, one the segmentation ( workingData.GetPointer() == referenceData.GetPointer() ) //one node is selected as reference and working image // one item is always ok (might be working or reference or nothing ) ); if (invalidSelection) { // TODO visible warning when two images are selected MITK_ERROR << "WARNING: No image, too many (>2) or two equal images were selected."; workingData = NULL; if( m_Controls->refImageSelector->GetSelectedNode().IsNull() ) referenceData = NULL; } if ( workingData.IsNotNull() && referenceData.IsNull() ) { // find the DataStorage parent of workingData // try to find a "normal image" parent, select this as reference image mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateNot::Pointer isNotBinary = mitk::NodePredicateNot::New( isBinary ); mitk::NodePredicateAnd::Pointer isNormalImage = mitk::NodePredicateAnd::New( isImage, isNotBinary ); mitk::DataStorage::SetOfObjects::ConstPointer possibleParents = this->GetDefaultDataStorage()->GetSources( workingData, isNormalImage ); if (possibleParents->size() > 0) { if (possibleParents->size() > 1) { // TODO visible warning for this rare case MITK_ERROR << "Selected binary image has multiple parents. Using arbitrary first one for segmentation."; } referenceData = (*possibleParents)[0]; } NodeTagMapType::iterator searchIter = m_WorkingDataObserverTags.find( workingData ); if ( searchIter == m_WorkingDataObserverTags.end() ) { //MITK_INFO<<"Creating new observer"; itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::OnWorkingNodeVisibilityChanged); m_WorkingDataObserverTags.insert( std::pair( workingData, workingData->GetProperty("visible")->AddObserver( itk::ModifiedEvent(), command ) ) ); workingData->GetProperty("visible")->Modified(); return; } if(workingData->IsVisible(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1")))) { //set comboBox to reference image disconnect( m_Controls->refImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnComboBoxSelectionChanged( const mitk::DataNode* ) ) ); m_Controls->refImageSelector->setCurrentIndex( m_Controls->refImageSelector->Find(workingData) ); connect( m_Controls->refImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnComboBoxSelectionChanged( const mitk::DataNode* ) ) ); // if Image and Surface are selected, enable button if ( (m_Controls->refImageSelector->GetSelectedNode().IsNull()) || (m_Controls->MaskSurfaces->GetSelectedNode().IsNull()) || (!referenceData)) m_Controls->CreateSegmentationFromSurface->setEnabled(false); else m_Controls->CreateSegmentationFromSurface->setEnabled(true); SetToolManagerSelection(referenceData, workingData); FireNodeSelected(workingData); } else { SetToolManagerSelection(NULL, NULL); FireNodeSelected(workingData); } } else { //set comboBox to reference image disconnect( m_Controls->refImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnComboBoxSelectionChanged( const mitk::DataNode* ) ) ); m_Controls->refImageSelector->setCurrentIndex( m_Controls->refImageSelector->Find(referenceData) ); connect( m_Controls->refImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnComboBoxSelectionChanged( const mitk::DataNode* ) ) ); // if Image and Surface are selected, enable button if ( (m_Controls->refImageSelector->GetSelectedNode().IsNull()) || (m_Controls->MaskSurfaces->GetSelectedNode().IsNull()) || (!referenceData)) m_Controls->CreateSegmentationFromSurface->setEnabled(false); else m_Controls->CreateSegmentationFromSurface->setEnabled(true); SetToolManagerSelection(referenceData, workingData); FireNodeSelected(referenceData); } } void QmitkSegmentationView::OnContourMarkerSelected(const mitk::DataNode *node) { //TODO renderWindow anders bestimmen, siehe CheckAlignment QmitkRenderWindow* selectedRenderWindow = 0; QmitkRenderWindow* RenderWindow1 = this->GetActiveStdMultiWidget()->GetRenderWindow1(); QmitkRenderWindow* RenderWindow2 = this->GetActiveStdMultiWidget()->GetRenderWindow2(); QmitkRenderWindow* RenderWindow3 = this->GetActiveStdMultiWidget()->GetRenderWindow3(); QmitkRenderWindow* RenderWindow4 = this->GetActiveStdMultiWidget()->GetRenderWindow4(); bool PlanarFigureInitializedWindow = false; // find initialized renderwindow if (node->GetBoolProperty("PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, RenderWindow1->GetRenderer())) { selectedRenderWindow = RenderWindow1; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, RenderWindow2->GetRenderer())) { selectedRenderWindow = RenderWindow2; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, RenderWindow3->GetRenderer())) { selectedRenderWindow = RenderWindow3; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, RenderWindow4->GetRenderer())) { selectedRenderWindow = RenderWindow4; } // make node visible if (selectedRenderWindow) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t+1).c_str())-1; // gets the context of the "Mitk" (Core) module (always has id 1) // TODO Workaround until CTL plugincontext is available mitk::ModuleContext* context = mitk::ModuleRegistry::GetModule(1)->GetModuleContext(); // Workaround end mitk::ServiceReference serviceRef = context->GetServiceReference(); //mitk::ServiceReference serviceRef = mitk::GetModuleContext()->GetServiceReference(); mitk::PlanePositionManagerService* service = dynamic_cast(context->GetService(serviceRef)); selectedRenderWindow->GetSliceNavigationController()->ExecuteOperation(service->GetPlanePosition(id)); selectedRenderWindow->GetRenderer()->GetDisplayGeometry()->Fit(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } mitk::DataNode::Pointer QmitkSegmentationView::FindFirstRegularImage( std::vector nodes ) { if (nodes.empty()) return NULL; for(unsigned int i = 0; i < nodes.size(); ++i) { //mitk::DataNode::Pointer node = i.value() bool isImage(false); if (nodes.at(i)->GetData()) { isImage = dynamic_cast(nodes.at(i)->GetData()) != NULL; } // make sure this is not a binary image bool isSegmentation(false); nodes.at(i)->GetBoolProperty("binary", isSegmentation); // return first proper mitk::Image if (isImage && !isSegmentation) return nodes.at(i); } return NULL; } mitk::DataNode::Pointer QmitkSegmentationView::FindFirstSegmentation( std::vector nodes ) { if (nodes.empty()) return NULL; for(unsigned int i = 0; i < nodes.size(); ++i) { bool isImage(false); if (nodes.at(i)->GetData()) { isImage = dynamic_cast(nodes.at(i)->GetData()) != NULL; } bool isSegmentation(false); nodes.at(i)->GetBoolProperty("binary", isSegmentation); // return first proper binary mitk::Image if (isImage && isSegmentation) { return nodes.at(i); } } return NULL; } void QmitkSegmentationView::SetToolManagerSelection(const mitk::DataNode* referenceData, const mitk::DataNode* workingData) { // called as a result of new BlueBerry selections // tells the ToolManager for manual segmentation about new selections // updates GUI information about what the user should select mitk::ToolManager* toolManager = m_Controls->m_ManualToolSelectionBox->GetToolManager(); toolManager->SetReferenceData(const_cast(referenceData)); toolManager->SetWorkingData( const_cast(workingData)); // check original image m_Controls->btnNewSegmentation->setEnabled(referenceData != NULL); if (referenceData) { m_Controls->lblReferenceImageSelectionWarning->hide(); } else { m_Controls->lblReferenceImageSelectionWarning->show(); m_Controls->lblWorkingImageSelectionWarning->hide(); m_Controls->lblSegImage->hide(); m_Controls->lblSegmentation->hide(); } //TODO remove statement // check, wheter reference image is aligned like render windows. Otherwise display a visible warning (because 2D tools will probably not work) CheckImageAlignment(); // check segmentation if (referenceData) { if (!workingData) { m_Controls->lblWorkingImageSelectionWarning->show(); if( m_Controls->widgetStack->currentIndex() == 0 ) { m_Controls->lblSegImage->hide(); m_Controls->lblSegmentation->hide(); } } else { m_Controls->lblWorkingImageSelectionWarning->hide(); this->FireNodeSelected(const_cast(workingData)); if( m_Controls->widgetStack->currentIndex() == 0 ) { m_Controls->lblSegmentation->setText( workingData->GetName().c_str() ); m_Controls->lblSegmentation->show(); m_Controls->lblSegImage->show(); } } } } //TODO remove function void QmitkSegmentationView::CheckImageAlignment() { bool wrongAlignment(true); mitk::DataNode::Pointer node = m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetReferenceData(0); if (node.IsNotNull()) { mitk::Image::Pointer image = dynamic_cast( node->GetData() ); if (image.IsNotNull() && m_MultiWidget) { wrongAlignment = !( IsRenderWindowAligned(m_MultiWidget->GetRenderWindow1(), image ) && IsRenderWindowAligned(m_MultiWidget->GetRenderWindow2(), image ) && IsRenderWindowAligned(m_MultiWidget->GetRenderWindow3(), image ) ); } } m_Controls->lblAlignmentWarning->setVisible(wrongAlignment); } //TODO remove function bool QmitkSegmentationView::IsRenderWindowAligned(QmitkRenderWindow* renderWindow, mitk::Image* image) { if (!renderWindow) return false; // for all 2D renderwindows of m_MultiWidget check alignment mitk::PlaneGeometry::ConstPointer displayPlane = dynamic_cast( renderWindow->GetRenderer()->GetCurrentWorldGeometry2D() ); if (displayPlane.IsNull()) return false; int affectedDimension(-1); int affectedSlice(-1); return mitk::SegTool2D::DetermineAffectedImageSlice( image, displayPlane, affectedDimension, affectedSlice ); } //TODO remove function void QmitkSegmentationView::ForceDisplayPreferencesUponAllImages() { if (!m_Parent || !m_Parent->isVisible()) return; // check all images and segmentations in DataStorage: // (items in brackets are implicitly done by previous steps) // 1. // if a reference image is selected, // show the reference image // and hide all other images (orignal and segmentation), // (and hide all segmentations of the other original images) // and show all the reference's segmentations // if no reference image is selected, do do nothing // // 2. // if a segmentation is selected, // show it // (and hide all all its siblings (childs of the same parent, incl, NULL parent)) // if no segmentation is selected, do nothing if (!m_Controls) return; // might happen on initialization (preferences loaded) mitk::DataNode::Pointer referenceData = m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetReferenceData(0); mitk::DataNode::Pointer workingData = m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetWorkingData(0); // 1. if (referenceData.IsNotNull()) { // iterate all images mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); mitk::DataStorage::SetOfObjects::ConstPointer allImages = this->GetDefaultDataStorage()->GetSubset( isImage ); //mitk::DataStorage::SetOfObjects::ConstPointer allSegmentationChilds = this->GetDefaultDataStorage()->GetDerivations(referenceData, isImage ); for ( mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter) { mitk::DataNode* node = *iter; // apply display preferences ApplyDisplayOptions(node); // set visibility if(!node->IsSelected() || (node->IsSelected() && !node->IsVisible(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1"))))) node->SetVisibility((node == referenceData) || node->IsSelected() ); } } // 2. //if (workingData.IsNotNull() && !workingData->IsSelected()) //{ // workingData->SetVisibility(true); //} mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSegmentationView::ApplyDisplayOptions(mitk::DataNode* node) { if (!node) return; bool isBinary(false); node->GetPropertyValue("binary", isBinary); if (isBinary) { node->SetProperty( "outline binary", mitk::BoolProperty::New( this->GetPreferences()->GetBool("draw outline", true)) ); node->SetProperty( "outline width", mitk::FloatProperty::New( 2.0 ) ); node->SetProperty( "opacity", mitk::FloatProperty::New( this->GetPreferences()->GetBool("draw outline", true) ? 1.0 : 0.3 ) ); node->SetProperty( "volumerendering", mitk::BoolProperty::New( this->GetPreferences()->GetBool("volume rendering", false) ) ); } } void QmitkSegmentationView::CreateQtPartControl(QWidget* parent) { // setup the basic GUI of this view m_Parent = parent; m_Controls = new Ui::QmitkSegmentationControls; m_Controls->setupUi(parent); m_Controls->lblWorkingImageSelectionWarning->hide(); m_Controls->lblAlignmentWarning->hide(); m_Controls->lblSegImage->hide(); m_Controls->lblSegmentation->hide(); m_Controls->refImageSelector->SetDataStorage(this->GetDefaultDataStorage()); m_Controls->refImageSelector->SetPredicate(mitk::NodePredicateDataType::New("Image")); if( m_Controls->refImageSelector->GetSelectedNode().IsNotNull() ) m_Controls->lblReferenceImageSelectionWarning->hide(); else m_Controls->refImageSelector->hide(); mitk::ToolManager* toolManager = m_Controls->m_ManualToolSelectionBox->GetToolManager(); toolManager->SetDataStorage( *(this->GetDefaultDataStorage()) ); assert ( toolManager ); // all part of open source MITK m_Controls->m_ManualToolSelectionBox->SetGenerateAccelerators(true); m_Controls->m_ManualToolSelectionBox->SetToolGUIArea( m_Controls->m_ManualToolGUIContainer ); m_Controls->m_ManualToolSelectionBox->SetDisplayedToolGroups("Add Subtract Paint Wipe 'Region Growing' Correction Fill Erase"); m_Controls->m_ManualToolSelectionBox->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingData ); // available only in the 3M application if ( !m_Controls->m_OrganToolSelectionBox->children().count() ) { m_Controls->widgetStack->setItemEnabled( 1, false ); } m_Controls->m_OrganToolSelectionBox->SetToolManager( *toolManager ); m_Controls->m_OrganToolSelectionBox->SetToolGUIArea( m_Controls->m_OrganToolGUIContainer ); m_Controls->m_OrganToolSelectionBox->SetDisplayedToolGroups("'Hippocampus left' 'Hippocampus right' 'Lung left' 'Lung right' 'Liver' 'Heart LV' 'Endocard LV' 'Epicard LV' 'Prostate'"); m_Controls->m_OrganToolSelectionBox->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceData ); // available only in the 3M application if ( !m_Controls->m_LesionToolSelectionBox->children().count() ) { m_Controls->widgetStack->setItemEnabled( 2, false ); } m_Controls->m_LesionToolSelectionBox->SetToolManager( *toolManager ); m_Controls->m_LesionToolSelectionBox->SetToolGUIArea( m_Controls->m_LesionToolGUIContainer ); m_Controls->m_LesionToolSelectionBox->SetDisplayedToolGroups("'Lymph Node'"); m_Controls->m_LesionToolSelectionBox->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceData ); toolManager->NewNodesGenerated += mitk::MessageDelegate( this, &QmitkSegmentationView::NewNodesGenerated ); // update the list of segmentations toolManager->NewNodeObjectsGenerated += mitk::MessageDelegate1( this, &QmitkSegmentationView::NewNodeObjectsGenerated ); // update the list of segmentations // create signal/slot connections connect( m_Controls->refImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnComboBoxSelectionChanged( const mitk::DataNode* ) ) ); connect( m_Controls->btnNewSegmentation, SIGNAL(clicked()), this, SLOT(CreateNewSegmentation()) ); connect( m_Controls->CreateSegmentationFromSurface, SIGNAL(clicked()), this, SLOT(CreateSegmentationFromSurface()) ); - connect( m_Controls->m_ManualToolSelectionBox, SIGNAL(ToolSelected(int)), this, SLOT(ManualToolSelected(int)) ); connect( m_Controls->widgetStack, SIGNAL(currentChanged(int)), this, SLOT(ToolboxStackPageChanged(int)) ); connect(m_Controls->MaskSurfaces, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnSurfaceSelectionChanged( ) ) ); connect(m_Controls->MaskSurfaces, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnSurfaceSelectionChanged( ) ) ); connect(m_Controls->m_SlicesInterpolator, SIGNAL(SignalShowMarkerNodes(bool)), this, SLOT(OnShowMarkerNodes(bool))); m_Controls->MaskSurfaces->SetDataStorage(this->GetDefaultDataStorage()); m_Controls->MaskSurfaces->SetPredicate(mitk::NodePredicateDataType::New("Surface")); //// create helper class to provide context menus for segmentations in data manager // m_PostProcessing = new QmitkSegmentationPostProcessing(this->GetDefaultDataStorage(), this, m_Parent); } //void QmitkSegmentationView::OnPlaneModeChanged(int i) //{ // //if plane mode changes, disable all tools // if (m_MultiWidget) // { // mitk::ToolManager* toolManager = m_Controls->m_ManualToolSelectionBox->GetToolManager(); // // if (toolManager) // { // if (toolManager->GetActiveToolID() >= 0) // { // toolManager->ActivateTool(-1); // } // else // { // m_MultiWidget->EnableNavigationControllerEventListening(); // } // } // } //} // ATTENTION some methods for handling the known list of (organ names, colors) are defined in QmitkSegmentationOrganNamesHandling.cpp diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h index 86802542e1..5d114f3800 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h @@ -1,166 +1,163 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 QmitkSegmentationView_h #define QmitkSegmentationView_h #include "QmitkFunctionality.h" #include #include "ui_QmitkSegmentationControls.h" class QmitkRenderWindow; // class QmitkSegmentationPostProcessing; /** * \ingroup ToolManagerEtAl * \ingroup org_mitk_gui_qt_segmentation_internal * \warning Implementation of this class is split up into two .cpp files to make things more compact. Check both this file and QmitkSegmentationOrganNamesHandling.cpp */ class QmitkSegmentationView : public QmitkFunctionality { Q_OBJECT public: QmitkSegmentationView(); virtual ~QmitkSegmentationView(); typedef std::map NodeTagMapType; /*! \brief Invoked when the DataManager selection changed */ virtual void OnSelectionChanged(mitk::DataNode* node); virtual void OnSelectionChanged(std::vector nodes); // reaction to new segmentations being created by segmentation tools void NewNodesGenerated(); void NewNodeObjectsGenerated(mitk::ToolManager::DataVectorType*); // QmitkFunctionality's activate/deactivate virtual void Activated(); virtual void Deactivated(); // QmitkFunctionality's changes regarding THE QmitkStdMultiWidget virtual void StdMultiWidgetAvailable(QmitkStdMultiWidget& stdMultiWidget); virtual void StdMultiWidgetNotAvailable(); virtual void StdMultiWidgetClosed(QmitkStdMultiWidget& stdMultiWidget); // BlueBerry's notification about preference changes (e.g. from a dialog) virtual void OnPreferencesChanged(const berry::IBerryPreferences*); // observer to mitk::RenderingManager's RenderingManagerViewsInitializedEvent event void RenderingManagerReinitialized(const itk::EventObject&); // observer to mitk::SliceController's SliceRotation event void SliceRotation(const itk::EventObject&); static const std::string VIEW_ID; protected slots: void OnComboBoxSelectionChanged(const mitk::DataNode* node); // reaction to the button "New segmentation" void CreateNewSegmentation(); // reaction to the button "New segmentation" void CreateSegmentationFromSurface(); - // called when a segmentation tool is activated - void ManualToolSelected(int id); - // called when one of "Manual", "Organ", "Lesion" pages of the QToolbox is selected void ToolboxStackPageChanged(int id); void OnSurfaceSelectionChanged(); //called when the checkbox Remember Contour Positions is selected/deselected void OnWorkingNodeVisibilityChanged(); void OnShowMarkerNodes(bool); protected: // a type for handling lists of DataNodes typedef std::vector NodeList; // set available multiwidget void SetMultiWidget(QmitkStdMultiWidget* multiWidget); // actively query the current selection of data manager //void PullCurrentDataManagerSelection(); // reactions to selection events from data manager (and potential other senders) //void BlueBerrySelectionChanged(berry::IWorkbenchPart::Pointer sourcepart, berry::ISelection::ConstPointer selection); mitk::DataNode::Pointer FindFirstRegularImage( std::vector nodes ); mitk::DataNode::Pointer FindFirstSegmentation( std::vector nodes ); // propagate BlueBerry selection to ToolManager for manual segmentation void SetToolManagerSelection(const mitk::DataNode* referenceData, const mitk::DataNode* workingData); // checks if selected reference image is aligned with the slices stack orientation of the StdMultiWidget void CheckImageAlignment(); // checks if given render window aligns with the slices of given image bool IsRenderWindowAligned(QmitkRenderWindow* renderWindow, mitk::Image* image); // make sure all images/segmentations look as selected by the users in this view's preferences void ForceDisplayPreferencesUponAllImages(); // decorates a DataNode according to the user preference settings void ApplyDisplayOptions(mitk::DataNode* node); // GUI setup void CreateQtPartControl(QWidget* parent); // handling of a list of known (organ name, organ color) combination // ATTENTION these methods are defined in QmitkSegmentationOrganNamesHandling.cpp QStringList GetDefaultOrganColorString(); void UpdateOrganList(QStringList& organColors, const QString& organname, mitk::Color colorname); void AppendToOrganList(QStringList& organColors, const QString& organname, int r, int g, int b); // If a contourmarker is selected, the plane in the related widget will be reoriented according to the marker`s geometry void OnContourMarkerSelected (const mitk::DataNode* node); void NodeRemoved(const mitk::DataNode* node); // the Qt parent of our GUI (NOT of this object) QWidget* m_Parent; // our GUI Ui::QmitkSegmentationControls * m_Controls; // THE currently existing QmitkStdMultiWidget QmitkStdMultiWidget * m_MultiWidget; // QmitkSegmentationPostProcessing* m_PostProcessing; unsigned long m_RenderingManagerObserverTag; unsigned long m_SlicesRotationObserverTag1; unsigned long m_SlicesRotationObserverTag2; unsigned long m_VisibilityChangedObserverTag; NodeTagMapType m_WorkingDataObserverTags; }; #endif /*QMITKsegmentationVIEW_H_*/ diff --git a/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/QmitkStdMultiWidgetEditor.cpp b/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/QmitkStdMultiWidgetEditor.cpp index b1da9c22d0..2703d2c74c 100644 --- a/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/QmitkStdMultiWidgetEditor.cpp +++ b/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/QmitkStdMultiWidgetEditor.cpp @@ -1,539 +1,550 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "QmitkStdMultiWidgetEditor.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include class QmitkStdMultiWidgetEditorPrivate { public: QmitkStdMultiWidgetEditorPrivate(); ~QmitkStdMultiWidgetEditorPrivate(); QmitkStdMultiWidget* m_StdMultiWidget; QmitkMouseModeSwitcher* m_MouseModeToolbar; std::string m_FirstBackgroundColor; std::string m_SecondBackgroundColor; bool m_MenuWidgetsEnabled; berry::IPartListener::Pointer m_PartListener; QHash m_RenderWindows; QStringList m_EnabledInteractors; }; struct QmitkStdMultiWidgetPartListener : public berry::IPartListener { berryObjectMacro(QmitkStdMultiWidgetPartListener) QmitkStdMultiWidgetPartListener(QmitkStdMultiWidgetEditorPrivate* dd) : d(dd) {} Events::Types GetPartEventTypes() const { return Events::CLOSED | Events::HIDDEN | Events::VISIBLE; } void PartClosed (berry::IWorkbenchPartReference::Pointer partRef) { if (partRef->GetId() == QmitkStdMultiWidgetEditor::EDITOR_ID) { QmitkStdMultiWidgetEditor::Pointer stdMultiWidgetEditor = partRef->GetPart(false).Cast(); if (d->m_StdMultiWidget == stdMultiWidgetEditor->GetStdMultiWidget()) { d->m_StdMultiWidget->RemovePlanesFromDataStorage(); stdMultiWidgetEditor->RequestActivateMenuWidget(false); stdMultiWidgetEditor->EnableInteractors(false); } } } void PartHidden (berry::IWorkbenchPartReference::Pointer partRef) { if (partRef->GetId() == QmitkStdMultiWidgetEditor::EDITOR_ID) { QmitkStdMultiWidgetEditor::Pointer stdMultiWidgetEditor = partRef->GetPart(false).Cast(); if (d->m_StdMultiWidget == stdMultiWidgetEditor->GetStdMultiWidget()) { d->m_StdMultiWidget->RemovePlanesFromDataStorage(); stdMultiWidgetEditor->RequestActivateMenuWidget(false); stdMultiWidgetEditor->EnableInteractors(false); } } } void PartVisible (berry::IWorkbenchPartReference::Pointer partRef) { if (partRef->GetId() == QmitkStdMultiWidgetEditor::EDITOR_ID) { QmitkStdMultiWidgetEditor::Pointer stdMultiWidgetEditor = partRef->GetPart(false).Cast(); if (d->m_StdMultiWidget == stdMultiWidgetEditor->GetStdMultiWidget()) { d->m_StdMultiWidget->AddPlanesToDataStorage(); stdMultiWidgetEditor->RequestActivateMenuWidget(true); stdMultiWidgetEditor->EnableInteractors(true); } } } private: QmitkStdMultiWidgetEditorPrivate* const d; }; QmitkStdMultiWidgetEditorPrivate::QmitkStdMultiWidgetEditorPrivate() : m_StdMultiWidget(0), m_MouseModeToolbar(0) , m_MenuWidgetsEnabled(false) , m_PartListener(new QmitkStdMultiWidgetPartListener(this)) {} QmitkStdMultiWidgetEditorPrivate::~QmitkStdMultiWidgetEditorPrivate() { } const std::string QmitkStdMultiWidgetEditor::EDITOR_ID = "org.mitk.editors.stdmultiwidget"; QmitkStdMultiWidgetEditor::QmitkStdMultiWidgetEditor() : d(new QmitkStdMultiWidgetEditorPrivate) { } QmitkStdMultiWidgetEditor::~QmitkStdMultiWidgetEditor() { this->GetSite()->GetPage()->RemovePartListener(d->m_PartListener); } QmitkStdMultiWidget* QmitkStdMultiWidgetEditor::GetStdMultiWidget() { return d->m_StdMultiWidget; } -QmitkRenderWindow *QmitkStdMultiWidgetEditor::GetActiveRenderWindow() const +QmitkRenderWindow *QmitkStdMultiWidgetEditor::GetActiveQmitkRenderWindow() const { if (d->m_StdMultiWidget) return d->m_StdMultiWidget->GetRenderWindow1(); return 0; } -QHash QmitkStdMultiWidgetEditor::GetRenderWindows() const +QHash QmitkStdMultiWidgetEditor::GetQmitkRenderWindows() const { return d->m_RenderWindows; } -QmitkRenderWindow *QmitkStdMultiWidgetEditor::GetRenderWindow(const QString &id) const +QmitkRenderWindow *QmitkStdMultiWidgetEditor::GetQmitkRenderWindow(const QString &id) const { - if (d->m_RenderWindows.contains(id)) return d->m_RenderWindows[id]; + static bool alreadyWarned = false; + + if(!alreadyWarned) + { + MITK_WARN(id == "transversal") << "QmitkStdMultiWidgetEditor::GetRenderWindow(\"transversal\") is deprecated. Use \"axial\" instead."; + alreadyWarned = true; + } + + if (d->m_RenderWindows.contains(id)) + return d->m_RenderWindows[id]; + return 0; } mitk::Point3D QmitkStdMultiWidgetEditor::GetSelectedPosition(const QString & /*id*/) const { return d->m_StdMultiWidget->GetCrossPosition(); } void QmitkStdMultiWidgetEditor::SetSelectedPosition(const mitk::Point3D &pos, const QString &/*id*/) { d->m_StdMultiWidget->MoveCrossToPosition(pos); } void QmitkStdMultiWidgetEditor::EnableDecorations(bool enable, const QStringList &decorations) { if (decorations.isEmpty() || decorations.contains(DECORATION_BORDER)) { enable ? d->m_StdMultiWidget->EnableColoredRectangles() : d->m_StdMultiWidget->DisableColoredRectangles(); } if (decorations.isEmpty() || decorations.contains(DECORATION_LOGO)) { enable ? d->m_StdMultiWidget->EnableDepartmentLogo() : d->m_StdMultiWidget->DisableDepartmentLogo(); } if (decorations.isEmpty() || decorations.contains(DECORATION_MENU)) { d->m_StdMultiWidget->ActivateMenuWidget(enable); } if (decorations.isEmpty() || decorations.contains(DECORATION_BACKGROUND)) { enable ? d->m_StdMultiWidget->EnableGradientBackground() : d->m_StdMultiWidget->DisableGradientBackground(); } } bool QmitkStdMultiWidgetEditor::IsDecorationEnabled(const QString &decoration) const { if (decoration == DECORATION_BORDER) { return d->m_StdMultiWidget->IsColoredRectanglesEnabled(); } else if (decoration == DECORATION_LOGO) { return d->m_StdMultiWidget->IsColoredRectanglesEnabled(); } else if (decoration == DECORATION_MENU) { return d->m_StdMultiWidget->IsMenuWidgetEnabled(); } else if (decoration == DECORATION_BACKGROUND) { return d->m_StdMultiWidget->GetGradientBackgroundFlag(); } return false; } QStringList QmitkStdMultiWidgetEditor::GetDecorations() const { QStringList decorations; decorations << DECORATION_BORDER << DECORATION_LOGO << DECORATION_MENU << DECORATION_BACKGROUND; return decorations; } mitk::SlicesRotator* QmitkStdMultiWidgetEditor::GetSlicesRotator() const { return d->m_StdMultiWidget->GetSlicesRotator(); } mitk::SlicesSwiveller* QmitkStdMultiWidgetEditor::GetSlicesSwiveller() const { return d->m_StdMultiWidget->GetSlicesSwiveller(); } void QmitkStdMultiWidgetEditor::EnableSlicingPlanes(bool enable) { d->m_StdMultiWidget->SetWidgetPlanesVisibility(enable); } bool QmitkStdMultiWidgetEditor::IsSlicingPlanesEnabled() const { mitk::DataNode::Pointer node = this->d->m_StdMultiWidget->GetWidgetPlane1(); if (node.IsNotNull()) { bool visible = false; node->GetVisibility(visible, 0); return visible; } else { return false; } } void QmitkStdMultiWidgetEditor::EnableLinkedNavigation(bool enable) { enable ? d->m_StdMultiWidget->EnableNavigationControllerEventListening() : d->m_StdMultiWidget->DisableNavigationControllerEventListening(); } bool QmitkStdMultiWidgetEditor::IsLinkedNavigationEnabled() const { return d->m_StdMultiWidget->IsCrosshairNavigationEnabled(); } void QmitkStdMultiWidgetEditor::CreateQtPartControl(QWidget* parent) { if (d->m_StdMultiWidget == 0) { QHBoxLayout* layout = new QHBoxLayout(parent); layout->setContentsMargins(0,0,0,0); if (d->m_MouseModeToolbar == NULL) { d->m_MouseModeToolbar = new QmitkMouseModeSwitcher(parent); // delete by Qt via parent layout->addWidget(d->m_MouseModeToolbar); } d->m_StdMultiWidget = new QmitkStdMultiWidget(parent); d->m_RenderWindows.insert("transversal", d->m_StdMultiWidget->GetRenderWindow1()); + d->m_RenderWindows.insert("axial", d->m_StdMultiWidget->GetRenderWindow1()); d->m_RenderWindows.insert("sagittal", d->m_StdMultiWidget->GetRenderWindow2()); d->m_RenderWindows.insert("coronal", d->m_StdMultiWidget->GetRenderWindow3()); d->m_RenderWindows.insert("3d", d->m_StdMultiWidget->GetRenderWindow4()); d->m_MouseModeToolbar->setMouseModeSwitcher( d->m_StdMultiWidget->GetMouseModeSwitcher() ); connect( d->m_MouseModeToolbar, SIGNAL( MouseModeSelected(mitk::MouseModeSwitcher::MouseMode) ), d->m_StdMultiWidget, SLOT( MouseModeSelected(mitk::MouseModeSwitcher::MouseMode) ) ); layout->addWidget(d->m_StdMultiWidget); mitk::DataStorage::Pointer ds = this->GetDataStorage(); // Tell the multiWidget which (part of) the tree to render d->m_StdMultiWidget->SetDataStorage(ds); - // Initialize views as transversal, sagittal, coronar to all data objects in DataStorage + // Initialize views as axial, sagittal, coronar to all data objects in DataStorage // (from top-left to bottom) mitk::TimeSlicedGeometry::Pointer geo = ds->ComputeBoundingGeometry3D(ds->GetAll()); mitk::RenderingManager::GetInstance()->InitializeViews(geo); // Initialize bottom-right view as 3D view d->m_StdMultiWidget->GetRenderWindow4()->GetRenderer()->SetMapperID( mitk::BaseRenderer::Standard3D ); // Enable standard handler for levelwindow-slider d->m_StdMultiWidget->EnableStandardLevelWindow(); // Add the displayed views to the tree to see their positions // in 2D and 3D d->m_StdMultiWidget->AddDisplayPlaneSubTree(); d->m_StdMultiWidget->EnableNavigationControllerEventListening(); // Store the initial visibility status of the menu widget. d->m_MenuWidgetsEnabled = d->m_StdMultiWidget->IsMenuWidgetEnabled(); this->GetSite()->GetPage()->AddPartListener(d->m_PartListener); berry::IPreferences::Pointer prefs = this->GetPreferences(); this->OnPreferencesChanged(dynamic_cast(prefs.GetPointer())); // Store the initial interactor status of the mouse mode. if (d->m_StdMultiWidget->GetMouseModeSwitcher()->GetInteractionScheme() == mitk::MouseModeSwitcher::MITK ) { d->m_EnabledInteractors << INTERACTOR_MITK; } else if (d->m_StdMultiWidget->GetMouseModeSwitcher()->GetInteractionScheme() == mitk::MouseModeSwitcher::PACS ) { d->m_EnabledInteractors << INTERACTOR_PACS; } this->RequestUpdate(); } } void QmitkStdMultiWidgetEditor::OnPreferencesChanged(const berry::IBerryPreferences* prefs) { // Enable change of logo. If no DepartmentLogo was set explicitly, MBILogo is used. // Set new department logo by prefs->Set("DepartmentLogo", "PathToImage"); std::vector keys = prefs->Keys(); for( int i = 0; i < keys.size(); ++i ) { if( keys[i] == "DepartmentLogo") { std::string departmentLogoLocation = prefs->Get("DepartmentLogo", ""); if (departmentLogoLocation.empty()) { d->m_StdMultiWidget->DisableDepartmentLogo(); } else { d->m_StdMultiWidget->SetDepartmentLogoPath(departmentLogoLocation.c_str()); d->m_StdMultiWidget->EnableDepartmentLogo(); } break; } } // preferences for gradient background float color = 255.0; QString firstColorName = QString::fromStdString (prefs->GetByteArray("first background color", "")); QColor firstColor(firstColorName); mitk::Color upper; if (firstColorName=="") // default values { upper[0] = 0.1; upper[1] = 0.1; upper[2] = 0.1; } else { upper[0] = firstColor.red() / color; upper[1] = firstColor.green() / color; upper[2] = firstColor.blue() / color; } QString secondColorName = QString::fromStdString (prefs->GetByteArray("second background color", "")); QColor secondColor(secondColorName); mitk::Color lower; if (secondColorName=="") // default values { lower[0] = 0.5; lower[1] = 0.5; lower[2] = 0.5; } else { lower[0] = secondColor.red() / color; lower[1] = secondColor.green() / color; lower[2] = secondColor.blue() / color; } d->m_StdMultiWidget->SetGradientBackgroundColors(upper, lower); d->m_StdMultiWidget->EnableGradientBackground(); // Set preferences respecting zooming and padding bool constrainedZooming = prefs->GetBool("Use constrained zooming and padding", false); mitk::RenderingManager::GetInstance()->SetConstrainedPaddingZooming(constrainedZooming); 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); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); // level window setting bool showLevelWindowWidget = prefs->GetBool("Show level/window widget", true); if (showLevelWindowWidget) { d->m_StdMultiWidget->EnableStandardLevelWindow(); } else { d->m_StdMultiWidget->DisableStandardLevelWindow(); } // mouse modes toolbar bool newMode = prefs->GetBool("PACS like mouse interaction", false); d->m_MouseModeToolbar->setVisible( newMode ); d->m_StdMultiWidget->GetMouseModeSwitcher()->SetInteractionScheme( newMode ? mitk::MouseModeSwitcher::PACS : mitk::MouseModeSwitcher::MITK ); } void QmitkStdMultiWidgetEditor::SetFocus() { if (d->m_StdMultiWidget != 0) d->m_StdMultiWidget->setFocus(); } void QmitkStdMultiWidgetEditor::RequestActivateMenuWidget(bool on) { if (d->m_StdMultiWidget) { if (on) { d->m_StdMultiWidget->ActivateMenuWidget(d->m_MenuWidgetsEnabled); } else { d->m_MenuWidgetsEnabled = d->m_StdMultiWidget->IsMenuWidgetEnabled(); d->m_StdMultiWidget->ActivateMenuWidget(false); } } } void QmitkStdMultiWidgetEditor::EnableInteractors(bool enable, const QStringList& interactors) { if (d->m_StdMultiWidget) { if (interactors.isEmpty()) { if (enable) { if (!d->m_EnabledInteractors.isEmpty()) { // i.e. enable previously stored interactors. this->EnableInteractors(true, d->m_EnabledInteractors); } else { // pick a default. QStringList defaultInteractor; defaultInteractor << INTERACTOR_MITK; this->EnableInteractors(true, defaultInteractor); } } else { // Requesting de-activation, so we store the state, so that when re-activated we can restore it. QStringList currentlyEnabledInteractors; if (this->IsInteractorEnabled(INTERACTOR_MITK)) { currentlyEnabledInteractors << INTERACTOR_MITK; } if (this->IsInteractorEnabled(INTERACTOR_PACS)) { currentlyEnabledInteractors << INTERACTOR_PACS; } d->m_EnabledInteractors.clear(); d->m_EnabledInteractors << currentlyEnabledInteractors; d->m_StdMultiWidget->GetMouseModeSwitcher()->SetInteractionScheme(mitk::MouseModeSwitcher::OFF); } } else { if (enable && interactors.contains(INTERACTOR_MITK)) { d->m_StdMultiWidget->GetMouseModeSwitcher()->SetInteractionScheme(mitk::MouseModeSwitcher::MITK); } if (enable && interactors.contains(INTERACTOR_PACS)) { d->m_StdMultiWidget->GetMouseModeSwitcher()->SetInteractionScheme(mitk::MouseModeSwitcher::PACS); } } } } bool QmitkStdMultiWidgetEditor::IsInteractorEnabled(const QString& interactor) const { bool isEnabled = false; if (d->m_StdMultiWidget) { if ( (interactor == INTERACTOR_MITK && d->m_StdMultiWidget->GetMouseModeSwitcher()->GetInteractionScheme() == mitk::MouseModeSwitcher::MITK) || (interactor == INTERACTOR_PACS && d->m_StdMultiWidget->GetMouseModeSwitcher()->GetInteractionScheme() == mitk::MouseModeSwitcher::PACS) ) { isEnabled = true; } } return isEnabled; } QStringList QmitkStdMultiWidgetEditor::GetInteractors() const { QStringList interactors; interactors << INTERACTOR_MITK << INTERACTOR_PACS; return interactors; } diff --git a/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/QmitkStdMultiWidgetEditor.h b/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/QmitkStdMultiWidgetEditor.h index 09618f8c3b..806f9d489e 100644 --- a/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/QmitkStdMultiWidgetEditor.h +++ b/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/QmitkStdMultiWidgetEditor.h @@ -1,141 +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 QMITKSTDMULTIWIDGETEDITOR_H_ #define QMITKSTDMULTIWIDGETEDITOR_H_ #include #include #include class QmitkStdMultiWidget; class QmitkMouseModeSwitcher; class QmitkStdMultiWidgetEditorPrivate; /** * \ingroup org_mitk_gui_qt_stdmultiwidgeteditor */ class ORG_MITK_GUI_QT_STDMULTIWIDGETEDITOR QmitkStdMultiWidgetEditor : public QmitkAbstractRenderEditor, public mitk::ILinkedRenderWindowPart { Q_OBJECT public: berryObjectMacro(QmitkStdMultiWidgetEditor) static const std::string EDITOR_ID; QmitkStdMultiWidgetEditor(); ~QmitkStdMultiWidgetEditor(); QmitkStdMultiWidget* GetStdMultiWidget(); /** * Request the QmitkRenderWindowMenus to be either off, or whatever was the last known state, which is * useful when responding to the PartOpened, PartClosed, PartHidden methods. * * \param on If true will request the QmitkStdMultiWidget to set the QmitkRenderWindowMenu to * whatever was the last known state, and if false will turn the QmitkRenderWindowMenu off. * */ void RequestActivateMenuWidget(bool on); // ------------------- mitk::IRenderWindowPart ---------------------- /** - * \see mitk::IRenderWindowPart::GetActiveRenderWindow() + * \see mitk::IRenderWindowPart::GetActiveQmitkRenderWindow() */ - QmitkRenderWindow* GetActiveRenderWindow() const; + QmitkRenderWindow* GetActiveQmitkRenderWindow() const; /** - * \see mitk::IRenderWindowPart::GetRenderWindows() + * \see mitk::IRenderWindowPart::GetQmitkRenderWindows() */ - QHash GetRenderWindows() const; + QHash GetQmitkRenderWindows() const; /** - * \see mitk::IRenderWindowPart::GetRenderWindow(QString) + * \see mitk::IRenderWindowPart::GetQmitkRenderWindow(QString) */ - QmitkRenderWindow* GetRenderWindow(const QString& id) const; + QmitkRenderWindow* GetQmitkRenderWindow(const QString& id) const; /** * \see mitk::IRenderWindowPart::GetSelectionPosition() */ mitk::Point3D GetSelectedPosition(const QString& id = QString()) const; /** * \see mitk::IRenderWindowPart::SetSelectedPosition() */ void SetSelectedPosition(const mitk::Point3D& pos, const QString& id = QString()); /** * \see mitk::IRenderWindowPart::EnableDecorations() */ void EnableDecorations(bool enable, const QStringList& decorations = QStringList()); /** * \see mitk::IRenderWindowPart::IsDecorationEnabled() */ bool IsDecorationEnabled(const QString& decoration) const; /** * \see mitk::IRenderWindowPart::GetDecorations() */ QStringList GetDecorations() const; /** * \see mitk::IRenderWindowPart::EnableInteractors() */ void EnableInteractors(bool enable, const QStringList& interactors = QStringList()); /** * \see mitk::IRenderWindowPart::IsInteractorEnabled() */ bool IsInteractorEnabled(const QString& interactor) const; /** * \see mitk::IRenderWindowPart::GetInteractors() */ QStringList GetInteractors() const; // ------------------- mitk::ILinkedRenderWindowPart ---------------------- mitk::SlicesRotator* GetSlicesRotator() const; mitk::SlicesSwiveller* GetSlicesSwiveller() const; void EnableSlicingPlanes(bool enable); bool IsSlicingPlanesEnabled() const; void EnableLinkedNavigation(bool enable); bool IsLinkedNavigationEnabled() const; protected: void SetFocus(); void OnPreferencesChanged(const berry::IBerryPreferences*); void CreateQtPartControl(QWidget* parent); private: const QScopedPointer d; }; #endif /*QMITKSTDMULTIWIDGETEDITOR_H_*/ diff --git a/Plugins/org.mitk.gui.qt.toftutorial/documentation/Manual/Manual.dox b/Plugins/org.mitk.gui.qt.toftutorial/documentation/Manual/Manual.dox index d63ec1f100..e8726726bb 100644 --- a/Plugins/org.mitk.gui.qt.toftutorial/documentation/Manual/Manual.dox +++ b/Plugins/org.mitk.gui.qt.toftutorial/documentation/Manual/Manual.dox @@ -1,13 +1,13 @@ /** -\bundlemainpage{org_toftutorial} ToFTutorial +\page org_toftutorial ToFTutorial \image html icon.png "Icon of ToFTutorial" Available sections: - \ref ToFTutorialOverview \section ToFTutorialOverview This is the description for the ToFTutorial. */ diff --git a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp index c74763a040..81259d43d7 100644 --- a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp +++ b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp @@ -1,570 +1,605 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) -Copyright (c) German Cancer Research Center, +Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR +This software is distributed WITHOUT ANY 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 "QmitkToFUtilView.h" #include #include // Qt #include #include // MITK #include #include #include #include #include #include // VTK #include // ITK #include const std::string QmitkToFUtilView::VIEW_ID = "org.mitk.views.tofutil"; QmitkToFUtilView::QmitkToFUtilView() : QmitkAbstractView() , m_Controls(NULL), m_MultiWidget( NULL ) , m_MitkDistanceImage(NULL), m_MitkAmplitudeImage(NULL), m_MitkIntensityImage(NULL), m_Surface(NULL) , m_DistanceImageNode(NULL), m_AmplitudeImageNode(NULL), m_IntensityImageNode(NULL), m_RGBImageNode(NULL), m_SurfaceNode(NULL) , m_ToFImageRecorder(NULL), m_ToFImageGrabber(NULL), m_ToFDistanceImageToSurfaceFilter(NULL), m_ToFCompositeFilter(NULL) , m_SurfaceDisplayCount(0), m_2DDisplayCount(0) , m_RealTimeClock(NULL) , m_StepsForFramerate(100) , m_2DTimeBefore(0.0) , m_2DTimeAfter(0.0) , m_VideoEnabled(false) { this->m_Frametimer = new QTimer(this); this->m_ToFDistanceImageToSurfaceFilter = mitk::ToFDistanceImageToSurfaceFilter::New(); this->m_ToFCompositeFilter = mitk::ToFCompositeFilter::New(); this->m_ToFImageRecorder = mitk::ToFImageRecorder::New(); this->m_ToFSurfaceVtkMapper3D = mitk::ToFSurfaceVtkMapper3D::New(); } QmitkToFUtilView::~QmitkToFUtilView() { - OnToFCameraStopped(); - OnToFCameraDisconnected(); - ResetGUIToDefault(); + OnToFCameraStopped(); + OnToFCameraDisconnected(); } void QmitkToFUtilView::SetFocus() { m_Controls->m_ToFConnectionWidget->setFocus(); } void QmitkToFUtilView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkToFUtilViewControls; m_Controls->setupUi( parent ); connect(m_Frametimer, SIGNAL(timeout()), this, SLOT(OnUpdateCamera())); connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(ToFCameraConnected()), this, SLOT(OnToFCameraConnected()) ); connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(ToFCameraDisconnected()), this, SLOT(OnToFCameraDisconnected()) ); connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(ToFCameraSelected(const QString)), this, SLOT(OnToFCameraSelected(const QString)) ); connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(ToFCameraStarted()), this, SLOT(OnToFCameraStarted()) ); connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(ToFCameraStopped()), this, SLOT(OnToFCameraStopped()) ); connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(RecordingStarted()), this, SLOT(OnToFCameraStopped()) ); connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(RecordingStopped()), this, SLOT(OnToFCameraStarted()) ); connect( (QObject*)(m_Controls->m_TextureCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnTextureCheckBoxChecked(bool)) ); connect( (QObject*)(m_Controls->m_VideoTextureCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnVideoTextureCheckBoxChecked(bool)) ); } } void QmitkToFUtilView::Activated() { //get the current RenderWindowPart or open a new one if there is none if(this->GetRenderWindowPart(OPEN)) { mitk::ILinkedRenderWindowPart* linkedRenderWindowPart = dynamic_cast(this->GetRenderWindowPart()); if(linkedRenderWindowPart == 0) { MITK_ERROR << "No linked StdMultiWidget avaiable!!!"; } else { linkedRenderWindowPart->EnableSlicingPlanes(false); } - GetRenderWindowPart()->GetRenderWindow("transversal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Transversal); - GetRenderWindowPart()->GetRenderWindow("transversal")->GetSliceNavigationController()->SliceLockedOn(); - GetRenderWindowPart()->GetRenderWindow("sagittal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Transversal); + GetRenderWindowPart()->GetRenderWindow("axial")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); + GetRenderWindowPart()->GetRenderWindow("axial")->GetSliceNavigationController()->SliceLockedOn(); + GetRenderWindowPart()->GetRenderWindow("sagittal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); GetRenderWindowPart()->GetRenderWindow("sagittal")->GetSliceNavigationController()->SliceLockedOn(); - GetRenderWindowPart()->GetRenderWindow("coronal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Transversal); + GetRenderWindowPart()->GetRenderWindow("coronal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); GetRenderWindowPart()->GetRenderWindow("coronal")->GetSliceNavigationController()->SliceLockedOn(); this->GetRenderWindowPart()->GetRenderingManager()->InitializeViews(); this->UseToFVisibilitySettings(true); m_Controls->m_ToFCompositeFilterWidget->SetToFCompositeFilter(this->m_ToFCompositeFilter); m_Controls->m_ToFCompositeFilterWidget->SetDataStorage(this->GetDataStorage()); if (this->m_ToFImageGrabber.IsNull()) { m_Controls->m_ToFRecorderWidget->setEnabled(false); m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); + m_Controls->m_ToFCompositeFilterWidget->setEnabled(false); + m_Controls->tofMeasurementWidget->setEnabled(false); + m_Controls->SurfacePropertiesBox->setEnabled(false); } } } void QmitkToFUtilView::ActivatedZombieView(berry::IWorkbenchPartReference::Pointer /*zombieView*/) { ResetGUIToDefault(); } void QmitkToFUtilView::Deactivated() { + } void QmitkToFUtilView::Visible() { } void QmitkToFUtilView::Hidden() { + + ResetGUIToDefault(); } void QmitkToFUtilView::OnToFCameraConnected() { this->m_SurfaceDisplayCount = 0; this->m_2DDisplayCount = 0; this->m_ToFImageGrabber = m_Controls->m_ToFConnectionWidget->GetToFImageGrabber(); this->m_ToFImageRecorder->SetCameraDevice(this->m_ToFImageGrabber->GetCameraDevice()); m_Controls->m_ToFRecorderWidget->SetParameter(this->m_ToFImageGrabber, this->m_ToFImageRecorder); m_Controls->m_ToFRecorderWidget->setEnabled(true); m_Controls->m_ToFRecorderWidget->ResetGUIToInitial(); + // initialize measurement widget + m_Controls->tofMeasurementWidget->InitializeWidget(this->GetRenderWindowPart()->GetQmitkRenderWindows(),this->GetDataStorage()); //TODO this->m_RealTimeClock = mitk::RealTimeClock::New(); this->m_2DTimeBefore = this->m_RealTimeClock->GetCurrentStamp(); try { this->m_VideoSource = mitk::OpenCVVideoSource::New(); this->m_VideoSource->SetVideoCameraInput(0, false); this->m_VideoSource->StartCapturing(); if(!this->m_VideoSource->IsCapturingEnabled()) { MITK_INFO << "unable to initialize video grabbing/playback"; this->m_VideoEnabled = false; m_Controls->m_VideoTextureCheckBox->setEnabled(false); } else { this->m_VideoEnabled = true; m_Controls->m_VideoTextureCheckBox->setEnabled(true); } if (this->m_VideoEnabled) { this->m_VideoSource->FetchFrame(); this->m_VideoCaptureHeight = this->m_VideoSource->GetImageHeight(); this->m_VideoCaptureWidth = this->m_VideoSource->GetImageWidth(); this->m_VideoTexture = this->m_VideoSource->GetVideoTexture(); this->m_ToFDistanceImageToSurfaceFilter->SetTextureImageWidth(this->m_VideoCaptureWidth); this->m_ToFDistanceImageToSurfaceFilter->SetTextureImageHeight(this->m_VideoCaptureHeight); this->m_ToFSurfaceVtkMapper3D->SetTextureWidth(this->m_VideoCaptureWidth); this->m_ToFSurfaceVtkMapper3D->SetTextureHeight(this->m_VideoCaptureHeight); } } catch (std::logic_error& e) { QMessageBox::warning(NULL, "Warning", QString(e.what())); MITK_ERROR << e.what(); return; } this->RequestRenderWindowUpdate(); } void QmitkToFUtilView::ResetGUIToDefault() { if(this->GetRenderWindowPart()) { mitk::ILinkedRenderWindowPart* linkedRenderWindowPart = dynamic_cast(this->GetRenderWindowPart()); if(linkedRenderWindowPart == 0) { MITK_ERROR << "No linked StdMultiWidget avaiable!!!"; } else { linkedRenderWindowPart->EnableSlicingPlanes(true); } - GetRenderWindowPart()->GetRenderWindow("transversal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Transversal); - GetRenderWindowPart()->GetRenderWindow("transversal")->GetSliceNavigationController()->SliceLockedOff(); + GetRenderWindowPart()->GetRenderWindow("axial")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); + GetRenderWindowPart()->GetRenderWindow("axial")->GetSliceNavigationController()->SliceLockedOff(); GetRenderWindowPart()->GetRenderWindow("sagittal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); GetRenderWindowPart()->GetRenderWindow("sagittal")->GetSliceNavigationController()->SliceLockedOff(); GetRenderWindowPart()->GetRenderWindow("coronal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Frontal); GetRenderWindowPart()->GetRenderWindow("coronal")->GetSliceNavigationController()->SliceLockedOff(); this->UseToFVisibilitySettings(false); //global reinit this->GetRenderWindowPart()->GetRenderingManager()->InitializeViews(/*this->GetDataStorage()->ComputeBoundingGeometry3D(this->GetDataStorage()->GetAll())*/); this->RequestRenderWindowUpdate(); } } void QmitkToFUtilView::OnToFCameraDisconnected() { m_Controls->m_ToFRecorderWidget->OnStop(); m_Controls->m_ToFRecorderWidget->setEnabled(false); m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); + m_Controls->tofMeasurementWidget->setEnabled(false); + m_Controls->SurfacePropertiesBox->setEnabled(false); + //clean up measurement widget + m_Controls->tofMeasurementWidget->CleanUpWidget(); + if(this->m_VideoSource) { this->m_VideoSource->StopCapturing(); this->m_VideoSource = NULL; } - this->RequestRenderWindowUpdate(); } void QmitkToFUtilView::OnToFCameraStarted() { if (m_ToFImageGrabber.IsNotNull()) { // initial update of image grabber this->m_ToFImageGrabber->Update(); this->m_ToFCompositeFilter->SetInput(0,this->m_ToFImageGrabber->GetOutput(0)); this->m_ToFCompositeFilter->SetInput(1,this->m_ToFImageGrabber->GetOutput(1)); this->m_ToFCompositeFilter->SetInput(2,this->m_ToFImageGrabber->GetOutput(2)); // initial update of composite filter this->m_ToFCompositeFilter->Update(); this->m_MitkDistanceImage = m_ToFCompositeFilter->GetOutput(0); this->m_DistanceImageNode = ReplaceNodeData("Distance image",m_MitkDistanceImage); this->m_MitkAmplitudeImage = m_ToFCompositeFilter->GetOutput(1); this->m_AmplitudeImageNode = ReplaceNodeData("Amplitude image",m_MitkAmplitudeImage); this->m_MitkIntensityImage = m_ToFCompositeFilter->GetOutput(2); this->m_IntensityImageNode = ReplaceNodeData("Intensity image",m_MitkIntensityImage); std::string rgbFileName; m_ToFImageGrabber->GetCameraDevice()->GetStringProperty("RGBImageFileName",rgbFileName); if ((m_SelectedCamera=="Microsoft Kinect")||(rgbFileName!="")) { this->m_RGBImageNode = ReplaceNodeData("RGB image",this->m_ToFImageGrabber->GetOutput(3)); } else { this->m_RGBImageNode = NULL; } this->m_ToFDistanceImageToSurfaceFilter->SetInput(0,m_MitkDistanceImage); this->m_ToFDistanceImageToSurfaceFilter->SetInput(1,m_MitkAmplitudeImage); this->m_ToFDistanceImageToSurfaceFilter->SetInput(2,m_MitkIntensityImage); this->m_Surface = this->m_ToFDistanceImageToSurfaceFilter->GetOutput(0); this->m_SurfaceNode = ReplaceNodeData("Surface",m_Surface); this->UseToFVisibilitySettings(true); m_Controls->m_ToFCompositeFilterWidget->UpdateFilterParameter(); // initialize visualization widget m_Controls->m_ToFVisualisationSettingsWidget->Initialize(this->m_DistanceImageNode, this->m_AmplitudeImageNode, this->m_IntensityImageNode); + // set distance image to measurement widget + m_Controls->tofMeasurementWidget->SetDistanceImage(m_MitkDistanceImage); this->m_Frametimer->start(0); m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(true); + m_Controls->m_ToFCompositeFilterWidget->setEnabled(true); + m_Controls->tofMeasurementWidget->setEnabled(true); + m_Controls->SurfacePropertiesBox->setEnabled(true); if (m_Controls->m_TextureCheckBox->isChecked()) { OnTextureCheckBoxChecked(true); } if (m_Controls->m_VideoTextureCheckBox->isChecked()) { OnVideoTextureCheckBoxChecked(true); } } m_Controls->m_TextureCheckBox->setEnabled(true); - // initialize point set measurement - m_Controls->tofMeasurementWidget->InitializeWidget(this->GetRenderWindowPart()->GetRenderWindows(),this->GetDataStorage(),m_MitkDistanceImage); } void QmitkToFUtilView::OnToFCameraStopped() { m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); + m_Controls->m_ToFCompositeFilterWidget->setEnabled(false); + m_Controls->tofMeasurementWidget->setEnabled(false); + m_Controls->SurfacePropertiesBox->setEnabled(false); + this->m_Frametimer->stop(); } void QmitkToFUtilView::OnToFCameraSelected(const QString selected) { m_SelectedCamera = selected; if ((selected=="PMD CamBoard")||(selected=="PMD O3D")) { MITK_INFO<<"Surface representation currently not available for CamBoard and O3. Intrinsic parameters missing."; this->m_Controls->m_SurfaceCheckBox->setEnabled(false); this->m_Controls->m_TextureCheckBox->setEnabled(false); this->m_Controls->m_VideoTextureCheckBox->setEnabled(false); this->m_Controls->m_SurfaceCheckBox->setChecked(false); this->m_Controls->m_TextureCheckBox->setChecked(false); this->m_Controls->m_VideoTextureCheckBox->setChecked(false); } else { this->m_Controls->m_SurfaceCheckBox->setEnabled(true); this->m_Controls->m_TextureCheckBox->setEnabled(true); // TODO enable when bug 8106 is solved this->m_Controls->m_VideoTextureCheckBox->setEnabled(true); } } void QmitkToFUtilView::OnUpdateCamera() { if (m_Controls->m_VideoTextureCheckBox->isChecked() && this->m_VideoEnabled && this->m_VideoSource) { this->m_VideoTexture = this->m_VideoSource->GetVideoTexture(); ProcessVideoTransform(); } if (m_Controls->m_SurfaceCheckBox->isChecked()) { // update surface m_ToFDistanceImageToSurfaceFilter->SetTextureIndex(m_Controls->m_ToFVisualisationSettingsWidget->GetSelectedImageIndex()); this->m_Surface->Update(); vtkColorTransferFunction* colorTransferFunction = m_Controls->m_ToFVisualisationSettingsWidget->GetSelectedColorTransferFunction(); this->m_ToFSurfaceVtkMapper3D->SetVtkScalarsToColors(colorTransferFunction); if (this->m_SurfaceDisplayCount<2) { this->m_SurfaceNode->SetData(this->m_Surface); this->m_SurfaceNode->SetMapper(mitk::BaseRenderer::Standard3D, m_ToFSurfaceVtkMapper3D); this->GetRenderWindowPart()->GetRenderingManager()->InitializeViews( this->m_Surface->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS, true); mitk::Point3D surfaceCenter= this->m_Surface->GetGeometry()->GetCenter(); vtkCamera* camera3d = GetRenderWindowPart()->GetRenderWindow("3d")->GetRenderer()->GetVtkRenderer()->GetActiveCamera(); camera3d->SetPosition(0,0,-50); camera3d->SetViewUp(0,-1,0); camera3d->SetFocalPoint(0,0,surfaceCenter[2]); camera3d->SetViewAngle(40); camera3d->SetClippingRange(1, 10000); } this->m_SurfaceDisplayCount++; } else { // update pipeline this->m_MitkDistanceImage->Update(); } this->RequestRenderWindowUpdate(); this->m_2DDisplayCount++; if ((this->m_2DDisplayCount % this->m_StepsForFramerate) == 0) { this->m_2DTimeAfter = this->m_RealTimeClock->GetCurrentStamp() - this->m_2DTimeBefore; MITK_INFO << " 2D-Display-framerate (fps): " << this->m_StepsForFramerate / (this->m_2DTimeAfter/1000); this->m_2DTimeBefore = this->m_RealTimeClock->GetCurrentStamp(); } } void QmitkToFUtilView::ProcessVideoTransform() { IplImage *src, *dst; src = cvCreateImageHeader(cvSize(this->m_VideoCaptureWidth, this->m_VideoCaptureHeight), IPL_DEPTH_8U, 3); src->imageData = (char*)this->m_VideoTexture; CvPoint2D32f srcTri[3], dstTri[3]; CvMat* rot_mat = cvCreateMat(2,3,CV_32FC1); CvMat* warp_mat = cvCreateMat(2,3,CV_32FC1); dst = cvCloneImage(src); dst->origin = src->origin; cvZero( dst ); int xOffset = 0;//m_Controls->m_XOffsetSpinBox->value(); int yOffset = 0;//m_Controls->m_YOffsetSpinBox->value(); int zoom = 0;//m_Controls->m_ZoomSpinBox->value(); // Compute warp matrix srcTri[0].x = 0 + zoom; srcTri[0].y = 0 + zoom; srcTri[1].x = src->width - 1 - zoom; srcTri[1].y = 0 + zoom; srcTri[2].x = 0 + zoom; srcTri[2].y = src->height - 1 - zoom; dstTri[0].x = 0; dstTri[0].y = 0; dstTri[1].x = src->width - 1; dstTri[1].y = 0; dstTri[2].x = 0; dstTri[2].y = src->height - 1; cvGetAffineTransform( srcTri, dstTri, warp_mat ); cvWarpAffine( src, dst, warp_mat ); cvCopy ( dst, src ); // Compute warp matrix srcTri[0].x = 0; srcTri[0].y = 0; srcTri[1].x = src->width - 1; srcTri[1].y = 0; srcTri[2].x = 0; srcTri[2].y = src->height - 1; dstTri[0].x = srcTri[0].x + xOffset; dstTri[0].y = srcTri[0].y + yOffset; dstTri[1].x = srcTri[1].x + xOffset; dstTri[1].y = srcTri[1].y + yOffset; dstTri[2].x = srcTri[2].x + xOffset; dstTri[2].y = srcTri[2].y + yOffset; cvGetAffineTransform( srcTri, dstTri, warp_mat ); cvWarpAffine( src, dst, warp_mat ); cvCopy ( dst, src ); src->imageData = NULL; cvReleaseImage( &src ); cvReleaseImage( &dst ); cvReleaseMat( &rot_mat ); cvReleaseMat( &warp_mat ); } void QmitkToFUtilView::OnTextureCheckBoxChecked(bool checked) { if(m_SurfaceNode.IsNotNull()) { if (checked) { this->m_SurfaceNode->SetBoolProperty("scalar visibility", true); } else { this->m_SurfaceNode->SetBoolProperty("scalar visibility", false); } } } void QmitkToFUtilView::OnVideoTextureCheckBoxChecked(bool checked) { if (checked) { if (this->m_VideoEnabled) { this->m_ToFSurfaceVtkMapper3D->SetTexture(this->m_VideoTexture); } else { this->m_ToFSurfaceVtkMapper3D->SetTexture(NULL); } } - else +} + +void QmitkToFUtilView::OnChangeCoronalWindowOutput(int index) +{ + this->OnToFCameraStopped(); + if(index == 0) + { + if(this->m_IntensityImageNode.IsNotNull()) + this->m_IntensityImageNode->SetVisibility(false); + if(this->m_RGBImageNode.IsNotNull()) + this->m_RGBImageNode->SetVisibility(true); + } + else if(index == 1) { - this->m_ToFSurfaceVtkMapper3D->SetTexture(NULL); + if(this->m_IntensityImageNode.IsNotNull()) + this->m_IntensityImageNode->SetVisibility(true); + if(this->m_RGBImageNode.IsNotNull()) + this->m_RGBImageNode->SetVisibility(false); } + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + this->OnToFCameraStarted(); } mitk::DataNode::Pointer QmitkToFUtilView::ReplaceNodeData( std::string nodeName, mitk::BaseData* data ) { mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode(nodeName); if (node.IsNull()) { node = mitk::DataNode::New(); node->SetData(data); node->SetName(nodeName); node->SetBoolProperty("binary",false); this->GetDataStorage()->Add(node); } else { node->SetData(data); } return node; } void QmitkToFUtilView::UseToFVisibilitySettings(bool useToF) { // set node properties if (m_DistanceImageNode.IsNotNull()) { this->m_DistanceImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); this->m_DistanceImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetRenderWindow("sagittal")->GetRenderWindow() ) ); this->m_DistanceImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetRenderWindow("coronal")->GetRenderWindow() ) ); this->m_DistanceImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetRenderWindow("3d")->GetRenderWindow() ) ); this->m_DistanceImageNode->SetBoolProperty("use color",!useToF); this->m_DistanceImageNode->GetPropertyList()->DeleteProperty("LookupTable"); } if (m_AmplitudeImageNode.IsNotNull()) { this->m_AmplitudeImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); - this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetRenderWindow("transversal")->GetRenderWindow() ) ); + this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetRenderWindow("axial")->GetRenderWindow() ) ); this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetRenderWindow("coronal")->GetRenderWindow() ) ); this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetRenderWindow("3d")->GetRenderWindow() ) ); this->m_AmplitudeImageNode->SetBoolProperty("use color",!useToF); this->m_AmplitudeImageNode->GetPropertyList()->DeleteProperty("LookupTable"); } if (m_IntensityImageNode.IsNotNull()) { this->m_IntensityImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); - this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetRenderWindow("transversal")->GetRenderWindow() ) ); + this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetRenderWindow("axial")->GetRenderWindow() ) ); this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetRenderWindow("sagittal")->GetRenderWindow() ) ); this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetRenderWindow("3d")->GetRenderWindow() ) ); this->m_IntensityImageNode->SetBoolProperty("use color",!useToF); this->m_IntensityImageNode->GetPropertyList()->DeleteProperty("LookupTable"); } if ((m_RGBImageNode.IsNotNull())) { this->m_RGBImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); - this->m_RGBImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetRenderWindow("transversal")->GetRenderWindow() ) ); + this->m_RGBImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetRenderWindow("axial")->GetRenderWindow() ) ); this->m_RGBImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetRenderWindow("sagittal")->GetRenderWindow() ) ); this->m_RGBImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetRenderWindow("3d")->GetRenderWindow() ) ); } // initialize images if (m_MitkDistanceImage.IsNotNull()) { this->GetRenderWindowPart()->GetRenderingManager()->InitializeViews( this->m_MitkDistanceImage->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS, true); } if(this->m_SurfaceNode.IsNotNull()) { - QHash renderWindowHashMap = this->GetRenderWindowPart()->GetRenderWindows(); + QHash renderWindowHashMap = this->GetRenderWindowPart()->GetQmitkRenderWindows(); QHashIterator i(renderWindowHashMap); while (i.hasNext()){ i.next(); this->m_SurfaceNode->SetVisibility( false, mitk::BaseRenderer::GetInstance(i.value()->GetRenderWindow()) ); } this->m_SurfaceNode->SetVisibility( true, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetRenderWindow("3d")->GetRenderWindow() ) ); } //disable/enable gradient background this->GetRenderWindowPart()->EnableDecorations(!useToF, QStringList(QString("background"))); } diff --git a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.h b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.h index 25a5bcab6a..1fbf7a0d06 100644 --- a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.h +++ b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.h @@ -1,184 +1,188 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkToFUtilView_h #define QmitkToFUtilView_h #include #include #include #include #include class QTimer; #include #include #include #include #include #include #include #include /*! \brief QmitkToFUtilView Application that allows simple playing, recording, visualization, processing and measurement of Time-of-Flight (ToF) data. Currently the following features are implemented:
  • Connecting and showing ToF data from various cameras (PMD CamCube 2/3, PMD CamBoard, PMD O3, MESA SwissRanger)
  • Recording and playing of ToF data
  • Color coded visualization of ToF images
  • Preprocessing of the distance data: Threshold, median, average and bilateral filtering; surface generation
  • Simple measurement and PointSet definition
\sa QmitkFunctionality \ingroup Functionalities */ class QmitkToFUtilView : public QmitkAbstractView, public mitk::IZombieViewPart { // 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; QmitkToFUtilView(); ~QmitkToFUtilView(); virtual void CreateQtPartControl(QWidget *parent); /// \brief Called when the functionality is activated. virtual void Activated(); /// \brief Called when the functionality is deactivated. In this case the zombie view of this functionality becomes active! virtual void ActivatedZombieView(berry::IWorkbenchPartReference::Pointer zombieView); virtual void Deactivated(); virtual void Visible(); virtual void Hidden(); void SetFocus(); protected slots: /*! \brief Slot triggered from the timer to update the images and visualization */ void OnUpdateCamera(); /*! \brief Slot called when the "Connect" button of the ConnectionWidget is pressed */ void OnToFCameraConnected(); /*! \brief Slot called when the "Disconnect" button of the ConnectionWidget is pressed */ void OnToFCameraDisconnected(); /*! \brief Slot called when the camera selection in the ConnectionWidget has changed */ void OnToFCameraSelected(const QString selected); /*! \brief Slot called when the "Start" button of the RecorderWidget is pressed */ void OnToFCameraStarted(); /*! \brief Slot called when the "Stop" button of the RecorderWidget is pressed */ void OnToFCameraStopped(); /*! \brief Slot invoked when the texture checkbox is checked. Enables the scalar visibility of the surface */ void OnTextureCheckBoxChecked(bool checked); /*! \brief Slot invoked when the video texture checkbox is checked. Enables the texture of the surface */ void OnVideoTextureCheckBoxChecked(bool checked); + /*! + \brief Slot invoked when user alters the coronal window input from RGB to Intensity or vice versa. + */ + void OnChangeCoronalWindowOutput(int index); protected: /*! \brief initialize the visibility settings of ToF data (images + surface) \param useToF true: distance image: widget1, amplitude image: widget 2, intensity image: widget 3; false: standard */ void UseToFVisibilitySettings(bool useToF); Ui::QmitkToFUtilViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; QTimer* m_Frametimer; ///< Timer used to continuously update the images QString m_SelectedCamera; ///< String holding the selected camera mitk::Image::Pointer m_MitkDistanceImage; ///< member holding a pointer to the distance image of the selected camera mitk::Image::Pointer m_MitkAmplitudeImage; ///< member holding a pointer to the amplitude image of the selected camera mitk::Image::Pointer m_MitkIntensityImage; ///< member holding a pointer to the intensity image of the selected camera mitk::Surface::Pointer m_Surface; ///< member holding a pointer to the surface generated from the distance image of the selected camera mitk::DataNode::Pointer m_DistanceImageNode; ///< DataNode holding the distance image of the selected camera mitk::DataNode::Pointer m_AmplitudeImageNode; ///< DataNode holding the amplitude image of the selected camera mitk::DataNode::Pointer m_IntensityImageNode; ///< DataNode holding the intensity image of the selected camera mitk::DataNode::Pointer m_RGBImageNode; ///< DataNode holding the rgb image of the selected camera mitk::DataNode::Pointer m_SurfaceNode; ///< DataNode holding the surface generated from the distanc image of the selected camera // ToF processing and recording filter mitk::ToFImageRecorder::Pointer m_ToFImageRecorder; ///< ToF image recorder used for lossless recording of ToF image data mitk::ToFImageGrabber::Pointer m_ToFImageGrabber; ///< Source of a ToF image processing pipeline. Provides pointers to distance, amplitude and intensity image mitk::ToFDistanceImageToSurfaceFilter::Pointer m_ToFDistanceImageToSurfaceFilter; ///< Filter for calculating a surface representation from a given distance image mitk::ToFCompositeFilter::Pointer m_ToFCompositeFilter; ///< Filter combining several processing steps (thresholding, Median filtering, Bilateral filtering) int m_SurfaceDisplayCount; ///< member used to determine whether surface is initialized or not int m_2DDisplayCount; ///< member used to determine whether frame rate output should be shown // members for calculating the frame rate mitk::RealTimeClock::Pointer m_RealTimeClock; ///< real time clock used to calculate the display framerate int m_StepsForFramerate; ///< number of steps used for calculating the display framerate double m_2DTimeBefore; ///< holds the time stamp at the beginning of the display framerate measurement double m_2DTimeAfter; ///< holds the time stamp at the end of the display framerate measurement // members used for displaying an external video source mitk::OpenCVVideoSource::Pointer m_VideoSource; ///< OpenCV video source to connect a video device unsigned char* m_VideoTexture; ///< texture used to show video image int m_VideoCaptureWidth; ///< width of the video image int m_VideoCaptureHeight; ///< height of the video image bool m_VideoEnabled; ///< flag indicating whether video grabbing is enabled. Set via the RGB texture checkbox private: /*! \brief helper method to replace data of the specified node. If node does not exist it will be created \param nodeName Name of the node \param data Data object to be replaced \return returns the node */ mitk::DataNode::Pointer ReplaceNodeData(std::string nodeName, mitk::BaseData* data); void ProcessVideoTransform(); /*! \brief Reset all GUI related things to default. E.g. show sagittal and coronal slices in the renderwindows. */ void ResetGUIToDefault(); mitk::ToFSurfaceVtkMapper3D::Pointer m_ToFSurfaceVtkMapper3D; }; #endif // _QMITKTOFUTILVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilViewControls.ui b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilViewControls.ui index 90d6a589dc..d7d4a1d26a 100644 --- a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilViewControls.ui +++ b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilViewControls.ui @@ -1,155 +1,161 @@ QmitkToFUtilViewControls 0 0 466 452 0 0 QmitkTemplate 0 0 0 0 0 0 true 0 0 - + + + true + Surface + + false + Surface true RGB Texture false Texture Qt::Vertical 20 311 QmitkToFConnectionWidget QWidget
QmitkToFConnectionWidget.h
1
QmitkToFRecorderWidget QWidget
QmitkToFRecorderWidget.h
1
QmitkToFVisualisationSettingsWidget QWidget
QmitkToFVisualisationSettingsWidget.h
1
QmitkToFCompositeFilterWidget QWidget
QmitkToFCompositeFilterWidget.h
1
QmitkToFPointSetWidget QWidget
QmitkToFPointSetWidget.h
1
diff --git a/Plugins/org.mitk.gui.qt.ultrasound/documentation/UserManual/Manual.dox b/Plugins/org.mitk.gui.qt.ultrasound/documentation/UserManual/Manual.dox index 9645991aea..5f9dfdc00d 100644 --- a/Plugins/org.mitk.gui.qt.ultrasound/documentation/UserManual/Manual.dox +++ b/Plugins/org.mitk.gui.qt.ultrasound/documentation/UserManual/Manual.dox @@ -1,19 +1,19 @@ /** -\bundlemainpage{org_mitk_gui_qt_ultrasound} Ultrasound +\page org_mitk_gui_qt_ultrasound Ultrasound \image html icon.xpm "Icon of Ultrasound" Available sections: - \ref org_mitk_gui_qt_ultrasoundOverview \section org_mitk_gui_qt_ultrasoundOverview Describe the features of your awesome plugin here
  • Increases productivity
  • Creates beautiful images
  • Generates PhD thesis
  • Brings world peace
*/ diff --git a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp index 6d9028e125..f19f8f6e32 100644 --- a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp +++ b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp @@ -1,116 +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. ===================================================================*/ // Blueberry #include #include //Mitk #include "mitkDataNode.h" // 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_Controls.m_BtnView, SIGNAL(clicked()), this, SLOT(OnClickedViewDevice()) ); connect( m_Timer, SIGNAL(timeout()), this, SLOT(DisplayImage())); //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::USDevice::US_PROPKEY_ISACTIVE + "=true)"; + m_Controls.m_ActiveVideoDevices->Initialize(mitk::USDevice::US_PROPKEY_LABEL ,filter); + 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_Node->SetData(image); // m_Image->Update(); this->RequestRenderWindowUpdate(); } void UltrasoundSupport::OnClickedViewDevice() { // We use the activity state of the timer to determine whether we are currently viewing images if ( ! m_Timer->isActive() ) // Activate Imaging { - m_Device = m_Controls.m_ActiveVideoDevices->GetSelectedServiceAsClass(); + m_Device = m_Controls.m_ActiveVideoDevices->GetSelectedService(); if (m_Device.IsNull()){ m_Timer->stop(); return; } m_Device->UpdateOutputData(0); m_Image = m_Device->GetOutput(0); m_Node->SetData(m_Device->GetOutput(0)); int interval = (1000 / m_Controls.m_FrameRate->value()); m_Timer->setInterval(interval); m_Timer->start(); m_Controls.m_BtnView->setText("Stop Viewing"); } else - { //deactivate Imaging + { //deactivate imaging m_Controls.m_BtnView->setText("Start Viewing"); m_Timer->stop(); m_Node->ReleaseData(); this->RequestRenderWindowUpdate(); } } 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:"); } \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.volumevisualization/documentation/UserManual/QmitkVolumeVisualizationUserManual.dox b/Plugins/org.mitk.gui.qt.volumevisualization/documentation/UserManual/QmitkVolumeVisualizationUserManual.dox index bd6c6fb438..2972552f37 100644 --- a/Plugins/org.mitk.gui.qt.volumevisualization/documentation/UserManual/QmitkVolumeVisualizationUserManual.dox +++ b/Plugins/org.mitk.gui.qt.volumevisualization/documentation/UserManual/QmitkVolumeVisualizationUserManual.dox @@ -1,150 +1,150 @@ /** -\bundlemainpage{org_volvis} The Volume Visualization Module +\page org_mitk_views_volumevisualization The Volume Visualization Module \image html icon.png "Icon of the Module" Available sections:
  • \ref QVV_Overview
  • \ref QVV_EnableVRPage
  • \ref QVV_PresetPage
  • \ref QVV_ThresholdBell
  • \ref QVV_Editing
\section QVV_Overview Overview The Volume Visualization Module is a basic tool for visualizing three dimensional medical images. MITK provides generic transfer function presets for medical CT data. These functions, that map the gray-value to color and opacity, can be interactively edited. Additionally, there are controls to quickly generate common used transfer function shapes like the threshold and bell curve to help identify a range of grey-values. \image html vroverview.png "" \section QVV_EnableVRPage Enable Volume Rendering \subsection QVV_LoadingImage Loading an image into the application Load an image into the application by
  • dragging a file into the application window.
  • selecting file / load from the menu.
Volume Visualization imposes following restrictions on images:
  • It has to be a 3D-Image Scalar image, that means a normal CT or MRT.
  • 3D+T are supported for rendering, but the histograms are not computed.
  • Also be aware that volume visualization requires a huge amount of memory. Very large images may not work, unless you use the 64bit version.
\subsection QVV_EnableVR Enable Volumerendering \image html checkboxen.png "" Select an image in datamanager and click on the checkbox left of "Volumerendering". Please be patient, while the image is prepared for rendering, which can take up to a half minute. \subsection QVV_LODGPU The LOD & GPU checkboxes Volume Rendering requires a lot of computing resources including processor, memory and graphics card. To run volume rendering on smaller platforms, enable the LOD checkbox (level-of-detail rendering). Level-of-detail first renders a lower quality preview to increase interactivity. If the user stops to interact a normal quality rendering is issued. The GPU checkbox tries to use computing resources on the graphics card to accelerate volume rendering. It requires a powerful graphics card and OpenGL hardware support for shaders, but achieves much higher frame rates than software-rendering. \section QVV_PresetPage Applying premade presets \subsection QVV_Preset Internal presets There are some internal presets given, that can be used with normal CT data (given in Houndsfield units). A large set of medical data has been tested with that presets, but it may not suit on some special cases. Click on the "Preset" tab for using internal or custom presets. \image html mitkInternalPresets.png ""
  • "CT Generic" is the default transferfunction that is first applied.
  • "CT Black&White" does not use any colors, as it may be distracting on some data.
  • "CT Cardiac" tries to increase detail on CTs from the heart.
  • "CT Bone" emphasizes bones and shows other areas more transparent.
  • "CT Bone (Gradient)" is like "CT Bone", but shows from other organs only the surface by using the gradient.
  • "MR Generic" is the default transferfunction that we use on MRT data (which is not normalized like CT data).
  • "CT Thorax small" tries to increase detail.
  • "CT Thorax large" tries to increase detail.
\subsection QVV_CustomPreset Saving and loading custom presets After creating or editing a transferfunction (see \ref QVV_Editing or \ref QVV_ThresholdBell), the custom transferfunction can be stored and later retrieved on the filesystem. Click "Save" (respectively "Load") button to save (load) the threshold-, color- and gradient function combined in a single .xml file. \section QVV_ThresholdBell Interactively create transferfunctions Beside the possibility to directly edit the transferfunctions (\ref QVV_Editing), a one-click generation of two commonly known shapes is given. Both generators have two parameters, that can be modified by first clicking on the cross and then moving the mouse up/down and left/right. The first parameter "center" (controlled by horizontal movement of the mouse) specifies the gravalue where the center of the shape will be located. The second parameter "width" (controlled by vertical movement of the mouse) specifies the width (or steepness) of the shape. \subsection Threshold Click on the "Threshold" tab to active the threshold function generator. \image html threshold.png "" A threshold shape begins with zero and raises to one across the "center" parameter. Lower widths results in steeper threshold functions. \subsection Bell Click on the "Bell" tab to active the threshold function generator. \image html bell.png "" A threshold shape begins with zero and raises to one at the "center" parameter and the lowers agains to zero. The "width" parameter correspondens to the width of the bell. \section QVV_Editing Customize transferfunctions in detail \subsection QVV_Navigate Choosing grayvalue interval to edit \image html slider.png "" To navigate across the grayvalue range or to zoom in some ranges use the "range"-slider. All three function editors have in common following:
  • By left-clicking a new point is added.
  • By right-clicking a point is deleted.
  • By left-clicking and holding, an exisiting point can be dragged.
  • By pressing arrow keys, the currently selected point is moved.
  • By pressing the "DELETE" key, the currently selected point is deleted.
  • Between points the transferfunctions are linear interpolated.
There are three transferfunctions to customize: \subsection QVV_GO Grayvalue -> Opacity \image html opacity.png "grayvalues will be mapped to opacity." An opacity of 0 means total transparent, an opacity of 1 means total opaque. \subsection QVV_GC Grayvalue -> Color \image html color.png "grayvalues will be mapped to color." The color transferfunction editor also allows by double-clicking a point to change its color. \subsection QVV_GGO Grayvalue and Gradient -> Opacity \image html gradient.png "" Here the influence of the gradient is controllable at specific grayvalues. */ diff --git a/Utilities/KWStyle/MITKFiles.txt.in b/Utilities/KWStyle/MITKFiles.txt.in index de23a6ab8a..dc85c3f6fc 100644 --- a/Utilities/KWStyle/MITKFiles.txt.in +++ b/Utilities/KWStyle/MITKFiles.txt.in @@ -1,346 +1,346 @@ @MITK_SOURCE_DIR@/Core/Code/*.cpp @MITK_SOURCE_DIR@/Core/Code/*.h @MITK_SOURCE_DIR@/Core/Code/Algorithms/*.cpp @MITK_SOURCE_DIR@/Core/Code/Algorithms/*.h @MITK_SOURCE_DIR@/Core/Code/Interactions/*.cpp @MITK_SOURCE_DIR@/Core/Code/Interactions/*.h @MITK_SOURCE_DIR@/Core/Code/DataManagement/*.cpp @MITK_SOURCE_DIR@/Core/Code/DataManagement/*.h @MITK_SOURCE_DIR@/Core/Code/Controllers/*.cpp @MITK_SOURCE_DIR@/Core/Code/Controllers/*.h @MITK_SOURCE_DIR@/Core/Code/Rendering/*.cpp @MITK_SOURCE_DIR@/Core/Code/Rendering/*.h @MITK_SOURCE_DIR@/Core/Code/IO/*.cpp @MITK_SOURCE_DIR@/Core/Code/IO/*.h @MITK_SOURCE_DIR@/Core/Code/Testing/*.cpp @MITK_SOURCE_DIR@/Core/Code/Testing/*.h @MITK_SOURCE_DIR@/Core/Code/Testing/Data/*.cpp @MITK_SOURCE_DIR@/Core/Code/Testing/Data/*.h @MITK_SOURCE_DIR@/CoreUI/Qmitk/*.cpp @MITK_SOURCE_DIR@/CoreUI/Qmitk/*.h @MITK_SOURCE_DIR@/CoreUI/BundleTesting/*.cpp @MITK_SOURCE_DIR@/CoreUI/BundleTesting/*.h @MITK_SOURCE_DIR@/CoreUI/BundleTesting/org.mitk.gui.qt.common.tests/*.cpp @MITK_SOURCE_DIR@/CoreUI/BundleTesting/org.mitk.gui.qt.common.tests/*.h @MITK_SOURCE_DIR@/CoreUI/BundleTesting/org.mitk.gui.qt.common.tests/src/*.cpp @MITK_SOURCE_DIR@/CoreUI/BundleTesting/org.mitk.gui.qt.common.tests/src/*.h @MITK_SOURCE_DIR@/CoreUI/BundleTesting/org.mitk.gui.qt.common.tests/src/api/*.cpp @MITK_SOURCE_DIR@/CoreUI/BundleTesting/org.mitk.gui.qt.common.tests/src/api/*.h @MITK_SOURCE_DIR@/CoreUI/Bundles/org.mitk.core.services/*.cpp @MITK_SOURCE_DIR@/CoreUI/Bundles/org.mitk.core.services/*.h @MITK_SOURCE_DIR@/CoreUI/Bundles/org.mitk.core.services/src/*.cpp @MITK_SOURCE_DIR@/CoreUI/Bundles/org.mitk.core.services/src/*.h @MITK_SOURCE_DIR@/CoreUI/Bundles/org.mitk.core.services/src/internal/*.cpp @MITK_SOURCE_DIR@/CoreUI/Bundles/org.mitk.core.services/src/internal/*.h @MITK_SOURCE_DIR@/CoreUI/Bundles/org.mitk.gui.qt.application/*.cpp @MITK_SOURCE_DIR@/CoreUI/Bundles/org.mitk.gui.qt.application/*.h @MITK_SOURCE_DIR@/CoreUI/Bundles/org.mitk.gui.qt.application/src/*.cpp @MITK_SOURCE_DIR@/CoreUI/Bundles/org.mitk.gui.qt.application/src/*.h @MITK_SOURCE_DIR@/CoreUI/Bundles/org.mitk.gui.qt.application/src/internal/*.cpp @MITK_SOURCE_DIR@/CoreUI/Bundles/org.mitk.gui.qt.application/src/internal/*.h @MITK_SOURCE_DIR@/CoreUI/Bundles/org.mitk.gui.qt.common/*.cpp @MITK_SOURCE_DIR@/CoreUI/Bundles/org.mitk.gui.qt.common/*.h @MITK_SOURCE_DIR@/CoreUI/Bundles/org.mitk.gui.qt.common/src/*.cpp @MITK_SOURCE_DIR@/CoreUI/Bundles/org.mitk.gui.qt.common/src/*.h @MITK_SOURCE_DIR@/CoreUI/Bundles/org.mitk.gui.qt.common/src/internal/*.cpp @MITK_SOURCE_DIR@/CoreUI/Bundles/org.mitk.gui.qt.common/src/internal/*.h @MITK_SOURCE_DIR@/CoreUI/Bundles/org.mitk.gui.common/*.cpp @MITK_SOURCE_DIR@/CoreUI/Bundles/org.mitk.gui.common/*.h @MITK_SOURCE_DIR@/CoreUI/Bundles/org.mitk.gui.common/src/*.cpp @MITK_SOURCE_DIR@/CoreUI/Bundles/org.mitk.gui.common/src/*.h @MITK_SOURCE_DIR@/Modules/MitkExt/*.cpp @MITK_SOURCE_DIR@/Modules/MitkExt/*.h @MITK_SOURCE_DIR@/Modules/MitkExt/Algorithms/*.cpp @MITK_SOURCE_DIR@/Modules/MitkExt/Algorithms/*.h @MITK_SOURCE_DIR@/Modules/MitkExt/Interactions/*.cpp @MITK_SOURCE_DIR@/Modules/MitkExt/Interactions/*.h @MITK_SOURCE_DIR@/Modules/MitkExt/DataManagement/*.cpp @MITK_SOURCE_DIR@/Modules/MitkExt/DataManagement/*.h @MITK_SOURCE_DIR@/Modules/MitkExt/DataManagement/mitkDataStorage/*.cpp @MITK_SOURCE_DIR@/Modules/MitkExt/DataManagement/mitkDataStorage/*.h @MITK_SOURCE_DIR@/Modules/MitkExt/Controllers/*.cpp @MITK_SOURCE_DIR@/Modules/MitkExt/Controllers/*.h @MITK_SOURCE_DIR@/Modules/MitkExt/Rendering/*.cpp @MITK_SOURCE_DIR@/Modules/MitkExt/Rendering/*.h @MITK_SOURCE_DIR@/Modules/MitkExt/IO/*.cpp @MITK_SOURCE_DIR@/Modules/MitkExt/IO/*.h @MITK_SOURCE_DIR@/Modules/MitkExt/Testing/*.cpp @MITK_SOURCE_DIR@/Modules/MitkExt/Testing/*.h @MITK_SOURCE_DIR@/Modules/MitkExt/Testing/Data/*.cpp @MITK_SOURCE_DIR@/Modules/MitkExt/Testing/Data/*.h @MITK_SOURCE_DIR@/Modules/RigidRegistration/*.cpp @MITK_SOURCE_DIR@/Modules/RigidRegistration/*.h @MITK_SOURCE_DIR@/Modules/RigidRegistration/Testing/*.cpp @MITK_SOURCE_DIR@/Modules/RigidRegistration/Testing/*.h @MITK_SOURCE_DIR@/Modules/IGTUI/*.cpp @MITK_SOURCE_DIR@/Modules/IGTUI/*.h @MITK_SOURCE_DIR@/Modules/IGTUI/Qmitk/*.cpp @MITK_SOURCE_DIR@/Modules/IGTUI/Qmitk/*.h @MITK_SOURCE_DIR@/Modules/RigidRegistrationUI/*.cpp @MITK_SOURCE_DIR@/Modules/RigidRegistrationUI/*.h @MITK_SOURCE_DIR@/Modules/RigidRegistrationUI/RigidRegistrationTransforms/*.cpp @MITK_SOURCE_DIR@/Modules/RigidRegistrationUI/RigidRegistrationTransforms/*.h @MITK_SOURCE_DIR@/Modules/RigidRegistrationUI/RigidRegistrationOptimizer/*.cpp @MITK_SOURCE_DIR@/Modules/RigidRegistrationUI/RigidRegistrationOptimizer/*.h @MITK_SOURCE_DIR@/Modules/RigidRegistrationUI/RigidRegistrationMetrics/*.cpp @MITK_SOURCE_DIR@/Modules/RigidRegistrationUI/RigidRegistrationMetrics/*.h @MITK_SOURCE_DIR@/Modules/GPGPU/*.cpp @MITK_SOURCE_DIR@/Modules/GPGPU/*.h @MITK_SOURCE_DIR@/Modules/DeformableRegistrationUI/*.cpp @MITK_SOURCE_DIR@/Modules/DeformableRegistrationUI/*.h @MITK_SOURCE_DIR@/Modules/FLApplications/*.cpp @MITK_SOURCE_DIR@/Modules/FLApplications/*.h @MITK_SOURCE_DIR@/Modules/FLApplications/MITKFLExample/*.cpp @MITK_SOURCE_DIR@/Modules/FLApplications/MITKFLExample/*.h @MITK_SOURCE_DIR@/Modules/QmitkExt/*.cpp @MITK_SOURCE_DIR@/Modules/QmitkExt/*.h @MITK_SOURCE_DIR@/Modules/QmitkExt/QmitkPropertyObservers/*.cpp @MITK_SOURCE_DIR@/Modules/QmitkExt/QmitkPropertyObservers/*.h @MITK_SOURCE_DIR@/Modules/QmitkExt/QmitkFunctionalityComponents/*.cpp @MITK_SOURCE_DIR@/Modules/QmitkExt/QmitkFunctionalityComponents/*.h @MITK_SOURCE_DIR@/Modules/QmitkExt/QmitkAboutDialog/*.cpp @MITK_SOURCE_DIR@/Modules/QmitkExt/QmitkAboutDialog/*.h @MITK_SOURCE_DIR@/Modules/QmitkExt/Testing/*.cpp @MITK_SOURCE_DIR@/Modules/QmitkExt/Testing/*.h @MITK_SOURCE_DIR@/Modules/QmitkExt/QmitkApplicationBase/*.cpp @MITK_SOURCE_DIR@/Modules/QmitkExt/QmitkApplicationBase/*.h @MITK_SOURCE_DIR@/Modules/SceneSerialization/*.cpp @MITK_SOURCE_DIR@/Modules/SceneSerialization/*.h @MITK_SOURCE_DIR@/Modules/SceneSerialization/BasePropertySerializer/*.cpp @MITK_SOURCE_DIR@/Modules/SceneSerialization/BasePropertySerializer/*.h @MITK_SOURCE_DIR@/Modules/SceneSerialization/BaseDataSerializer/*.cpp @MITK_SOURCE_DIR@/Modules/SceneSerialization/BaseDataSerializer/*.h @MITK_SOURCE_DIR@/Modules/SceneSerialization/Testing/*.cpp @MITK_SOURCE_DIR@/Modules/SceneSerialization/Testing/*.h @MITK_SOURCE_DIR@/Modules/SceneSerialization/BasePropertyDeserializer/*.cpp @MITK_SOURCE_DIR@/Modules/SceneSerialization/BasePropertyDeserializer/*.h @MITK_SOURCE_DIR@/Modules/FLmitk/*.cpp @MITK_SOURCE_DIR@/Modules/FLmitk/*.h @MITK_SOURCE_DIR@/Modules/OpenCVVideoSupport/*.cpp @MITK_SOURCE_DIR@/Modules/OpenCVVideoSupport/*.h @MITK_SOURCE_DIR@/Modules/OpenCVVideoSupport/Testing/*.cpp @MITK_SOURCE_DIR@/Modules/OpenCVVideoSupport/Testing/*.h @MITK_SOURCE_DIR@/Modules/DeformableRegistration/*.cpp @MITK_SOURCE_DIR@/Modules/DeformableRegistration/*.h @MITK_SOURCE_DIR@/Modules/DeformableRegistration/Testing/*.cpp @MITK_SOURCE_DIR@/Modules/DeformableRegistration/Testing/*.h @MITK_SOURCE_DIR@/Modules/DiffusionImaging/*.cpp @MITK_SOURCE_DIR@/Modules/DiffusionImaging/*.h @MITK_SOURCE_DIR@/Modules/DiffusionImaging/Reconstruction/*.cpp @MITK_SOURCE_DIR@/Modules/DiffusionImaging/Reconstruction/*.h @MITK_SOURCE_DIR@/Modules/DiffusionImaging/Algorithms/*.cpp @MITK_SOURCE_DIR@/Modules/DiffusionImaging/Algorithms/*.h @MITK_SOURCE_DIR@/Modules/DiffusionImaging/Tractography/*.cpp @MITK_SOURCE_DIR@/Modules/DiffusionImaging/Tractography/*.h @MITK_SOURCE_DIR@/Modules/DiffusionImaging/Rendering/*.cpp @MITK_SOURCE_DIR@/Modules/DiffusionImaging/Rendering/*.h @MITK_SOURCE_DIR@/Modules/DiffusionImaging/DicomImport/*.cpp @MITK_SOURCE_DIR@/Modules/DiffusionImaging/DicomImport/*.h @MITK_SOURCE_DIR@/Modules/DiffusionImaging/Testing/*.cpp @MITK_SOURCE_DIR@/Modules/DiffusionImaging/Testing/*.h @MITK_SOURCE_DIR@/Modules/DiffusionImaging/IODataStructures/*.cpp @MITK_SOURCE_DIR@/Modules/DiffusionImaging/IODataStructures/*.h @MITK_SOURCE_DIR@/Modules/DiffusionImaging/IODataStructures/DiffusionWeightedImages/*.cpp @MITK_SOURCE_DIR@/Modules/DiffusionImaging/IODataStructures/DiffusionWeightedImages/*.h @MITK_SOURCE_DIR@/Modules/DiffusionImaging/IODataStructures/TensorImages/*.cpp @MITK_SOURCE_DIR@/Modules/DiffusionImaging/IODataStructures/TensorImages/*.h @MITK_SOURCE_DIR@/Modules/DiffusionImaging/IODataStructures/QBallImages/*.cpp @MITK_SOURCE_DIR@/Modules/DiffusionImaging/IODataStructures/QBallImages/*.h @MITK_SOURCE_DIR@/Modules/IGT/*.cpp @MITK_SOURCE_DIR@/Modules/IGT/*.h @MITK_SOURCE_DIR@/Modules/IGT/IGTTrackingDevices/*.cpp @MITK_SOURCE_DIR@/Modules/IGT/IGTTrackingDevices/*.h @MITK_SOURCE_DIR@/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/*.cpp @MITK_SOURCE_DIR@/Modules/IGT/IGTTrackingDevices/TrackingVolumeData/*.h @MITK_SOURCE_DIR@/Modules/IGT/IGTFilters/*.cpp @MITK_SOURCE_DIR@/Modules/IGT/IGTFilters/*.h @MITK_SOURCE_DIR@/Modules/IGT/IGTToolManagement/*.cpp @MITK_SOURCE_DIR@/Modules/IGT/IGTToolManagement/*.h @MITK_SOURCE_DIR@/Modules/IGT/IGTTutorial/*.cpp @MITK_SOURCE_DIR@/Modules/IGT/IGTTutorial/*.h @MITK_SOURCE_DIR@/Modules/IGT/Testing/*.cpp @MITK_SOURCE_DIR@/Modules/IGT/Testing/*.h @MITK_SOURCE_DIR@/Modules/IGT/Testing/Data/*.cpp @MITK_SOURCE_DIR@/Modules/IGT/Testing/Data/*.h @MITK_SOURCE_DIR@/Modules/Bundles/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.viewinitialization/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.viewinitialization/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.viewinitialization/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.viewinitialization/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.viewinitialization/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.viewinitialization/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.pointbasedregistration/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.pointbasedregistration/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.pointbasedregistration/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.pointbasedregistration/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.pointbasedregistration/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.pointbasedregistration/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.rigidregistration/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.rigidregistration/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.rigidregistration/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.rigidregistration/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.rigidregistration/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.rigidregistration/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.regiongrowing/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.regiongrowing/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.regiongrowing/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.regiongrowing/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.regiongrowing/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.regiongrowing/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.imagestatistics/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.imagestatistics/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.imagestatistics/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.imagestatistics/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.imagestatistics/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.imagestatistics/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.imagecropper/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.imagecropper/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.imagecropper/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.imagecropper/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.imagecropper/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.imagecropper/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.segmentation/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.segmentation/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.segmentation/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.segmentation/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.segmentation/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.segmentation/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.imagenavigator/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.imagenavigator/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.imagenavigator/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.imagenavigator/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.imagenavigator/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.imagenavigator/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.core.jobs/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.core.jobs/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.core.jobs/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.core.jobs/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.core.jobs/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.core.jobs/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.simplemeasurement/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.simplemeasurement/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.simplemeasurement/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.simplemeasurement/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.simplemeasurement/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.simplemeasurement/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.extapplication/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.extapplication/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.extapplication/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.extapplication/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.extapplication/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.extapplication/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.ext/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.ext/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.ext/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.ext/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.ext/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.ext/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.moviemaker/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.moviemaker/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.moviemaker/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.moviemaker/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.moviemaker/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.moviemaker/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.core.ext/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.core.ext/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.core.ext/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.core.ext/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.core.ext/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.core.ext/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.simpleexample/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.simpleexample/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.simpleexample/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.simpleexample/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.simpleexample/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.simpleexample/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.igttoolpairnavigation/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.igttoolpairnavigation/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.igttoolpairnavigation/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.igttoolpairnavigation/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.igttoolpairnavigation/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.igttoolpairnavigation/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.deformableregistration/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.deformableregistration/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.deformableregistration/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.deformableregistration/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.deformableregistration/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.deformableregistration/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.volumevisualization/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.volumevisualization/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.volumevisualization/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.volumevisualization/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.volumevisualization/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.volumevisualization/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.igttutorial/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.igttutorial/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.igttutorial/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.igttutorial/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.igttutorial/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.igttutorial/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.isosurface/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.isosurface/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.isosurface/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.isosurface/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.isosurface/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.isosurface/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.volumetry/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.volumetry/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.volumetry/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.volumetry/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.volumetry/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.volumetry/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.colourimageprocessing/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.colourimageprocessing/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.colourimageprocessing/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.colourimageprocessing/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.colourimageprocessing/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.colourimageprocessing/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.igtexample/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.igtexample/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.igtexample/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.igtexample/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.igtexample/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.igtexample/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.pointsetinteraction/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.pointsetinteraction/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.pointsetinteraction/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.pointsetinteraction/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.pointsetinteraction/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.pointsetinteraction/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.basicimageprocessing/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.basicimageprocessing/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.basicimageprocessing/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.basicimageprocessing/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.basicimageprocessing/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.basicimageprocessing/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.datamanager/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.datamanager/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.datamanager/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.datamanager/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.datamanager/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.datamanager/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.materialeditor/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.materialeditor/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.materialeditor/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.materialeditor/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.materialeditor/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.materialeditor/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.measurement/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.measurement/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.measurement/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.measurement/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.measurement/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.gui.qt.measurement/src/internal/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.diffusionimaging/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.diffusionimaging/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.diffusionimaging/src/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.diffusionimaging/src/*.h @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.diffusionimaging/src/internal/*.cpp @MITK_SOURCE_DIR@/Modules/Bundles/org.mitk.diffusionimaging/src/internal/*.h -@MITK_SOURCE_DIR@/Applications/ExtApp/*.cpp -@MITK_SOURCE_DIR@/Applications/ExtApp/*.h +@MITK_SOURCE_DIR@/Applications/mitkWorkbench/*.cpp +@MITK_SOURCE_DIR@/Applications/mitkWorkbench/*.h @MITK_SOURCE_DIR@/Applications/Tutorial/*.cpp @MITK_SOURCE_DIR@/Applications/Tutorial/*.h @MITK_SOURCE_DIR@/Applications/CoreApp/*.cpp @MITK_SOURCE_DIR@/Applications/CoreApp/*.h