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 4ed3bf4d41..968578ae91 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,163 +1,174 @@ /*=================================================================== 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); +#ifdef __APPLE__ + QFont fnt = ui.tableView->font(); + fnt.setPointSize(11); + ui.tableView->setFont(fnt); +#endif 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.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 ) { + ui.tableView->setVisible(false); ui.tableView->resizeRowsToContents(); //only resize columns when first entry is added static bool first = true; if(first) { ui.tableView->resizeColumnsToContents(); first = false; } + ui.tableView->setVisible(true); QTimer::singleShot(0,this,SLOT( slotScrollDown() ) ); } void QtLogView::showEvent( QShowEvent * event ) { + ui.tableView->setVisible(false); ui.tableView->resizeColumnsToContents(); ui.tableView->resizeRowsToContents(); + ui.tableView->setVisible(true); } void QtLogView::on_ShowAdvancedFields_clicked( bool checked ) { + ui.tableView->setVisible(false); QtLogPlugin::GetInstance()->GetLogModel()->SetShowAdvancedFiels( checked ); ui.tableView->resizeColumnsToContents(); + ui.tableView->setVisible(true); 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 ) { + ui.tableView->setVisible(false); QtLogPlugin::GetInstance()->GetLogModel()->SetShowCategory( checked ); ui.tableView->resizeColumnsToContents(); + ui.tableView->setVisible(true); 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(); 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.ui b/BlueBerry/Bundles/org.blueberry.ui.qt.log/src/internal/berryQtLogView.ui index a2374ea8cc..adc2d4fca9 100644 --- a/BlueBerry/Bundles/org.blueberry.ui.qt.log/src/internal/berryQtLogView.ui +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.log/src/internal/berryQtLogView.ui @@ -1,180 +1,177 @@ QtLogViewClass 0 0 596 - 282 + 292 0 0 QtLogView 0 0 Filter: 0 0 8 Qt::ScrollBarAlwaysOn false false false QAbstractItemView::NoDragDrop true QAbstractItemView::ExtendedSelection QAbstractItemView::SelectRows Qt::ElideLeft QAbstractItemView::ScrollPerPixel QAbstractItemView::ScrollPerPixel false Qt::DashLine false false 64 0 false 16 false 8 Show categories true advanced fields false Qt::Horizontal 40 20 Copy to clipboard - - - - + 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 0a94374be3..80ee8b8f98 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"); + 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"); + 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("Level"); - case 1: return QVariant("Message"); - case 2: return QVariant("Category"); + 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/CMakeExternals/DCMTK.cmake b/CMakeExternals/DCMTK.cmake index 3265921650..8d6b36a1bd 100644 --- a/CMakeExternals/DCMTK.cmake +++ b/CMakeExternals/DCMTK.cmake @@ -1,65 +1,70 @@ #----------------------------------------------------------------------------- # DCMTK #----------------------------------------------------------------------------- if(MITK_USE_DCMTK) # Sanity checks if(DEFINED DCMTK_DIR AND NOT EXISTS ${DCMTK_DIR}) message(FATAL_ERROR "DCMTK_DIR variable is defined but corresponds to non-existing directory") endif() set(proj DCMTK) set(proj_DEPENDENCIES ) set(DCMTK_DEPENDS ${proj}) +if(CMAKE_GENERATOR MATCHES Xcode) + set(DCMTK_PATCH_COMMAND ${CMAKE_COMMAND} -DTEMPLATE_FILE:FILEPATH=${MITK_SOURCE_DIR}/CMakeExternals/EmptyFileForPatching.dummy -P ${MITK_SOURCE_DIR}/CMakeExternals/PatchDCMTK-20122202.cmake) +endif() + if(NOT DEFINED DCMTK_DIR) if(UNIX) set(DCMTK_CXX_FLAGS "-fPIC") set(DCMTK_C_FLAGS "-fPIC") endif(UNIX) if(DCMTK_DICOM_ROOT_ID) set(DCMTK_CXX_FLAGS "${DCMTK_CXX_FLAGS} -DSITE_UID_ROOT=\\\"${DCMTK_DICOM_ROOT_ID}\\\"") set(DCMTK_C_FLAGS "${DCMTK_CXX_FLAGS} -DSITE_UID_ROOT=\\\"${DCMTK_DICOM_ROOT_ID}\\\"") endif() set (dcmtk_shared_flags "-DBUILD_SHARED_LIBS:BOOL=${MITK_DCMTK_BUILD_SHARED_LIBS}") if (NOT MITK_DCMTK_BUILD_SHARED_LIBS) set (dcmtk_shared_flags ${dcmtk_shared_flags} "-DDCMTK_FORCE_FPIC_ON_UNIX:BOOL=ON") endif() ExternalProject_Add(${proj} SOURCE_DIR ${CMAKE_BINARY_DIR}/${proj}-src BINARY_DIR ${proj}-build PREFIX ${proj}-cmake URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/dcmtk-3.6.1_20120222.tar.gz URL_MD5 86fa9e0f91e4e0c6b44d513ea48391d6 INSTALL_DIR ${proj}-install + PATCH_COMMAND ${DCMTK_PATCH_COMMAND} CMAKE_GENERATOR ${gen} CMAKE_ARGS ${ep_common_args} -DDCMTK_OVERWRITE_WIN32_COMPILER_FLAGS:BOOL=OFF ${dcmtk_shared_flags} "-DCMAKE_CXX_FLAGS:STRING=${ep_common_CXX_FLAGS} ${DCMTK_CXX_FLAGS}" "-DCMAKE_C_FLAGS:STRING=${ep_common_C_FLAGS} ${DCMTK_C_FLAGS}" -DCMAKE_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 70ab82637a..a1de5f6636 100644 --- a/CMakeExternals/MITKData.cmake +++ b/CMakeExternals/MITKData.cmake @@ -1,39 +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 16d96097) + set(revision_tag 66dc8282) #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/CMakeExternals/MITKData.cmake b/CMakeExternals/MITKData.cmake.BACKUP.9452.cmake similarity index 91% copy from CMakeExternals/MITKData.cmake copy to CMakeExternals/MITKData.cmake.BACKUP.9452.cmake index 70ab82637a..c2dd0c371b 100644 --- a/CMakeExternals/MITKData.cmake +++ b/CMakeExternals/MITKData.cmake.BACKUP.9452.cmake @@ -1,39 +1,43 @@ #----------------------------------------------------------------------------- # 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) +<<<<<<< HEAD set(revision_tag 16d96097) +======= + set(revision_tag 66dc8282) +>>>>>>> bug-14224-DefaultCalibrationFiles #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/CMakeExternals/MITKData.cmake b/CMakeExternals/MITKData.cmake.BASE.9452.cmake similarity index 96% copy from CMakeExternals/MITKData.cmake copy to CMakeExternals/MITKData.cmake.BASE.9452.cmake index 70ab82637a..a01699470f 100644 --- a/CMakeExternals/MITKData.cmake +++ b/CMakeExternals/MITKData.cmake.BASE.9452.cmake @@ -1,39 +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 16d96097) + set(revision_tag 55445f45) #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/CMakeExternals/MITKData.cmake b/CMakeExternals/MITKData.cmake.LOCAL.9452.cmake similarity index 100% copy from CMakeExternals/MITKData.cmake copy to CMakeExternals/MITKData.cmake.LOCAL.9452.cmake diff --git a/CMakeExternals/MITKData.cmake b/CMakeExternals/MITKData.cmake.REMOTE.9452.cmake similarity index 96% copy from CMakeExternals/MITKData.cmake copy to CMakeExternals/MITKData.cmake.REMOTE.9452.cmake index 70ab82637a..a1de5f6636 100644 --- a/CMakeExternals/MITKData.cmake +++ b/CMakeExternals/MITKData.cmake.REMOTE.9452.cmake @@ -1,39 +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 16d96097) + set(revision_tag 66dc8282) #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/CMakeExternals/PatchDCMTK-20122202.cmake b/CMakeExternals/PatchDCMTK-20122202.cmake new file mode 100644 index 0000000000..274bcc8dfd --- /dev/null +++ b/CMakeExternals/PatchDCMTK-20122202.cmake @@ -0,0 +1,24 @@ +# Called by DCMTK.cmake (ExternalProject_Add) as a patch for DCMTK. +# Changes DCMTK_BUILD_DATE so that superbuild will work with Xcode + +# read whole file +file(STRINGS CMakeLists.txt sourceCode NEWLINE_CONSUME) + +# Changing the way DCMTK_BUILD_DATE is set in CMakeLists.txt +# This way it is not a compiler flag but set in the dcmtk config file +string(REGEX REPLACE "ADD_DEFINITIONS[(]\"-DDCMTK_BUILD_DATE" "set(DCMTK_BUILD_DATE \"\\\\\"2012-02-22\\\\\"\")\n#ADD_DEFINITIONS[(]\"-DDCMTK_BUILD_DATE" sourceCode ${sourceCode}) + +# set variable CONTENTS, which is substituted in TEMPLATE_FILE +set(CONTENTS ${sourceCode}) +configure_file(${TEMPLATE_FILE} CMakeLists.txt @ONLY) + +# read whole file +file(STRINGS CMake/osconfig.h.in sourceCode2 NEWLINE_CONSUME) + +# Add DCMTK_BUILD_DATE to osconfig.h.in +string(REGEX REPLACE "\"@DCMTK_PACKAGE_DATE@\"" "\"@DCMTK_PACKAGE_DATE@\"\n\n#define DCMTK_BUILD_DATE @DCMTK_BUILD_DATE@\n" sourceCode2 ${sourceCode2}) + +# set variable CONTENTS, which is substituted in TEMPLATE_FILE +set(CONTENTS ${sourceCode2}) +configure_file(${TEMPLATE_FILE} CMake/osconfig.h.in @ONLY) + diff --git a/Core/Code/Algorithms/mitkExtractSliceFilter.cpp b/Core/Code/Algorithms/mitkExtractSliceFilter.cpp index a62493d69b..1347945728 100644 --- a/Core/Code/Algorithms/mitkExtractSliceFilter.cpp +++ b/Core/Code/Algorithms/mitkExtractSliceFilter.cpp @@ -1,600 +1,482 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkExtractSliceFilter.h" #include #include #include #include #include #include - +#include mitk::ExtractSliceFilter::ExtractSliceFilter(vtkImageReslice* reslicer ){ if(reslicer == NULL){ m_Reslicer = vtkSmartPointer::New(); } else { m_Reslicer = reslicer; } m_TimeStep = 0; m_Reslicer->ReleaseDataFlagOn(); m_InterpolationMode = ExtractSliceFilter::RESLICE_NEAREST; m_ResliceTransform = NULL; m_InPlaneResampleExtentByGeometry = false; m_OutPutSpacing = new mitk::ScalarType[2]; m_OutputDimension = 2; m_ZSpacing = 1.0; m_ZMin = 0; m_ZMax = 0; m_VtkOutputRequested = false; } mitk::ExtractSliceFilter::~ExtractSliceFilter(){ m_ResliceTransform = NULL; m_WorldGeometry = NULL; delete [] m_OutPutSpacing; } void mitk::ExtractSliceFilter::GenerateOutputInformation(){ //TODO try figure out how to set the specs of the slice before it is actually extracted /*Image::Pointer output = this->GetOutput(); Image::ConstPointer input = this->GetInput(); if (input.IsNull()) return; unsigned int dimensions[2]; dimensions[0] = m_WorldGeometry->GetExtent(0); dimensions[1] = m_WorldGeometry->GetExtent(1); output->Initialize(input->GetPixelType(), 2, dimensions, 1);*/ } void mitk::ExtractSliceFilter::GenerateInputRequestedRegion(){ //As we want all pixel information fo the image in our plane, the requested region //is set to the largest possible region in the image. //This is needed because an oblique plane has a larger extent then the image //and the in pipeline it is checked via PropagateResquestedRegion(). But the //extent of the slice is actually fitting because it is oblique within the image. ImageToImageFilter::InputImagePointer input = const_cast< ImageToImageFilter::InputImageType* > ( this->GetInput() ); input->SetRequestedRegionToLargestPossibleRegion(); } mitk::ScalarType* mitk::ExtractSliceFilter::GetOutputSpacing(){ return m_OutPutSpacing; } void mitk::ExtractSliceFilter::GenerateData(){ mitk::Image *input = const_cast< mitk::Image * >( this->GetInput() ); if (!input) { MITK_ERROR << "mitk::ExtractSliceFilter: No input image available. Please set the input!" << std::endl; itkExceptionMacro("mitk::ExtractSliceFilter: No input image available. Please set the input!"); return; } if(!m_WorldGeometry) { MITK_ERROR << "mitk::ExtractSliceFilter: No Geometry for reslicing available." << std::endl; itkExceptionMacro("mitk::ExtractSliceFilter: No Geometry for reslicing available."); return; } const TimeSlicedGeometry *inputTimeGeometry = this->GetInput()->GetTimeSlicedGeometry(); if ( ( inputTimeGeometry == NULL ) || ( inputTimeGeometry->GetTimeSteps() == 0 ) ) { itkWarningMacro(<<"Error reading input image TimeSlicedGeometry."); return; } // is it a valid timeStep? if ( inputTimeGeometry->IsValidTime( m_TimeStep ) == false ) { itkWarningMacro(<<"This is not a valid timestep: "<< m_TimeStep ); return; } // check if there is something to display. if ( ! input->IsVolumeSet( m_TimeStep ) ) { itkWarningMacro(<<"No volume data existent at given timestep "<< m_TimeStep ); return; } /*================#BEGIN setup vtkImageRslice properties================*/ Point3D origin; Vector3D right, bottom, normal; double widthInMM, heightInMM; Vector2D extent; const PlaneGeometry* planeGeometry = dynamic_cast(m_WorldGeometry); if ( planeGeometry != NULL ) { //if the worldGeomatry is a PlaneGeometry everthing is straight forward origin = planeGeometry->GetOrigin(); right = planeGeometry->GetAxisVector( 0 ); bottom = planeGeometry->GetAxisVector( 1 ); normal = planeGeometry->GetNormal(); if ( m_InPlaneResampleExtentByGeometry ) { // Resampling grid corresponds to the current world geometry. This // means that the spacing of the output 2D image depends on the // currently selected world geometry, and *not* on the image itself. extent[0] = m_WorldGeometry->GetExtent( 0 ); extent[1] = m_WorldGeometry->GetExtent( 1 ); } else { // Resampling grid corresponds to the input geometry. This means that // the spacing of the output 2D image is directly derived from the // associated input image, regardless of the currently selected world // geometry. Vector3D rightInIndex, bottomInIndex; inputTimeGeometry->GetGeometry3D( m_TimeStep )->WorldToIndex( right, rightInIndex ); inputTimeGeometry->GetGeometry3D( m_TimeStep )->WorldToIndex( bottom, bottomInIndex ); extent[0] = rightInIndex.GetNorm(); extent[1] = bottomInIndex.GetNorm(); } // Get the extent of the current world geometry and calculate resampling // spacing therefrom. widthInMM = m_WorldGeometry->GetExtentInMM( 0 ); heightInMM = m_WorldGeometry->GetExtentInMM( 1 ); m_OutPutSpacing[0] = widthInMM / extent[0]; m_OutPutSpacing[1] = heightInMM / extent[1]; right.Normalize(); bottom.Normalize(); normal.Normalize(); /* * Transform the origin to center based coordinates. * Note: * This is needed besause vtk's origin is center based too (!!!) ( see 'The VTK book' page 88 ) * and the worldGeometry surrouding the image is no imageGeometry. So the worldGeometry * has its origin at the corner of the voxel and needs to be transformed. */ origin += right * ( m_OutPutSpacing[0] * 0.5 ); origin += bottom * ( m_OutPutSpacing[1] * 0.5 ); //set the tranform for reslicing. // Use inverse transform of the input geometry for reslicing the 3D image. // This is needed if the image volume already transformed if(m_ResliceTransform.IsNotNull()) m_Reslicer->SetResliceTransform(m_ResliceTransform->GetVtkTransform()->GetLinearInverse()); // Set background level to TRANSLUCENT (see Geometry2DDataVtkMapper3D), // else the background of the image turns out gray m_Reslicer->SetBackgroundLevel( -32768 ); } else{ //Code for curved planes, mostly taken 1:1 from imageVtkMapper2D and not tested yet. // Do we have an AbstractTransformGeometry? // This is the case for AbstractTransformGeometry's (e.g. a ThinPlateSplineCurvedGeometry ) const mitk::AbstractTransformGeometry* abstractGeometry = dynamic_cast< const AbstractTransformGeometry * >(m_WorldGeometry); if(abstractGeometry != NULL) { m_ResliceTransform = abstractGeometry; extent[0] = abstractGeometry->GetParametricExtent(0); extent[1] = abstractGeometry->GetParametricExtent(1); widthInMM = abstractGeometry->GetParametricExtentInMM(0); heightInMM = abstractGeometry->GetParametricExtentInMM(1); m_OutPutSpacing[0] = widthInMM / extent[0]; m_OutPutSpacing[1] = heightInMM / extent[1]; origin = abstractGeometry->GetPlane()->GetOrigin(); right = abstractGeometry->GetPlane()->GetAxisVector(0); right.Normalize(); bottom = abstractGeometry->GetPlane()->GetAxisVector(1); bottom.Normalize(); normal = abstractGeometry->GetPlane()->GetNormal(); normal.Normalize(); // Use a combination of the InputGeometry *and* the possible non-rigid // AbstractTransformGeometry for reslicing the 3D Image vtkSmartPointer composedResliceTransform = vtkSmartPointer::New(); composedResliceTransform->Identity(); composedResliceTransform->Concatenate( inputTimeGeometry->GetGeometry3D( m_TimeStep )->GetVtkTransform()->GetLinearInverse() ); composedResliceTransform->Concatenate( abstractGeometry->GetVtkAbstractTransform() ); m_Reslicer->SetResliceTransform( composedResliceTransform ); // Set background level to BLACK instead of translucent, to avoid // boundary artifacts (see Geometry2DDataVtkMapper3D) m_Reslicer->SetBackgroundLevel( -1023 ); } else { itkExceptionMacro("mitk::ExtractSliceFilter: No fitting geometry for reslice axis!"); return; } } if(m_ResliceTransform.IsNotNull()){ //if the resliceTransform is set the reslice axis are recalculated. //Thus the geometry information is not fitting. Therefor a unitSpacingFilter //is used to set up a global spacing of 1 and compensate the transform. vtkSmartPointer unitSpacingImageFilter = vtkSmartPointer::New() ; unitSpacingImageFilter->ReleaseDataFlagOn(); unitSpacingImageFilter->SetOutputSpacing( 1.0, 1.0, 1.0 ); unitSpacingImageFilter->SetInput( input->GetVtkImageData(m_TimeStep) ); m_Reslicer->SetInput(unitSpacingImageFilter->GetOutput() ); } else { //if no tranform is set the image can be used directly m_Reslicer->SetInput(input->GetVtkImageData(m_TimeStep)); } /*setup the plane where vktImageReslice extracts the slice*/ //ResliceAxesOrigin is the ancor point of the plane double originInVtk[3]; itk2vtk(origin, originInVtk); m_Reslicer->SetResliceAxesOrigin(originInVtk); //the cosines define the plane: x and y are the direction vectors, n is the planes normal //this specifies a matrix 3x3 // x1 y1 n1 // x2 y2 n2 // x3 y3 n3 double cosines[9]; vnl2vtk(right.GetVnlVector(), cosines);//x vnl2vtk(bottom.GetVnlVector(), cosines + 3);//y vnl2vtk(normal.GetVnlVector(), cosines + 6);//n m_Reslicer->SetResliceAxesDirectionCosines(cosines); //we only have one slice, not a volume m_Reslicer->SetOutputDimensionality(m_OutputDimension); //set the interpolation mode for slicing switch(this->m_InterpolationMode){ case RESLICE_NEAREST: m_Reslicer->SetInterpolationModeToNearestNeighbor(); break; case RESLICE_LINEAR: m_Reslicer->SetInterpolationModeToLinear(); break; case RESLICE_CUBIC: m_Reslicer->SetInterpolationModeToCubic(); default: //the default interpolation used by mitk m_Reslicer->SetInterpolationModeToNearestNeighbor(); } /*========== BEGIN setup extent of the slice ==========*/ int xMin, xMax, yMin, yMax; xMin = yMin = 0; xMax = static_cast< int >( extent[0]); yMax = static_cast< int >( extent[1]); vtkFloatingPointType sliceBounds[6]; if (m_WorldGeometry->GetReferenceGeometry()) { for ( int i = 0; i < 6; ++i ) { sliceBounds[i] = 0.0; } if (this->GetClippedPlaneBounds( m_WorldGeometry->GetReferenceGeometry(), planeGeometry, sliceBounds )) { // Calculate output extent (integer values) xMin = static_cast< int >( sliceBounds[0] / m_OutPutSpacing[0] + 0.5 ); xMax = static_cast< int >( sliceBounds[1] / m_OutPutSpacing[0] + 0.5 ); yMin = static_cast< int >( sliceBounds[2] / m_OutPutSpacing[1] + 0.5 ); yMax = static_cast< int >( sliceBounds[3] / m_OutPutSpacing[1] + 0.5 ); } // ELSE we use the default values } // Set the output extents! First included pixel index and last included pixel index // xMax and yMax are one after the last pixel. so they have to be decremented by 1. // In case we have a 2D image, xMax or yMax might be 0. in this case, do not decrement, but take 0. m_Reslicer->SetOutputExtent(xMin, std::max(0, xMax-1), yMin, std::max(0, yMax-1), m_ZMin, m_ZMax ); /*========== END setup extent of the slice ==========*/ m_Reslicer->SetOutputOrigin( 0.0, 0.0, 0.0 ); m_Reslicer->SetOutputSpacing( m_OutPutSpacing[0], m_OutPutSpacing[1], m_ZSpacing ); //TODO check the following lines, they are responsible wether vtk error outputs appear or not m_Reslicer->UpdateWholeExtent(); //this produces a bad allocation error for 2D images //m_Reslicer->GetOutput()->UpdateInformation(); //m_Reslicer->GetOutput()->SetUpdateExtentToWholeExtent(); //start the pipeline m_Reslicer->Update(); /*================ #END setup vtkImageRslice properties================*/ if(m_VtkOutputRequested){ return; //no converting to mitk //no mitk geometry will be set, as the output is vtkImageData only!!! } else { /*================ #BEGIN Get the slice from vtkImageReslice and convert it to mit::Image================*/ vtkImageData* reslicedImage; reslicedImage = m_Reslicer->GetOutput(); if(!reslicedImage) { itkWarningMacro(<<"Reslicer returned empty image"); return; } mitk::Image::Pointer resultImage = this->GetOutput(); //initialize resultimage with the specs of the vtkImageData object returned from vtkImageReslice if (reslicedImage->GetDataDimension() == 1) { // If original image was 2D, the slice might have an y extent of 0. // Still i want to ensure here that Image is 2D resultImage->Initialize(reslicedImage,1,-1,-1,1); } else { resultImage->Initialize(reslicedImage); } //transfer the voxel data resultImage->SetVolume(reslicedImage->GetScalarPointer()); //set the geometry from current worldgeometry for the reusultimage //this is needed that the image has the correct mitk geometry //the originalGeometry is the Geometry of the result slice AffineGeometryFrame3D::Pointer originalGeometryAGF = m_WorldGeometry->Clone(); Geometry2D::Pointer originalGeometry = dynamic_cast( originalGeometryAGF.GetPointer() ); originalGeometry->GetIndexToWorldTransform()->SetMatrix(m_WorldGeometry->GetIndexToWorldTransform()->GetMatrix()); //the origin of the worldGeometry is transformed to center based coordinates to be an imageGeometry Point3D sliceOrigin = originalGeometry->GetOrigin(); sliceOrigin += right * ( m_OutPutSpacing[0] * 0.5 ); sliceOrigin += bottom * ( m_OutPutSpacing[1] * 0.5 ); //a worldGeometry is no imageGeometry, thus it is manually set to true originalGeometry->ImageGeometryOn(); /*At this point we have to adjust the geometry because the origin isn't correct. The wrong origin is related to the rotation of the current world geometry plane. This causes errors on transfering world to index coordinates. We just shift the origin in each direction about the amount of the expanding (needed while rotating the plane). */ Vector3D axis0 = originalGeometry->GetAxisVector(0); Vector3D axis1 = originalGeometry->GetAxisVector(1); axis0.Normalize(); axis1.Normalize(); //adapt the origin. Note that for orthogonal planes the minima are '0' and thus the origin stays the same. sliceOrigin += (axis0 * (xMin * m_OutPutSpacing[0])) + (axis1 * (yMin * m_OutPutSpacing[1])); originalGeometry->SetOrigin(sliceOrigin); originalGeometry->Modified(); resultImage->SetGeometry( originalGeometry ); /*the bounds as well as the extent of the worldGeometry are not adapted correctly during crosshair rotation. This is only a quick fix and has to be evaluated. The new bounds are set via the max values of the calcuted slice extent. It will look like [ 0, x, 0, y, 0, 1]. */ mitk::BoundingBox::BoundsArrayType boundsCopy; boundsCopy[0] = boundsCopy[2] = boundsCopy[4] = 0; boundsCopy[5] = 1; boundsCopy[1] = xMax - xMin; boundsCopy[3] = yMax - yMin; resultImage->GetGeometry()->SetBounds(boundsCopy); /*================ #END Get the slice from vtkImageReslice and convert it to mitk Image================*/ } } bool mitk::ExtractSliceFilter::GetClippedPlaneBounds(vtkFloatingPointType bounds[6]){ if(!m_WorldGeometry || !this->GetInput()) return false; return this->GetClippedPlaneBounds(m_WorldGeometry->GetReferenceGeometry(), dynamic_cast< const PlaneGeometry * >( m_WorldGeometry ), bounds); } bool mitk::ExtractSliceFilter::GetClippedPlaneBounds( const Geometry3D *boundingGeometry, const PlaneGeometry *planeGeometry, vtkFloatingPointType *bounds ) { - bool b = this->CalculateClippedPlaneBounds(boundingGeometry, planeGeometry, bounds); + bool b = mitk::PlaneClipping::CalculateClippedPlaneBounds(boundingGeometry, planeGeometry, bounds); return b; } - - -bool mitk::ExtractSliceFilter -::CalculateClippedPlaneBounds( const Geometry3D *boundingGeometry, - const PlaneGeometry *planeGeometry, vtkFloatingPointType *bounds ) -{ - // Clip the plane with the bounding geometry. To do so, the corner points - // of the bounding box are transformed by the inverse transformation - // matrix, and the transformed bounding box edges derived therefrom are - // clipped with the plane z=0. The resulting min/max values are taken as - // bounds for the image reslicer. - const BoundingBox *boundingBox = boundingGeometry->GetBoundingBox(); - - BoundingBox::PointType bbMin = boundingBox->GetMinimum(); - BoundingBox::PointType bbMax = boundingBox->GetMaximum(); - - vtkPoints *points = vtkPoints::New(); - if(boundingGeometry->GetImageGeometry()) - { - points->InsertPoint( 0, bbMin[0]-0.5, bbMin[1]-0.5, bbMin[2]-0.5 ); - points->InsertPoint( 1, bbMin[0]-0.5, bbMin[1]-0.5, bbMax[2]-0.5 ); - points->InsertPoint( 2, bbMin[0]-0.5, bbMax[1]-0.5, bbMax[2]-0.5 ); - points->InsertPoint( 3, bbMin[0]-0.5, bbMax[1]-0.5, bbMin[2]-0.5 ); - points->InsertPoint( 4, bbMax[0]-0.5, bbMin[1]-0.5, bbMin[2]-0.5 ); - points->InsertPoint( 5, bbMax[0]-0.5, bbMin[1]-0.5, bbMax[2]-0.5 ); - points->InsertPoint( 6, bbMax[0]-0.5, bbMax[1]-0.5, bbMax[2]-0.5 ); - points->InsertPoint( 7, bbMax[0]-0.5, bbMax[1]-0.5, bbMin[2]-0.5 ); - } - else - { - points->InsertPoint( 0, bbMin[0], bbMin[1], bbMin[2] ); - points->InsertPoint( 1, bbMin[0], bbMin[1], bbMax[2] ); - points->InsertPoint( 2, bbMin[0], bbMax[1], bbMax[2] ); - points->InsertPoint( 3, bbMin[0], bbMax[1], bbMin[2] ); - points->InsertPoint( 4, bbMax[0], bbMin[1], bbMin[2] ); - points->InsertPoint( 5, bbMax[0], bbMin[1], bbMax[2] ); - points->InsertPoint( 6, bbMax[0], bbMax[1], bbMax[2] ); - points->InsertPoint( 7, bbMax[0], bbMax[1], bbMin[2] ); - } - - vtkPoints *newPoints = vtkPoints::New(); - - vtkTransform *transform = vtkTransform::New(); - transform->Identity(); - transform->Concatenate( - planeGeometry->GetVtkTransform()->GetLinearInverse() - ); - - transform->Concatenate( boundingGeometry->GetVtkTransform() ); - - transform->TransformPoints( points, newPoints ); - transform->Delete(); - - bounds[0] = bounds[2] = 10000000.0; - bounds[1] = bounds[3] = -10000000.0; - bounds[4] = bounds[5] = 0.0; - - this->LineIntersectZero( newPoints, 0, 1, bounds ); - this->LineIntersectZero( newPoints, 1, 2, bounds ); - this->LineIntersectZero( newPoints, 2, 3, bounds ); - this->LineIntersectZero( newPoints, 3, 0, bounds ); - this->LineIntersectZero( newPoints, 0, 4, bounds ); - this->LineIntersectZero( newPoints, 1, 5, bounds ); - this->LineIntersectZero( newPoints, 2, 6, bounds ); - this->LineIntersectZero( newPoints, 3, 7, bounds ); - this->LineIntersectZero( newPoints, 4, 5, bounds ); - this->LineIntersectZero( newPoints, 5, 6, bounds ); - this->LineIntersectZero( newPoints, 6, 7, bounds ); - this->LineIntersectZero( newPoints, 7, 4, bounds ); - - // clean up vtk data - points->Delete(); - newPoints->Delete(); - - if ( (bounds[0] > 9999999.0) || (bounds[2] > 9999999.0) - || (bounds[1] < -9999999.0) || (bounds[3] < -9999999.0) ) - { - return false; - } - else - { - // The resulting bounds must be adjusted by the plane spacing, since we - // we have so far dealt with index coordinates - const float *planeSpacing = planeGeometry->GetFloatSpacing(); - bounds[0] *= planeSpacing[0]; - bounds[1] *= planeSpacing[0]; - bounds[2] *= planeSpacing[1]; - bounds[3] *= planeSpacing[1]; - bounds[4] *= planeSpacing[2]; - bounds[5] *= planeSpacing[2]; - return true; - } -} - -bool mitk::ExtractSliceFilter -::LineIntersectZero( vtkPoints *points, int p1, int p2, - vtkFloatingPointType *bounds ) -{ - vtkFloatingPointType point1[3]; - vtkFloatingPointType point2[3]; - points->GetPoint( p1, point1 ); - points->GetPoint( p2, point2 ); - - if ( (point1[2] * point2[2] <= 0.0) && (point1[2] != point2[2]) ) - { - double x, y; - x = ( point1[0] * point2[2] - point1[2] * point2[0] ) / ( point2[2] - point1[2] ); - y = ( point1[1] * point2[2] - point1[2] * point2[1] ) / ( point2[2] - point1[2] ); - - if ( x < bounds[0] ) { bounds[0] = x; } - if ( x > bounds[1] ) { bounds[1] = x; } - if ( y < bounds[2] ) { bounds[2] = y; } - if ( y > bounds[3] ) { bounds[3] = y; } - bounds[4] = bounds[5] = 0.0; - return true; - } - return false; -} diff --git a/Core/Code/Algorithms/mitkExtractSliceFilter.h b/Core/Code/Algorithms/mitkExtractSliceFilter.h index 493569c056..8dd9ac2a14 100644 --- a/Core/Code/Algorithms/mitkExtractSliceFilter.h +++ b/Core/Code/Algorithms/mitkExtractSliceFilter.h @@ -1,186 +1,174 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #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 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; this->Modified(); } /** \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/mitkPlaneClipping.h b/Core/Code/Algorithms/mitkPlaneClipping.h new file mode 100644 index 0000000000..1d7da8505b --- /dev/null +++ b/Core/Code/Algorithms/mitkPlaneClipping.h @@ -0,0 +1,141 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef MITKPLANECLIPPING_H_HEADER_INCLUDED +#define MITKPLANECLIPPING_H_HEADER_INCLUDED + +#include +#include +#include +#include + +namespace mitk { +namespace PlaneClipping { + +/** \brief Internal helper method for intersection testing used only in CalculateClippedPlaneBounds() */ +static bool LineIntersectZero( vtkPoints *points, int p1, int p2, vtkFloatingPointType *bounds ) +{ + vtkFloatingPointType point1[3]; + vtkFloatingPointType point2[3]; + points->GetPoint( p1, point1 ); + points->GetPoint( p2, point2 ); + + if ( (point1[2] * point2[2] <= 0.0) && (point1[2] != point2[2]) ) + { + double x, y; + x = ( point1[0] * point2[2] - point1[2] * point2[0] ) / ( point2[2] - point1[2] ); + y = ( point1[1] * point2[2] - point1[2] * point2[1] ) / ( point2[2] - point1[2] ); + + if ( x < bounds[0] ) { bounds[0] = x; } + if ( x > bounds[1] ) { bounds[1] = x; } + if ( y < bounds[2] ) { bounds[2] = y; } + if ( y > bounds[3] ) { bounds[3] = y; } + bounds[4] = bounds[5] = 0.0; + return true; + } + return false; +} + +/** \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. */ +static bool CalculateClippedPlaneBounds( const Geometry3D *boundingGeometry, const PlaneGeometry *planeGeometry, vtkFloatingPointType *bounds ) +{ + // Clip the plane with the bounding geometry. To do so, the corner points + // of the bounding box are transformed by the inverse transformation + // matrix, and the transformed bounding box edges derived therefrom are + // clipped with the plane z=0. The resulting min/max values are taken as + // bounds for the image reslicer. + const mitk::BoundingBox *boundingBox = boundingGeometry->GetBoundingBox(); + + mitk::BoundingBox::PointType bbMin = boundingBox->GetMinimum(); + mitk::BoundingBox::PointType bbMax = boundingBox->GetMaximum(); + + vtkSmartPointer points = vtkSmartPointer::New(); + if(boundingGeometry->GetImageGeometry()) + { + points->InsertPoint( 0, bbMin[0]-0.5, bbMin[1]-0.5, bbMin[2]-0.5 ); + points->InsertPoint( 1, bbMin[0]-0.5, bbMin[1]-0.5, bbMax[2]-0.5 ); + points->InsertPoint( 2, bbMin[0]-0.5, bbMax[1]-0.5, bbMax[2]-0.5 ); + points->InsertPoint( 3, bbMin[0]-0.5, bbMax[1]-0.5, bbMin[2]-0.5 ); + points->InsertPoint( 4, bbMax[0]-0.5, bbMin[1]-0.5, bbMin[2]-0.5 ); + points->InsertPoint( 5, bbMax[0]-0.5, bbMin[1]-0.5, bbMax[2]-0.5 ); + points->InsertPoint( 6, bbMax[0]-0.5, bbMax[1]-0.5, bbMax[2]-0.5 ); + points->InsertPoint( 7, bbMax[0]-0.5, bbMax[1]-0.5, bbMin[2]-0.5 ); + } + else + { + points->InsertPoint( 0, bbMin[0], bbMin[1], bbMin[2] ); + points->InsertPoint( 1, bbMin[0], bbMin[1], bbMax[2] ); + points->InsertPoint( 2, bbMin[0], bbMax[1], bbMax[2] ); + points->InsertPoint( 3, bbMin[0], bbMax[1], bbMin[2] ); + points->InsertPoint( 4, bbMax[0], bbMin[1], bbMin[2] ); + points->InsertPoint( 5, bbMax[0], bbMin[1], bbMax[2] ); + points->InsertPoint( 6, bbMax[0], bbMax[1], bbMax[2] ); + points->InsertPoint( 7, bbMax[0], bbMax[1], bbMin[2] ); + } + + vtkSmartPointer newPoints = vtkSmartPointer::New(); + + vtkSmartPointer transform = vtkSmartPointer::New(); + transform->Identity(); + transform->Concatenate( planeGeometry->GetVtkTransform()->GetLinearInverse() ); + + transform->Concatenate( boundingGeometry->GetVtkTransform() ); + + transform->TransformPoints( points, newPoints ); + + bounds[0] = bounds[2] = 10000000.0; + bounds[1] = bounds[3] = -10000000.0; + bounds[4] = bounds[5] = 0.0; + + LineIntersectZero( newPoints, 0, 1, bounds ); + LineIntersectZero( newPoints, 1, 2, bounds ); + LineIntersectZero( newPoints, 2, 3, bounds ); + LineIntersectZero( newPoints, 3, 0, bounds ); + LineIntersectZero( newPoints, 0, 4, bounds ); + LineIntersectZero( newPoints, 1, 5, bounds ); + LineIntersectZero( newPoints, 2, 6, bounds ); + LineIntersectZero( newPoints, 3, 7, bounds ); + LineIntersectZero( newPoints, 4, 5, bounds ); + LineIntersectZero( newPoints, 5, 6, bounds ); + LineIntersectZero( newPoints, 6, 7, bounds ); + LineIntersectZero( newPoints, 7, 4, bounds ); + + if ( (bounds[0] > 9999999.0) || (bounds[2] > 9999999.0) + || (bounds[1] < -9999999.0) || (bounds[3] < -9999999.0) ) + { + return false; + } + else + { + // The resulting bounds must be adjusted by the plane spacing, since we + // we have so far dealt with index coordinates + const float *planeSpacing = planeGeometry->GetFloatSpacing(); + bounds[0] *= planeSpacing[0]; + bounds[1] *= planeSpacing[0]; + bounds[2] *= planeSpacing[1]; + bounds[3] *= planeSpacing[1]; + bounds[4] *= planeSpacing[2]; + bounds[5] *= planeSpacing[2]; + return true; + } +} + +} +} + +#endif \ No newline at end of file diff --git a/Core/Code/Controllers/mitkCoreActivator.cpp b/Core/Code/Controllers/mitkCoreActivator.cpp index 05aa5c211d..ca124745f1 100644 --- a/Core/Code/Controllers/mitkCoreActivator.cpp +++ b/Core/Code/Controllers/mitkCoreActivator.cpp @@ -1,161 +1,170 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkRenderingManager.h" #include "mitkPlanePositionManager.h" #include "mitkCoreDataNodeReader.h" #include "mitkStandardFileLocations.h" #include #include void HandleMicroServicesMessages(mitk::MsgType type, const char* msg) { switch (type) { case mitk::DebugMsg: MITK_DEBUG << msg; break; case mitk::InfoMsg: MITK_INFO << msg; break; case mitk::WarningMsg: MITK_WARN << msg; break; case mitk::ErrorMsg: MITK_ERROR << msg; break; } } #if defined(_WIN32) || defined(_WIN64) std::string GetProgramPath() { char path[512]; std::size_t index = std::string(path, GetModuleFileName(NULL, path, 512)).find_last_of('\\'); return std::string(path, index); } #elif defined(__APPLE__) #include std::string GetProgramPath() { char path[512]; uint32_t size = sizeof(path); if (_NSGetExecutablePath(path, &size) == 0) { std::size_t index = std::string(path).find_last_of('/'); std::string strPath = std::string(path, index); const char* execPath = strPath.c_str(); mitk::StandardFileLocations::GetInstance()->AddDirectoryForSearch(execPath,false); return strPath; } return std::string(); } #else #include #include #include std::string GetProgramPath() { std::stringstream ss; ss << "/proc/" << getpid() << "/exe"; char proc[512]; ssize_t ch = readlink(ss.str().c_str(), proc, 512); if (ch == -1) return std::string(); std::size_t index = std::string(proc).find_last_of('/'); return std::string(proc, index); } #endif void AddMitkAutoLoadPaths(const std::string& programPath) { mitk::ModuleSettings::AddAutoLoadPath(programPath); #ifdef __APPLE__ // Walk up three directories since that is where the .dylib files are located // for build trees. std::string additionalPath = programPath; bool addPath = true; for(int i = 0; i < 3; ++i) { std::size_t index = additionalPath.find_last_of('/'); if (index != std::string::npos) { additionalPath = additionalPath.substr(0, index); } else { addPath = false; break; } } if (addPath) { mitk::ModuleSettings::AddAutoLoadPath(additionalPath); } #endif } /* * This is the module activator for the "Mitk" module. It registers core services * like ... */ class MitkCoreActivator : public mitk::ModuleActivator { public: void Load(mitk::ModuleContext* context) { // Handle messages from CppMicroServices mitk::installMsgHandler(HandleMicroServicesMessages); // Add the current application directory to the auto-load paths. // This is useful for third-party executables. std::string programPath = GetProgramPath(); if (programPath.empty()) { MITK_WARN << "Could not get the program path."; } else { AddMitkAutoLoadPaths(programPath); } //m_RenderingManager = mitk::RenderingManager::New(); //context->RegisterService(renderingManager.GetPointer()); m_PlanePositionManager = mitk::PlanePositionManagerService::New(); context->RegisterService(m_PlanePositionManager); m_CoreDataNodeReader = mitk::CoreDataNodeReader::New(); context->RegisterService(m_CoreDataNodeReader); + + /* + There IS an option to exchange ALL vtkTexture instances against vtkNeverTranslucentTextureFactory. + This code is left here as a reminder, just in case we might need to do that some time. + + vtkNeverTranslucentTextureFactory* textureFactory = vtkNeverTranslucentTextureFactory::New(); + vtkObjectFactory::RegisterFactory( textureFactory ); + textureFactory->Delete(); + */ } void Unload(mitk::ModuleContext* ) { // The mitk::ModuleContext* argument of the Unload() method // will always be 0 for the Mitk library. It makes no sense // to use it at this stage anyway, since all libraries which // know about the module system have already been unloaded. } private: //mitk::RenderingManager::Pointer m_RenderingManager; mitk::PlanePositionManagerService::Pointer m_PlanePositionManager; mitk::CoreDataNodeReader::Pointer m_CoreDataNodeReader; }; US_EXPORT_MODULE_ACTIVATOR(Mitk, MitkCoreActivator) diff --git a/Core/Code/CppMicroServices/CMake/usCTestScript.cmake b/Core/Code/CppMicroServices/CMake/usCTestScript.cmake index af6ee829a7..7feac62e8e 100644 --- a/Core/Code/CppMicroServices/CMake/usCTestScript.cmake +++ b/Core/Code/CppMicroServices/CMake/usCTestScript.cmake @@ -1,131 +1,131 @@ macro(build_and_test) set(CTEST_SOURCE_DIRECTORY ${US_SOURCE_DIR}) set(CTEST_BINARY_DIRECTORY "${CTEST_DASHBOARD_ROOT}/${CTEST_PROJECT_NAME}_${CTEST_DASHBOARD_NAME}") #if(NOT CTEST_BUILD_NAME) # set(CTEST_BUILD_NAME "${CMAKE_SYSTEM}_${CTEST_COMPILER}_${CTEST_DASHBOARD_NAME}") #endif() ctest_empty_binary_directory(${CTEST_BINARY_DIRECTORY}) ctest_start("Experimental") if(NOT EXISTS "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt") file(WRITE "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt" "${CTEST_INITIAL_CACHE}") endif() ctest_configure(RETURN_VALUE res) if (res) message(FATAL_ERROR "CMake configure error") endif() ctest_build(RETURN_VALUE res) if (res) message(FATAL_ERROR "CMake build error") endif() ctest_test(RETURN_VALUE res PARALLEL_LEVEL ${CTEST_PARALLEL_LEVEL}) if (res) message(FATAL_ERROR "CMake test error") endif() if(WITH_MEMCHECK AND CTEST_MEMORYCHECK_COMMAND) ctest_memcheck() endif() if(WITH_COVERAGE AND CTEST_COVERAGE_COMMAND) ctest_coverage() endif() #ctest_submit() endmacro() -function(create_initial_cache var _shared _threading _sf _c++11 _autoload) +function(create_initial_cache var _shared _threading _sf _cxx11 _autoload) set(_initial_cache " US_BUILD_TESTING:BOOL=ON US_BUILD_SHARED_LIBS:BOOL=${_shared} US_ENABLE_THREADING_SUPPORT:BOOL=${_threading} US_ENABLE_SERVICE_FACTORY_SUPPORT:BOOL=${_sf} - US_USE_C++11:BOOL=${_c++11} + US_USE_C++11:BOOL=${_cxx11} US_ENABLE_AUTOLOADING_SUPPORT:BOOL=${_autoload} ") set(${var} ${_initial_cache} PARENT_SCOPE) if(_shared) set(CTEST_DASHBOARD_NAME "shared") else() set(CTEST_DASHBOARD_NAME "static") endif() if(_threading) set(CTEST_DASHBOARD_NAME "${CTEST_DASHBOARD_NAME}-threading") endif() if(_sf) set(CTEST_DASHBOARD_NAME "${CTEST_DASHBOARD_NAME}-servicefactory") endif() - if(_c++11) + if(_cxx11) set(CTEST_DASHBOARD_NAME "${CTEST_DASHBOARD_NAME}-cxx11") endif() if(_autoload) set(CTEST_DASHBOARD_NAME "${CTEST_DASHBOARD_NAME}-autoloading") endif() set(CTEST_DASHBOARD_NAME ${CTEST_DASHBOARD_NAME} PARENT_SCOPE) endfunction() #========================================================= set(CTEST_PROJECT_NAME CppMicroServices) if(NOT CTEST_PARALLEL_LEVEL) set(CTEST_PARALLEL_LEVEL 1) endif() # SHARED THREADING SERVICE_FACTORY C++11 AUTOLOAD set(config0 0 0 0 0 0 ) set(config1 0 0 0 0 1 ) set(config2 0 0 0 1 0 ) set(config3 0 0 0 1 1 ) set(config4 0 0 1 0 0 ) set(config5 0 0 1 0 1 ) set(config6 0 0 1 1 0 ) set(config7 0 0 1 1 1 ) set(config8 0 1 0 0 0 ) set(config9 0 1 0 0 1 ) set(config10 0 1 0 1 0 ) set(config11 0 1 0 1 1 ) set(config12 0 1 1 0 0 ) set(config13 0 1 1 0 1 ) set(config14 0 1 1 1 0 ) set(config15 0 1 1 1 1 ) set(config16 1 0 0 0 0 ) set(config17 1 0 0 0 1 ) set(config18 1 0 0 1 0 ) set(config19 1 0 0 1 1 ) set(config20 1 0 1 0 0 ) set(config21 1 0 1 0 1 ) set(config22 1 0 1 1 0 ) set(config23 1 0 1 1 1 ) set(config24 1 1 0 0 0 ) set(config25 1 1 0 0 1 ) set(config26 1 1 0 1 0 ) set(config27 1 1 0 1 1 ) set(config28 1 1 1 0 0 ) set(config29 1 1 1 0 1 ) set(config30 1 1 1 1 0 ) set(config31 1 1 1 1 1 ) foreach(i ${US_BUILD_CONFIGURATION}) create_initial_cache(CTEST_INITIAL_CACHE ${config${i}}) message("Testing build configuration: ${CTEST_DASHBOARD_NAME}") build_and_test() endforeach() diff --git a/Core/Code/CppMicroServices/CMake/usFunctionEmbedResources.cmake b/Core/Code/CppMicroServices/CMake/usFunctionEmbedResources.cmake index 907f04339f..edec0a7485 100644 --- a/Core/Code/CppMicroServices/CMake/usFunctionEmbedResources.cmake +++ b/Core/Code/CppMicroServices/CMake/usFunctionEmbedResources.cmake @@ -1,92 +1,97 @@ #! Embed resources into a shared library or executable. #! #! This CMake function uses an external command line program to generate a source #! file containing data from external resources such as text files or images. The path #! to the generated source file is appended to the \c src_var variable. #! #! Each module can call this function (at most once) to embed resources and make them #! available at runtime through the Module class. Resources can also be embedded into #! executables, using the EXECUTABLE_NAME argument instead of LIBRARY_NAME. #! #! Example usage: #! \verbatim #! set(module_srcs ) #! usFunctionEmbedResources(module_srcs #! LIBRARY_NAME "mylib" #! ROOT_DIR resources #! FILES config.properties logo.png #! ) #! #! \param LIBRARY_NAME (required if EXECUTABLE_NAME is empty) The library name of the module #! which will include the generated source file, without extension. #! \param EXECUTABLE_NAME (required if LIBRARY_NAME is empty) The name of the executable #! which will include the generated source file. #! \param ROOT_DIR (optional) The root path for all resources listed after the FILES argument. #! If no or a relative path is given, it is considered relativ to the current CMake source directory. #! \param FILES (optional) A list of resources (paths to external files in the file system) relative #! to the ROOT_DIR argument or the current CMake source directory if ROOT_DIR is empty. #! function(usFunctionEmbedResources src_var) MACRO_PARSE_ARGUMENTS(US_RESOURCE "LIBRARY_NAME;EXECUTABLE_NAME;ROOT_DIR;FILES" "" ${ARGN}) if(NOT src_var) message(SEND_ERROR "Output variable name not specified.") endif() if(US_RESOURCE_EXECUTABLE_NAME AND US_RESOURCE_LIBRARY_NAME) message(SEND_ERROR "Only one of LIBRARY_NAME or EXECUTABLE_NAME can be specified.") endif() if(NOT US_RESOURCE_LIBRARY_NAME AND NOT US_RESOURCE_EXECUTABLE_NAME) message(SEND_ERROR "LIBRARY_NAME or EXECUTABLE_NAME argument not specified.") endif() if(NOT US_RESOURCE_FILES) message(WARNING "No FILES argument given. Skipping resource processing.") return() endif() if(NOT US_RESOURCE_ROOT_DIR) set(US_RESOURCE_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) endif() if(NOT IS_ABSOLUTE ${US_RESOURCE_ROOT_DIR}) set(US_RESOURCE_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${US_RESOURCE_ROOT_DIR}") endif() if(NOT IS_DIRECTORY ${US_RESOURCE_ROOT_DIR}) message(SEND_ERROR "The ROOT_DIR argument is not a directory: ${US_RESOURCE_ROOT_DIR}") endif() set(absolute_res_files) foreach(res_file ${US_RESOURCE_FILES}) set(res_file "${US_RESOURCE_ROOT_DIR}/${res_file}") if(IS_DIRECTORY ${res_file}) message(SEND_ERROR "A resource cannot be a directory: ${res_file}") endif() if(NOT EXISTS ${res_file}) message(SEND_ERROR "Resource does not exists: ${res_file}") endif() get_filename_component(res_file "${res_file}" REALPATH) file(TO_NATIVE_PATH "${res_file}" res_file) list(APPEND absolute_res_files ${res_file}) endforeach() if(US_RESOURCE_LIBRARY_NAME) set(us_cpp_resource_file "${CMAKE_CURRENT_BINARY_DIR}/${US_RESOURCE_LIBRARY_NAME}_resources.cpp") set(us_lib_name ${US_RESOURCE_LIBRARY_NAME}) else() set(us_cpp_resource_file "${CMAKE_CURRENT_BINARY_DIR}/${US_RESOURCE_EXECUTABLE_NAME}_resources.cpp") set(us_lib_name "\"\"") endif() + set(resource_compiler ${CppMicroServices_RCC_EXECUTABLE}) + if(TARGET ${CppMicroServices_RCC_EXECUTABLE_NAME}) + set(resource_compiler ${CppMicroServices_RCC_EXECUTABLE_NAME}) + endif() + add_custom_command( OUTPUT ${us_cpp_resource_file} - COMMAND ${CppMicroServices_RCC_EXECUTABLE} "${us_lib_name}" ${us_cpp_resource_file} ${absolute_res_files} + COMMAND ${resource_compiler} "${us_lib_name}" ${us_cpp_resource_file} ${absolute_res_files} WORKING_DIRECTORY ${US_RESOURCE_ROOT_DIR} DEPENDS ${absolute_res_files} COMMENT "Generating embedded resource file ${us_cpp_resource_name}" ) set(${src_var} "${${src_var}};${us_cpp_resource_file}" PARENT_SCOPE) endfunction() diff --git a/Core/Code/DataManagement/mitkSurface.cpp b/Core/Code/DataManagement/mitkSurface.cpp index aef0f49b77..24428d0980 100644 --- a/Core/Code/DataManagement/mitkSurface.cpp +++ b/Core/Code/DataManagement/mitkSurface.cpp @@ -1,382 +1,386 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ - #include "mitkSurface.h" #include "mitkInteractionConst.h" #include "mitkSurfaceOperation.h" +#include #include -#include "vtkSmartPointer.h" +static vtkPolyData* DeepCopy(vtkPolyData* other) +{ + if (other == NULL) + return NULL; + + vtkPolyData* copy = vtkPolyData::New(); + copy->DeepCopy(other); + + return copy; +} + +static void Delete(vtkPolyData* polyData) +{ + if (polyData != NULL) + polyData->Delete(); +} -mitk::Surface::Surface() : -m_CalculateBoundingBox( false ) +static void Update(vtkPolyData* polyData) +{ + if (polyData != NULL) + polyData->Update(); +} + +mitk::Surface::Surface() + : m_CalculateBoundingBox(false) { this->InitializeEmpty(); } -mitk::Surface::Surface(const mitk::Surface& other) : BaseData(other), -m_LargestPossibleRegion(other.m_LargestPossibleRegion), -m_RequestedRegion(other.m_RequestedRegion), -m_CalculateBoundingBox(other.m_CalculateBoundingBox) +mitk::Surface::Surface(const mitk::Surface& other) + : BaseData(other), + m_LargestPossibleRegion(other.m_LargestPossibleRegion), + m_RequestedRegion(other.m_RequestedRegion), + m_CalculateBoundingBox(other.m_CalculateBoundingBox) { - if(other.m_PolyDataSeries.at(0) != NULL) + if(!other.m_PolyDatas.empty()) { - this->m_PolyDataSeries = std::vector(); - for ( VTKPolyDataSeries::const_iterator it = other.m_PolyDataSeries.begin(); it != other.m_PolyDataSeries.end(); ++it ) - { - vtkPolyData* poly = vtkPolyData::New(); - poly->DeepCopy(*it); - m_PolyDataSeries.push_back(poly); - //poly->Delete(); - } + m_PolyDatas.resize(other.m_PolyDatas.size()); + std::transform(other.m_PolyDatas.begin(), other.m_PolyDatas.end(), m_PolyDatas.begin(), DeepCopy); } else { this->InitializeEmpty(); } } +void mitk::Surface::Swap(mitk::Surface& other) +{ + std::swap(m_PolyDatas, other.m_PolyDatas); + std::swap(m_LargestPossibleRegion, other.m_LargestPossibleRegion); + std::swap(m_RequestedRegion, other.m_RequestedRegion); + std::swap(m_CalculateBoundingBox, other.m_CalculateBoundingBox); +} + +mitk::Surface& mitk::Surface::operator=(Surface other) +{ + this->Swap(other); + return *this; +} + mitk::Surface::~Surface() { this->ClearData(); } void mitk::Surface::ClearData() { - for ( VTKPolyDataSeries::iterator it = m_PolyDataSeries.begin(); it != m_PolyDataSeries.end(); ++it ) - { - if ( ( *it ) != NULL ) - ( *it )->Delete(); - } - m_PolyDataSeries.clear(); + using ::Delete; + + std::for_each(m_PolyDatas.begin(), m_PolyDatas.end(), Delete); + m_PolyDatas.clear(); Superclass::ClearData(); } +const mitk::Surface::RegionType& mitk::Surface::GetLargestPossibleRegion() const +{ + m_LargestPossibleRegion.SetIndex(3, 0); + m_LargestPossibleRegion.SetSize(3, GetTimeSlicedGeometry()->GetTimeSteps()); + + return m_LargestPossibleRegion; +} + +const mitk::Surface::RegionType& mitk::Surface::GetRequestedRegion() const +{ + return m_RequestedRegion; +} + void mitk::Surface::InitializeEmpty() { - vtkPolyData* pdnull = NULL; - m_PolyDataSeries.resize( 1, pdnull ); - Superclass::InitializeTimeSlicedGeometry(1); + if (!m_PolyDatas.empty()) + this->ClearData(); + + Superclass::InitializeTimeSlicedGeometry(); + m_PolyDatas.push_back(NULL); m_Initialized = true; } -void mitk::Surface::SetVtkPolyData( vtkPolyData* polydata, unsigned int t ) +void mitk::Surface::SetVtkPolyData(vtkPolyData* polyData, unsigned int t) { - // Adapt the size of the data vector if necessary - this->Expand( t+1 ); + this->Expand(t + 1); - if(m_PolyDataSeries[ t ] != NULL) + if (m_PolyDatas[t] != NULL) { - if ( m_PolyDataSeries[ t ] == polydata ) + if (m_PolyDatas[t] == polyData) return; - // we do not need the reference on the object any longer - m_PolyDataSeries[ t ]->Delete(); - } - m_PolyDataSeries[ t ] = polydata; - // call m_VtkPolyData->Register(NULL) to tell - // the reference counting that we want to keep a - // reference on the object - if(m_PolyDataSeries[ t ] != NULL) - { - m_PolyDataSeries[ t ]->Register( NULL ); + + m_PolyDatas[t]->Delete(); } - this->Modified(); + + m_PolyDatas[t] = polyData; + + if(polyData != NULL) + polyData->Register(NULL); + m_CalculateBoundingBox = true; + + this->Modified(); this->UpdateOutputInformation(); } bool mitk::Surface::IsEmptyTimeStep(unsigned int t) const { if(!IsInitialized()) return false; - vtkPolyData* polydata = const_cast(this)->GetVtkPolyData(t); - return - (polydata == NULL) || - ( - (polydata->GetNumberOfVerts() <= 0) && - (polydata->GetNumberOfPolys() <= 0) && - (polydata->GetNumberOfStrips() <= 0) && - (polydata->GetNumberOfLines() <= 0) - ); + + vtkPolyData* polyData = const_cast(this)->GetVtkPolyData(t); + + return polyData == NULL || ( + polyData->GetNumberOfLines() == 0 && + polyData->GetNumberOfPolys() == 0 && + polyData->GetNumberOfStrips() == 0 && + polyData->GetNumberOfVerts() == 0 + ); } -vtkPolyData* mitk::Surface::GetVtkPolyData( unsigned int t ) +vtkPolyData* mitk::Surface::GetVtkPolyData(unsigned int t) { - - if ( t < m_PolyDataSeries.size() ) + if (t < m_PolyDatas.size()) { - vtkPolyData* polydata = m_PolyDataSeries[ t ]; - if((polydata==NULL) && (GetSource().GetPointer()!=NULL)) + if(m_PolyDatas[t] == NULL && this->GetSource().IsNotNull()) { - RegionType requestedregion; - requestedregion.SetIndex(3, t); - requestedregion.SetSize(3, 1); - SetRequestedRegion(&requestedregion); - GetSource()->Update(); + RegionType requestedRegion; + requestedRegion.SetIndex(3, t); + requestedRegion.SetSize(3, 1); + + this->SetRequestedRegion(&requestedRegion); + this->GetSource()->Update(); } - polydata = m_PolyDataSeries[ t ]; - return polydata; + + return m_PolyDatas[t]; } - else - return NULL; + + return NULL; } void mitk::Surface::UpdateOutputInformation() { - if ( this->GetSource() ) - { + if (this->GetSource().IsNotNull()) this->GetSource()->UpdateOutputInformation(); - } - if ( ( m_CalculateBoundingBox ) && ( m_PolyDataSeries.size() > 0 ) ) - CalculateBoundingBox(); + + if (m_CalculateBoundingBox == true && !m_PolyDatas.empty()) + this->CalculateBoundingBox(); else - GetTimeSlicedGeometry()->UpdateInformation(); + this->GetTimeSlicedGeometry()->UpdateInformation(); } void mitk::Surface::CalculateBoundingBox() { - // - // first make sure, that the associated time sliced geometry has - // the same number of geometry 3d's as vtkPolyDatas are present - // - mitk::TimeSlicedGeometry* timeGeometry = GetTimeSlicedGeometry(); - if ( timeGeometry->GetTimeSteps() != m_PolyDataSeries.size() ) - { - itkExceptionMacro(<<"timeGeometry->GetTimeSteps() != m_PolyDataSeries.size() -- use Initialize(timeSteps) with correct number of timeSteps!"); - } + mitk::TimeSlicedGeometry* timeSlicedGeometry = this->GetTimeSlicedGeometry(); - // - // Iterate over the vtkPolyDatas and update the Geometry - // information of each of the items. - // - for ( unsigned int i = 0 ; i < m_PolyDataSeries.size() ; ++i ) + if (timeSlicedGeometry->GetTimeSteps() != m_PolyDatas.size()) + mitkThrow() << "Number of geometry time steps is inconsistent with number of poly data pointers."; + + for (unsigned int i = 0; i < m_PolyDatas.size(); ++i) { - vtkPolyData* polyData = m_PolyDataSeries[ i ]; - vtkFloatingPointType bounds[ ] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; - if ( ( polyData != NULL ) && ( polyData->GetNumberOfPoints() > 0 ) ) + vtkPolyData* polyData = m_PolyDatas[i]; + vtkFloatingPointType bounds[6] = {0}; + + if (polyData != NULL && polyData->GetNumberOfPoints() > 0) { polyData->Update(); polyData->ComputeBounds(); - polyData->GetBounds( bounds ); + polyData->GetBounds(bounds); } - mitk::Geometry3D::Pointer g3d = timeGeometry->GetGeometry3D( i ); - assert( g3d.IsNotNull() ); - g3d->SetFloatBounds( bounds ); + + mitk::Geometry3D::Pointer geometry = timeSlicedGeometry->GetGeometry3D(i); + + if (geometry.IsNull()) + mitkThrow() << "Time-sliced geometry is invalid (equals NULL)."; + + geometry->SetFloatBounds(bounds); } - timeGeometry->UpdateInformation(); - mitk::BoundingBox::Pointer bb = const_cast( timeGeometry->GetBoundingBox() ); - itkDebugMacro( << "boundingbox min: "<< bb->GetMinimum()); - itkDebugMacro( << "boundingbox max: "<< bb->GetMaximum()); + timeSlicedGeometry->UpdateInformation(); m_CalculateBoundingBox = false; } void mitk::Surface::SetRequestedRegionToLargestPossibleRegion() { m_RequestedRegion = GetLargestPossibleRegion(); } bool mitk::Surface::RequestedRegionIsOutsideOfTheBufferedRegion() { - RegionType::IndexValueType end = m_RequestedRegion.GetIndex(3)+m_RequestedRegion.GetSize(3); + RegionType::IndexValueType end = m_RequestedRegion.GetIndex(3) + m_RequestedRegion.GetSize(3); - if(((RegionType::IndexValueType)m_PolyDataSeries.size())(m_PolyDatas.size()) < end) return true; - for( RegionType::IndexValueType t=m_RequestedRegion.GetIndex(3); t=0) && - (m_RequestedRegion.GetIndex(3)+m_RequestedRegion.GetSize(3)<=m_PolyDataSeries.size()) ) + if(m_RequestedRegion.GetIndex(3) >= 0 && m_RequestedRegion.GetIndex(3) + m_RequestedRegion.GetSize(3) <= m_PolyDatas.size()) return true; return false; } -void mitk::Surface::SetRequestedRegion( itk::DataObject *data ) +void mitk::Surface::SetRequestedRegion(itk::DataObject* data) { - mitk::Surface *surfaceData; + mitk::Surface* surface = dynamic_cast(data); - surfaceData = dynamic_cast(data); - - if (surfaceData) - { - m_RequestedRegion = surfaceData->GetRequestedRegion(); - } + if (surface != NULL) + m_RequestedRegion = surface->GetRequestedRegion(); else - { - // pointer could not be cast back down - itkExceptionMacro( << "mitk::Surface::SetRequestedRegion(DataObject*) cannot cast " << typeid(data).name() << " to " << typeid(Surface*).name() ); - } + mitkThrow() << "Data object used to get requested region is not a mitk::Surface."; } -void mitk::Surface::SetRequestedRegion(Surface::RegionType *region) //by arin +void mitk::Surface::SetRequestedRegion(Surface::RegionType* region) { - if(region!=NULL) - { - m_RequestedRegion = *region; - } - else - { - // pointer could not be cast back down - itkExceptionMacro( << "mitk::Surface::SetRequestedRegion(Surface::RegionType*) cannot cast " << typeid(region).name() << " to " << typeid(Surface*).name() ); - } + if (region == NULL) + mitkThrow() << "Requested region is invalid (equals NULL)"; + + m_RequestedRegion = *region; } -void mitk::Surface::CopyInformation( const itk::DataObject * data) +void mitk::Surface::CopyInformation(const itk::DataObject* data) { - Superclass::CopyInformation( data ); + Superclass::CopyInformation(data); - const mitk::Surface* surfaceData; + const mitk::Surface* surface = dynamic_cast(data); - surfaceData = dynamic_cast( data ); + if (surface == NULL) + mitkThrow() << "Data object used to get largest possible region is not a mitk::Surface."; - if ( surfaceData ) - { - m_LargestPossibleRegion = surfaceData->GetLargestPossibleRegion(); - } - else - { - // pointer could not be cast back down - itkExceptionMacro( << "mitk::Surface::CopyInformation(const DataObject *data) cannot cast " << typeid(data).name() << " to " << typeid(surfaceData).name() ); - } + m_LargestPossibleRegion = surface->GetLargestPossibleRegion(); } void mitk::Surface::Update() { - if ( GetSource().IsNull() ) - { - for ( VTKPolyDataSeries::iterator it = m_PolyDataSeries.begin() ; it != m_PolyDataSeries.end() ; ++it ) - { - if ( ( *it ) != NULL ) - ( *it )->Update(); - } - } + using ::Update; + + if (this->GetSource().IsNull()) + std::for_each(m_PolyDatas.begin(), m_PolyDatas.end(), Update); + Superclass::Update(); } -void mitk::Surface::Expand( unsigned int timeSteps ) +void mitk::Surface::Expand(unsigned int timeSteps) { - // check if the vector is long enough to contain the new element - // at the given position. If not, expand it with sufficient zero-filled elements. - if ( timeSteps > m_PolyDataSeries.size() ) + if (timeSteps > m_PolyDatas.size()) { - Superclass::Expand( timeSteps ); - vtkPolyData* pdnull = NULL; - m_PolyDataSeries.resize( timeSteps, pdnull ); + Superclass::Expand(timeSteps); + + m_PolyDatas.resize(timeSteps); m_CalculateBoundingBox = true; } } -void mitk::Surface::ExecuteOperation(Operation *operation) +void mitk::Surface::ExecuteOperation(Operation* operation) { - switch ( operation->GetOperationType() ) + switch (operation->GetOperationType()) { - case OpSURFACECHANGED: + case OpSURFACECHANGED: + { + mitk::SurfaceOperation* surfaceOperation = dynamic_cast(operation); - mitk::SurfaceOperation* surfOp = dynamic_cast(operation); - if( ! surfOp ) break; + if(surfaceOperation == NULL) + break; - unsigned int time = surfOp->GetTimeStep(); + unsigned int timeStep = surfaceOperation->GetTimeStep(); - if(m_PolyDataSeries[ time ] != NULL) - { - vtkPolyData* updatePoly = surfOp->GetVtkPolyData(); - if( updatePoly ){ - this->SetVtkPolyData( updatePoly, time ); - this->CalculateBoundingBox(); + if(m_PolyDatas[timeStep] != NULL) + { + vtkPolyData* updatedPolyData = surfaceOperation->GetVtkPolyData(); + + if(updatedPolyData != NULL) + { + this->SetVtkPolyData(updatedPolyData, timeStep); + this->CalculateBoundingBox(); + this->Modified(); + } } + + break; } - break; + + default: + return; } - this->Modified(); } unsigned int mitk::Surface::GetSizeOfPolyDataSeries() const { - return m_PolyDataSeries.size(); + return m_PolyDatas.size(); } -void mitk::Surface::Graft( const DataObject* data ) +void mitk::Surface::Graft(const DataObject* data) { - const Self* surface; - try - { - surface = dynamic_cast( data ); - } - catch(...) - { - itkExceptionMacro( << "mitk::Surface::Graft cannot cast " - << typeid(data).name() << " to " - << typeid(const Self *).name() ); - return; - } + const Surface* surface = dynamic_cast(data); + + if(surface == NULL) + mitkThrow() << "Data object used to graft surface is not a mitk::Surface."; + + this->CopyInformation(data); + m_PolyDatas.clear(); - if(!surface) + for (unsigned int i = 0; i < surface->GetSizeOfPolyDataSeries(); ++i) { - // pointer could not be cast back down - itkExceptionMacro( << "mitk::Surface::Graft cannot cast " - << typeid(data).name() << " to " - << typeid(const Self *).name() ); - return; + m_PolyDatas.push_back(vtkPolyData::New()); + m_PolyDatas.back()->DeepCopy(const_cast(surface)->GetVtkPolyData(i)); } - - this->CopyInformation( data ); - //clear list of PolyData's - m_PolyDataSeries.clear(); - // do copy - for (unsigned int i=0; iGetSizeOfPolyDataSeries(); i++) - { - m_PolyDataSeries.push_back(vtkPolyData::New()); - m_PolyDataSeries.back()->DeepCopy( const_cast(surface)->GetVtkPolyData( i ) ); - //CopyStructure( const_cast(surface)->GetVtkPolyData( i ) ); - } } -void mitk::Surface::PrintSelf( std::ostream& os, itk::Indent indent ) const +void mitk::Surface::PrintSelf(std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf(os, indent); - os << indent << "\nNumber PolyDatas: " << m_PolyDataSeries.size() << "\n"; + os << indent << "\nNumber PolyDatas: " << m_PolyDatas.size() << "\n"; + unsigned int count = 0; - for (VTKPolyDataSeries::const_iterator it = m_PolyDataSeries.begin(); it != m_PolyDataSeries.end(); ++it) + + for (std::vector::const_iterator it = m_PolyDatas.begin(); it != m_PolyDatas.end(); ++it) { - vtkPolyData* pd = *it; - if(pd != NULL) + os << "\n"; + + if(*it != NULL) { - os << "\n"; - os << indent << "PolyData at time step " << count << ". \n"; - os << indent << "Number of cells " << pd->GetNumberOfCells() << ": \n"; - os << indent << "Number of points " << pd->GetNumberOfPoints() << ": \n\n"; - os << indent << "VTKPolyData : \n"; - pd->Print(os); + os << indent << "PolyData at time step " << count << ":\n"; + os << indent << "Number of cells: " << (*it)->GetNumberOfCells() << "\n"; + os << indent << "Number of points: " << (*it)->GetNumberOfPoints() << "\n\n"; + os << indent << "VTKPolyData:\n"; + + (*it)->Print(os); } else - os << indent << "\nEmpty PolyData at time step " << count << ".\n"; + { + os << indent << "Empty PolyData at time step " << count << "\n"; + } - count++; + ++count; } } diff --git a/Core/Code/DataManagement/mitkSurface.h b/Core/Code/DataManagement/mitkSurface.h index cce81fa05c..00553d52f2 100644 --- a/Core/Code/DataManagement/mitkSurface.h +++ b/Core/Code/DataManagement/mitkSurface.h @@ -1,115 +1,79 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 MITKSURFACEDATA_H_HEADER_INCLUDED -#define MITKSURFACEDATA_H_HEADER_INCLUDED +#ifndef mitkSurface_h +#define mitkSurface_h #include "mitkBaseData.h" #include "itkImageRegion.h" class vtkPolyData; -namespace mitk { - - //##Documentation - //## @brief Class for storing surfaces (vtkPolyData) - //## @ingroup Data +namespace mitk +{ + /** + * \brief Class for storing surfaces (vtkPolyData). + * \ingroup Data + */ class MITK_CORE_EXPORT Surface : public BaseData { - protected: - public: - // not yet the best chioce of a region-type for surfaces, but it works for the time being - typedef itk::ImageRegion< 5 > RegionType; + typedef itk::ImageRegion<5> RegionType; mitkClassMacro(Surface, BaseData); itkNewMacro(Self); mitkCloneMacro(Surface); - virtual void SetVtkPolyData(vtkPolyData* polydata, unsigned int t = 0); - + void CalculateBoundingBox(); + virtual void CopyInformation(const itk::DataObject *data); + virtual void ExecuteOperation(Operation *operation); + virtual void Expand( unsigned int timeSteps = 1 ); + const RegionType& GetLargestPossibleRegion() const; + virtual const RegionType& GetRequestedRegion() const; + unsigned int GetSizeOfPolyDataSeries() const; virtual vtkPolyData* GetVtkPolyData(unsigned int t = 0); - - virtual void UpdateOutputInformation(); - - virtual void SetRequestedRegionToLargestPossibleRegion(); - + virtual void Graft( const DataObject* data ); + virtual bool IsEmptyTimeStep(unsigned int t) const; + virtual void PrintSelf( std::ostream& os, itk::Indent indent ) const; virtual bool RequestedRegionIsOutsideOfTheBufferedRegion(); - - virtual bool VerifyRequestedRegion(); - virtual void SetRequestedRegion(itk::DataObject *data); - virtual void SetRequestedRegion(Surface::RegionType *region); - - virtual void CopyInformation(const itk::DataObject *data); - - virtual bool IsEmptyTimeStep(unsigned int t) const; - - unsigned int GetSizeOfPolyDataSeries() const; - + virtual void SetRequestedRegionToLargestPossibleRegion(); + virtual void SetVtkPolyData(vtkPolyData* polydata, unsigned int t = 0); + virtual void Swap(Surface& other); virtual void Update(); - - virtual void Expand( unsigned int timeSteps = 1 ); - - virtual void Graft( const DataObject* data ); - - const RegionType& GetLargestPossibleRegion() const - { - m_LargestPossibleRegion.SetIndex(3, 0); - m_LargestPossibleRegion.SetSize(3, GetTimeSlicedGeometry()->GetTimeSteps()); - return m_LargestPossibleRegion; - } - - //##Documentation - //## Get the region object that defines the size and starting index - //## for the region of the image requested (i.e., the region of the - //## image to be operated on by a filter). - virtual const RegionType& GetRequestedRegion() const - { - return m_RequestedRegion; - } - - void CalculateBoundingBox(); - - virtual void PrintSelf( std::ostream& os, itk::Indent indent ) const; - - virtual void ExecuteOperation(Operation *operation); + virtual void UpdateOutputInformation(); + virtual bool VerifyRequestedRegion(); protected: - - typedef std::vector< vtkPolyData* > VTKPolyDataSeries; - Surface(); - Surface(const Surface& other); - virtual ~Surface(); - virtual void ClearData(); + Surface(const Surface& other); + Surface& operator=(Surface other); + virtual void ClearData(); virtual void InitializeEmpty(); - //member variables - VTKPolyDataSeries m_PolyDataSeries; /// variable holds the poly datas of the surface - mutable RegionType m_LargestPossibleRegion; /// variable holds the largest possible region the surface is contained in + private: + std::vector m_PolyDatas; + mutable RegionType m_LargestPossibleRegion; RegionType m_RequestedRegion; - bool m_CalculateBoundingBox; /// flag to calculate the bounding box + bool m_CalculateBoundingBox; }; +} -} // namespace mitk - -#endif /* MITKSURFACEDATA_H_HEADER_INCLUDED */ +#endif diff --git a/Core/Code/Interactions/mitkDispatcher.cpp b/Core/Code/Interactions/mitkDispatcher.cpp index e14376a7de..4207d4dbca 100644 --- a/Core/Code/Interactions/mitkDispatcher.cpp +++ b/Core/Code/Interactions/mitkDispatcher.cpp @@ -1,230 +1,233 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDispatcher.h" #include "mitkInteractionEvent.h" #include "mitkInternalEvent.h" // MicroServices #include "mitkGetModuleContext.h" #include "mitkModule.h" #include "mitkModuleRegistry.h" #include "mitkInteractionEventObserver.h" mitk::Dispatcher::Dispatcher() : - m_ProcessingMode(REGULAR), m_EventObserverTracker(GetModuleContext()) + m_ProcessingMode(REGULAR) { - m_EventObserverTracker.Open(); + m_EventObserverTracker = new mitk::ServiceTracker(GetModuleContext()); + m_EventObserverTracker->Open(); } void mitk::Dispatcher::AddDataInteractor(const DataNode* dataNode) { RemoveDataInteractor(dataNode); RemoveOrphanedInteractors(); DataInteractor::Pointer dataInteractor = dataNode->GetDataInteractor(); if (dataInteractor.IsNotNull()) { m_Interactors.push_back(dataInteractor); } } /* * Note: One DataInteractor can only have one DataNode and vice versa, * BUT the m_Interactors list may contain another DataInteractor that is still connected to this DataNode, * in this case we have to remove >1 DataInteractor. (Some special case of switching DataNodes between DataInteractors and registering a * DataNode to a DataStorage after assigning it to an DataInteractor) */ void mitk::Dispatcher::RemoveDataInteractor(const DataNode* dataNode) { for (ListInteractorType::iterator it = m_Interactors.begin(); it != m_Interactors.end();) { if ((*it)->GetDataNode() == dataNode) { it = m_Interactors.erase(it); } else { ++it; } } } size_t mitk::Dispatcher::GetNumberOfInteractors() { return m_Interactors.size(); } mitk::Dispatcher::~Dispatcher() { + m_EventObserverTracker->Close(); + delete m_EventObserverTracker; } bool mitk::Dispatcher::ProcessEvent(InteractionEvent* event) { InteractionEvent::Pointer p = event; //MITK_INFO << event->GetEventClass(); bool eventIsHandled = false; /* Filter out and handle Internal Events separately */ InternalEvent* internalEvent = dynamic_cast(event); if (internalEvent != NULL) { eventIsHandled = HandleInternalEvent(internalEvent); // InternalEvents that are handled are not sent to the listeners if (eventIsHandled) { return true; } } switch (m_ProcessingMode) { case CONNECTEDMOUSEACTION: // finished connected mouse action if (p->GetEventClass() == "MouseReleaseEvent") { m_ProcessingMode = REGULAR; eventIsHandled = m_SelectedInteractor->HandleEvent(event, m_SelectedInteractor->GetDataNode()); } // give event to selected interactor if (eventIsHandled == false) { eventIsHandled = m_SelectedInteractor->HandleEvent(event, m_SelectedInteractor->GetDataNode()); } break; case GRABINPUT: eventIsHandled = m_SelectedInteractor->HandleEvent(event, m_SelectedInteractor->GetDataNode()); SetEventProcessingMode(m_SelectedInteractor); break; case PREFERINPUT: if (m_SelectedInteractor->HandleEvent(event, m_SelectedInteractor->GetDataNode()) == true) { SetEventProcessingMode(m_SelectedInteractor); eventIsHandled = true; } break; case REGULAR: break; } // Standard behavior. Is executed in STANDARD mode and PREFERINPUT mode, if preferred interactor rejects event. if (m_ProcessingMode == REGULAR || (m_ProcessingMode == PREFERINPUT && eventIsHandled == false)) { m_Interactors.sort(cmp()); // sorts interactors by layer (descending); for (std::list::iterator it = m_Interactors.begin(); it != m_Interactors.end(); ++it) { // explicit copy of pointer because HandleEvent function causes the m_Interactors list to be updated, // which in turn invalidates the iterator. DataInteractor::Pointer dataInteractor = *it; if (dataInteractor->HandleEvent(event, dataInteractor->GetDataNode())) { // if an event is handled several properties are checked, in order to determine the processing mode of the dispatcher SetEventProcessingMode(dataInteractor); if (p->GetEventClass() == "MousePressEvent" && m_ProcessingMode == REGULAR) { m_SelectedInteractor = dataInteractor; m_ProcessingMode = CONNECTEDMOUSEACTION; } eventIsHandled = true; break; } } } /* Notify InteractionEventObserver */ std::list listEventObserver; - m_EventObserverTracker.GetServiceReferences(listEventObserver); + m_EventObserverTracker->GetServiceReferences(listEventObserver); for (std::list::iterator it = listEventObserver.begin(); it != listEventObserver.end(); ++it) { Any patternName = it->GetProperty("org.mitk.statemachinepattern"); //if (!patternName.Empty() || patternName.ToString() == "") //{ - InteractionEventObserver* interactionEventObserver = m_EventObserverTracker.GetService(*it); + InteractionEventObserver* interactionEventObserver = m_EventObserverTracker->GetService(*it); if (interactionEventObserver != NULL) { interactionEventObserver->Notify(event, eventIsHandled); } //} } // Process event queue if (!m_QueuedEvents.empty()) { InteractionEvent::Pointer e = m_QueuedEvents.front(); m_QueuedEvents.pop_front(); ProcessEvent(e); } return eventIsHandled; } /* * Checks if DataNodes associated with DataInteractors point back to them. * If not remove the DataInteractors. (This can happen when s.o. tries to set DataNodes to multiple DataInteractors) */ void mitk::Dispatcher::RemoveOrphanedInteractors() { for (ListInteractorType::iterator it = m_Interactors.begin(); it != m_Interactors.end();) { DataNode::Pointer dn = (*it)->GetDataNode(); if (dn.IsNull()) { it = m_Interactors.erase(it); } else { DataInteractor::Pointer interactor = dn->GetDataInteractor(); if (interactor != it->GetPointer()) { it = m_Interactors.erase(it); } else { ++it; } } } } void mitk::Dispatcher::QueueEvent(InteractionEvent* event) { m_QueuedEvents.push_back(event); } void mitk::Dispatcher::SetEventProcessingMode(DataInteractor::Pointer dataInteractor) { m_ProcessingMode = dataInteractor->GetMode(); if (dataInteractor->GetMode() != REGULAR) { m_SelectedInteractor = dataInteractor; } } bool mitk::Dispatcher::HandleInternalEvent(InternalEvent* internalEvent) { if (internalEvent->GetSignalName() == IntDeactivateMe && internalEvent->GetTargetInteractor() != NULL) { internalEvent->GetTargetInteractor()->GetDataNode()->SetDataInteractor(NULL); internalEvent->GetTargetInteractor()->SetDataNode(NULL); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); return true; } return false; } diff --git a/Core/Code/Interactions/mitkDispatcher.h b/Core/Code/Interactions/mitkDispatcher.h index 2ba95e36d4..89a580d88e 100644 --- a/Core/Code/Interactions/mitkDispatcher.h +++ b/Core/Code/Interactions/mitkDispatcher.h @@ -1,131 +1,131 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 mitkDispatcher_h #define mitkDispatcher_h #include "itkLightObject.h" #include "itkObjectFactory.h" #include "mitkCommon.h" #include "mitkDataNode.h" #include "mitkDataInteractor.h" #include #include #include "mitkServiceTracker.h" namespace mitk { class InternalEvent; class InteractionEvent; - class InteractionEventObserver; + struct InteractionEventObserver; /** * \class Dispatcher * \brief Manages event distribution * * Receives Events (Mouse-,Key-, ... Events) and dispatches them to the registered DataInteractor Objects. * The order in which DataInteractors are offered to handle an event is determined by layer of their associated DataNode. * Higher layers are preferred. * * \ingroup Interaction */ class MITK_CORE_EXPORT Dispatcher: public itk::LightObject { public: mitkClassMacro(Dispatcher, itk::LightObject); itkNewMacro(Self); typedef std::list ListInteractorType; typedef std::list > ListEventsType; /** * To post new Events which are to be handled by the Dispatcher. * * @return Returns true if the event has been handled by an DataInteractor, and false else. */ bool ProcessEvent(InteractionEvent* event); /** * Adds an Event to the Dispatchers EventQueue, these events will be processed after a a regular posted event has been fully handled. * This allows DataInteractors to post their own events without interrupting regular Dispatching workflow. * It is important to note that the queued events will be processed AFTER the state change of a current transition (which queued the events) * is performed. * * \note 1) If an event is added from an other source than an DataInteractor / Observer its execution will be delayed until the next regular event * comes in. * \note 2) Make sure you're not causing infinite loops! */ void QueueEvent(InteractionEvent* event); /** * Adds the DataInteractor that is associated with the DataNode to the Dispatcher Queue. * If there already exists an DataInteractor that has a reference to the same DataNode, it is removed. * Note that within this method also all other DataInteractors are checked and removed if they are no longer active, * and were not removed properly. */ void AddDataInteractor(const DataNode* dataNode); /** * Remove all DataInteractors related to this Node, to prevent double entries and dead references. */ void RemoveDataInteractor(const DataNode* dataNode); size_t GetNumberOfInteractors(); // DEBUG TESTING protected: Dispatcher(); virtual ~Dispatcher(); private: struct cmp{ bool operator()(DataInteractor::Pointer d1, DataInteractor::Pointer d2){ return (d1->GetLayer() > d2->GetLayer()); } }; std::list m_Interactors; ListEventsType m_QueuedEvents; /** * Removes all Interactors without a DataNode pointing to them, this is necessary especially when a DataNode is assigned to a new Interactor */ void RemoveOrphanedInteractors(); /** * See \ref DispatcherEventDistSection for a description of ProcessEventModes */ ProcessEventMode m_ProcessingMode; DataInteractor::Pointer m_SelectedInteractor; void SetEventProcessingMode(DataInteractor::Pointer); /** * Function to handle special internal events, * such as events that are directed at a specific DataInteractor, * or the request to delete an Interactor and its DataNode. */ bool HandleInternalEvent(InternalEvent* internalEvent); /** * Hold microservice reference to object that takes care of informing the InteractionEventObservers about InteractionEvents */ - mitk::ServiceTracker m_EventObserverTracker; + mitk::ServiceTracker* m_EventObserverTracker; }; } /* namespace mitk */ #endif /* mitkDispatcher_h */ diff --git a/Core/Code/Interactions/mitkEventMapper.cpp b/Core/Code/Interactions/mitkEventMapper.cpp index 23515bdbaf..82db98a890 100644 --- a/Core/Code/Interactions/mitkEventMapper.cpp +++ b/Core/Code/Interactions/mitkEventMapper.cpp @@ -1,710 +1,706 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /** * EventMapping: * This class maps the Events, usually given by the OS or here by QT, to a MITK internal EventId. * It loads all information from the xml-file (possible, understandable Events with the mitkEventID). * If an event appears, the method MapEvent is called with the event params. * This Method looks up the event params, and tries to find an mitkEventId to it. * If yes, then sends the event and the found ID to the globalStateMachine, which handles all * further operations of that event. * */ #include "mitkEventMapper.h" #include "mitkInteractionConst.h" #include "mitkStateEvent.h" #include "mitkOperationEvent.h" #include "mitkGlobalInteraction.h" #include #include "mitkStandardFileLocations.h" //#include #include "mitkConfig.h" #include "mitkCoreObjectFactory.h" #include #include #include #include // us #include "mitkModule.h" #include "mitkModuleResource.h" #include "mitkModuleResourceStream.h" #include "mitkModuleRegistry.h" #include #include namespace mitk { vtkStandardNewMacro(EventMapper); } #ifdef MBI_INTERNAL_CONFERENCE #include #include #include #include #include #endif //MBI_INTERNAL_CONFERENCE //XML Event const std::string mitk::EventMapper::STYLE = "STYLE"; const std::string mitk::EventMapper::NAME = "NAME"; const std::string mitk::EventMapper::ID = "ID"; const std::string mitk::EventMapper::TYPE = "TYPE"; const std::string mitk::EventMapper::BUTTON = "BUTTON"; const std::string mitk::EventMapper::BUTTONSTATE = "BUTTONSTATE"; const std::string mitk::EventMapper::KEY = "KEY"; const std::string mitk::EventMapper::EVENTS = "events"; const std::string mitk::EventMapper::EVENT = "event"; mitk::EventMapper::EventDescriptionVec mitk::EventMapper::m_EventDescriptions; std::string mitk::EventMapper::m_XmlFileName; mitk::StateEvent mitk::EventMapper::m_StateEvent; std::string mitk::EventMapper::m_StyleName; struct ltstr { bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) < 0; } }; mitk::EventMapper::EventMapper() { //map with string to key for mapping string from xml-file to int m_EventConstMap["Type_None"] = mitk::Type_None; // invalid event m_EventConstMap["Type_Timer"] = mitk::Type_Timer; // timer event m_EventConstMap["Type_MouseButtonPress"] = mitk::Type_MouseButtonPress; // mouse button pressed m_EventConstMap["Type_MouseButtonRelease"] = mitk::Type_MouseButtonRelease; // mouse button released m_EventConstMap["Type_MouseButtonDblClick"] = mitk::Type_MouseButtonDblClick; // mouse button double click m_EventConstMap["Type_MouseMove"] = mitk::Type_MouseMove; // mouse move m_EventConstMap["Type_KeyPress"] = mitk::Type_KeyPress; // key pressed m_EventConstMap["Type_KeyRelease"] = mitk::Type_KeyRelease; // key released m_EventConstMap["Type_FocusIn"] = 8; // keyboard focus received m_EventConstMap["Type_FocusOut"] = 9; // keyboard focus lost m_EventConstMap["Type_Enter"] = 10; // mouse enters widget m_EventConstMap["Type_Leave"] = 11; // mouse leaves widget m_EventConstMap["Type_Paint"] = 12; // paint widget m_EventConstMap["Type_Move"] = 13; // move widget m_EventConstMap["Type_Resize"] = 14; // resize widget m_EventConstMap["Type_Create"] = 15; // after object creation m_EventConstMap["Type_Destroy"] = 16; // during object destruction m_EventConstMap["Type_Show"] = 17; // widget is shown m_EventConstMap["Type_Hide"] = 18; // widget is hidden m_EventConstMap["Type_Close"] = 19; // request to close widget m_EventConstMap["Type_Quit"] = 20; // request to quit application m_EventConstMap["Type_Reparent"] = 21; // widget has been reparented m_EventConstMap["Type_ShowMinimized"] = 22; // widget is shown minimized m_EventConstMap["Type_ShowNormal"] = 23; // widget is shown normal m_EventConstMap["Type_WindowActivate"] = 24; // window was activated m_EventConstMap["Type_WindowDeactivate"] = 25; // window was deactivated m_EventConstMap["Type_ShowToParent"] = 26; // widget is shown to parent m_EventConstMap["Type_HideToParent"] = 27; // widget is hidden to parent m_EventConstMap["Type_ShowMaximized"] = 28; // widget is shown maximized m_EventConstMap["Type_ShowFullScreen"] = 29; // widget is shown full-screen m_EventConstMap["Type_Accel"] = 30; // accelerator event m_EventConstMap["Type_Wheel"] = 31; // wheel event m_EventConstMap["Type_AccelAvailable"] = 32; // accelerator available event m_EventConstMap["Type_CaptionChange"] = 33; // caption changed m_EventConstMap["Type_IconChange"] = 34; // icon changed m_EventConstMap["Type_ParentFontChange"] = 35; // parent font changed m_EventConstMap["Type_ApplicationFontChange"] = 36;// application font changed m_EventConstMap["Type_ParentPaletteChange"] = 37; // parent palette changed m_EventConstMap["Type_ApplicationPaletteChange"] = 38;// application palette changed m_EventConstMap["Type_PaletteChange"] = 39; // widget palette changed m_EventConstMap["Type_Clipboard"] = 40; // internal clipboard event m_EventConstMap["Type_Speech"] = 42; // reserved for speech input m_EventConstMap["Type_SockAct"] = 50; // socket activation m_EventConstMap["Type_AccelOverride"] = 51; // accelerator override event m_EventConstMap["Type_DeferredDelete"] = 52; // deferred delete event m_EventConstMap["Type_DragEnter"] = 60; // drag moves into widget m_EventConstMap["Type_DragMove"] = 61; // drag moves in widget m_EventConstMap["Type_DragLeave"] = 62; // drag leaves or is cancelled m_EventConstMap["Type_Drop"] = 63; // actual drop m_EventConstMap["Type_DragResponse"] = 64; // drag accepted/rejected m_EventConstMap["Type_ChildInserted"] = 70; // new child widget m_EventConstMap["Type_ChildRemoved"] = 71; // deleted child widget m_EventConstMap["Type_LayoutHint"] = 72; // child min/max size changed m_EventConstMap["Type_ShowWindowRequest"] = 73; // widget's window should be mapped m_EventConstMap["Type_ActivateControl"] = 80; // ActiveX activation m_EventConstMap["Type_DeactivateControl"] = 81; // ActiveX deactivation m_EventConstMap["Type_ContextMenu"] = 82; // context popup menu m_EventConstMap["Type_IMStart"] = 83; // input method composition start m_EventConstMap["Type_IMCompose"] = 84; // input method composition m_EventConstMap["Type_IMEnd"] = 85; // input method composition end m_EventConstMap["Type_Accessibility"] = 86; // accessibility information is requested m_EventConstMap["Type_TabletMove"] = 87; // Wacom tablet event m_EventConstMap["Type_LocaleChange"] = 88; // the system locale changed m_EventConstMap["Type_LanguageChange"] = 89; // the application language changed m_EventConstMap["Type_LayoutDirectionChange"] = 90; // the layout direction changed m_EventConstMap["Type_Style"] = 91; // internal style event m_EventConstMap["Type_TabletPress"] = 92; // tablet press m_EventConstMap["Type_TabletRelease"] = 93; // tablet release // apparently not necessary, since the IDs can be assigned earlier (in the AddOns after they are generated in the driver) //m_EventConstMap["Type_TDMouseInput"] = mitk::Type_TDMouseInput; // 3D mouse input occured m_EventConstMap["Type_User"] = 1000; // first user event id m_EventConstMap["Type_MaxUser"] = 65535; // last user event id //ButtonState m_EventConstMap["BS_NoButton"] = mitk::BS_NoButton;//0x0000 m_EventConstMap["BS_LeftButton"] = mitk::BS_LeftButton;//0x0001 m_EventConstMap["BS_RightButton"] = mitk::BS_RightButton;//0x0002 m_EventConstMap["BS_MidButton"] = mitk::BS_MidButton;//0x0004 m_EventConstMap["BS_MouseButtonMask"] = mitk::BS_MouseButtonMask;//0x0007 m_EventConstMap["BS_ShiftButton"] = mitk::BS_ShiftButton;//0x0008 m_EventConstMap["BS_ControlButton"] = mitk::BS_ControlButton;//0x0010 m_EventConstMap["BS_AltButton"] = mitk::BS_AltButton;//0x0020 m_EventConstMap["BS_KeyButtonMask"] = mitk::BS_KeyButtonMask;//0x0038 m_EventConstMap["BS_Keypad"] = mitk::BS_Keypad;//0x4000 //Modifier m_EventConstMap["Mod_SHIFT"] = 0x00200000; m_EventConstMap["Mod_CTRL"] = 0x00400000; m_EventConstMap["Mod_ALT"] = 0x00800000; m_EventConstMap["Mod_MODIFIER_MASK"] = 0x00e00000; m_EventConstMap["Mod_UNICODE_ACCEL"] = 0x10000000; m_EventConstMap["Mod_ASCII_ACCEL"] = 0x10000000; //Key m_EventConstMap["Key_Escape"] = 0x1000; m_EventConstMap["Key_Tab"] = 0x1001; m_EventConstMap["Key_Backtab"] = 0x1002; m_EventConstMap["Key_BackTab"] = 0x1002; m_EventConstMap["Key_Backspace"] = 0x1003; m_EventConstMap["Key_BackSpace"] = 0x1003; m_EventConstMap["Key_Return"] = 0x1004; m_EventConstMap["Key_Enter"] = 0x1005; m_EventConstMap["Key_Insert"] = 0x1006; m_EventConstMap["Key_Delete"] = 0x1007; m_EventConstMap["Key_Pause"] = 0x1008; m_EventConstMap["Key_Print"] = 0x1009; m_EventConstMap["Key_SysReq"] = 0x100a; m_EventConstMap["Key_Home"] = 0x1010; m_EventConstMap["Key_End"] = 0x1011; m_EventConstMap["Key_Left"] = 0x1012; m_EventConstMap["Key_Up"] = 0x1013; m_EventConstMap["Key_Right"] = 0x1014; m_EventConstMap["Key_Down"] = 0x1015; m_EventConstMap["Key_Prior"] = 0x1016; m_EventConstMap["Key_PageUp"] = 0x1016; m_EventConstMap["Key_Next"] = 0x1017; m_EventConstMap["Key_PageDown"] = 0x1017; m_EventConstMap["Key_Shift"] = 0x1020; m_EventConstMap["Key_Control"] = 0x1021; m_EventConstMap["Key_Meta"] = 0x1022; m_EventConstMap["Key_Alt"] = 0x1023; m_EventConstMap["Key_CapsLock"] = 0x1024; m_EventConstMap["Key_NumLock"] = 0x1025; m_EventConstMap["Key_ScrollLock"] = 0x1026; m_EventConstMap["Key_F1"] = 0x1030; m_EventConstMap["Key_F2"] = 0x1031; m_EventConstMap["Key_F3"] = 0x1032; m_EventConstMap["Key_F4"] = 0x1033; m_EventConstMap["Key_F5"] = 0x1034; m_EventConstMap["Key_F6"] = 0x1035; m_EventConstMap["Key_F7"] = 0x1036; m_EventConstMap["Key_F8"] = 0x1037; m_EventConstMap["Key_F9"] = 0x1038; m_EventConstMap["Key_F10"] = 0x1039; m_EventConstMap["Key_F11"] = 0x103a; m_EventConstMap["Key_F12"] = 0x103b; m_EventConstMap["Key_F13"] = 0x103c; m_EventConstMap["Key_F14"] = 0x103d; m_EventConstMap["Key_F15"] = 0x103e; m_EventConstMap["Key_F16"] = 0x103f; m_EventConstMap["Key_F17"] = 0x1040; m_EventConstMap["Key_F18"] = 0x1041; m_EventConstMap["Key_F19"] = 0x1042; m_EventConstMap["Key_F20"] = 0x1043; m_EventConstMap["Key_F21"] = 0x1044; m_EventConstMap["Key_F22"] = 0x1045; m_EventConstMap["Key_F23"] = 0x1046; m_EventConstMap["Key_F24"] = 0x1047; m_EventConstMap["Key_F25"] = 0x1048; m_EventConstMap["Key_F26"] = 0x1049; m_EventConstMap["Key_F27"] = 0x104a; m_EventConstMap["Key_F28"] = 0x104b; m_EventConstMap["Key_F29"] = 0x104c; m_EventConstMap["Key_F30"] = 0x104d; m_EventConstMap["Key_F31"] = 0x104e; m_EventConstMap["Key_F32"] = 0x104f; m_EventConstMap["Key_F33"] = 0x1050; m_EventConstMap["Key_F34"] = 0x1051; m_EventConstMap["Key_F35"] = 0x1052; m_EventConstMap["Key_Super_L"] = 0x1053; m_EventConstMap["Key_Super_R"] = 0x1054; m_EventConstMap["Key_Menu"] = 0x1055; m_EventConstMap["Key_Hyper_L"] = 0x1056; m_EventConstMap["Key_Hyper_R"] = 0x1057; m_EventConstMap["Key_Help"] = 0x1058; m_EventConstMap["Key_Muhenkan"] = 0x1122; m_EventConstMap["Key_Henkan"] = 0x1123; m_EventConstMap["Key_Hiragana_Katakana"] = 0x1127; m_EventConstMap["Key_Zenkaku_Hankaku"] = 0x112A; m_EventConstMap["Key_Space"] = 0x20; m_EventConstMap["Key_Any"] = 0x20; m_EventConstMap["Key_Exclam"] = 0x21; m_EventConstMap["Key_QuoteDbl"] = 0x22; m_EventConstMap["Key_NumberSign"] = 0x23; m_EventConstMap["Key_Dollar"] = 0x24; m_EventConstMap["Key_Percent"] = 0x25; m_EventConstMap["Key_Ampersand"] = 0x26; m_EventConstMap["Key_Apostrophe"] = 0x27; m_EventConstMap["Key_ParenLeft"] = 0x28; m_EventConstMap["Key_ParenRight"] = 0x29; m_EventConstMap["Key_Asterisk"] = 0x2a; m_EventConstMap["Key_Plus"] = 0x2b; m_EventConstMap["Key_Comma"] = 0x2c; m_EventConstMap["Key_Minus"] = 0x2d; m_EventConstMap["Key_Period"] = 0x2e; m_EventConstMap["Key_Slash"] = 0x2f; m_EventConstMap["Key_0"] = 0x30; m_EventConstMap["Key_1"] = 0x31; m_EventConstMap["Key_2"] = 0x32; m_EventConstMap["Key_3"] = 0x33; m_EventConstMap["Key_4"] = 0x34; m_EventConstMap["Key_5"] = 0x35; m_EventConstMap["Key_6"] = 0x36; m_EventConstMap["Key_7"] = 0x37; m_EventConstMap["Key_8"] = 0x38; m_EventConstMap["Key_9"] = 0x39; m_EventConstMap["Key_Colon"] = 0x3a; m_EventConstMap["Key_Semicolon"] = 0x3b; m_EventConstMap["Key_Less"] = 0x3c; m_EventConstMap["Key_Equal"] = 0x3d; m_EventConstMap["Key_Greater"] = 0x3e; m_EventConstMap["Key_Question"] = 0x3f; m_EventConstMap["Key_At"] = 0x40; m_EventConstMap["Key_A"] = 0x41; m_EventConstMap["Key_B"] = 0x42; m_EventConstMap["Key_C"] = 0x43; m_EventConstMap["Key_D"] = 0x44; m_EventConstMap["Key_E"] = 0x45; m_EventConstMap["Key_F"] = 0x46; m_EventConstMap["Key_G"] = 0x47; m_EventConstMap["Key_H"] = 0x48; m_EventConstMap["Key_I"] = 0x49; m_EventConstMap["Key_J"] = 0x4a; m_EventConstMap["Key_K"] = 0x4b; m_EventConstMap["Key_L"] = 0x4c; m_EventConstMap["Key_M"] = 0x4d; m_EventConstMap["Key_N"] = 0x4e; m_EventConstMap["Key_O"] = 0x4f; m_EventConstMap["Key_P"] = 0x50; m_EventConstMap["Key_Q"] = 0x51; m_EventConstMap["Key_R"] = 0x52; m_EventConstMap["Key_S"] = 0x53; m_EventConstMap["Key_T"] = 0x54; m_EventConstMap["Key_U"] = 0x55; m_EventConstMap["Key_V"] = 0x56; m_EventConstMap["Key_W"] = 0x57; m_EventConstMap["Key_X"] = 0x58; m_EventConstMap["Key_Y"] = 0x59; m_EventConstMap["Key_Z"] = 0x5a; m_EventConstMap["Key_BracketLeft"] = 0x5b; m_EventConstMap["Key_Backslash"] = 0x5c; m_EventConstMap["Key_BracketRight"] = 0x5d; m_EventConstMap["Key_AsciiCircum"] = 0x5e; m_EventConstMap["Key_Underscore"] = 0x5f; m_EventConstMap["Key_QuoteLeft"] = 0x60; m_EventConstMap["Key_BraceLeft"] = 0x7b; m_EventConstMap["Key_Bar"] = 0x7c; m_EventConstMap["Key_BraceRight"] = 0x7d; m_EventConstMap["Key_AsciiTilde"] = 0x7e; m_EventConstMap["Key_nobreakspace"] = 0x0a0; m_EventConstMap["Key_exclamdown"] = 0x0a1; m_EventConstMap["Key_cent"] = 0x0a2; m_EventConstMap["Key_sterling"] = 0x0a3; m_EventConstMap["Key_currency"] = 0x0a4; m_EventConstMap["Key_yen"] = 0x0a5; m_EventConstMap["Key_brokenbar"] = 0x0a6; m_EventConstMap["Key_section"] = 0x0a7; m_EventConstMap["Key_diaeresis"] = 0x0a8; m_EventConstMap["Key_copyright"] = 0x0a9; m_EventConstMap["Key_ordfeminine"] = 0x0aa; m_EventConstMap["Key_guillemotleft"] = 0x0ab; m_EventConstMap["Key_notsign"] = 0x0ac; m_EventConstMap["Key_hyphen"] = 0x0ad; m_EventConstMap["Key_registered"] = 0x0ae; m_EventConstMap["Key_macron"] = 0x0af; m_EventConstMap["Key_degree"] = 0x0b0; m_EventConstMap["Key_plusminus"] = 0x0b1; m_EventConstMap["Key_twosuperior"] = 0x0b2; m_EventConstMap["Key_threesuperior"] = 0x0b3; m_EventConstMap["Key_acute"] = 0x0b4; m_EventConstMap["Key_mu"] = 0x0b5; m_EventConstMap["Key_paragraph"] = 0x0b6; m_EventConstMap["Key_periodcentered"] = 0x0b7; m_EventConstMap["Key_cedilla"] = 0x0b8; m_EventConstMap["Key_onesuperior"] = 0x0b9; m_EventConstMap["Key_masculine"] = 0x0ba; m_EventConstMap["Key_guillemotright"] = 0x0bb; m_EventConstMap["Key_onequarter"] = 0x0bc; m_EventConstMap["Key_onehalf"] = 0x0bd; m_EventConstMap["Key_threequarters"] = 0x0be; m_EventConstMap["Key_questiondown"] = 0x0bf; m_EventConstMap["Key_Agrave"] = 0x0c0; m_EventConstMap["Key_Aacute"] = 0x0c1; m_EventConstMap["Key_Acircumflex"] = 0x0c2; m_EventConstMap["Key_Atilde"] = 0x0c3; m_EventConstMap["Key_Adiaeresis"] = 0x0c4; m_EventConstMap["Key_Aring"] = 0x0c5; m_EventConstMap["Key_AE"] = 0x0c6; m_EventConstMap["Key_Ccedilla"] = 0x0c7; m_EventConstMap["Key_Egrave"] = 0x0c8; m_EventConstMap["Key_Eacute"] = 0x0c9; m_EventConstMap["Key_Ecircumflex"] = 0x0ca; m_EventConstMap["Key_Ediaeresis"] = 0x0cb; m_EventConstMap["Key_Igrave"] = 0x0cc; m_EventConstMap["Key_Iacute"] = 0x0cd; m_EventConstMap["Key_Icircumflex"] = 0x0ce; m_EventConstMap["Key_Idiaeresis"] = 0x0cf; m_EventConstMap["Key_ETH"] = 0x0d0; m_EventConstMap["Key_Ntilde"] = 0x0d1; m_EventConstMap["Key_Ograve"] = 0x0d2; m_EventConstMap["Key_Oacute"] = 0x0d3; m_EventConstMap["Key_Ocircumflex"] = 0x0d4; m_EventConstMap["Key_Otilde"] = 0x0d5; m_EventConstMap["Key_Odiaeresis"] = 0x0d6; m_EventConstMap["Key_multiply"] = 0x0d7; m_EventConstMap["Key_Ooblique"] = 0x0d8; m_EventConstMap["Key_Ugrave"] = 0x0d9; m_EventConstMap["Key_Uacute"] = 0x0da; m_EventConstMap["Key_Ucircumflex"] = 0x0db; m_EventConstMap["Key_Udiaeresis"] = 0x0dc; m_EventConstMap["Key_Yacute"] = 0x0dd; m_EventConstMap["Key_THORN"] = 0x0de; m_EventConstMap["Key_ssharp"] = 0x0df; m_EventConstMap["Key_agrave"] = 0x0e0; m_EventConstMap["Key_aacute"] = 0x0e1; m_EventConstMap["Key_acircumflex"] = 0x0e2; m_EventConstMap["Key_atilde"] = 0x0e3; m_EventConstMap["Key_adiaeresis"] = 0x0e4; m_EventConstMap["Key_aring"] = 0x0e5; m_EventConstMap["Key_ae"] = 0x0e6; m_EventConstMap["Key_ccedilla"] = 0x0e7; m_EventConstMap["Key_egrave"] = 0x0e8; m_EventConstMap["Key_eacute"] = 0x0e9; m_EventConstMap["Key_ecircumflex"] = 0x0ea; m_EventConstMap["Key_ediaeresis"] = 0x0eb; m_EventConstMap["Key_igrave"] = 0x0ec; m_EventConstMap["Key_iacute"] = 0x0ed; m_EventConstMap["Key_icircumflex"] = 0x0ee; m_EventConstMap["Key_idiaeresis"] = 0x0ef; m_EventConstMap["Key_eth"] = 0x0f0; m_EventConstMap["Key_ntilde"] = 0x0f1; m_EventConstMap["Key_ograve"] = 0x0f2; m_EventConstMap["Key_oacute"] = 0x0f3; m_EventConstMap["Key_ocircumflex"] = 0x0f4; m_EventConstMap["Key_otilde"] = 0x0f5; m_EventConstMap["Key_odiaeresis"] = 0x0f6; m_EventConstMap["Key_division"] = 0x0f7; m_EventConstMap["Key_oslash"] = 0x0f8; m_EventConstMap["Key_ugrave"] = 0x0f9; m_EventConstMap["Key_uacute"] = 0x0fa; m_EventConstMap["Key_ucircumflex"] = 0x0fb; m_EventConstMap["Key_udiaeresis"] = 0x0fc; m_EventConstMap["Key_yacute"] = 0x0fd; m_EventConstMap["Key_thorn"] = 0x0fe; m_EventConstMap["Key_ydiaeresis"] = 0x0ff; m_EventConstMap["Key_unknown"] = 0xffff; m_EventConstMap["Key_none"] = 0xffff; } mitk::EventMapper::~EventMapper() { } //##Documentation //## searches for the event in m_EventDescription and adds the corresponding eventID //## bool mitk::EventMapper::MapEvent(Event* event, GlobalInteraction* globalInteraction, int mitkPostedEventID ) { int eventID = mitkPostedEventID; if( mitkPostedEventID == 0 ) { //search the event in the list of event descriptions, if found, then take the number and produce a stateevent EventDescriptionVecIter iter; for (iter = m_EventDescriptions.begin(); iter!=m_EventDescriptions.end();iter++) { if (*iter == *event) break; } if (iter == m_EventDescriptions.end())//not found return false; eventID = (*iter).GetId(); } //set the Menger_Var m_StateEvent and send to StateMachine, which does everything further! m_StateEvent.Set( eventID, event ); /* Group and Object EventId: then EventMapper has the power to decide which operations hang together; each event causes n (n e N) operations (e.g. StateChanges, data-operations...). Undo must recall all these coherent operations, so all of the same objectId. But Undo has also the power to recall more operationsets, for example a set for building up a new object, so that a newly build up object is deleted after a Undo and not only the latest set point. The StateMachines::ExecuteAction have the power to descide weather a new GroupID has to be calculated (by example after the editing of a new object) A user interaction with the mouse is started by a mousePressEvent, continues with a MouseMove and finishes with a MouseReleaseEvent */ switch (event->GetType()) { case mitk::Type_MouseButtonPress://Increase mitk::OperationEvent::IncCurrObjectEventId(); break; case mitk::Type_MouseMove://same break; case mitk::Type_MouseButtonRelease://same break; case mitk::Type_User://same break; case mitk::Type_KeyPress://Increase mitk::OperationEvent::IncCurrObjectEventId(); break; default://increase mitk::OperationEvent::IncCurrObjectEventId(); } #ifdef MBI_INTERNAL_CONFERENCE //Conference - pass local events through if ( mitkPostedEventID == 0 ) { mitk::CoreObjectFactory::GetInstance()->MapEvent(event,eventID); } #endif //MBI_INTERNAL_CONFERENCE mitk::OperationEvent::ExecuteIncrement(); if ( globalInteraction != NULL ) { return globalInteraction->HandleEvent( &m_StateEvent ); } else { return mitk::GlobalInteraction::GetInstance()->HandleEvent(&m_StateEvent); } } bool mitk::EventMapper::LoadBehavior(std::string fileName) { if ( fileName.empty() ) return false; if (m_XmlFileName.length() > 0) { if (fileName.compare(m_XmlFileName) == 0) return true; // this is nothing bad, we already loaded this file. } this->SetFileName( fileName.c_str() ); m_XmlFileName = fileName.c_str(); return ( this->Parse() ); } bool mitk::EventMapper::LoadBehaviorString(std::string xmlString) { if ( xmlString.empty() ) return false; return ( this->Parse(xmlString.c_str(), xmlString.length()) ); } bool mitk::EventMapper::LoadStandardBehavior() { - Module* module = GetModuleContext()->GetModule(); - if (module == NULL) { - mitkThrow()<< ("Module context unavailable." ); - return false; - } + Module* module = ModuleRegistry::GetModule("Mitk"); ModuleResource resource = module->GetResource("Interactions/Legacy/StateMachine.xml"); if (!resource.IsValid()) { mitkThrow()<< ("Resource not valid. State machine pattern not found:Interactions/Legacy/StateMachine.xml" ); } mitk::ModuleResourceStream stream(resource); - this->SetStream(&stream); - return this->Parse(); + std::string patternString((std::istreambuf_iterator(stream)), std::istreambuf_iterator()); + return this->LoadBehaviorString(patternString); } //##Documentation //## @brief converts the given const String declared in the xml-file //## to the defined const int inline int mitk::EventMapper::convertConstString2ConstInt(std::string input) { ConstMapIter tempIt = m_EventConstMap.find(input.c_str()); if (tempIt != m_EventConstMap.end()) { return (tempIt)->second; } //mitk::StatusBar::GetInstance()->DisplayText("Warning! from mitkEventMapper.cpp: Couldn't find matching Event Int from Event String in XML-File"); return -1;//for didn't find anything } void mitk::EventMapper::StartElement (const char *elementName, const char **atts) { if ( elementName == EVENT ) { // EventDescription(int type, int button, int buttonState,int key, std::string name, int id) EventDescription eventDescr( convertConstString2ConstInt( ReadXMLStringAttribut( TYPE, atts )), convertConstString2ConstInt( ReadXMLStringAttribut( BUTTON, atts )), ReadXMLIntegerAttribut( BUTTONSTATE, atts ), convertConstString2ConstInt( ReadXMLStringAttribut( KEY, atts )), ReadXMLStringAttribut( NAME, atts ), ReadXMLIntegerAttribut( ID, atts )); //check for a double entry unless it is an event for internal usage if (eventDescr.GetType()!= mitk::Type_User) { for (EventDescriptionVecIter iter = m_EventDescriptions.begin(); iter!=m_EventDescriptions.end(); iter++) { if (*iter == eventDescr) { MITK_DEBUG << "Event description " << eventDescr.GetName() << " already present! Skipping event description"; return; } } } m_EventDescriptions.push_back(eventDescr); } else if ( elementName == EVENTS ) m_StyleName = ReadXMLStringAttribut( STYLE, atts ); } std::string mitk::EventMapper::GetStyleName() const { return m_StyleName; } std::string mitk::EventMapper::ReadXMLStringAttribut( std::string name, const char** atts ) { if(atts) { const char** attsIter = atts; while(*attsIter) { if ( name == *attsIter ) { attsIter++; return *attsIter; } attsIter++; attsIter++; } } return std::string(); } int mitk::EventMapper::ReadXMLIntegerAttribut( std::string name, const char** atts ) { std::string s = ReadXMLStringAttribut( name, atts ); static const std::string hex = "0x"; int result; if ( s[0] == hex[0] && s[1] == hex[1] ) result = strtol( s.c_str(), NULL, 16 ); else result = atoi( s.c_str() ); return result; } void mitk::EventMapper::SetStateEvent(mitk::Event* event) { m_StateEvent.Set( m_StateEvent.GetId(), event ); } bool mitk::EventMapper::RefreshStateEvent(mitk::StateEvent* stateEvent) { //search the event within stateEvent in the list of event descriptions, if found adapt stateEvent ID EventDescriptionVecIter iter; for (iter = m_EventDescriptions.begin(); iter!=m_EventDescriptions.end(); iter++) { if (*iter == *(stateEvent->GetEvent())) break; } if (iter != m_EventDescriptions.end())//found { stateEvent->Set((*iter).GetId(), stateEvent->GetEvent()); return true; } else return false; return false; } void mitk::EventMapper::AddEventMapperAddOn(mitk::EventMapperAddOn* newAddOn) { bool addOnAlreadyAdded = false; for(AddOnVectorType::const_iterator it = this->m_AddOnVector.begin();it != m_AddOnVector.end();it++) { if(*it == newAddOn) { addOnAlreadyAdded = true; break; } } if(!addOnAlreadyAdded) { m_AddOnVector.push_back(newAddOn); MITK_INFO << "AddOn Count: " << m_AddOnVector.size(); } } void mitk::EventMapper::RemoveEventMapperAddOn(mitk::EventMapperAddOn* unusedAddOn) { for(AddOnVectorType::iterator it = this->m_AddOnVector.begin();it != m_AddOnVector.end();it++) { if(*it == unusedAddOn) { m_AddOnVector.erase(it); break; } } } diff --git a/Core/Code/Interactions/mitkMouseModeSwitcher.cpp b/Core/Code/Interactions/mitkMouseModeSwitcher.cpp index 5412233987..2c8169dfb4 100644 --- a/Core/Code/Interactions/mitkMouseModeSwitcher.cpp +++ b/Core/Code/Interactions/mitkMouseModeSwitcher.cpp @@ -1,110 +1,110 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkMouseModeSwitcher.h" // us #include "mitkGetModuleContext.h" #include "mitkModule.h" #include "mitkModuleRegistry.h" #include "mitkInteractionEventObserver.h" mitk::MouseModeSwitcher::MouseModeSwitcher() : m_ActiveInteractionScheme(MITK), m_ActiveMouseMode(MousePointer), m_CurrentObserver(NULL) { this->InitializeListeners(); this->SetInteractionScheme(m_ActiveInteractionScheme); } mitk::MouseModeSwitcher::~MouseModeSwitcher() { -// m_ServiceRegistration.Unregister(); + m_ServiceRegistration.Unregister(); } void mitk::MouseModeSwitcher::InitializeListeners() { if (m_CurrentObserver.IsNull()) { m_CurrentObserver = mitk::DisplayInteractor::New(); m_CurrentObserver->LoadStateMachine("DisplayInteraction.xml"); m_CurrentObserver->LoadEventConfig("DisplayConfigMITK.xml"); // Register as listener via micro services - ServiceRegistration m_ServiceRegistration = GetModuleContext()->RegisterService( + m_ServiceRegistration = GetModuleContext()->RegisterService( m_CurrentObserver.GetPointer()); } } void mitk::MouseModeSwitcher::SetInteractionScheme(InteractionScheme scheme) { switch (scheme) { case MITK: { m_CurrentObserver->LoadEventConfig("DisplayConfigMITK.xml"); } break; case PACS: { m_CurrentObserver->LoadEventConfig("DisplayConfigPACS.xml"); } break; } m_ActiveInteractionScheme = scheme; this->InvokeEvent(MouseModeChangedEvent()); } void mitk::MouseModeSwitcher::SelectMouseMode(MouseMode mode) { if (m_ActiveInteractionScheme != PACS) return; switch (mode) { case MousePointer: { m_CurrentObserver->LoadEventConfig("DisplayConfigPACS.xml"); break; } // case 0 case Scroll: { m_CurrentObserver->AddEventConfig("DisplayConfigPACSScroll.xml"); break; } case LevelWindow: { m_CurrentObserver->AddEventConfig("DisplayConfigPACSLevelWindow.xml"); break; } case Zoom: { m_CurrentObserver->AddEventConfig("DisplayConfigPACSZoom.xml"); break; } case Pan: { m_CurrentObserver->AddEventConfig("DisplayConfigPACSPan.xml"); break; } } // end switch (mode) m_ActiveMouseMode = mode; this->InvokeEvent(MouseModeChangedEvent()); } mitk::MouseModeSwitcher::MouseMode mitk::MouseModeSwitcher::GetCurrentMouseMode() const { return m_ActiveMouseMode; } diff --git a/Core/Code/Interactions/mitkMouseReleaseEvent.cpp b/Core/Code/Interactions/mitkMouseReleaseEvent.cpp index 4433732ed4..1a8a6d5354 100644 --- a/Core/Code/Interactions/mitkMouseReleaseEvent.cpp +++ b/Core/Code/Interactions/mitkMouseReleaseEvent.cpp @@ -1,83 +1,83 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkException.h" #include "mitkMouseReleaseEvent.h" -mitk::MouseReleaseEvent::MouseReleaseEvent(mitk::BaseRenderer* baseRenderer = NULL, +mitk::MouseReleaseEvent::MouseReleaseEvent(mitk::BaseRenderer* baseRenderer, mitk::Point2D mousePosition, mitk::MouseButtons buttonStates, mitk::ModifierKeys modifiers, mitk::MouseButtons eventButton) : InteractionPositionEvent(baseRenderer, mousePosition, "MouseReleaseEvent") , m_EventButton(eventButton) ,m_ButtonStates(buttonStates) , m_Modifiers(modifiers) { } mitk::MouseButtons mitk::MouseReleaseEvent::GetEventButton() const { return m_EventButton; } void mitk::MouseReleaseEvent::SetEventButton(MouseButtons buttons) { m_EventButton = buttons; } mitk::ModifierKeys mitk::MouseReleaseEvent::GetModifiers() const { return m_Modifiers; } mitk::MouseButtons mitk::MouseReleaseEvent::GetButtonStates() const { return m_ButtonStates; } void mitk::MouseReleaseEvent::SetModifiers(ModifierKeys modifiers) { m_Modifiers = modifiers; } void mitk::MouseReleaseEvent::SetButtonStates(MouseButtons buttons) { m_ButtonStates = buttons; } mitk::MouseReleaseEvent::~MouseReleaseEvent() { } bool mitk::MouseReleaseEvent::MatchesTemplate(mitk::InteractionEvent::Pointer interactionEvent) { mitk::MouseReleaseEvent* mre = dynamic_cast(interactionEvent.GetPointer()); if (mre == NULL) { return false; } return (this->GetEventButton() == mre->GetEventButton() && this->GetModifiers() == mre->GetModifiers() && this->GetButtonStates() == mre->GetButtonStates() ); } bool mitk::MouseReleaseEvent::IsSuperClassOf(InteractionEvent::Pointer baseClass) { return (dynamic_cast(baseClass.GetPointer()) != NULL) ; } diff --git a/Core/Code/Rendering/mitkBaseRenderer.cpp b/Core/Code/Rendering/mitkBaseRenderer.cpp index d6c516ed04..0e1015498e 100644 --- a/Core/Code/Rendering/mitkBaseRenderer.cpp +++ b/Core/Code/Rendering/mitkBaseRenderer.cpp @@ -1,835 +1,835 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkBaseRenderer.h" #include "mitkMapper.h" #include "mitkResliceMethodProperty.h" // Geometries #include "mitkPlaneGeometry.h" #include "mitkSlicedGeometry3D.h" // Controllers #include "mitkCameraController.h" #include "mitkSliceNavigationController.h" #include "mitkCameraRotationController.h" #include "mitkVtkInteractorCameraController.h" #ifdef MITK_USE_TD_MOUSE #include "mitkTDMouseVtkCameraController.h" #else #include "mitkCameraController.h" #endif #include "mitkVtkLayerController.h" // Events // TODO: INTERACTION_LEGACY #include "mitkEventMapper.h" #include "mitkGlobalInteraction.h" #include "mitkPositionEvent.h" #include "mitkDisplayPositionEvent.h" #include "mitkProperties.h" #include "mitkWeakPointerProperty.h" #include "mitkInteractionConst.h" // VTK #include #include #include #include #include #include #include mitk::BaseRenderer::BaseRendererMapType mitk::BaseRenderer::baseRendererMap; mitk::BaseRenderer* mitk::BaseRenderer::GetInstance(vtkRenderWindow * renWin) { for (BaseRendererMapType::iterator mapit = baseRendererMap.begin(); mapit != baseRendererMap.end(); mapit++) { if ((*mapit).first == renWin) return (*mapit).second; } return NULL; } void mitk::BaseRenderer::AddInstance(vtkRenderWindow* renWin, BaseRenderer* baseRenderer) { if (renWin == NULL || baseRenderer == NULL) return; // ensure that no BaseRenderer is managed twice mitk::BaseRenderer::RemoveInstance(renWin); baseRendererMap.insert(BaseRendererMapType::value_type(renWin, baseRenderer)); } void mitk::BaseRenderer::RemoveInstance(vtkRenderWindow* renWin) { BaseRendererMapType::iterator mapit = baseRendererMap.find(renWin); if (mapit != baseRendererMap.end()) baseRendererMap.erase(mapit); } mitk::BaseRenderer* mitk::BaseRenderer::GetByName(const std::string& name) { for (BaseRendererMapType::iterator mapit = baseRendererMap.begin(); mapit != baseRendererMap.end(); mapit++) { if ((*mapit).second->m_Name == name) return (*mapit).second; } return NULL; } vtkRenderWindow* mitk::BaseRenderer::GetRenderWindowByName(const std::string& name) { for (BaseRendererMapType::iterator mapit = baseRendererMap.begin(); mapit != baseRendererMap.end(); mapit++) { if ((*mapit).second->m_Name == name) return (*mapit).first; } return NULL; } mitk::BaseRenderer::BaseRenderer(const char* name, vtkRenderWindow * renWin, mitk::RenderingManager* rm) : m_RenderWindow(NULL), m_VtkRenderer(NULL), m_MapperID(defaultMapper), m_DataStorage(NULL), m_RenderingManager(rm), m_LastUpdateTime(0), m_CameraController( NULL), m_SliceNavigationController(NULL), m_CameraRotationController(NULL), /*m_Size(),*/ m_Focused(false), m_WorldGeometry(NULL), m_TimeSlicedWorldGeometry(NULL), m_CurrentWorldGeometry(NULL), m_CurrentWorldGeometry2D(NULL), m_DisplayGeometry( NULL), m_Slice(0), m_TimeStep(), m_CurrentWorldGeometry2DUpdateTime(), m_DisplayGeometryUpdateTime(), m_TimeStepUpdateTime(), m_WorldGeometryData( NULL), m_DisplayGeometryData(NULL), m_CurrentWorldGeometry2DData(NULL), m_WorldGeometryNode(NULL), m_DisplayGeometryNode(NULL), m_CurrentWorldGeometry2DNode( NULL), m_DisplayGeometryTransformTime(0), m_CurrentWorldGeometry2DTransformTime(0), m_Name(name), /*m_Bounds(),*/m_EmptyWorldGeometry( true), m_DepthPeelingEnabled(true), m_MaxNumberOfPeels(100), m_NumberOfVisibleLODEnabledMappers(0) { m_Bounds[0] = 0; m_Bounds[1] = 0; m_Bounds[2] = 0; m_Bounds[3] = 0; m_Bounds[4] = 0; m_Bounds[5] = 0; if (name != NULL) { m_Name = name; } else { m_Name = "unnamed renderer"; itkWarningMacro(<< "Created unnamed renderer. Bad for serialization. Please choose a name."); } if (renWin != NULL) { m_RenderWindow = renWin; m_RenderWindow->Register(NULL); } else { itkWarningMacro(<< "Created mitkBaseRenderer without vtkRenderWindow present."); } m_Size[0] = 0; m_Size[1] = 0; //instances.insert( this ); //adding this BaseRenderer to the List of all BaseRenderer // TODO: INTERACTION_LEGACY m_RenderingManager->GetGlobalInteraction()->AddFocusElement(this); m_BindDispatcherInteractor = new mitk::BindDispatcherInteractor(); WeakPointerProperty::Pointer rendererProp = WeakPointerProperty::New((itk::Object*) this); m_CurrentWorldGeometry2D = mitk::PlaneGeometry::New(); m_CurrentWorldGeometry2DData = mitk::Geometry2DData::New(); m_CurrentWorldGeometry2DData->SetGeometry2D(m_CurrentWorldGeometry2D); m_CurrentWorldGeometry2DNode = mitk::DataNode::New(); m_CurrentWorldGeometry2DNode->SetData(m_CurrentWorldGeometry2DData); m_CurrentWorldGeometry2DNode->GetPropertyList()->SetProperty("renderer", rendererProp); m_CurrentWorldGeometry2DNode->GetPropertyList()->SetProperty("layer", IntProperty::New(1000)); m_CurrentWorldGeometry2DNode->SetProperty("reslice.thickslices", mitk::ResliceMethodProperty::New()); m_CurrentWorldGeometry2DNode->SetProperty("reslice.thickslices.num", mitk::IntProperty::New(1)); m_CurrentWorldGeometry2DTransformTime = m_CurrentWorldGeometry2DNode->GetVtkTransform()->GetMTime(); m_DisplayGeometry = mitk::DisplayGeometry::New(); m_DisplayGeometry->SetWorldGeometry(m_CurrentWorldGeometry2D); m_DisplayGeometryData = mitk::Geometry2DData::New(); m_DisplayGeometryData->SetGeometry2D(m_DisplayGeometry); m_DisplayGeometryNode = mitk::DataNode::New(); m_DisplayGeometryNode->SetData(m_DisplayGeometryData); m_DisplayGeometryNode->GetPropertyList()->SetProperty("renderer", rendererProp); m_DisplayGeometryTransformTime = m_DisplayGeometryNode->GetVtkTransform()->GetMTime(); mitk::SliceNavigationController::Pointer sliceNavigationController = mitk::SliceNavigationController::New("navigation"); sliceNavigationController->SetRenderer(this); sliceNavigationController->ConnectGeometrySliceEvent(this); sliceNavigationController->ConnectGeometryUpdateEvent(this); sliceNavigationController->ConnectGeometryTimeEvent(this, false); m_SliceNavigationController = sliceNavigationController; m_CameraRotationController = mitk::CameraRotationController::New(); m_CameraRotationController->SetRenderWindow(m_RenderWindow); m_CameraRotationController->AcquireCamera(); //if TD Mouse Interaction is activated, then call TDMouseVtkCameraController instead of VtkInteractorCameraController #ifdef MITK_USE_TD_MOUSE m_CameraController = mitk::TDMouseVtkCameraController::New(); #else m_CameraController = mitk::CameraController::New(NULL); #endif m_VtkRenderer = vtkRenderer::New(); if (mitk::VtkLayerController::GetInstance(m_RenderWindow) == NULL) { mitk::VtkLayerController::AddInstance(m_RenderWindow, m_VtkRenderer); mitk::VtkLayerController::GetInstance(m_RenderWindow)->InsertSceneRenderer(m_VtkRenderer); } else mitk::VtkLayerController::GetInstance(m_RenderWindow)->InsertSceneRenderer(m_VtkRenderer); } mitk::BaseRenderer::~BaseRenderer() { if (m_VtkRenderer != NULL) { m_VtkRenderer->Delete(); m_VtkRenderer = NULL; } if (m_CameraController.IsNotNull()) m_CameraController->SetRenderer(NULL); m_RenderingManager->GetGlobalInteraction()->RemoveFocusElement(this); mitk::VtkLayerController::RemoveInstance(m_RenderWindow); RemoveAllLocalStorages(); m_DataStorage = NULL; if (m_BindDispatcherInteractor != NULL) { delete m_BindDispatcherInteractor; } if (m_RenderWindow != NULL) { m_RenderWindow->Delete(); m_RenderWindow = NULL; } } void mitk::BaseRenderer::RemoveAllLocalStorages() { this->InvokeEvent(mitk::BaseRenderer::RendererResetEvent()); std::list::iterator it; for (it = m_RegisteredLocalStorageHandlers.begin(); it != m_RegisteredLocalStorageHandlers.end(); it++) (*it)->ClearLocalStorage(this, false); m_RegisteredLocalStorageHandlers.clear(); } void mitk::BaseRenderer::RegisterLocalStorageHandler(mitk::BaseLocalStorageHandler *lsh) { m_RegisteredLocalStorageHandlers.push_back(lsh); } -mitk::Dispatcher::Pointer mitk::BaseRenderer::GetDispatcher() const +mitk::Dispatcher::Pointer mitk::BaseRenderer::GetDispatcher() { return m_BindDispatcherInteractor->GetDispatcher(); } mitk::Point3D mitk::BaseRenderer::Map2DRendererPositionTo3DWorldPosition(Point2D* mousePosition) const { Point2D p_mm; Point3D position; if (m_MapperID == 1) { GetDisplayGeometry()->ULDisplayToDisplay(*mousePosition, *mousePosition); GetDisplayGeometry()->DisplayToWorld(*mousePosition, p_mm); GetDisplayGeometry()->Map(p_mm, position); } else if (m_MapperID == 2) { GetDisplayGeometry()->ULDisplayToDisplay(*mousePosition, *mousePosition); PickWorldPoint(*mousePosition, position); } return position; } void mitk::BaseRenderer::UnregisterLocalStorageHandler(mitk::BaseLocalStorageHandler *lsh) { m_RegisteredLocalStorageHandlers.remove(lsh); } void mitk::BaseRenderer::SetDataStorage(DataStorage* storage) { if (storage != NULL) { m_DataStorage = storage; m_BindDispatcherInteractor->SetDataStorage(m_DataStorage); this->Modified(); } } const mitk::BaseRenderer::MapperSlotId mitk::BaseRenderer::defaultMapper = 1; void mitk::BaseRenderer::Paint() { } void mitk::BaseRenderer::Initialize() { } void mitk::BaseRenderer::Resize(int w, int h) { m_Size[0] = w; m_Size[1] = h; if (m_CameraController) m_CameraController->Resize(w, h); //(formerly problematic on windows: vtkSizeBug) GetDisplayGeometry()->SetSizeInDisplayUnits(w, h); } void mitk::BaseRenderer::InitRenderer(vtkRenderWindow* renderwindow) { if (m_RenderWindow != NULL) { m_RenderWindow->Delete(); } m_RenderWindow = renderwindow; if (m_RenderWindow != NULL) { m_RenderWindow->Register(NULL); } RemoveAllLocalStorages(); if (m_CameraController.IsNotNull()) { m_CameraController->SetRenderer(this); } //BUG (#1551) added settings for depth peeling m_RenderWindow->SetAlphaBitPlanes(1); m_VtkRenderer->SetUseDepthPeeling(m_DepthPeelingEnabled); m_VtkRenderer->SetMaximumNumberOfPeels(m_MaxNumberOfPeels); m_VtkRenderer->SetOcclusionRatio(0.1); } void mitk::BaseRenderer::InitSize(int w, int h) { m_Size[0] = w; m_Size[1] = h; GetDisplayGeometry()->SetSizeInDisplayUnits(w, h, false); GetDisplayGeometry()->Fit(); } void mitk::BaseRenderer::SetSlice(unsigned int slice) { if (m_Slice != slice) { m_Slice = slice; if (m_TimeSlicedWorldGeometry.IsNotNull()) { SlicedGeometry3D* slicedWorldGeometry = dynamic_cast(m_TimeSlicedWorldGeometry->GetGeometry3D(m_TimeStep)); if (slicedWorldGeometry != NULL) { if (m_Slice >= slicedWorldGeometry->GetSlices()) m_Slice = slicedWorldGeometry->GetSlices() - 1; SetCurrentWorldGeometry2D(slicedWorldGeometry->GetGeometry2D(m_Slice)); SetCurrentWorldGeometry(slicedWorldGeometry); } } else Modified(); } } void mitk::BaseRenderer::SetTimeStep(unsigned int timeStep) { if (m_TimeStep != timeStep) { m_TimeStep = timeStep; m_TimeStepUpdateTime.Modified(); if (m_TimeSlicedWorldGeometry.IsNotNull()) { if (m_TimeStep >= m_TimeSlicedWorldGeometry->GetTimeSteps()) m_TimeStep = m_TimeSlicedWorldGeometry->GetTimeSteps() - 1; SlicedGeometry3D* slicedWorldGeometry = dynamic_cast(m_TimeSlicedWorldGeometry->GetGeometry3D(m_TimeStep)); if (slicedWorldGeometry != NULL) { SetCurrentWorldGeometry2D(slicedWorldGeometry->GetGeometry2D(m_Slice)); SetCurrentWorldGeometry(slicedWorldGeometry); } } else Modified(); } } int mitk::BaseRenderer::GetTimeStep(const mitk::BaseData* data) const { if ((data == NULL) || (data->IsInitialized() == false)) { return -1; } return data->GetTimeSlicedGeometry()->MSToTimeStep(GetTime()); } mitk::ScalarType mitk::BaseRenderer::GetTime() const { if (m_TimeSlicedWorldGeometry.IsNull()) { return 0; } else { ScalarType timeInMS = m_TimeSlicedWorldGeometry->TimeStepToMS(GetTimeStep()); if (timeInMS == ScalarTypeNumericTraits::NonpositiveMin()) return 0; else return timeInMS; } } void mitk::BaseRenderer::SetWorldGeometry(mitk::Geometry3D* geometry) { itkDebugMacro("setting WorldGeometry to " << geometry); if (m_WorldGeometry != geometry) { if (geometry->GetBoundingBox()->GetDiagonalLength2() == 0) return; m_WorldGeometry = geometry; m_TimeSlicedWorldGeometry = dynamic_cast(geometry); SlicedGeometry3D* slicedWorldGeometry; if (m_TimeSlicedWorldGeometry.IsNotNull()) { itkDebugMacro("setting TimeSlicedWorldGeometry to " << m_TimeSlicedWorldGeometry); if (m_TimeStep >= m_TimeSlicedWorldGeometry->GetTimeSteps()) m_TimeStep = m_TimeSlicedWorldGeometry->GetTimeSteps() - 1; slicedWorldGeometry = dynamic_cast(m_TimeSlicedWorldGeometry->GetGeometry3D(m_TimeStep)); } else { slicedWorldGeometry = dynamic_cast(geometry); } Geometry2D::Pointer geometry2d; if (slicedWorldGeometry != NULL) { if (m_Slice >= slicedWorldGeometry->GetSlices() && (m_Slice != 0)) m_Slice = slicedWorldGeometry->GetSlices() - 1; geometry2d = slicedWorldGeometry->GetGeometry2D(m_Slice); if (geometry2d.IsNull()) { PlaneGeometry::Pointer plane = mitk::PlaneGeometry::New(); plane->InitializeStandardPlane(slicedWorldGeometry); geometry2d = plane; } SetCurrentWorldGeometry(slicedWorldGeometry); } else { geometry2d = dynamic_cast(geometry); if (geometry2d.IsNull()) { PlaneGeometry::Pointer plane = PlaneGeometry::New(); plane->InitializeStandardPlane(geometry); geometry2d = plane; } SetCurrentWorldGeometry(geometry); } SetCurrentWorldGeometry2D(geometry2d); // calls Modified() } if (m_CurrentWorldGeometry2D.IsNull()) itkWarningMacro("m_CurrentWorldGeometry2D is NULL"); } void mitk::BaseRenderer::SetDisplayGeometry(mitk::DisplayGeometry* geometry2d) { itkDebugMacro("setting DisplayGeometry to " << geometry2d); if (m_DisplayGeometry != geometry2d) { m_DisplayGeometry = geometry2d; m_DisplayGeometryData->SetGeometry2D(m_DisplayGeometry); m_DisplayGeometryUpdateTime.Modified(); Modified(); } } void mitk::BaseRenderer::SetCurrentWorldGeometry2D(mitk::Geometry2D* geometry2d) { if (m_CurrentWorldGeometry2D != geometry2d) { m_CurrentWorldGeometry2D = geometry2d; m_CurrentWorldGeometry2DData->SetGeometry2D(m_CurrentWorldGeometry2D); m_DisplayGeometry->SetWorldGeometry(m_CurrentWorldGeometry2D); m_CurrentWorldGeometry2DUpdateTime.Modified(); Modified(); } } void mitk::BaseRenderer::SendUpdateSlice() { m_DisplayGeometryUpdateTime.Modified(); m_CurrentWorldGeometry2DUpdateTime.Modified(); } void mitk::BaseRenderer::SetCurrentWorldGeometry(mitk::Geometry3D* geometry) { m_CurrentWorldGeometry = geometry; if (geometry == NULL) { m_Bounds[0] = 0; m_Bounds[1] = 0; m_Bounds[2] = 0; m_Bounds[3] = 0; m_Bounds[4] = 0; m_Bounds[5] = 0; m_EmptyWorldGeometry = true; return; } BoundingBox::Pointer boundingBox = m_CurrentWorldGeometry->CalculateBoundingBoxRelativeToTransform(NULL); const BoundingBox::BoundsArrayType& worldBounds = boundingBox->GetBounds(); m_Bounds[0] = worldBounds[0]; m_Bounds[1] = worldBounds[1]; m_Bounds[2] = worldBounds[2]; m_Bounds[3] = worldBounds[3]; m_Bounds[4] = worldBounds[4]; m_Bounds[5] = worldBounds[5]; if (boundingBox->GetDiagonalLength2() <= mitk::eps) m_EmptyWorldGeometry = true; else m_EmptyWorldGeometry = false; } void mitk::BaseRenderer::SetGeometry(const itk::EventObject & geometrySendEvent) { const SliceNavigationController::GeometrySendEvent* sendEvent = dynamic_cast(&geometrySendEvent); assert(sendEvent!=NULL); SetWorldGeometry(sendEvent->GetTimeSlicedGeometry()); } void mitk::BaseRenderer::UpdateGeometry(const itk::EventObject & geometryUpdateEvent) { const SliceNavigationController::GeometryUpdateEvent* updateEvent = dynamic_cast(&geometryUpdateEvent); if (updateEvent == NULL) return; if (m_CurrentWorldGeometry.IsNotNull()) { SlicedGeometry3D* slicedWorldGeometry = dynamic_cast(m_CurrentWorldGeometry.GetPointer()); if (slicedWorldGeometry) { Geometry2D* geometry2D = slicedWorldGeometry->GetGeometry2D(m_Slice); SetCurrentWorldGeometry2D(geometry2D); // calls Modified() } } } void mitk::BaseRenderer::SetGeometrySlice(const itk::EventObject & geometrySliceEvent) { const SliceNavigationController::GeometrySliceEvent* sliceEvent = dynamic_cast(&geometrySliceEvent); assert(sliceEvent!=NULL); SetSlice(sliceEvent->GetPos()); } void mitk::BaseRenderer::SetGeometryTime(const itk::EventObject & geometryTimeEvent) { const SliceNavigationController::GeometryTimeEvent * timeEvent = dynamic_cast(&geometryTimeEvent); assert(timeEvent!=NULL); SetTimeStep(timeEvent->GetPos()); } const double* mitk::BaseRenderer::GetBounds() const { return m_Bounds; } void mitk::BaseRenderer::MousePressEvent(mitk::MouseEvent *me) { //set the Focus on the renderer /*bool success =*/m_RenderingManager->GetGlobalInteraction()->SetFocus(this); /* if (! success) mitk::StatusBar::GetInstance()->DisplayText("Warning! from mitkBaseRenderer.cpp: Couldn't focus this BaseRenderer!"); */ //if (m_CameraController) //{ // if(me->GetButtonState()!=512) // provisorisch: Ctrl nicht durchlassen. Bald wird aus m_CameraController eine StateMachine // m_CameraController->MousePressEvent(me); //} if (m_MapperID == 1) { Point2D p(me->GetDisplayPosition()); Point2D p_mm; Point3D position; GetDisplayGeometry()->ULDisplayToDisplay(p, p); GetDisplayGeometry()->DisplayToWorld(p, p_mm); GetDisplayGeometry()->Map(p_mm, position); mitk::PositionEvent event(this, me->GetType(), me->GetButton(), me->GetButtonState(), mitk::Key_unknown, p, position); mitk::EventMapper::MapEvent(&event, m_RenderingManager->GetGlobalInteraction()); } else if (m_MapperID > 1) //==2 for 3D and ==5 for stencil { Point2D p(me->GetDisplayPosition()); GetDisplayGeometry()->ULDisplayToDisplay(p, p); me->SetDisplayPosition(p); mitk::EventMapper::MapEvent(me, m_RenderingManager->GetGlobalInteraction()); } } void mitk::BaseRenderer::MouseReleaseEvent(mitk::MouseEvent *me) { //if (m_CameraController) //{ // if(me->GetButtonState()!=512) // provisorisch: Ctrl nicht durchlassen. Bald wird aus m_CameraController eine StateMachine // m_CameraController->MouseReleaseEvent(me); //} if (m_MapperID == 1) { Point2D p(me->GetDisplayPosition()); Point2D p_mm; Point3D position; GetDisplayGeometry()->ULDisplayToDisplay(p, p); GetDisplayGeometry()->DisplayToWorld(p, p_mm); GetDisplayGeometry()->Map(p_mm, position); mitk::PositionEvent event(this, me->GetType(), me->GetButton(), me->GetButtonState(), mitk::Key_unknown, p, position); mitk::EventMapper::MapEvent(&event, m_RenderingManager->GetGlobalInteraction()); } else if (m_MapperID == 2) { Point2D p(me->GetDisplayPosition()); GetDisplayGeometry()->ULDisplayToDisplay(p, p); me->SetDisplayPosition(p); mitk::EventMapper::MapEvent(me, m_RenderingManager->GetGlobalInteraction()); } } void mitk::BaseRenderer::MouseMoveEvent(mitk::MouseEvent *me) { //if (m_CameraController) //{ // if((me->GetButtonState()<=512) || (me->GetButtonState()>=516))// provisorisch: Ctrl nicht durchlassen. Bald wird aus m_CameraController eine StateMachine // m_CameraController->MouseMoveEvent(me); //} if (m_MapperID == 1) { Point2D p(me->GetDisplayPosition()); Point2D p_mm; Point3D position; GetDisplayGeometry()->ULDisplayToDisplay(p, p); GetDisplayGeometry()->DisplayToWorld(p, p_mm); GetDisplayGeometry()->Map(p_mm, position); mitk::PositionEvent event(this, me->GetType(), me->GetButton(), me->GetButtonState(), mitk::Key_unknown, p, position); mitk::EventMapper::MapEvent(&event, m_RenderingManager->GetGlobalInteraction()); } else if (m_MapperID == 2) { Point2D p(me->GetDisplayPosition()); GetDisplayGeometry()->ULDisplayToDisplay(p, p); me->SetDisplayPosition(p); mitk::EventMapper::MapEvent(me, m_RenderingManager->GetGlobalInteraction()); } } void mitk::BaseRenderer::PickWorldPoint(const mitk::Point2D& displayPoint, mitk::Point3D& worldPoint) const { mitk::Point2D worldPoint2D; GetDisplayGeometry()->DisplayToWorld(displayPoint, worldPoint2D); GetDisplayGeometry()->Map(worldPoint2D, worldPoint); } void mitk::BaseRenderer::WheelEvent(mitk::WheelEvent * we) { if (m_MapperID == 1) { Point2D p(we->GetDisplayPosition()); Point2D p_mm; Point3D position; GetDisplayGeometry()->ULDisplayToDisplay(p, p); GetDisplayGeometry()->DisplayToWorld(p, p_mm); GetDisplayGeometry()->Map(p_mm, position); mitk::PositionEvent event(this, we->GetType(), we->GetButton(), we->GetButtonState(), mitk::Key_unknown, p, position); mitk::EventMapper::MapEvent(we, m_RenderingManager->GetGlobalInteraction()); mitk::EventMapper::MapEvent(&event, m_RenderingManager->GetGlobalInteraction()); } else if (m_MapperID == 2) { Point2D p(we->GetDisplayPosition()); GetDisplayGeometry()->ULDisplayToDisplay(p, p); we->SetDisplayPosition(p); mitk::EventMapper::MapEvent(we, m_RenderingManager->GetGlobalInteraction()); } } void mitk::BaseRenderer::KeyPressEvent(mitk::KeyEvent *ke) { if (m_MapperID == 1) { Point2D p(ke->GetDisplayPosition()); Point2D p_mm; Point3D position; GetDisplayGeometry()->ULDisplayToDisplay(p, p); GetDisplayGeometry()->DisplayToWorld(p, p_mm); GetDisplayGeometry()->Map(p_mm, position); mitk::KeyEvent event(this, ke->GetType(), ke->GetButton(), ke->GetButtonState(), ke->GetKey(), ke->GetText(), p); mitk::EventMapper::MapEvent(&event, m_RenderingManager->GetGlobalInteraction()); } else if (m_MapperID == 2) { Point2D p(ke->GetDisplayPosition()); GetDisplayGeometry()->ULDisplayToDisplay(p, p); ke->SetDisplayPosition(p); mitk::EventMapper::MapEvent(ke, m_RenderingManager->GetGlobalInteraction()); } } void mitk::BaseRenderer::DrawOverlayMouse(mitk::Point2D& itkNotUsed(p2d)) { MITK_INFO<<"BaseRenderer::DrawOverlayMouse()- should be inconcret implementation OpenGLRenderer."<RequestUpdate(this->m_RenderWindow); } void mitk::BaseRenderer::ForceImmediateUpdate() { m_RenderingManager->ForceImmediateUpdate(this->m_RenderWindow); } unsigned int mitk::BaseRenderer::GetNumberOfVisibleLODEnabledMappers() const { return m_NumberOfVisibleLODEnabledMappers; } mitk::RenderingManager* mitk::BaseRenderer::GetRenderingManager() const { return m_RenderingManager.GetPointer(); } /*! Sets the new Navigation controller */ void mitk::BaseRenderer::SetSliceNavigationController(mitk::SliceNavigationController *SlicenavigationController) { if (SlicenavigationController == NULL) return; //disconnect old from globalinteraction m_RenderingManager->GetGlobalInteraction()->RemoveListener(SlicenavigationController); //copy worldgeometry SlicenavigationController->SetInputWorldGeometry(SlicenavigationController->GetCreatedWorldGeometry()); SlicenavigationController->Update(); //set new m_SliceNavigationController = SlicenavigationController; m_SliceNavigationController->SetRenderer(this); if (m_SliceNavigationController.IsNotNull()) { m_SliceNavigationController->ConnectGeometrySliceEvent(this); m_SliceNavigationController->ConnectGeometryUpdateEvent(this); m_SliceNavigationController->ConnectGeometryTimeEvent(this, false); } } /*! Sets the new camera controller and deletes the vtkRenderWindowInteractor in case of the VTKInteractorCameraController */ void mitk::BaseRenderer::SetCameraController(CameraController* cameraController) { mitk::VtkInteractorCameraController::Pointer vtkInteractorCameraController = dynamic_cast(cameraController); if (vtkInteractorCameraController.IsNotNull()) MITK_INFO<<"!!!WARNING!!!: RenderWindow interaction events are no longer handled via CameraController (See Bug #954)."<SetRenderer(NULL); m_CameraController = NULL; m_CameraController = cameraController; m_CameraController->SetRenderer(this); } void mitk::BaseRenderer::PrintSelf(std::ostream& os, itk::Indent indent) const { os << indent << " MapperID: " << m_MapperID << std::endl; os << indent << " Slice: " << m_Slice << std::endl; os << indent << " TimeStep: " << m_TimeStep << std::endl; os << indent << " WorldGeometry: "; if (m_WorldGeometry.IsNull()) os << "NULL" << std::endl; else m_WorldGeometry->Print(os, indent); os << indent << " CurrentWorldGeometry2D: "; if (m_CurrentWorldGeometry2D.IsNull()) os << "NULL" << std::endl; else m_CurrentWorldGeometry2D->Print(os, indent); os << indent << " CurrentWorldGeometry2DUpdateTime: " << m_CurrentWorldGeometry2DUpdateTime << std::endl; os << indent << " CurrentWorldGeometry2DTransformTime: " << m_CurrentWorldGeometry2DTransformTime << std::endl; os << indent << " DisplayGeometry: "; if (m_DisplayGeometry.IsNull()) os << "NULL" << std::endl; else m_DisplayGeometry->Print(os, indent); os << indent << " DisplayGeometryTransformTime: " << m_DisplayGeometryTransformTime << std::endl; Superclass::PrintSelf(os, indent); } void mitk::BaseRenderer::SetDepthPeelingEnabled(bool enabled) { m_DepthPeelingEnabled = enabled; m_VtkRenderer->SetUseDepthPeeling(enabled); } void mitk::BaseRenderer::SetMaxNumberOfPeels(int maxNumber) { m_MaxNumberOfPeels = maxNumber; m_VtkRenderer->SetMaximumNumberOfPeels(maxNumber); } diff --git a/Core/Code/Rendering/mitkBaseRenderer.h b/Core/Code/Rendering/mitkBaseRenderer.h index be2274f90e..db2f18f4ba 100644 --- a/Core/Code/Rendering/mitkBaseRenderer.h +++ b/Core/Code/Rendering/mitkBaseRenderer.h @@ -1,611 +1,611 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 BASERENDERER_H_HEADER_INCLUDED_C1CCA0F4 #define BASERENDERER_H_HEADER_INCLUDED_C1CCA0F4 #include "mitkDataStorage.h" #include "mitkGeometry2D.h" #include "mitkTimeSlicedGeometry.h" #include "mitkDisplayGeometry.h" #include "mitkGeometry2DData.h" #include "mitkCameraController.h" #include "mitkDisplayPositionEvent.h" #include "mitkWheelEvent.h" //#include "mitkMapper.h" #include "mitkSliceNavigationController.h" #include "mitkCameraController.h" #include "mitkCameraRotationController.h" #include "mitkBindDispatcherInteractor.h" #include "mitkDispatcher.h" #include #include #include #include namespace mitk { class NavigationController; class SliceNavigationController; class CameraRotationController; class CameraController; class DataStorage; class Mapper; class BaseLocalStorageHandler; //##Documentation //## @brief Organizes the rendering process //## //## Organizes the rendering process. A Renderer contains a reference to a //## DataStorage and asks the mappers of the data objects to render //## the data into the renderwindow it is associated to. //## //## \#Render() checks if rendering is currently allowed by calling //## RenderWindow::PrepareRendering(). Initialization of a rendering context //## can also be performed in this method. //## //## The actual rendering code has been moved to \#Repaint() //## Both \#Repaint() and \#Update() are declared protected now. //## //## Note: Separation of the Repaint and Update processes (rendering vs //## creating a vtk prop tree) still needs to be worked on. The whole //## rendering process also should be reworked to use VTK based classes for //## both 2D and 3D rendering. //## @ingroup Renderer class MITK_CORE_EXPORT BaseRenderer: public itk::Object { public: typedef std::map BaseRendererMapType; static BaseRendererMapType baseRendererMap; static BaseRenderer* GetInstance(vtkRenderWindow * renWin); static void AddInstance(vtkRenderWindow* renWin, BaseRenderer* baseRenderer); static void RemoveInstance(vtkRenderWindow* renWin); static BaseRenderer* GetByName(const std::string& name); static vtkRenderWindow* GetRenderWindowByName(const std::string& name); #pragma GCC visibility push(default) itkEventMacro( RendererResetEvent, itk::AnyEvent ); #pragma GCC visibility pop /** Standard class typedefs. */ mitkClassMacro(BaseRenderer, itk::Object); BaseRenderer(const char* name = NULL, vtkRenderWindow * renWin = NULL, mitk::RenderingManager* rm = NULL); //##Documentation //## @brief MapperSlotId defines which kind of mapper (e.g., 2D or 3D) shoud be used. typedef int MapperSlotId; enum StandardMapperSlot { Standard2D = 1, Standard3D = 2 }; virtual void SetDataStorage(DataStorage* storage); ///< set the datastorage that will be used for rendering //##Documentation //## return the DataStorage that is used for rendering virtual DataStorage::Pointer GetDataStorage() const { return m_DataStorage.GetPointer(); } //##Documentation //## @brief Access the RenderWindow into which this renderer renders. vtkRenderWindow* GetRenderWindow() const { return m_RenderWindow; } vtkRenderer* GetVtkRenderer() const { return m_VtkRenderer; } //##Documentation //## @brief Returns the Dispatcher which handles Events for this BaseRenderer - Dispatcher::Pointer GetDispatcher() const; + Dispatcher::Pointer GetDispatcher(); //##Documentation //## @brief Default mapper id to use. static const MapperSlotId defaultMapper; //##Documentation //## @brief Do the rendering and flush the result. virtual void Paint(); //##Documentation //## @brief Initialize the RenderWindow. Should only be called from RenderWindow. virtual void Initialize(); //##Documentation //## @brief Called to inform the renderer that the RenderWindow has been resized. virtual void Resize(int w, int h); //##Documentation //## @brief Initialize the renderer with a RenderWindow (@a renderwindow). virtual void InitRenderer(vtkRenderWindow* renderwindow); //##Documentation //## @brief Set the initial size. Called by RenderWindow after it has become //## visible for the first time. virtual void InitSize(int w, int h); //##Documentation //## @brief Draws a point on the widget. //## Should be used during conferences to show the position of the remote mouse virtual void DrawOverlayMouse(Point2D& p2d); //##Documentation //## @brief Set/Get the WorldGeometry (m_WorldGeometry) for 3D and 2D rendering, that describing the //## (maximal) area to be rendered. //## //## Depending of the type of the passed Geometry3D more or less information can be extracted: //## \li if it is a Geometry2D (which is a sub-class of Geometry3D), m_CurrentWorldGeometry2D is //## also set to point to it. m_TimeSlicedWorldGeometry is set to NULL. //## \li if it is a TimeSlicedGeometry, m_TimeSlicedWorldGeometry is also set to point to it. //## If m_TimeSlicedWorldGeometry contains instances of SlicedGeometry3D, m_CurrentWorldGeometry2D is set to //## one of geometries stored in the SlicedGeometry3D according to the value of m_Slice; otherwise //## a PlaneGeometry describing the top of the bounding-box of the Geometry3D is set as the //## m_CurrentWorldGeometry2D. //## \li otherwise a PlaneGeometry describing the top of the bounding-box of the Geometry3D //## is set as the m_CurrentWorldGeometry2D. m_TimeSlicedWorldGeometry is set to NULL. //## @todo add calculation of PlaneGeometry describing the top of the bounding-box of the Geometry3D //## when the passed Geometry3D is not sliced. //## \sa m_WorldGeometry //## \sa m_TimeSlicedWorldGeometry //## \sa m_CurrentWorldGeometry2D virtual void SetWorldGeometry(Geometry3D* geometry); itkGetConstObjectMacro(WorldGeometry, Geometry3D) //##Documentation //## @brief Get the current 3D-worldgeometry (m_CurrentWorldGeometry) used for 3D-rendering itkGetConstObjectMacro(CurrentWorldGeometry, Geometry3D) //##Documentation //## @brief Get the current 2D-worldgeometry (m_CurrentWorldGeometry2D) used for 2D-rendering itkGetConstObjectMacro(CurrentWorldGeometry2D, Geometry2D) //##Documentation //## Calculates the bounds of the DataStorage (if it contains any valid data), //## creates a geometry from these bounds and sets it as world geometry of the renderer. //## //## Call this method to re-initialize the renderer to the current DataStorage //## (e.g. after loading an additional dataset), to ensure that the view is //## aligned correctly. //## \warn This is not implemented yet. virtual bool SetWorldGeometryToDataStorageBounds() { return false; } //##Documentation //## @brief Set/Get the DisplayGeometry (for 2D rendering) //## //## The DisplayGeometry describes which part of the Geometry2D m_CurrentWorldGeometry2D //## is displayed. virtual void SetDisplayGeometry(DisplayGeometry* geometry2d); itkGetConstObjectMacro(DisplayGeometry, DisplayGeometry) itkGetObjectMacro(DisplayGeometry, DisplayGeometry) //##Documentation //## @brief Set/Get m_Slice which defines together with m_TimeStep the 2D geometry //## stored in m_TimeSlicedWorldGeometry used as m_CurrentWorldGeometry2D //## //## \sa m_Slice virtual void SetSlice(unsigned int slice); itkGetConstMacro(Slice, unsigned int) //##Documentation //## @brief Set/Get m_TimeStep which defines together with m_Slice the 2D geometry //## stored in m_TimeSlicedWorldGeometry used as m_CurrentWorldGeometry2D //## //## \sa m_TimeStep virtual void SetTimeStep(unsigned int timeStep); itkGetConstMacro(TimeStep, unsigned int) //##Documentation //## @brief Get the time-step of a BaseData object which //## exists at the time of the currently displayed content //## //## Returns -1 or mitk::BaseData::m_TimeSteps if there //## is no data at the current time. //## \sa GetTimeStep, m_TimeStep int GetTimeStep(const BaseData* data) const; //##Documentation //## @brief Get the time in ms of the currently displayed content //## //## \sa GetTimeStep, m_TimeStep ScalarType GetTime() const; //##Documentation //## @brief SetWorldGeometry is called according to the geometrySliceEvent, //## which is supposed to be a SliceNavigationController::GeometrySendEvent virtual void SetGeometry(const itk::EventObject & geometrySliceEvent); //##Documentation //## @brief UpdateWorldGeometry is called to re-read the 2D geometry from the //## slice navigation controller virtual void UpdateGeometry(const itk::EventObject & geometrySliceEvent); //##Documentation //## @brief SetSlice is called according to the geometrySliceEvent, //## which is supposed to be a SliceNavigationController::GeometrySliceEvent virtual void SetGeometrySlice(const itk::EventObject & geometrySliceEvent); //##Documentation //## @brief SetTimeStep is called according to the geometrySliceEvent, //## which is supposed to be a SliceNavigationController::GeometryTimeEvent virtual void SetGeometryTime(const itk::EventObject & geometryTimeEvent); //##Documentation //## @brief Get a data object containing the DisplayGeometry (for 2D rendering) itkGetObjectMacro(DisplayGeometryData, Geometry2DData) //##Documentation //## @brief Get a data object containing the WorldGeometry (for 2D rendering) itkGetObjectMacro(WorldGeometryData, Geometry2DData) //##Documentation //## @brief Get a DataNode pointing to a data object containing the WorldGeometry (3D and 2D rendering) itkGetObjectMacro(WorldGeometryNode, DataNode) //##Documentation //## @brief Get a DataNode pointing to a data object containing the DisplayGeometry (for 2D rendering) itkGetObjectMacro(DisplayGeometryNode, DataNode) //##Documentation //## @brief Get a DataNode pointing to a data object containing the current 2D-worldgeometry m_CurrentWorldGeometry2D (for 2D rendering) itkGetObjectMacro(CurrentWorldGeometry2DNode, DataNode) //##Documentation //## @brief Sets timestamp of CurrentWorldGeometry2D and DisplayGeometry and forces so reslicing in that renderwindow void SendUpdateSlice(); //##Documentation //## @brief Get timestamp of last call of SetCurrentWorldGeometry2D unsigned long GetCurrentWorldGeometry2DUpdateTime() { return m_CurrentWorldGeometry2DUpdateTime; } //##Documentation //## @brief Get timestamp of last call of SetDisplayGeometry unsigned long GetDisplayGeometryUpdateTime() { return m_CurrentWorldGeometry2DUpdateTime; } //##Documentation //## @brief Get timestamp of last change of current TimeStep unsigned long GetTimeStepUpdateTime() { return m_TimeStepUpdateTime; } //##Documentation //## @brief Perform a picking: find the x,y,z world coordinate of a //## display x,y coordinate. //## @warning Has to be overwritten in subclasses for the 3D-case. //## //## Implemented here only for 2D-rendering by using //## m_DisplayGeometry virtual void PickWorldPoint(const Point2D& diplayPosition, Point3D& worldPosition) const; /** \brief Determines the object (mitk::DataNode) closest to the current * position by means of picking * * \warning Implementation currently empty for 2D rendering; intended to be * implemented for 3D renderers */ virtual DataNode* PickObject(const Point2D& /*displayPosition*/, Point3D& /*worldPosition*/) const { return NULL; } //##Documentation //## @brief Get the MapperSlotId to use. itkGetMacro(MapperID, MapperSlotId) itkGetConstMacro(MapperID, MapperSlotId) //##Documentation //## @brief Set the MapperSlotId to use. itkSetMacro(MapperID, MapperSlotId) //##Documentation //## @brief Has the renderer the focus? itkGetMacro(Focused, bool) //##Documentation //## @brief Tell the renderer that it is focused. The caller is responsible for focus management, //## not the renderer itself. itkSetMacro(Focused, bool) //##Documentation //## @brief Sets whether depth peeling is enabled or not void SetDepthPeelingEnabled(bool enabled); //##Documentation //## @brief Sets maximal number of peels void SetMaxNumberOfPeels(int maxNumber); itkGetMacro(Size, int*) void SetSliceNavigationController(SliceNavigationController* SlicenavigationController); void SetCameraController(CameraController* cameraController); itkGetObjectMacro(CameraController, CameraController) itkGetObjectMacro(SliceNavigationController, SliceNavigationController) itkGetObjectMacro(CameraRotationController, CameraRotationController) itkGetMacro(EmptyWorldGeometry, bool) //##Documentation //## @brief Mouse event dispatchers //## @note for internal use only. preliminary. virtual void MousePressEvent(MouseEvent*); //##Documentation //## @brief Mouse event dispatchers //## @note for internal use only. preliminary. virtual void MouseReleaseEvent(MouseEvent*); //##Documentation //## @brief Mouse event dispatchers //## @note for internal use only. preliminary. virtual void MouseMoveEvent(MouseEvent*); //##Documentation //## @brief Wheel event dispatcher //## @note for internal use only. preliminary. virtual void WheelEvent(mitk::WheelEvent* we); //##Documentation //## @brief Key event dispatcher //## @note for internal use only. preliminary. virtual void KeyPressEvent(KeyEvent*); //##Documentation //## @brief get the name of the Renderer //## @note const char * GetName() const { return m_Name.c_str(); } //##Documentation //## @brief get the x_size of the RendererWindow //## @note int GetSizeX() const { return m_Size[0]; } //##Documentation //## @brief get the y_size of the RendererWindow //## @note int GetSizeY() const { return m_Size[1]; } const double* GetBounds() const; void RequestUpdate(); void ForceImmediateUpdate(); /** Returns number of mappers which are visible and have level-of-detail * rendering enabled */ unsigned int GetNumberOfVisibleLODEnabledMappers() const; ///** //* \brief Setter for the RenderingManager that handles this instance of BaseRenderer //*/ //void SetRenderingManager( mitk::RenderingManager* ); /** * \brief Getter for the RenderingManager that handles this instance of BaseRenderer */ virtual mitk::RenderingManager* GetRenderingManager() const; /** * \brief Provides (1) world coordinates for a given mouse position and (2) * translates mousePosition to Display coordinates */ virtual Point3D Map2DRendererPositionTo3DWorldPosition(Point2D* mousePosition) const; protected: virtual ~BaseRenderer(); //##Documentation //## @brief Call update of all mappers. To be implemented in subclasses. virtual void Update() = 0; vtkRenderWindow* m_RenderWindow; vtkRenderer* m_VtkRenderer; //##Documentation //## @brief MapperSlotId to use. Defines which kind of mapper (e.g., 2D or 3D) shoud be used. MapperSlotId m_MapperID; //##Documentation //## @brief The DataStorage that is used for rendering. DataStorage::Pointer m_DataStorage; //##Documentation //## @brief The RenderingManager that manages this instance RenderingManager::Pointer m_RenderingManager; //##Documentation //## @brief Timestamp of last call of Update(). unsigned long m_LastUpdateTime; //##Documentation //## @brief CameraController for 3D rendering //## @note preliminary. CameraController::Pointer m_CameraController; SliceNavigationController::Pointer m_SliceNavigationController; CameraRotationController::Pointer m_CameraRotationController; //##Documentation //## @brief Size of the RenderWindow. int m_Size[2]; //##Documentation //## @brief Contains whether the renderer that it is focused. The caller of //## SetFocused is responsible for focus management, not the renderer itself. //## is doubled because of mitk::FocusManager in GlobalInteraction!!! (ingmar) bool m_Focused; //##Documentation //## @brief Sets m_CurrentWorldGeometry2D virtual void SetCurrentWorldGeometry2D(Geometry2D* geometry2d); //##Documentation //## @brief Sets m_CurrentWorldGeometry virtual void SetCurrentWorldGeometry(Geometry3D* geometry); private: //##Documentation //## Pointer to the worldgeometry, describing the maximal area to be rendered //## (3D as well as 2D). //## It is const, since we are not allowed to change it (it may be taken //## directly from the geometry of an image-slice and thus it would be //## very strange when suddenly the image-slice changes its geometry). //## \sa SetWorldGeometry Geometry3D::Pointer m_WorldGeometry; //##Documentation //## m_TimeSlicedWorldGeometry is set by SetWorldGeometry if the passed Geometry3D is a //## TimeSlicedGeometry (or a sub-class of it). If it contains instances of SlicedGeometry3D, //## m_Slice and m_TimeStep (set via SetSlice and SetTimeStep, respectively) define //## which 2D geometry stored in m_TimeSlicedWorldGeometry (if available) //## is used as m_CurrentWorldGeometry2D. //## \sa m_CurrentWorldGeometry2D TimeSlicedGeometry::Pointer m_TimeSlicedWorldGeometry; //##Documentation //## Pointer to the current 3D-worldgeometry. Geometry3D::Pointer m_CurrentWorldGeometry; //##Documentation //## Pointer to the current 2D-worldgeometry. The 2D-worldgeometry //## describes the maximal area (2D manifold) to be rendered in case we //## are doing 2D-rendering. More precisely, a subpart of this according //## to m_DisplayGeometry is displayed. //## It is const, since we are not allowed to change it (it may be taken //## directly from the geometry of an image-slice and thus it would be //## very strange when suddenly the image-slice changes its geometry). Geometry2D::Pointer m_CurrentWorldGeometry2D; //##Documentation //## Pointer to the displaygeometry. The displaygeometry describes the //## geometry of the \em visible area in the window controlled by the renderer //## in case we are doing 2D-rendering. //## It is const, since we are not allowed to change it. DisplayGeometry::Pointer m_DisplayGeometry; //##Documentation //## Defines together with m_Slice which 2D geometry stored in m_TimeSlicedWorldGeometry //## is used as m_CurrentWorldGeometry2D: m_TimeSlicedWorldGeometry->GetGeometry2D(m_Slice, m_TimeStep). //## \sa m_TimeSlicedWorldGeometry unsigned int m_Slice; //##Documentation //## Defines together with m_TimeStep which 2D geometry stored in m_TimeSlicedWorldGeometry //## is used as m_CurrentWorldGeometry2D: m_TimeSlicedWorldGeometry->GetGeometry2D(m_Slice, m_TimeStep). //## \sa m_TimeSlicedWorldGeometry unsigned int m_TimeStep; //##Documentation //## @brief timestamp of last call of SetWorldGeometry itk::TimeStamp m_CurrentWorldGeometry2DUpdateTime; //##Documentation //## @brief timestamp of last call of SetDisplayGeometry itk::TimeStamp m_DisplayGeometryUpdateTime; //##Documentation //## @brief timestamp of last change of the current time step itk::TimeStamp m_TimeStepUpdateTime; //##Documentation //## @brief Helper class which establishes connection between Interactors and Dispatcher via a common DataStorage. BindDispatcherInteractor* m_BindDispatcherInteractor; protected: virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; //##Documentation //## Data object containing the m_WorldGeometry defined above. Geometry2DData::Pointer m_WorldGeometryData; //##Documentation //## Data object containing the m_DisplayGeometry defined above. Geometry2DData::Pointer m_DisplayGeometryData; //##Documentation //## Data object containing the m_CurrentWorldGeometry2D defined above. Geometry2DData::Pointer m_CurrentWorldGeometry2DData; //##Documentation //## DataNode objects containing the m_WorldGeometryData defined above. DataNode::Pointer m_WorldGeometryNode; //##Documentation //## DataNode objects containing the m_DisplayGeometryData defined above. DataNode::Pointer m_DisplayGeometryNode; //##Documentation //## DataNode objects containing the m_CurrentWorldGeometry2DData defined above. DataNode::Pointer m_CurrentWorldGeometry2DNode; //##Documentation //## @brief test only unsigned long m_DisplayGeometryTransformTime; //##Documentation //## @brief test only unsigned long m_CurrentWorldGeometry2DTransformTime; std::string m_Name; double m_Bounds[6]; bool m_EmptyWorldGeometry; bool m_DepthPeelingEnabled; int m_MaxNumberOfPeels; typedef std::set LODEnabledMappersType; /** Number of mappers which are visible and have level-of-detail * rendering enabled */ unsigned int m_NumberOfVisibleLODEnabledMappers; // Local Storage Handling for mappers protected: std::list m_RegisteredLocalStorageHandlers; public: void RemoveAllLocalStorages(); void RegisterLocalStorageHandler(mitk::BaseLocalStorageHandler *lsh); void UnregisterLocalStorageHandler(mitk::BaseLocalStorageHandler *lsh); }; } // namespace mitk #endif /* BASERENDERER_H_HEADER_INCLUDED_C1CCA0F4 */ diff --git a/Core/Code/Rendering/mitkGeometry2DDataVtkMapper3D.cpp b/Core/Code/Rendering/mitkGeometry2DDataVtkMapper3D.cpp index c40246cf26..afc74023d7 100644 --- a/Core/Code/Rendering/mitkGeometry2DDataVtkMapper3D.cpp +++ b/Core/Code/Rendering/mitkGeometry2DDataVtkMapper3D.cpp @@ -1,586 +1,588 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkGeometry2DDataVtkMapper3D.h" #include "mitkImageVtkMapper2D.h" #include "mitkSmartPointerProperty.h" #include "mitkSurface.h" #include "mitkVtkRepresentationProperty.h" #include "mitkWeakPointerProperty.h" #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateOr.h" +#include "vtkNeverTranslucentTexture.h" #include #include #include #include #include #include #include #include #include #include -#include #include #include namespace mitk { Geometry2DDataVtkMapper3D::Geometry2DDataVtkMapper3D() : m_NormalsActorAdded(false), m_DataStorage(NULL) { m_EdgeTuber = vtkTubeFilter::New(); m_EdgeMapper = vtkPolyDataMapper::New(); m_SurfaceCreator = Geometry2DDataToSurfaceFilter::New(); m_SurfaceCreatorBoundingBox = BoundingBox::New(); m_SurfaceCreatorPointsContainer = BoundingBox::PointsContainer::New(); m_Edges = vtkFeatureEdges::New(); m_Edges->BoundaryEdgesOn(); m_Edges->FeatureEdgesOff(); m_Edges->NonManifoldEdgesOff(); m_Edges->ManifoldEdgesOff(); m_EdgeTransformer = vtkTransformPolyDataFilter::New(); m_NormalsTransformer = vtkTransformPolyDataFilter::New(); m_EdgeActor = vtkActor::New(); m_BackgroundMapper = vtkPolyDataMapper::New(); m_BackgroundActor = vtkActor::New(); m_Prop3DAssembly = vtkAssembly::New(); m_ImageAssembly = vtkAssembly::New(); m_SurfaceCreatorBoundingBox->SetPoints( m_SurfaceCreatorPointsContainer ); m_Cleaner = vtkCleanPolyData::New(); m_Cleaner->PieceInvariantOn(); m_Cleaner->ConvertLinesToPointsOn(); m_Cleaner->ConvertPolysToLinesOn(); m_Cleaner->ConvertStripsToPolysOn(); m_Cleaner->PointMergingOn(); // Make sure that the FeatureEdge algorithm is initialized with a "valid" // (though empty) input vtkPolyData *emptyPolyData = vtkPolyData::New(); m_Cleaner->SetInput( emptyPolyData ); emptyPolyData->Delete(); m_Edges->SetInput(m_Cleaner->GetOutput()); m_EdgeTransformer->SetInput( m_Edges->GetOutput() ); m_EdgeTuber->SetInput( m_EdgeTransformer->GetOutput() ); m_EdgeTuber->SetVaryRadiusToVaryRadiusOff(); m_EdgeTuber->SetNumberOfSides( 12 ); m_EdgeTuber->CappingOn(); m_EdgeMapper->SetInput( m_EdgeTuber->GetOutput() ); m_EdgeMapper->ScalarVisibilityOff(); m_BackgroundMapper->SetInput(emptyPolyData); m_EdgeActor->SetMapper( m_EdgeMapper ); m_BackgroundActor->GetProperty()->SetAmbient( 0.5 ); m_BackgroundActor->GetProperty()->SetColor( 0.0, 0.0, 0.0 ); - m_BackgroundActor->GetProperty()->SetOpacity( 1.0 ); + m_BackgroundActor->GetProperty()->SetOpacity( 0.0 ); m_BackgroundActor->SetMapper( m_BackgroundMapper ); vtkProperty * backfaceProperty = m_BackgroundActor->MakeProperty(); backfaceProperty->SetColor( 0.0, 0.0, 0.0 ); m_BackgroundActor->SetBackfaceProperty( backfaceProperty ); backfaceProperty->Delete(); m_FrontHedgeHog = vtkHedgeHog::New(); m_BackHedgeHog = vtkHedgeHog::New(); m_FrontNormalsMapper = vtkPolyDataMapper::New(); m_FrontNormalsMapper->SetInput( m_FrontHedgeHog->GetOutput() ); m_BackNormalsMapper = vtkPolyDataMapper::New(); m_Prop3DAssembly->AddPart( m_EdgeActor ); m_Prop3DAssembly->AddPart( m_ImageAssembly ); m_FrontNormalsActor = vtkActor::New(); m_FrontNormalsActor->SetMapper(m_FrontNormalsMapper); m_BackNormalsActor = vtkActor::New(); m_BackNormalsActor->SetMapper(m_BackNormalsMapper); m_ImageMapperDeletedCommand = MemberCommandType::New(); m_ImageMapperDeletedCommand->SetCallbackFunction( this, &Geometry2DDataVtkMapper3D::ImageMapperDeletedCallback ); } Geometry2DDataVtkMapper3D::~Geometry2DDataVtkMapper3D() { m_ImageAssembly->Delete(); m_Prop3DAssembly->Delete(); m_EdgeTuber->Delete(); m_EdgeMapper->Delete(); m_EdgeTransformer->Delete(); m_Cleaner->Delete(); m_Edges->Delete(); m_NormalsTransformer->Delete(); m_EdgeActor->Delete(); m_BackgroundMapper->Delete(); m_BackgroundActor->Delete(); m_FrontNormalsMapper->Delete(); m_FrontNormalsActor->Delete(); m_FrontHedgeHog->Delete(); m_BackNormalsMapper->Delete(); m_BackNormalsActor->Delete(); m_BackHedgeHog->Delete(); // Delete entries in m_ImageActors list one by one m_ImageActors.clear(); m_DataStorage = NULL; } vtkProp* Geometry2DDataVtkMapper3D::GetVtkProp(mitk::BaseRenderer * /*renderer*/) { if ( (this->GetDataNode() != NULL ) && (m_ImageAssembly != NULL) ) { // Do not transform the entire Prop3D assembly, but only the image part // here. The colored frame is transformed elsewhere (via m_EdgeTransformer), // since only vertices should be transformed there, not the poly data // itself, to avoid distortion for anisotropic datasets. m_ImageAssembly->SetUserTransform( this->GetDataNode()->GetVtkTransform() ); } return m_Prop3DAssembly; } void Geometry2DDataVtkMapper3D::UpdateVtkTransform(mitk::BaseRenderer * /*renderer*/) { m_ImageAssembly->SetUserTransform( this->GetDataNode()->GetVtkTransform(this->GetTimestep()) ); } const Geometry2DData* Geometry2DDataVtkMapper3D::GetInput() { return static_cast ( GetData() ); } void Geometry2DDataVtkMapper3D::SetDataStorageForTexture(mitk::DataStorage* storage) { if(storage != NULL && m_DataStorage != storage ) { m_DataStorage = storage; this->Modified(); } } void Geometry2DDataVtkMapper3D::ImageMapperDeletedCallback( itk::Object *caller, const itk::EventObject& /*event*/ ) { ImageVtkMapper2D *imageMapper = dynamic_cast< ImageVtkMapper2D * >( caller ); if ( (imageMapper != NULL) ) { if ( m_ImageActors.count( imageMapper ) > 0) { m_ImageActors[imageMapper].m_Sender = NULL; // sender is already destroying itself m_ImageActors.erase( imageMapper ); } } } void Geometry2DDataVtkMapper3D::GenerateDataForRenderer(BaseRenderer* renderer) { SetVtkMapperImmediateModeRendering(m_EdgeMapper); SetVtkMapperImmediateModeRendering(m_BackgroundMapper); // Remove all actors from the assembly, and re-initialize it with the // edge actor m_ImageAssembly->GetParts()->RemoveAllItems(); if ( !this->IsVisible(renderer) ) { // visibility has explicitly to be set in the single actors // due to problems when using cell picking: // even if the assembly is invisible, the renderer contains // references to the assemblies parts. During picking the // visibility of each part is checked, and not only for the // whole assembly. m_ImageAssembly->VisibilityOff(); m_EdgeActor->VisibilityOff(); return; } // visibility has explicitly to be set in the single actors // due to problems when using cell picking: // even if the assembly is invisible, the renderer contains // references to the assemblies parts. During picking the // visibility of each part is checked, and not only for the // whole assembly. m_ImageAssembly->VisibilityOn(); m_EdgeActor->VisibilityOn(); Geometry2DData::Pointer input = const_cast< Geometry2DData * >(this->GetInput()); if (input.IsNotNull() && (input->GetGeometry2D() != NULL)) { SmartPointerProperty::Pointer surfacecreatorprop; surfacecreatorprop = dynamic_cast< SmartPointerProperty * >(GetDataNode()->GetProperty("surfacegeometry", renderer)); if ( (surfacecreatorprop.IsNull()) || (surfacecreatorprop->GetSmartPointer().IsNull()) || ((m_SurfaceCreator = dynamic_cast (surfacecreatorprop->GetSmartPointer().GetPointer())).IsNull() ) ) { m_SurfaceCreator->PlaceByGeometryOn(); surfacecreatorprop = SmartPointerProperty::New( m_SurfaceCreator ); GetDataNode()->SetProperty("surfacegeometry", surfacecreatorprop); } m_SurfaceCreator->SetInput(input); int res; if (GetDataNode()->GetIntProperty("xresolution", res, renderer)) { m_SurfaceCreator->SetXResolution(res); } if (GetDataNode()->GetIntProperty("yresolution", res, renderer)) { m_SurfaceCreator->SetYResolution(res); } double tubeRadius = 1.0; // Radius of tubular edge surrounding plane // Clip the Geometry2D with the reference geometry bounds (if available) if ( input->GetGeometry2D()->HasReferenceGeometry() ) { Geometry3D *referenceGeometry = input->GetGeometry2D()->GetReferenceGeometry(); BoundingBox::PointType boundingBoxMin, boundingBoxMax; boundingBoxMin = referenceGeometry->GetBoundingBox()->GetMinimum(); boundingBoxMax = referenceGeometry->GetBoundingBox()->GetMaximum(); if ( referenceGeometry->GetImageGeometry() ) { for ( unsigned int i = 0; i < 3; ++i ) { boundingBoxMin[i] -= 0.5; boundingBoxMax[i] -= 0.5; } } m_SurfaceCreatorPointsContainer->CreateElementAt( 0 ) = boundingBoxMin; m_SurfaceCreatorPointsContainer->CreateElementAt( 1 ) = boundingBoxMax; m_SurfaceCreatorBoundingBox->ComputeBoundingBox(); m_SurfaceCreator->SetBoundingBox( m_SurfaceCreatorBoundingBox ); tubeRadius = referenceGeometry->GetDiagonalLength() / 450.0; } // If no reference geometry is available, clip with the current global // bounds else if (m_DataStorage.IsNotNull()) { m_SurfaceCreator->SetBoundingBox(m_DataStorage->ComputeVisibleBoundingBox(NULL, "includeInBoundingBox")); tubeRadius = sqrt( m_SurfaceCreator->GetBoundingBox()->GetDiagonalLength2() ) / 450.0; } // Calculate the surface of the Geometry2D m_SurfaceCreator->Update(); Surface *surface = m_SurfaceCreator->GetOutput(); // Check if there's something to display, otherwise return if ( (surface->GetVtkPolyData() == 0 ) || (surface->GetVtkPolyData()->GetNumberOfCells() == 0) ) { m_ImageAssembly->VisibilityOff(); return; } // add a graphical representation of the surface normals if requested DataNode* node = this->GetDataNode(); bool displayNormals = false; bool colorTwoSides = false; bool invertNormals = false; node->GetBoolProperty("draw normals 3D", displayNormals, renderer); node->GetBoolProperty("color two sides", colorTwoSides, renderer); node->GetBoolProperty("invert normals", invertNormals, renderer); //if we want to draw the display normals or render two sides we have to get the colors if( displayNormals || colorTwoSides ) { //get colors float frontColor[3] = { 0.0, 0.0, 1.0 }; node->GetColor( frontColor, renderer, "front color" ); float backColor[3] = { 1.0, 0.0, 0.0 }; node->GetColor( backColor, renderer, "back color" ); if ( displayNormals ) { m_NormalsTransformer->SetInput( surface->GetVtkPolyData() ); m_NormalsTransformer->SetTransform(node->GetVtkTransform(this->GetTimestep()) ); m_FrontHedgeHog->SetInput( m_NormalsTransformer->GetOutput() ); m_FrontHedgeHog->SetVectorModeToUseNormal(); m_FrontHedgeHog->SetScaleFactor( invertNormals ? 1.0 : -1.0 ); m_FrontNormalsActor->GetProperty()->SetColor( frontColor[0], frontColor[1], frontColor[2] ); m_BackHedgeHog->SetInput( m_NormalsTransformer->GetOutput() ); m_BackHedgeHog->SetVectorModeToUseNormal(); m_BackHedgeHog->SetScaleFactor( invertNormals ? -1.0 : 1.0 ); m_BackNormalsActor->GetProperty()->SetColor( backColor[0], backColor[1], backColor[2] ); //if there is no actor added yet, add one if ( !m_NormalsActorAdded ) { m_Prop3DAssembly->AddPart( m_FrontNormalsActor ); m_Prop3DAssembly->AddPart( m_BackNormalsActor ); m_NormalsActorAdded = true; } } //if we don't want to display normals AND there is an actor added remove the actor else if ( m_NormalsActorAdded ) { m_Prop3DAssembly->RemovePart( m_FrontNormalsActor ); m_Prop3DAssembly->RemovePart( m_BackNormalsActor ); m_NormalsActorAdded = false; } if ( colorTwoSides ) { if ( !invertNormals ) { m_BackgroundActor->GetProperty()->SetColor( backColor[0], backColor[1], backColor[2] ); m_BackgroundActor->GetBackfaceProperty()->SetColor( frontColor[0], frontColor[1], frontColor[2] ); } else { m_BackgroundActor->GetProperty()->SetColor( frontColor[0], frontColor[1], frontColor[2] ); m_BackgroundActor->GetBackfaceProperty()->SetColor( backColor[0], backColor[1], backColor[2] ); } } } // Add black background for all images (which may be transparent) m_BackgroundMapper->SetInput( surface->GetVtkPolyData() ); m_ImageAssembly->AddPart( m_BackgroundActor ); LayerSortedActorList layerSortedActors; // Traverse the data tree to find nodes resliced by ImageMapperGL2D mitk::NodePredicateOr::Pointer p = mitk::NodePredicateOr::New(); //use a predicate to get all data nodes which are "images" or inherit from mitk::Image mitk::TNodePredicateDataType< mitk::Image >::Pointer predicateAllImages = mitk::TNodePredicateDataType< mitk::Image >::New(); mitk::DataStorage::SetOfObjects::ConstPointer all = m_DataStorage->GetSubset(predicateAllImages); //process all found images for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { DataNode *node = it->Value(); if (node != NULL) this->ProcessNode(node, renderer, surface, layerSortedActors); } // Add all image actors to the assembly, sorted according to // layer property LayerSortedActorList::iterator actorIt; for ( actorIt = layerSortedActors.begin(); actorIt != layerSortedActors.end(); ++actorIt ) { m_ImageAssembly->AddPart( actorIt->second ); } // Configurate the tube-shaped frame: size according to the surface // bounds, color as specified in the plane's properties vtkPolyData *surfacePolyData = surface->GetVtkPolyData(); m_Cleaner->SetInput(surfacePolyData); m_EdgeTransformer->SetTransform(this->GetDataNode()->GetVtkTransform(this->GetTimestep()) ); // Adjust the radius according to extent m_EdgeTuber->SetRadius( tubeRadius ); // Get the plane's color and set the tube properties accordingly ColorProperty::Pointer colorProperty; colorProperty = dynamic_cast(this->GetDataNode()->GetProperty( "color" )); if ( colorProperty.IsNotNull() ) { const Color& color = colorProperty->GetColor(); m_EdgeActor->GetProperty()->SetColor(color.GetRed(), color.GetGreen(), color.GetBlue()); } else { m_EdgeActor->GetProperty()->SetColor( 1.0, 1.0, 1.0 ); } m_ImageAssembly->SetUserTransform(this->GetDataNode()->GetVtkTransform(this->GetTimestep()) ); } VtkRepresentationProperty* representationProperty; this->GetDataNode()->GetProperty(representationProperty, "material.representation", renderer); if ( representationProperty != NULL ) m_BackgroundActor->GetProperty()->SetRepresentation( representationProperty->GetVtkRepresentation() ); } void Geometry2DDataVtkMapper3D::ProcessNode( DataNode * node, BaseRenderer* renderer, Surface * surface, LayerSortedActorList &layerSortedActors ) { if ( node != NULL ) { //we need to get the information from the 2D mapper to render the texture on the 3D plane ImageVtkMapper2D *imageMapper = dynamic_cast< ImageVtkMapper2D * >( node->GetMapper(1) ); //GetMapper(1) provides the 2D mapper for the data node //if there is a 2D mapper, which is not the standard image mapper... if(!imageMapper && node->GetMapper(1)) { //... check if it is the composite mapper std::string cname(node->GetMapper(1)->GetNameOfClass()); if(!cname.compare("CompositeMapper")) //string.compare returns 0 if the two strings are equal. { //get the standard image mapper. //This is a special case in MITK and does only work for the CompositeMapper. imageMapper = dynamic_cast( node->GetMapper(3) ); } } if ( (node->IsVisible(renderer)) && imageMapper ) { WeakPointerProperty::Pointer rendererProp = dynamic_cast< WeakPointerProperty * >(GetDataNode()->GetPropertyList()->GetProperty("renderer")); if ( rendererProp.IsNotNull() ) { BaseRenderer::Pointer planeRenderer = dynamic_cast< BaseRenderer * >(rendererProp->GetWeakPointer().GetPointer()); // Retrieve and update image to be mapped const ImageVtkMapper2D::LocalStorage* localStorage = imageMapper->GetLocalStorage(planeRenderer); if ( planeRenderer.IsNotNull() ) { // perform update of imagemapper if needed (maybe the respective 2D renderwindow is not rendered/update before) imageMapper->Update(planeRenderer); // If it has not been initialized already in a previous pass, // generate an actor and a texture object to // render the image associated with the ImageVtkMapper2D. vtkActor *imageActor; vtkDataSetMapper *dataSetMapper = NULL; vtkTexture *texture; if ( m_ImageActors.count( imageMapper ) == 0 ) { dataSetMapper = vtkDataSetMapper::New(); //Enable rendering without copying the image. dataSetMapper->ImmediateModeRenderingOn(); - texture = vtkTexture::New(); + texture = vtkNeverTranslucentTexture::New(); texture->RepeatOff(); imageActor = vtkActor::New(); imageActor->SetMapper( dataSetMapper ); imageActor->SetTexture( texture ); + imageActor->GetProperty()->SetOpacity(0.999); // HACK! otherwise VTK wouldn't recognize this as translucent surface (if LUT values map to alpha < 255 + // improvement: apply "opacity" property onle HERE and also in 2D image mapper. DO NOT change LUT to achieve translucent images (see method ChangeOpacity in image mapper 2D) // Make imageActor the sole owner of the mapper and texture // objects dataSetMapper->UnRegister( NULL ); texture->UnRegister( NULL ); // Store the actor so that it may be accessed in following // passes. m_ImageActors[imageMapper].Initialize(imageActor, imageMapper, m_ImageMapperDeletedCommand); } else { // Else, retrieve the actor and associated objects from the // previous pass. imageActor = m_ImageActors[imageMapper].m_Actor; dataSetMapper = (vtkDataSetMapper *)imageActor->GetMapper(); texture = imageActor->GetTexture(); } // Set poly data new each time its object changes (e.g. when // switching between planar and curved geometries) if ( (dataSetMapper != NULL) && (dataSetMapper->GetInput() != surface->GetVtkPolyData()) ) { dataSetMapper->SetInput( surface->GetVtkPolyData() ); } //Check if the m_ReslicedImage is NULL. //This is the case when no image geometry is met by //the reslicer. In that case, the texture has to be //empty (black) and we don't have to do anything. //See fixed bug #13275 if(localStorage->m_ReslicedImage != NULL) { bool binaryOutline = node->IsOn( "outline binary", renderer ); if( binaryOutline ) { texture->SetInput( localStorage->m_ReslicedImage ); } else { texture->SetInput( localStorage->m_Texture->GetInput() ); } // VTK (mis-)interprets unsigned char (binary) images as color images; // So, we must manually turn on their mapping through a (gray scale) lookup table; texture->SetMapColorScalarsThroughLookupTable( localStorage->m_Texture->GetMapColorScalarsThroughLookupTable() ); //re-use properties from the 2D image mapper imageActor->SetProperty( localStorage->m_Actor->GetProperty() ); imageActor->GetProperty()->SetAmbient(0.5); // Set texture interpolation on/off bool textureInterpolation = node->IsOn( "texture interpolation", renderer ); texture->SetInterpolate( textureInterpolation ); //get the lookuptable from the 2D image mapper texture->SetLookupTable( localStorage->m_Texture->GetLookupTable() ); // Store this actor to be added to the actor assembly, sort // by layer int layer = 1; node->GetIntProperty( "layer", layer ); layerSortedActors.insert(std::pair< int, vtkActor * >( layer, imageActor ) ); } } } } } } void Geometry2DDataVtkMapper3D::ActorInfo::Initialize(vtkActor* actor, itk::Object* sender, itk::Command* command) { m_Actor = actor; m_Sender = sender; // Get informed when ImageMapper object is deleted, so that // the data structures built here can be deleted as well m_ObserverID = sender->AddObserver( itk::DeleteEvent(), command ); } Geometry2DDataVtkMapper3D::ActorInfo::ActorInfo() : m_Actor(NULL), m_Sender(NULL), m_ObserverID(0) { } Geometry2DDataVtkMapper3D::ActorInfo::~ActorInfo() { if(m_Sender != NULL) { m_Sender->RemoveObserver(m_ObserverID); } if(m_Actor != NULL) { m_Actor->Delete(); } } } // namespace mitk diff --git a/Core/Code/Rendering/mitkImageVtkMapper2D.cpp b/Core/Code/Rendering/mitkImageVtkMapper2D.cpp index 31238f5e42..d0d9fa5333 100644 --- a/Core/Code/Rendering/mitkImageVtkMapper2D.cpp +++ b/Core/Code/Rendering/mitkImageVtkMapper2D.cpp @@ -1,1039 +1,1061 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //MITK #include #include #include #include #include #include #include #include #include #include #include #include //#include #include #include "mitkImageStatisticsHolder.h" +#include "mitkPlaneClipping.h" //MITK Rendering #include "mitkImageVtkMapper2D.h" #include "vtkMitkThickSlicesFilter.h" -#include "vtkMitkApplyLevelWindowToRGBFilter.h" +#include "vtkMitkLevelWindowFilter.h" +#include "vtkNeverTranslucentTexture.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() ); + //The 3D RW Mapper (Geometry2DDataVtkMapper3D) is listening to this event, + //in order to delete the images from the 3D RW. + this->InvokeEvent( itk::DeleteEvent() ); } //set the two points defining the textured plane according to the dimension and spacing void mitk::ImageVtkMapper2D::GeneratePlane(mitk::BaseRenderer* renderer, vtkFloatingPointType planeBounds[6]) { - LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); - - float depth = this->CalculateLayerDepth(renderer); - //Set the origin to (xMin; yMin; depth) of the plane. This is necessary for obtaining the correct - //plane size in crosshair rotation and swivel mode. - localStorage->m_Plane->SetOrigin(planeBounds[0], planeBounds[2], depth); - //These two points define the axes of the plane in combination with the origin. - //Point 1 is the x-axis and point 2 the y-axis. - //Each plane is transformed according to the view (axial, coronal and saggital) afterwards. - localStorage->m_Plane->SetPoint1(planeBounds[1] , planeBounds[2], depth); //P1: (xMax, yMin, depth) - localStorage->m_Plane->SetPoint2(planeBounds[0], planeBounds[3], depth); //P2: (xMin, yMax, depth) + LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); + + float depth = this->CalculateLayerDepth(renderer); + //Set the origin to (xMin; yMin; depth) of the plane. This is necessary for obtaining the correct + //plane size in crosshair rotation and swivel mode. + localStorage->m_Plane->SetOrigin(planeBounds[0], planeBounds[2], depth); + //These two points define the axes of the plane in combination with the origin. + //Point 1 is the x-axis and point 2 the y-axis. + //Each plane is transformed according to the view (axial, coronal and saggital) afterwards. + localStorage->m_Plane->SetPoint1(planeBounds[1] , planeBounds[2], depth); //P1: (xMax, yMin, depth) + localStorage->m_Plane->SetPoint2(planeBounds[0], planeBounds[3], depth); //P2: (xMin, yMax, depth) } float mitk::ImageVtkMapper2D::CalculateLayerDepth(mitk::BaseRenderer* renderer) { - //get the clipping range to check how deep into z direction we can render images - double maxRange = renderer->GetVtkRenderer()->GetActiveCamera()->GetClippingRange()[1]; - - //Due to a VTK bug, we cannot use the whole clipping range. /100 is empirically determined - float depth = -maxRange*0.01; // divide by 100 - int layer = 0; - GetDataNode()->GetIntProperty( "layer", layer, renderer); - //add the layer property for each image to render images with a higher layer on top of the others - depth += layer*10; //*10: keep some room for each image (e.g. for QBalls in between) - if(depth > 0.0f) { - depth = 0.0f; - MITK_WARN << "Layer value exceeds clipping range. Set to minimum instead."; - } - return depth; + //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() ); + 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_Actors; + //return the actor corresponding to the renderer + return m_LSH.GetLocalStorage(renderer)->m_Actors; } void mitk::ImageVtkMapper2D::MitkRenderOverlay(BaseRenderer* renderer) { - if ( this->IsVisible(renderer)==false ) - return; - if ( this->GetVtkProp(renderer)->GetVisibility() ) - { - this->GetVtkProp(renderer)->RenderOverlay(renderer->GetVtkRenderer()); - } + 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() ); - } + 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()); - } + 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()); - } + 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); + LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); - mitk::Image *input = const_cast< mitk::Image * >( this->GetInput() ); - mitk::DataNode* datanode = this->GetDataNode(); + mitk::Image *input = const_cast< mitk::Image * >( this->GetInput() ); + mitk::DataNode* datanode = this->GetDataNode(); - if ( input == NULL || input->IsInitialized() == false ) - { - return; - } + 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; - } + //check if there is a valid worldGeometry + const Geometry2D *worldGeometry = renderer->GetCurrentWorldGeometry2D(); + if( ( worldGeometry == NULL ) || ( !worldGeometry->IsValid() ) || ( !worldGeometry->HasReferenceGeometry() )) + { + return; + } - input->Update(); + input->Update(); - // early out if there is no intersection of the current rendering geometry - // and the geometry of the image that is to be rendered. - if ( !RenderingGeometryIntersectsImage( worldGeometry, input->GetSlicedGeometry() ) ) - { - // set image to NULL, to clear the texture in 3D, because - // the latest image is used there if the plane is out of the geometry - // see bug-13275 - localStorage->m_ReslicedImage = NULL; - localStorage->m_Mapper->SetInput( localStorage->m_EmptyPolyData ); - return; - } + // early out if there is no intersection of the current rendering geometry + // and the geometry of the image that is to be rendered. + if ( !RenderingGeometryIntersectsImage( worldGeometry, input->GetSlicedGeometry() ) ) + { + // set image to NULL, to clear the texture in 3D, because + // the latest image is used there if the plane is out of the geometry + // see bug-13275 + localStorage->m_ReslicedImage = NULL; + localStorage->m_Mapper->SetInput( localStorage->m_EmptyPolyData ); + return; + } - //set main input for ExtractSliceFilter - localStorage->m_Reslicer->SetInput(input); - localStorage->m_Reslicer->SetWorldGeometry(worldGeometry); - localStorage->m_Reslicer->SetTimeStep( this->GetTimestep() ); + //set 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() ) ); + //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); + //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" ); + // 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 + int interpolationMode = VTK_RESLICE_NEAREST; + if ( resliceInterpolationProperty != NULL ) { - localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_NEAREST); + interpolationMode = resliceInterpolationProperty->GetInterpolation(); } - //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 + switch ( interpolationMode ) { - 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"; - } + 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; } - - - if(thickSlicesMode > 0) + } + 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) { - 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(); + 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 { - //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 ); + MITK_WARN << "no associated widget plane data tree node found"; + } + } + const PlaneGeometry *planeGeometry = dynamic_cast< const PlaneGeometry * >( worldGeometry ); - 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(); - } + if(thickSlicesMode > 0) + { + double dataZSpacing = 1.0; + Vector3D normInIndex, normal; - // 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; + 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 } - localStorage->m_Reslicer->GetClippedPlaneBounds(sliceBounds); + normal.Normalize(); + + input->GetTimeSlicedGeometry()->GetGeometry3D( this->GetTimestep() )->WorldToIndex( normal, normInIndex ); + + dataZSpacing = 1.0 / normInIndex.GetNorm(); + + localStorage->m_Reslicer->SetOutputDimensionality( 3 ); + localStorage->m_Reslicer->SetOutputSpacingZDirection(dataZSpacing); + localStorage->m_Reslicer->SetOutputExtentZDirection( -thickSlicesNum, 0+thickSlicesNum ); + + // Do the reslicing. Modified() is called to make sure that the reslicer is + // executed even though the input geometry information did not change; this + // is necessary when the input /em data, but not the /em geometry changes. + localStorage->m_TSFilter->SetThickSliceMode( thickSlicesMode-1 ); + localStorage->m_TSFilter->SetInput( localStorage->m_Reslicer->GetVtkOutput() ); + + //vtkFilter=>mitkFilter=>vtkFilter update mechanism will fail without calling manually + localStorage->m_Reslicer->Modified(); + localStorage->m_Reslicer->Update(); + + localStorage->m_TSFilter->Modified(); + localStorage->m_TSFilter->Update(); + localStorage->m_ReslicedImage = localStorage->m_TSFilter->GetOutput(); + } + else + { + //this is needed when thick mode was enable bevore. These variable have to be reset to default values + localStorage->m_Reslicer->SetOutputDimensionality( 2 ); + localStorage->m_Reslicer->SetOutputSpacingZDirection(1.0); + localStorage->m_Reslicer->SetOutputExtentZDirection( 0, 0 ); + + + localStorage->m_Reslicer->Modified(); + //start the pipeline with updating the largest possible, needed if the geometry of the input has changed + localStorage->m_Reslicer->UpdateLargestPossibleRegion(); + localStorage->m_ReslicedImage = localStorage->m_Reslicer->GetVtkOutput(); + } + + + // Bounds information for reslicing (only reuqired if reference geometry + // is present) + //this used for generating a vtkPLaneSource with the right size + vtkFloatingPointType sliceBounds[6]; + for ( int i = 0; i < 6; ++i ) + { + sliceBounds[i] = 0.0; + } + localStorage->m_Reslicer->GetClippedPlaneBounds(sliceBounds); + + //get the spacing of the slice + localStorage->m_mmPerPixel = localStorage->m_Reslicer->GetOutputSpacing(); + + + // calculate minimum bounding rect of IMAGE in texture + vtkFloatingPointType textureClippingBounds[6]; + for ( int i = 0; i < 6; ++i ) + { + textureClippingBounds[i] = 0.0; + } + // Calculate the actual bounds of the transformed plane clipped by the + // dataset bounding box; this is required for drawing the texture at the + // correct position during 3D mapping. + mitk::PlaneClipping::CalculateClippedPlaneBounds( input->GetGeometry(), planeGeometry, textureClippingBounds ); + + textureClippingBounds[0] = static_cast< int >( textureClippingBounds[0] / localStorage->m_mmPerPixel[0] + 0.5 ); + textureClippingBounds[1] = static_cast< int >( textureClippingBounds[1] / localStorage->m_mmPerPixel[0] + 0.5 ); + textureClippingBounds[2] = static_cast< int >( textureClippingBounds[2] / localStorage->m_mmPerPixel[1] + 0.5 ); + textureClippingBounds[3] = static_cast< int >( textureClippingBounds[3] / localStorage->m_mmPerPixel[1] + 0.5 ); + + //get the number of scalar components to distinguish between different image types + int numberOfComponents = localStorage->m_ReslicedImage->GetNumberOfScalarComponents(); + //get the binary property + bool binary = false; + bool binaryOutline = false; + datanode->GetBoolProperty( "binary", binary, renderer ); + if(binary) //binary image + { + datanode->GetBoolProperty( "outline binary", binaryOutline, renderer ); + if(binaryOutline) //contour rendering + { + if ( input->GetPixelType().GetBpe() <= 8 ) + { + //generate contours/outlines + localStorage->m_OutlinePolyData = CreateOutlinePolyData(renderer); - //get the spacing of the slice - localStorage->m_mmPerPixel = localStorage->m_Reslicer->GetOutputSpacing(); + float binaryOutlineWidth(1.0); + if ( datanode->GetFloatProperty( "outline width", binaryOutlineWidth, renderer ) ) + { + if ( localStorage->m_Actors->GetNumberOfPaths() > 1 ) + { + float binaryOutlineShadowWidth(1.5); + datanode->GetFloatProperty( "outline shadow width", binaryOutlineShadowWidth, renderer ); + dynamic_cast(localStorage->m_Actors->GetParts()->GetItemAsObject(0)) + ->GetProperty()->SetLineWidth( binaryOutlineWidth * binaryOutlineShadowWidth ); + } - //get the number of scalar components to distinguish between different image types - int numberOfComponents = localStorage->m_ReslicedImage->GetNumberOfScalarComponents(); - //get the binary property - bool binary = false; - bool binaryOutline = false; - datanode->GetBoolProperty( "binary", binary, renderer ); - if(binary) //binary image - { - datanode->GetBoolProperty( "outline binary", binaryOutline, renderer ); - if(binaryOutline) //contour rendering - { - if ( input->GetPixelType().GetBpe() <= 8 ) - { - //generate contours/outlines - localStorage->m_OutlinePolyData = CreateOutlinePolyData(renderer); - - float binaryOutlineWidth(1.0); - if ( datanode->GetFloatProperty( "outline width", binaryOutlineWidth, renderer ) ) - { - if ( localStorage->m_Actors->GetNumberOfPaths() > 1 ) - { - float binaryOutlineShadowWidth(1.5); - datanode->GetFloatProperty( "outline shadow width", binaryOutlineShadowWidth, renderer ); - - dynamic_cast(localStorage->m_Actors->GetParts()->GetItemAsObject(0)) - ->GetProperty()->SetLineWidth( binaryOutlineWidth * binaryOutlineShadowWidth ); - } - - 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!"; - } + localStorage->m_Actor->GetProperty()->SetLineWidth( binaryOutlineWidth ); } - this->ApplyLookuptable(renderer); - //Interpret the values as binary values - localStorage->m_Texture->MapColorScalarsThroughLookupTableOn(); + } + else + { + binaryOutline = false; + this->ApplyLookuptable(renderer, textureClippingBounds); + MITK_WARN << "Type of all binary images should be (un)signed char. Outline does not work on other pixel types!"; + } } - else if( numberOfComponents == 1 ) //gray images + else //standard binary image { - //Interpret the values as gray values - localStorage->m_Texture->MapColorScalarsThroughLookupTableOn(); - - this->ApplyLookuptable(renderer); + if(numberOfComponents != 1) + { + MITK_ERROR << "Rendering Error: Binary Images with more then 1 component are not supported!"; + } } - 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!"; - } + if (!(numberOfComponents == 1 || numberOfComponents == 3 || numberOfComponents == 4)) + { + MITK_WARN << "Unknown number of components!"; + } - this->ApplyOpacity( renderer ); - this->TransformActor( renderer ); + this->ApplyLookuptable(renderer, textureClippingBounds); - vtkActor* contourShadowActor = dynamic_cast (localStorage->m_Actors->GetParts()->GetItemAsObject(0)); - if(binary && binaryOutline) //connect the mapper with the polyData which contains the lines - { - //We need the contour for the binary outline property as actor - localStorage->m_Mapper->SetInput(localStorage->m_OutlinePolyData); - localStorage->m_Actor->SetTexture(NULL); //no texture for contours + // do not use a VTK lookup table (we do that ourselves in m_LevelWindowFilter) + localStorage->m_Texture->MapColorScalarsThroughLookupTableOff(); - bool binaryOutlineShadow( false ); - datanode->GetBoolProperty( "outline binary shadow", binaryOutlineShadow, renderer ); + this->ApplyColor( renderer ); + this->ApplyOpacity( renderer ); + this->TransformActor( renderer ); - if ( binaryOutlineShadow ) - contourShadowActor->SetVisibility( true ); - else - contourShadowActor->SetVisibility( false ); + vtkActor* contourShadowActor = dynamic_cast (localStorage->m_Actors->GetParts()->GetItemAsObject(0)); - } - else - { //Connect the mapper with the input texture. This is the standard case. - //setup the textured plane - this->GeneratePlane( renderer, sliceBounds ); - //set the plane as input for the mapper - localStorage->m_Mapper->SetInputConnection(localStorage->m_Plane->GetOutputPort()); - //set the texture for the actor - - localStorage->m_Actor->SetTexture(localStorage->m_Texture); - contourShadowActor->SetVisibility( false ); - } + if(binary && binaryOutline) //connect the mapper with the polyData which contains the lines + { + //We need the contour for the binary outline property as actor + localStorage->m_Mapper->SetInput(localStorage->m_OutlinePolyData); + localStorage->m_Actor->SetTexture(NULL); //no texture for contours - // We have been modified => save this for next Update() - localStorage->m_LastUpdateTime.Modified(); + bool binaryOutlineShadow( false ); + datanode->GetBoolProperty( "outline binary shadow", binaryOutlineShadow, renderer ); + + if ( binaryOutlineShadow ) + contourShadowActor->SetVisibility( true ); + else + contourShadowActor->SetVisibility( false ); + + } + else + { //Connect the mapper with the input texture. This is the standard case. + //setup the textured plane + this->GeneratePlane( renderer, sliceBounds ); + //set the plane as input for the mapper + localStorage->m_Mapper->SetInputConnection(localStorage->m_Plane->GetOutputPort()); + //set the texture for the actor + + localStorage->m_Actor->SetTexture(localStorage->m_Texture); + contourShadowActor->SetVisibility( false ); + } + + // We have been modified => save this for next Update() + localStorage->m_LastUpdateTime.Modified(); } void mitk::ImageVtkMapper2D::ApplyColor( mitk::BaseRenderer* renderer ) { - LocalStorage *localStorage = this->GetLocalStorage( renderer ); - - float rgb[3]= { 1.0f, 1.0f, 1.0f }; - - // check for color prop and use it for rendering if it exists - // binary image hovering & binary image selection - bool hover = false; - bool selected = false; - GetDataNode()->GetBoolProperty("binaryimage.ishovering", hover, renderer); - GetDataNode()->GetBoolProperty("selected", selected, renderer); - if(hover && !selected) + LocalStorage *localStorage = this->GetLocalStorage( renderer ); + + float rgb[3]= { 1.0f, 1.0f, 1.0f }; + + // check for color prop and use it for rendering if it exists + // binary image hovering & binary image selection + bool hover = false; + bool selected = false; + GetDataNode()->GetBoolProperty("binaryimage.ishovering", hover, renderer); + GetDataNode()->GetBoolProperty("selected", selected, renderer); + if(hover && !selected) + { + mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty + ("binaryimage.hoveringcolor", renderer)); + if(colorprop.IsNotNull()) { - 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 ); - } + memcpy(rgb, colorprop->GetColor().GetDataPointer(), 3*sizeof(float)); } - if(selected) + else { - 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 ); - } + GetColor( rgb, renderer ); } - if(!hover && !selected) + } + 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 ); + GetColor( rgb, renderer ); } - - double rgbConv[3] = {(double)rgb[0], (double)rgb[1], (double)rgb[2]}; //conversion to double for VTK - dynamic_cast (localStorage->m_Actors->GetParts()->GetItemAsObject(0))->GetProperty()->SetColor(rgbConv); - localStorage->m_Actor->GetProperty()->SetColor(rgbConv); - - if ( localStorage->m_Actors->GetParts()->GetNumberOfItems() > 1 ) + } + if(!hover && !selected) + { + GetColor( rgb, renderer ); + } + + double rgbConv[3] = {(double)rgb[0], (double)rgb[1], (double)rgb[2]}; //conversion to double for VTK + dynamic_cast (localStorage->m_Actors->GetParts()->GetItemAsObject(0))->GetProperty()->SetColor(rgbConv); + localStorage->m_Actor->GetProperty()->SetColor(rgbConv); + + if ( localStorage->m_Actors->GetParts()->GetNumberOfItems() > 1 ) + { + float rgb[3]= { 1.0f, 1.0f, 1.0f }; + mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty + ("outline binary shadow color", renderer)); + if(colorprop.IsNotNull()) { - float rgb[3]= { 1.0f, 1.0f, 1.0f }; - mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty - ("outline binary shadow color", renderer)); - if(colorprop.IsNotNull()) - { - memcpy(rgb, colorprop->GetColor().GetDataPointer(), 3*sizeof(float)); - } - double rgbConv[3] = {(double)rgb[0], (double)rgb[1], (double)rgb[2]}; //conversion to double for VTK - dynamic_cast( localStorage->m_Actors->GetParts()->GetItemAsObject(0) )->GetProperty()->SetColor(rgbConv); + memcpy(rgb, colorprop->GetColor().GetDataPointer(), 3*sizeof(float)); } + double rgbConv[3] = {(double)rgb[0], (double)rgb[1], (double)rgb[2]}; //conversion to double for VTK + dynamic_cast( localStorage->m_Actors->GetParts()->GetItemAsObject(0) )->GetProperty()->SetColor(rgbConv); + } } void mitk::ImageVtkMapper2D::ApplyOpacity( mitk::BaseRenderer* renderer ) { - LocalStorage* localStorage = this->GetLocalStorage( renderer ); - float opacity = 1.0f; - // check for opacity prop and use it for rendering if it exists - GetOpacity( opacity, renderer ); - //set the opacity according to the properties - localStorage->m_Actor->GetProperty()->SetOpacity(opacity); - if ( localStorage->m_Actors->GetParts()->GetNumberOfItems() > 1 ) - { - dynamic_cast( localStorage->m_Actors->GetParts()->GetItemAsObject(0) )->GetProperty()->SetOpacity(opacity); - } + 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); + if ( localStorage->m_Actors->GetParts()->GetNumberOfItems() > 1 ) + { + dynamic_cast( localStorage->m_Actors->GetParts()->GetItemAsObject(0) )->GetProperty()->SetOpacity(opacity); + } } -void mitk::ImageVtkMapper2D::ApplyLookuptable( mitk::BaseRenderer* renderer ) +void mitk::ImageVtkMapper2D::ApplyLookuptable( mitk::BaseRenderer* renderer, vtkFloatingPointType* bounds ) { - //Have the following 4 different use cases how to generate the lookuptable: - //1. We have a binary image -> The lut range is set to 0.0, 1.0 - //2. The user sets a lut we can use - //3. The user sets a transfer function we can use - //4. Nothing defined: The default color lookuptable is used - //@Warning: If the user sets a lut and a transfer function the lut will be used! - LocalStorage* localStorage = m_LSH.GetLocalStorage(renderer); - bool binary = false; - this->GetDataNode()->GetBoolProperty( "binary", binary, renderer ); - - mitk::TransferFunctionProperty::Pointer transferFunctionProperty = - dynamic_cast(this->GetDataNode()->GetProperty("Image Rendering.Transfer Function",renderer )); - - mitk::LookupTableProperty::Pointer lookupTableProp; - lookupTableProp = dynamic_cast - (this->GetDataNode()->GetProperty("LookupTable")); - - if(binary) // is it a binary image? + //Have the following 4 different use cases how to generate the lookuptable: + //1. We have a binary image -> The lut range is set to 0.0, 1.0 + //2. The user sets a lut we can use + //3. The user sets a transfer function we can use + //4. Nothing defined: The default color lookuptable is used + //@Warning: If the user sets a lut and a transfer function the lut will be used! + LocalStorage* localStorage = m_LSH.GetLocalStorage(renderer); + bool binary = false; + + this->GetDataNode()->GetBoolProperty( "binary", binary, renderer ); + + vtkLookupTable *usedLookupTable = localStorage->m_DefaultLookupTable; + vtkScalarsToColors *usedScalarsToColors = localStorage->m_DefaultLookupTable; + + // If lookup table or transferfunction use is requested... + mitk::LookupTableProperty::Pointer lookupTableProp = dynamic_cast(this->GetDataNode()->GetProperty("LookupTable")); + mitk::TransferFunctionProperty::Pointer transferFunctionProp = dynamic_cast(this->GetDataNode()->GetProperty("Image Rendering.Transfer Function",renderer )); + + if(binary) // is it a binary image? + { + usedScalarsToColors = usedLookupTable = localStorage->m_BinaryLookupTable; + } + else if( lookupTableProp.IsNotNull() ) // is a lookuptable set? + { + if( transferFunctionProp.IsNotNull() ) { - //default lookuptable for binary images - localStorage->m_Texture->GetLookupTable()->SetRange(0.0, 1.0); + MITK_WARN << "A LookupTable and a transfer function TransferFunction property is set! Only the Image Rendering.Transfer Function will be used. If you want to use the color transfer function, remove or rename the LookupTable property."; } - else if( lookupTableProp.IsNotNull() ) // is a lookuptable set? + //If a lookup table is supplied by the user: + //only update the lut, when the properties have changed... + if( lookupTableProp->GetLookupTable()->GetMTime() + <= this->GetDataNode()->GetPropertyList()->GetMTime() ) { - //If a lookup table is supplied by the user: - //only update the lut, when the properties have changed... - if( lookupTableProp->GetLookupTable()->GetMTime() - <= this->GetDataNode()->GetPropertyList()->GetMTime() ) - { - lookupTableProp->GetLookupTable()->ChangeOpacityForAll( lookupTableProp->GetLookupTable()->GetVtkLookupTable()->GetAlpha()*localStorage->m_Actor->GetProperty()->GetOpacity() ); - lookupTableProp->GetLookupTable()->ChangeOpacity(0, 0.0); - } - localStorage->m_Texture->SetLookupTable( lookupTableProp->GetLookupTable()->GetVtkLookupTable() ); - //If the user defines a lut, we dont want to use the color and take white instead. - dynamic_cast (localStorage->m_Actors->GetParts()->GetItemAsObject(0))->GetProperty()->SetColor(1.0, 1.0, 1.0); - localStorage->m_Actor->GetProperty()->SetColor(1.0, 1.0, 1.0); + lookupTableProp->GetLookupTable()->ChangeOpacityForAll( lookupTableProp->GetLookupTable()->GetVtkLookupTable()->GetAlpha()*localStorage->m_Actor->GetProperty()->GetOpacity() ); + lookupTableProp->GetLookupTable()->ChangeOpacity(0, 0.0); } - else if(transferFunctionProperty.IsNotNull()) // is a color transfer function set? - { - localStorage->m_Texture->SetLookupTable(transferFunctionProperty->GetValue()->GetColorTransferFunction()); - } - else - { - //default lookuptable - LevelWindow levelWindow; - this->GetLevelWindow( levelWindow, renderer ); - localStorage->m_Texture->SetLookupTable( localStorage->m_LookupTable ); - localStorage->m_Texture->GetLookupTable()->SetRange( levelWindow.GetLowerWindowBound(), levelWindow.GetUpperWindowBound() ); - this->ApplyColor( renderer ); - } - - localStorage->m_Texture->SetInput( localStorage->m_ReslicedImage ); - if((transferFunctionProperty.IsNotNull()) && (lookupTableProp.IsNotNull())) - { - MITK_WARN << "A LookupTable and a transfer function Image Rendering.Transfer Function property is set! Only the LookupTable will be used. If you want to use the color transfer function, remove or rename the LookupTable property."; - } - // check for texture interpolation property - bool textureInterpolation = false; - GetDataNode()->GetBoolProperty( "texture interpolation", textureInterpolation, renderer ); - - //set the interpolation modus according to the property - localStorage->m_Texture->SetInterpolate(textureInterpolation); + //If the user defines a lut, we dont want to use the color and take white instead. + dynamic_cast (localStorage->m_Actors->GetParts()->GetItemAsObject(0))->GetProperty()->SetColor(1.0, 1.0, 1.0); + localStorage->m_Actor->GetProperty()->SetColor(1.0, 1.0, 1.0); + usedScalarsToColors = usedLookupTable = lookupTableProp->GetLookupTable()->GetVtkLookupTable(); + } + else if(transferFunctionProp.IsNotNull()) // is a color transfer function set? + { + usedScalarsToColors = transferFunctionProp->GetValue()->GetColorTransferFunction(); + usedLookupTable = 0; + } + else + { + //default lookuptable + LevelWindow levelWindow; + this->GetLevelWindow( levelWindow, renderer ); + usedLookupTable->SetRange( levelWindow.GetLowerWindowBound(), levelWindow.GetUpperWindowBound() ); + this->ApplyColor( renderer ); + } + + localStorage->m_Texture->SetInput( localStorage->m_ReslicedImage ); + + // check for texture interpolation property + bool textureInterpolation = false; + GetDataNode()->GetBoolProperty( "texture interpolation", textureInterpolation, renderer ); + + //set the interpolation modus according to the property + localStorage->m_Texture->SetInterpolate(textureInterpolation); + + mitk::LevelWindow opacLevelWindow; + if( this->GetLevelWindow( opacLevelWindow, renderer, "opaclevelwindow" ) ) + { + //pass the opaque level window to the filter + localStorage->m_LevelWindowFilter->SetMinOpacity(opacLevelWindow.GetLowerWindowBound()); + localStorage->m_LevelWindowFilter->SetMaxOpacity(opacLevelWindow.GetUpperWindowBound()); + } + else + { + //no opaque level window + localStorage->m_LevelWindowFilter->SetMinOpacity(0.0); + localStorage->m_LevelWindowFilter->SetMaxOpacity(255.0); + } + + localStorage->m_LevelWindowFilter->SetLookupTable(usedScalarsToColors); + localStorage->m_LevelWindowFilter->SetInput(localStorage->m_ReslicedImage); + localStorage->m_LevelWindowFilter->SetClippingBounds(bounds); + //connect the texture with the output of the levelwindow filter + localStorage->m_Texture->SetInputConnection(localStorage->m_LevelWindowFilter->GetOutputPort()); } -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; - } + 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(); +} - mitk::Image* data = const_cast( this->GetInput() ); - if ( data == NULL ) +void mitk::ImageVtkMapper2D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) +{ + mitk::Image::Pointer image = dynamic_cast(node->GetData()); + + // Properties common for both images and segmentations + node->AddProperty( "depthOffset", mitk::FloatProperty::New( 0.0 ), renderer, overwrite ); + node->AddProperty( "outline binary", mitk::BoolProperty::New( false ), renderer, overwrite ); + node->AddProperty( "outline width", mitk::FloatProperty::New( 1.0 ), renderer, overwrite ); + node->AddProperty( "outline binary shadow", mitk::BoolProperty::New( false ), renderer, overwrite ); + node->AddProperty( "outline binary shadow color", ColorProperty::New(0.0,0.0,0.0), renderer, overwrite ); + node->AddProperty( "outline shadow width", mitk::FloatProperty::New( 1.5 ), renderer, overwrite ); + if(image->IsRotated()) node->AddProperty( "reslice interpolation", mitk::VtkResliceInterpolationProperty::New(VTK_RESLICE_CUBIC) ); + else node->AddProperty( "reslice interpolation", mitk::VtkResliceInterpolationProperty::New() ); + node->AddProperty( "texture interpolation", mitk::BoolProperty::New( mitk::DataNodeFactory::m_TextureInterpolationActive ) ); // set to user configurable default value (see global options) + node->AddProperty( "in plane resample extent by geometry", mitk::BoolProperty::New( false ) ); + node->AddProperty( "bounding box", mitk::BoolProperty::New( false ) ); + + std::string photometricInterpretation; // DICOM tag telling us how pixel values should be displayed + if ( node->GetStringProperty( "dicom.pixel.PhotometricInterpretation", photometricInterpretation ) ) + { + // modality provided by DICOM or other reader + if ( photometricInterpretation.find("MONOCHROME1") != std::string::npos ) // meaning: display MINIMUM pixels as WHITE { - return; + // generate LUT (white to black) + mitk::LookupTable::Pointer mitkLut = mitk::LookupTable::New(); + vtkLookupTable* bwLut = mitkLut->GetVtkLookupTable(); + bwLut->SetTableRange (0, 1); + bwLut->SetSaturationRange (0, 0); + bwLut->SetHueRange (0, 0); + bwLut->SetValueRange (1, 0); + bwLut->SetAlphaRange (1, 1); + bwLut->SetRampToLinear(); + bwLut->Build(); + mitk::LookupTableProperty::Pointer mitkLutProp = mitk::LookupTableProperty::New(); + mitkLutProp->SetLookupTable(mitkLut); + node->SetProperty( "LookupTable", mitkLutProp ); } - - // 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() ) ) ) + else + if ( photometricInterpretation.find("MONOCHROME2") != std::string::npos ) // meaning: display MINIMUM pixels as BLACK + { + // apply default LUT (black to white) + node->SetProperty( "color", mitk::ColorProperty::New( 1,1,1 ), renderer ); + } + // PALETTE interpretation should be handled ok by RGB loading + } + + 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() ) { - return; + minValue = centralSliceImage->GetStatistics()->GetScalarValueMin(); + maxValue = centralSliceImage->GetStatistics()->GetScalarValueMax(); + min2ndValue = centralSliceImage->GetStatistics()->GetScalarValue2ndMin(); + max2ndValue = centralSliceImage->GetStatistics()->GetScalarValue2ndMax(); } - - 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()) ) + if ((maxValue == min2ndValue && minValue == max2ndValue) || minValue == maxValue) { - this->GenerateDataForRenderer( renderer ); + // centralSlice is strange, lets look at all data + minValue = image->GetStatistics()->GetScalarValueMin(); + maxValue = image->GetStatistics()->GetScalarValueMaxNoRecompute(); + min2ndValue = image->GetStatistics()->GetScalarValue2ndMinNoRecompute(); + max2ndValue = image->GetStatistics()->GetScalarValue2ndMaxNoRecompute(); } - - // since we have checked that nothing important has changed, we can set - // m_LastUpdateTime to the current time - localStorage->m_LastUpdateTime.Modified(); -} - -void mitk::ImageVtkMapper2D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) -{ - mitk::Image::Pointer image = dynamic_cast(node->GetData()); - - // Properties common for both images and segmentations - node->AddProperty( "depthOffset", mitk::FloatProperty::New( 0.0 ), renderer, overwrite ); - node->AddProperty( "outline binary", mitk::BoolProperty::New( false ), renderer, overwrite ); - node->AddProperty( "outline width", mitk::FloatProperty::New( 1.0 ), renderer, overwrite ); - node->AddProperty( "outline binary shadow", mitk::BoolProperty::New( false ), renderer, overwrite ); - node->AddProperty( "outline binary shadow color", ColorProperty::New(0.0,0.0,0.0), renderer, overwrite ); - node->AddProperty( "outline shadow width", mitk::FloatProperty::New( 1.5 ), renderer, overwrite ); - if(image->IsRotated()) node->AddProperty( "reslice interpolation", mitk::VtkResliceInterpolationProperty::New(VTK_RESLICE_CUBIC) ); - else node->AddProperty( "reslice interpolation", mitk::VtkResliceInterpolationProperty::New() ); - node->AddProperty( "texture interpolation", mitk::BoolProperty::New( mitk::DataNodeFactory::m_TextureInterpolationActive ) ); // set to user configurable default value (see global options) - node->AddProperty( "in plane resample extent by geometry", mitk::BoolProperty::New( false ) ); - node->AddProperty( "bounding box", mitk::BoolProperty::New( false ) ); - - std::string photometricInterpretation; // DICOM tag telling us how pixel values should be displayed - if ( node->GetStringProperty( "dicom.pixel.PhotometricInterpretation", photometricInterpretation ) ) + 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( "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)) { - // modality provided by DICOM or other reader - if ( photometricInterpretation.find("MONOCHROME1") != std::string::npos ) // meaning: display MINIMUM pixels as WHITE + /* initialize level/window from DICOM tags */ + std::string sLevel; + std::string sWindow; + if ( image->GetPropertyList()->GetStringProperty( "dicom.voilut.WindowCenter", sLevel ) + && image->GetPropertyList()->GetStringProperty( "dicom.voilut.WindowWidth", sWindow ) ) + { + float level = atof( sLevel.c_str() ); + float window = atof( sWindow.c_str() ); + + mitk::LevelWindow contrast; + std::string sSmallestPixelValueInSeries; + std::string sLargestPixelValueInSeries; + + if ( image->GetPropertyList()->GetStringProperty( "dicom.series.SmallestPixelValueInSeries", sSmallestPixelValueInSeries ) + && image->GetPropertyList()->GetStringProperty( "dicom.series.LargestPixelValueInSeries", sLargestPixelValueInSeries ) ) { - // generate LUT (white to black) - mitk::LookupTable::Pointer mitkLut = mitk::LookupTable::New(); - vtkLookupTable* bwLut = mitkLut->GetVtkLookupTable(); - bwLut->SetTableRange (0, 1); - bwLut->SetSaturationRange (0, 0); - bwLut->SetHueRange (0, 0); - bwLut->SetValueRange (1, 0); - bwLut->SetAlphaRange (1, 1); - bwLut->SetRampToLinear(); - bwLut->Build(); - mitk::LookupTableProperty::Pointer mitkLutProp = mitk::LookupTableProperty::New(); - mitkLutProp->SetLookupTable(mitkLut); - node->SetProperty( "LookupTable", mitkLutProp ); + 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 - if ( photometricInterpretation.find("MONOCHROME2") != std::string::npos ) // meaning: display MINIMUM pixels as BLACK - { - // apply default LUT (black to white) - node->SetProperty( "color", mitk::ColorProperty::New( 1,1,1 ), renderer ); - } - // PALETTE interpretation should be handled ok by RGB loading - } - - bool isBinaryImage(false); - if ( ! node->GetBoolProperty("binary", isBinaryImage) ) - { - - // ok, property is not set, use heuristic to determine if this - // is a binary image - mitk::Image::Pointer centralSliceImage; - ScalarType minValue = 0.0; - ScalarType maxValue = 0.0; - ScalarType min2ndValue = 0.0; - ScalarType max2ndValue = 0.0; - mitk::ImageSliceSelector::Pointer sliceSelector = mitk::ImageSliceSelector::New(); - - sliceSelector->SetInput(image); - sliceSelector->SetSliceNr(image->GetDimension(2)/2); - sliceSelector->SetTimeNr(image->GetDimension(3)/2); - sliceSelector->SetChannelNr(image->GetDimension(4)/2); - sliceSelector->Update(); - centralSliceImage = sliceSelector->GetOutput(); - if ( centralSliceImage.IsNotNull() && centralSliceImage->IsInitialized() ) - { - minValue = centralSliceImage->GetStatistics()->GetScalarValueMin(); - maxValue = centralSliceImage->GetStatistics()->GetScalarValueMax(); - min2ndValue = centralSliceImage->GetStatistics()->GetScalarValue2ndMin(); - max2ndValue = centralSliceImage->GetStatistics()->GetScalarValue2ndMax(); - } - if ((maxValue == min2ndValue && minValue == max2ndValue) || minValue == maxValue) { - // centralSlice is strange, lets look at all data - minValue = image->GetStatistics()->GetScalarValueMin(); - maxValue = image->GetStatistics()->GetScalarValueMaxNoRecompute(); - min2ndValue = image->GetStatistics()->GetScalarValue2ndMinNoRecompute(); - max2ndValue = image->GetStatistics()->GetScalarValue2ndMaxNoRecompute(); + contrast.SetAuto( static_cast(node->GetData()), false, true ); // we need this as a fallback } - 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); + contrast.SetLevelWindow( level, window, true ); + node->SetProperty( "levelwindow", LevelWindowProperty::New( contrast ), renderer ); + } } - else //...or image type object + if(((overwrite) || (node->GetProperty("opaclevelwindow", renderer)==NULL)) + && (image->GetPixelType().GetPixelTypeId() == itk::ImageIOBase::RGBA) + && (image->GetPixelType().GetTypeId() == typeid( unsigned char)) ) { - node->AddProperty( "opacity", mitk::FloatProperty::New(1.0f), 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); + 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(image.IsNotNull() && image->IsInitialized()) - { - if((overwrite) || (node->GetProperty("levelwindow", renderer)==NULL)) - { - /* initialize level/window from DICOM tags */ - std::string sLevel; - std::string sWindow; - if ( image->GetPropertyList()->GetStringProperty( "dicom.voilut.WindowCenter", sLevel ) - && image->GetPropertyList()->GetStringProperty( "dicom.voilut.WindowWidth", sWindow ) ) - { - float level = atof( sLevel.c_str() ); - float window = atof( sWindow.c_str() ); - - mitk::LevelWindow contrast; - std::string sSmallestPixelValueInSeries; - std::string sLargestPixelValueInSeries; - - if ( image->GetPropertyList()->GetStringProperty( "dicom.series.SmallestPixelValueInSeries", sSmallestPixelValueInSeries ) - && image->GetPropertyList()->GetStringProperty( "dicom.series.LargestPixelValueInSeries", sLargestPixelValueInSeries ) ) - { - float smallestPixelValueInSeries = atof( sSmallestPixelValueInSeries.c_str() ); - float largestPixelValueInSeries = atof( sLargestPixelValueInSeries.c_str() ); - contrast.SetRangeMinMax( smallestPixelValueInSeries-1, largestPixelValueInSeries+1 ); // why not a little buffer? - // might remedy some l/w widget challenges - } - else - { - contrast.SetAuto( static_cast(node->GetData()), false, true ); // we need this as a fallback - } - - contrast.SetLevelWindow( level, window, true ); - node->SetProperty( "levelwindow", LevelWindowProperty::New( contrast ), renderer ); - } - } - if(((overwrite) || (node->GetProperty("opaclevelwindow", renderer)==NULL)) - && (image->GetPixelType().GetPixelTypeId() == itk::ImageIOBase::RGBA) - && (image->GetPixelType().GetTypeId() == typeid( unsigned char)) ) - { - mitk::LevelWindow opaclevwin; - opaclevwin.SetRangeMinMax(0,255); - opaclevwin.SetWindowBounds(0,255); - mitk::LevelWindowProperty::Pointer prop = mitk::LevelWindowProperty::New(opaclevwin); - node->SetProperty( "opaclevelwindow", prop, renderer ); - } - } - Superclass::SetDefaultProperties(node, renderer, overwrite); + } + Superclass::SetDefaultProperties(node, renderer, overwrite); } mitk::ImageVtkMapper2D::LocalStorage* mitk::ImageVtkMapper2D::GetLocalStorage(mitk::BaseRenderer* renderer) { - return m_LSH.GetLocalStorage(renderer); + return m_LSH.GetLocalStorage(renderer); } vtkSmartPointer mitk::ImageVtkMapper2D::CreateOutlinePolyData(mitk::BaseRenderer* renderer ){ - LocalStorage* localStorage = this->GetLocalStorage(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]; + //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; + 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); + //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 + vtkSmartPointer points = vtkSmartPointer::New(); //the points to draw + vtkSmartPointer lines = vtkSmartPointer::New(); //the lines to connect the points - // We take the pointer to the first pixel of the image - currentPixel = static_cast(localStorage->m_ReslicedImage->GetScalarPointer() ); + // We take the pointer to the first pixel of the image + currentPixel = static_cast(localStorage->m_ReslicedImage->GetScalarPointer() ); - while (y <= yMax) + while (y <= yMax) + { + //if the current pixel value is set to something + if ((currentPixel) && (*currentPixel != 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++; - } + //check in which direction a line is necessary + //a line is added if the neighbor of the current pixel has the value 0 + //and if the pixel is located at the edge of the image + + //if vvvvv not the first line vvvvv + if (y > yMin && *(currentPixel-line) == 0) + { //x direction - bottom edge of the pixel + //add the 2 points + vtkIdType p1 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); + vtkIdType p2 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); + //add the line between both points + lines->InsertNextCell(2); + lines->InsertCellPoint(p1); + lines->InsertCellPoint(p2); + } + + //if vvvvv not the last line vvvvv + if (y < yMax && *(currentPixel+line) == 0) + { //x direction - top edge of the pixel + vtkIdType p1 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); + vtkIdType p2 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); + lines->InsertNextCell(2); + lines->InsertCellPoint(p1); + lines->InsertCellPoint(p2); + } + + //if vvvvv not the first pixel vvvvv + if ( (x > xMin || y > yMin) && *(currentPixel-1) == 0) + { //y direction - left edge of the pixel + vtkIdType p1 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); + vtkIdType p2 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); + lines->InsertNextCell(2); + lines->InsertCellPoint(p1); + lines->InsertCellPoint(p2); + } + + //if vvvvv not the last pixel vvvvv + if ( (y < yMax || (x < xMax) ) && *(currentPixel+1) == 0) + { //y direction - right edge of the pixel + vtkIdType p1 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); + vtkIdType p2 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); + lines->InsertNextCell(2); + lines->InsertCellPoint(p1); + lines->InsertCellPoint(p2); + } + + /* now consider pixels at the edge of the image */ + + //if vvvvv left edge of image vvvvv + if (x == xMin) + { //draw left edge of the pixel + vtkIdType p1 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); + vtkIdType p2 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); + lines->InsertNextCell(2); + lines->InsertCellPoint(p1); + lines->InsertCellPoint(p2); + } + + //if vvvvv right edge of image vvvvv + if (x == xMax) + { //draw right edge of the pixel + vtkIdType p1 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); + vtkIdType p2 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); + lines->InsertNextCell(2); + lines->InsertCellPoint(p1); + lines->InsertCellPoint(p2); + } + + //if vvvvv bottom edge of image vvvvv + if (y == yMin) + { //draw bottom edge of the pixel + vtkIdType p1 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); + vtkIdType p2 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); + lines->InsertNextCell(2); + lines->InsertCellPoint(p1); + lines->InsertCellPoint(p2); + } + + //if vvvvv top edge of image vvvvv + if (y == yMax) + { //draw top edge of the pixel + vtkIdType p1 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); + vtkIdType p2 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); + lines->InsertNextCell(2); + lines->InsertCellPoint(p1); + lines->InsertCellPoint(p2); + } + }//end if currentpixel is set + + x++; + + if (x > xMax) + { //reached end of line + x = xMin; + y++; + } - // Increase the pointer-position to the next pixel. - // This is safe, as the while-loop and the x-reset logic above makes - // sure we do not exceed the bounds of the image - currentPixel++; - }//end of while - - // Create a polydata to store everything in - vtkSmartPointer polyData = vtkSmartPointer::New(); - // Add the points to the dataset - polyData->SetPoints(points); - // Add the lines to the dataset - polyData->SetLines(lines); - return polyData; + // Increase the pointer-position to the next pixel. + // This is safe, as the while-loop and the x-reset logic above makes + // sure we do not exceed the bounds of the image + currentPixel++; + }//end of while + + // Create a polydata to store everything in + vtkSmartPointer polyData = vtkSmartPointer::New(); + // Add the points to the dataset + polyData->SetPoints(points); + // Add the lines to the dataset + polyData->SetLines(lines); + return polyData; } void mitk::ImageVtkMapper2D::TransformActor(mitk::BaseRenderer* renderer) { - LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); - //get the transformation matrix of the reslicer in order to render the slice as axial, coronal or saggital - vtkSmartPointer trans = vtkSmartPointer::New(); - vtkSmartPointer matrix = localStorage->m_Reslicer->GetResliceAxes(); - trans->SetMatrix(matrix); - //transform the plane/contour (the actual actor) to the corresponding view (axial, coronal or saggital) - localStorage->m_Actor->SetUserTransform(trans); - //transform the origin to center based coordinates, because MITK is center based. - localStorage->m_Actor->SetPosition( -0.5*localStorage->m_mmPerPixel[0], -0.5*localStorage->m_mmPerPixel[1], 0.0); - - if ( localStorage->m_Actors->GetNumberOfPaths() > 1 ) - { - vtkActor* secondaryActor = dynamic_cast( localStorage->m_Actors->GetParts()->GetItemAsObject(0) ); - secondaryActor->SetUserTransform(trans); - secondaryActor->SetPosition( -0.5*localStorage->m_mmPerPixel[0], -0.5*localStorage->m_mmPerPixel[1], 0.0); - } + LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); + //get the transformation matrix of the reslicer in order to render the slice as axial, coronal or saggital + vtkSmartPointer trans = vtkSmartPointer::New(); + vtkSmartPointer matrix = localStorage->m_Reslicer->GetResliceAxes(); + trans->SetMatrix(matrix); + //transform the plane/contour (the actual actor) to the corresponding view (axial, coronal or saggital) + localStorage->m_Actor->SetUserTransform(trans); + //transform the origin to center based coordinates, because MITK is center based. + localStorage->m_Actor->SetPosition( -0.5*localStorage->m_mmPerPixel[0], -0.5*localStorage->m_mmPerPixel[1], 0.0); + + if ( localStorage->m_Actors->GetNumberOfPaths() > 1 ) + { + vtkActor* secondaryActor = dynamic_cast( localStorage->m_Actors->GetParts()->GetItemAsObject(0) ); + secondaryActor->SetUserTransform(trans); + secondaryActor->SetPosition( -0.5*localStorage->m_mmPerPixel[0], -0.5*localStorage->m_mmPerPixel[1], 0.0); + } } bool mitk::ImageVtkMapper2D::RenderingGeometryIntersectsImage( const Geometry2D* renderingGeometry, SlicedGeometry3D* imageGeometry ) { - // if either one of the two geometries is NULL we return true - // for safety reasons - if ( renderingGeometry == NULL || imageGeometry == NULL ) - return true; - - // get the distance for the first cornerpoint - ScalarType initialDistance = renderingGeometry->SignedDistance( imageGeometry->GetCornerPoint( 0 ) ); - for( int i=1; i<8; i++ ) + // 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 ) { - 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; - } + // we have an intersection and return true + return true; } + } - // all distances have the same sign, no intersection and we return false - return false; + // 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_Actors = vtkSmartPointer::New(); - m_Reslicer = mitk::ExtractSliceFilter::New(); - m_TSFilter = vtkSmartPointer::New(); - m_OutlinePolyData = vtkSmartPointer::New(); - m_ReslicedImage = vtkSmartPointer::New(); - m_EmptyPolyData = vtkSmartPointer::New(); - - //the following actions are always the same and thus can be performed - //in the constructor for each image (i.e. the image-corresponding local storage) - m_TSFilter->ReleaseDataFlagOn(); - - //built a default lookuptable - m_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(); - //map all black values to transparent - m_LookupTable->SetTableValue(0, 0.0, 0.0, 0.0, 0.0); - - //do not repeat the texture (the image) - m_Texture->RepeatOff(); - - //set the mapper for the actor - m_Actor->SetMapper( m_Mapper ); - - vtkSmartPointer outlineShadowActor = vtkSmartPointer::New(); - outlineShadowActor->SetMapper( m_Mapper ); - - m_Actors->AddPart( outlineShadowActor ); - m_Actors->AddPart( m_Actor ); - - //filter for RGB(A) images - m_LevelWindowToRGBFilterObject = new vtkMitkApplyLevelWindowToRGBFilter(); + //Do as much actions as possible in here to avoid double executions. + m_Plane = vtkSmartPointer::New(); + m_Texture = vtkSmartPointer::New().GetPointer(); + m_DefaultLookupTable = vtkSmartPointer::New(); + m_BinaryLookupTable = vtkSmartPointer::New(); + m_Mapper = vtkSmartPointer::New(); + m_Actor = vtkSmartPointer::New(); + m_Actors = vtkSmartPointer::New(); + m_Reslicer = mitk::ExtractSliceFilter::New(); + m_TSFilter = vtkSmartPointer::New(); + m_OutlinePolyData = vtkSmartPointer::New(); + m_ReslicedImage = vtkSmartPointer::New(); + m_EmptyPolyData = vtkSmartPointer::New(); + + //the following actions are always the same and thus can be performed + //in the constructor for each image (i.e. the image-corresponding local storage) + m_TSFilter->ReleaseDataFlagOn(); + + //built a default lookuptable + m_DefaultLookupTable->SetRampToLinear(); + m_DefaultLookupTable->SetSaturationRange( 0.0, 0.0 ); + m_DefaultLookupTable->SetHueRange( 0.0, 0.0 ); + m_DefaultLookupTable->SetValueRange( 0.0, 1.0 ); + m_DefaultLookupTable->Build(); + + m_BinaryLookupTable->SetRampToLinear(); + m_BinaryLookupTable->SetSaturationRange( 0.0, 0.0 ); + m_BinaryLookupTable->SetHueRange( 0.0, 0.0 ); + m_BinaryLookupTable->SetValueRange( 0.0, 1.0 ); + m_BinaryLookupTable->SetRange(0.0, 1.0); + // make first value transparent + { + double rgba[4]; + m_BinaryLookupTable->GetTableValue(0, rgba); + m_BinaryLookupTable->SetTableValue(0, rgba[0], rgba[1], rgba[2], 0); // background to 0 + } + m_BinaryLookupTable->Build(); + + //do not repeat the texture (the image) + m_Texture->RepeatOff(); + + //set the mapper for the actor + m_Actor->SetMapper( m_Mapper ); + + vtkSmartPointer outlineShadowActor = vtkSmartPointer::New(); + outlineShadowActor->SetMapper( m_Mapper ); + + m_Actors->AddPart( outlineShadowActor ); + m_Actors->AddPart( m_Actor ); + + //level window filter + m_LevelWindowFilter = new vtkMitkLevelWindowFilter(); } diff --git a/Core/Code/Rendering/mitkImageVtkMapper2D.h b/Core/Code/Rendering/mitkImageVtkMapper2D.h index 224e5554ff..d214fa45ec 100644 --- a/Core/Code/Rendering/mitkImageVtkMapper2D.h +++ b/Core/Code/Rendering/mitkImageVtkMapper2D.h @@ -1,294 +1,295 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKIMAGEVTKMAPPER2D_H_HEADER_INCLUDED_C10E906E #define MITKIMAGEVTKMAPPER2D_H_HEADER_INCLUDED_C10E906E //MITK #include //MITK Rendering #include "mitkBaseRenderer.h" #include "mitkVtkMapper2D.h" #include "mitkExtractSliceFilter.h" //VTK #include #include class vtkActor; class vtkPolyDataMapper; class vtkPlaneSource; class vtkImageData; class vtkLookupTable; class vtkImageReslice; class vtkImageChangeInformation; class vtkPoints; class vtkMitkThickSlicesFilter; class vtkPolyData; class vtkMitkApplyLevelWindowToRGBFilter; +class vtkMitkLevelWindowFilter; namespace mitk { - /** \brief Mapper to resample and display 2D slices of a 3D image. +/** \brief Mapper to resample and display 2D slices of a 3D image. * * The following image gives a brief overview of the mapping and the involved parts. * * \image html imageVtkMapper2Darchitecture.png * * First, the image is resliced by means of vtkImageReslice. The volume image * serves as input to the mapper in addition to spatial placement of the slice and a few other * properties such as thick slices. This code was already present in the old version * (mitkImageMapperGL2D). * - * Next, the obtained slice (m_ReslicedImage) is used to create a texture + * Next, the obtained slice (m_ReslicedImage) is put into a vtkMitkLevelWindowFilter + * and the scalar levelwindow, opacity levelwindow and optional clipping to + * local image bounds are applied + * + * Next, the output of the vtkMitkLevelWindowFilter is used to create a texture * (m_Texture) and a plane onto which the texture is rendered (m_Plane). For * mapping purposes, a vtkPolyDataMapper (m_Mapper) is utilized. Orthographic * projection is applied to create the effect of a 2D image. The mapper and the * texture are assigned to the actor (m_Actor) which is passed to the VTK rendering * pipeline via the method GetVtkProp(). * * In order to transform the textured plane to the correct position in space, the * same transformation as used for reslicing is applied to both the camera and the * vtkActor. All important steps are explained in more detail below. The resulting * 2D image (by reslicing the underlying 3D input image appropriately) can either * be directly rendered in a 2D view or just be calculated to be used later by another * rendering entity, e.g. in texture mapping in a 3D view. * * Properties that can be set for images and influence the imageMapper2D are: * * - \b "opacity": (FloatProperty) Opacity of the image * - \b "color": (ColorProperty) Color of the image * - \b "LookupTable": (mitkLookupTableProperty) If this property is set, * the default lookuptable will be ignored and the "LookupTable" value * will be used instead. * - \b "Image Rendering.Transfer Function": (mitkTransferFunctionProperty) If this * property is set, a color transferfunction will be used to color the image. * \warning This property will not have any effect if, the "LookupTable" property * is set. * - \b "binary": (BoolProperty) is the image a binary image or not * - \b "outline binary": (BoolProperty) show outline of the image or not * - \b "texture interpolation": (BoolProperty) texture interpolation of the image * - \b "reslice interpolation": (VtkResliceInterpolationProperty) reslice interpolation of the image * - \b "in plane resample extent by geometry": (BoolProperty) Do it or not * - \b "bounding box": (BoolProperty) Is the Bounding Box of the image shown or not * - \b "layer": (IntProperty) Layer of the image * - \b "volume annotation color": (ColorProperty) color of the volume annotation, TODO has to be reimplemented * - \b "volume annotation unit": (StringProperty) annotation unit as string (does not implicit convert the unit!) unit is ml or cm3, TODO has to be reimplemented * The default properties are: * - \b "opacity", mitk::FloatProperty::New(0.3f), renderer, overwrite ) * - \b "color", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ) * - \b "binary", mitk::BoolProperty::New( true ), renderer, overwrite ) * - \b "outline binary", mitk::BoolProperty::New( false ), renderer, overwrite ) * - \b "texture interpolation", mitk::BoolProperty::New( mitk::DataNodeFactory::m_TextureInterpolationActive ) ) * - \b "reslice interpolation", mitk::VtkResliceInterpolationProperty::New() ) * - \b "in plane resample extent by geometry", mitk::BoolProperty::New( false ) ) * - \b "bounding box", mitk::BoolProperty::New( false ) ) * - \b "layer", mitk::IntProperty::New(10), renderer, overwrite) - * - \b "Image Rendering.Transfer Function": Undefined. Must be set by the user. + * - \b "Image Rendering.Transfer Function": Default color transfer function for CTs * - \b "LookupTable": Undefined. Must be set by the user. * If the modality-property is set for an image, the mapper uses modality-specific default properties, * e.g. color maps, if they are defined. * \ingroup Mapper */ - class MITK_CORE_EXPORT ImageVtkMapper2D : public VtkMapper2D - { +class MITK_CORE_EXPORT ImageVtkMapper2D : public VtkMapper2D +{ - public: - /** Standard class typedefs. */ - mitkClassMacro( ImageVtkMapper2D,VtkMapper2D ); +public: + /** Standard class typedefs. */ + mitkClassMacro( ImageVtkMapper2D,VtkMapper2D ); - /** Method for creation through the object factory. */ - itkNewMacro(Self); + /** Method for creation through the object factory. */ + itkNewMacro(Self); - /** \brief Get the Image to map */ - const mitk::Image *GetInput(void); + /** \brief Get the Image to map */ + const mitk::Image *GetInput(void); - /** \brief Checks whether this mapper needs to update itself and generate + /** \brief Checks whether this mapper needs to update itself and generate * data. */ - virtual void Update(mitk::BaseRenderer * renderer); + virtual void Update(mitk::BaseRenderer * renderer); - //### methods of MITK-VTK rendering pipeline - virtual vtkProp* GetVtkProp(mitk::BaseRenderer* renderer); + //### methods of MITK-VTK rendering pipeline + virtual vtkProp* GetVtkProp(mitk::BaseRenderer* renderer); - virtual void MitkRenderOverlay(BaseRenderer* renderer); - virtual void MitkRenderOpaqueGeometry(BaseRenderer* renderer); - virtual void MitkRenderTranslucentGeometry(BaseRenderer* renderer); - virtual void MitkRenderVolumetricGeometry(BaseRenderer* renderer); - //### end of methods of MITK-VTK rendering pipeline + virtual void MitkRenderOverlay(BaseRenderer* renderer); + virtual void MitkRenderOpaqueGeometry(BaseRenderer* renderer); + virtual void MitkRenderTranslucentGeometry(BaseRenderer* renderer); + virtual void MitkRenderVolumetricGeometry(BaseRenderer* renderer); + //### end of methods of MITK-VTK rendering pipeline - /** \brief Internal class holding the mapper, actor, etc. for each of the 3 2D render windows */ - /** + /** \brief Internal class holding the mapper, actor, etc. for each of the 3 2D render windows */ + /** * To render transveral, coronal, and sagittal, the mapper is called three times. * For performance reasons, the corresponding data for each view is saved in the * internal helper class LocalStorage. This allows rendering n views with just * 1 mitkMapper using n vtkMapper. * */ - class MITK_CORE_EXPORT LocalStorage : public mitk::Mapper::BaseLocalStorage - { - public: - /** \brief Actor of a 2D render window. */ - vtkSmartPointer m_Actor; - - vtkSmartPointer m_Actors; - /** \brief Mapper of a 2D render window. */ - vtkSmartPointer m_Mapper; - /** \brief Current slice of a 2D render window.*/ - vtkSmartPointer m_ReslicedImage; - /** \brief Empty vtkPolyData that is set when rendering geometry does not + class MITK_CORE_EXPORT LocalStorage : public mitk::Mapper::BaseLocalStorage + { + public: + /** \brief Actor of a 2D render window. */ + vtkSmartPointer m_Actor; + + vtkSmartPointer m_Actors; + /** \brief Mapper of a 2D render window. */ + vtkSmartPointer m_Mapper; + /** \brief Current slice of a 2D render window.*/ + vtkSmartPointer m_ReslicedImage; + /** \brief Empty vtkPolyData that is set when rendering geometry does not * intersect the image geometry. * \warning This member variable is set to NULL, * if no image geometry is inside the plane geometry * of the respective render window. Any user of this * slice has to check whether it is set to NULL! */ vtkSmartPointer m_EmptyPolyData; /** \brief Plane on which the slice is rendered as texture. */ vtkSmartPointer m_Plane; /** \brief The texture which is used to render the current slice. */ vtkSmartPointer m_Texture; /** \brief The lookuptable for colors and level window */ - vtkSmartPointer m_LookupTable; + vtkSmartPointer m_DefaultLookupTable; + vtkSmartPointer m_BinaryLookupTable; /** \brief The actual reslicer (one per renderer) */ mitk::ExtractSliceFilter::Pointer m_Reslicer; /** \brief Filter for thick slices */ vtkSmartPointer m_TSFilter; - /** \brief PolyData object containg all lines/points needed for outlining the contour. + /** \brief PolyData object containg all lines/points needed for outlining the contour. This container is used to save a computed contour for the next rendering execution. For instance, if you zoom or pann, there is no need to recompute the contour. */ - vtkSmartPointer m_OutlinePolyData; + vtkSmartPointer m_OutlinePolyData; - /** \brief Timestamp of last update of stored data. */ - itk::TimeStamp m_LastUpdateTime; + /** \brief Timestamp of last update of stored data. */ + itk::TimeStamp m_LastUpdateTime; - /** \brief mmPerPixel relation between pixel and mm. (World spacing).*/ - mitk::ScalarType* m_mmPerPixel; + /** \brief mmPerPixel relation between pixel and mm. (World spacing).*/ + mitk::ScalarType* m_mmPerPixel; - /** \brief This filter is used to apply the level window to RBG(A) images. */ - vtkMitkApplyLevelWindowToRGBFilter* m_LevelWindowToRGBFilterObject; + /** \brief This filter is used to apply the level window to Grayvalue and RBG(A) images. */ + vtkMitkLevelWindowFilter* m_LevelWindowFilter; - /** \brief Default constructor of the local storage. */ - LocalStorage(); - /** \brief Default deconstructor of the local storage. */ - ~LocalStorage() - { - } - }; + /** \brief Default constructor of the local storage. */ + LocalStorage(); + /** \brief Default deconstructor of the local storage. */ + ~LocalStorage() + { + } + }; - /** \brief The LocalStorageHandler holds all (three) LocalStorages for the three 2D render windows. */ - mitk::Mapper::LocalStorageHandler m_LSH; + /** \brief The LocalStorageHandler holds all (three) LocalStorages for the three 2D render windows. */ + mitk::Mapper::LocalStorageHandler m_LSH; - /** \brief Get the LocalStorage corresponding to the current renderer. */ - LocalStorage* GetLocalStorage(mitk::BaseRenderer* renderer); + /** \brief Get the LocalStorage corresponding to the current renderer. */ + LocalStorage* GetLocalStorage(mitk::BaseRenderer* renderer); - /** \brief Set the default properties for general image rendering. */ - static void SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer = NULL, bool overwrite = false); + /** \brief Set the default properties for general image rendering. */ + static void SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer = NULL, bool overwrite = false); - protected: - /** \brief Transforms the actor to the actual position in 3D. +protected: + /** \brief Transforms the actor to the actual position in 3D. * \param renderer The current renderer corresponding to the render window. */ - void TransformActor(mitk::BaseRenderer* renderer); + void TransformActor(mitk::BaseRenderer* renderer); - /** \brief Generates a plane according to the size of the resliced image in milimeters. + /** \brief Generates a plane according to the size of the resliced image in milimeters. * * \image html texturedPlane.png * * In VTK a vtkPlaneSource is defined through three points. The origin and two * points defining the axes of the plane (see VTK documentation). The origin is * set to (xMin; yMin; Z), where xMin and yMin are the minimal bounds of the * resliced image in space. Z is relevant for blending and the layer property. * The center of the plane (C) is also the center of the view plane (cf. the image above). * * \note For the standard MITK view with three 2D render windows showing three * different slices, three such planes are generated. All these planes are generated * in the XY-plane (even if they depict a YZ-slice of the volume). * */ - void GeneratePlane(mitk::BaseRenderer* renderer, vtkFloatingPointType planeBounds[6]); + void GeneratePlane(mitk::BaseRenderer* renderer, vtkFloatingPointType planeBounds[6]); - /** \brief Generates a vtkPolyData object containing the outline of a given binary slice. + /** \brief Generates a vtkPolyData object containing the outline of a given binary slice. \param renderer: Pointer to the renderer containing the needed information \note This code is based on code from the iil library. */ - vtkSmartPointer CreateOutlinePolyData(mitk::BaseRenderer* renderer); + vtkSmartPointer CreateOutlinePolyData(mitk::BaseRenderer* renderer); - /** Default constructor */ - ImageVtkMapper2D(); - /** Default deconstructor */ - virtual ~ImageVtkMapper2D(); + /** Default constructor */ + ImageVtkMapper2D(); + /** Default deconstructor */ + virtual ~ImageVtkMapper2D(); - /** \brief Does the actual resampling, without rendering the image yet. + /** \brief Does the actual resampling, without rendering the image yet. * All the data is generated inside this method. The vtkProp (or Actor) * is filled with content (i.e. the resliced image). * * After generation, a 4x4 transformation matrix(t) of the current slice is obtained * from the vtkResliceImage object via GetReslicesAxis(). This matrix is * applied to each textured plane (actor->SetUserTransform(t)) to transform everything * to the actual 3D position (cf. the following image). * * \image html cameraPositioning3D.png * */ - virtual void GenerateDataForRenderer(mitk::BaseRenderer *renderer); - + virtual void GenerateDataForRenderer(mitk::BaseRenderer *renderer); - /** \brief This method uses the vtkCamera clipping range and the layer property + /** \brief This method uses the vtkCamera clipping range and the layer property * to calcualte the depth of the object (e.g. image or contour). The depth is used * to keep the correct order for the final VTK rendering.*/ - float CalculateLayerDepth(mitk::BaseRenderer* renderer); - - /** \brief This method applies a level window on RBG(A) images. - * It should only be called for internally for RGB(A) images. */ - void ApplyRBGALevelWindow( mitk::BaseRenderer* renderer ); + float CalculateLayerDepth(mitk::BaseRenderer* renderer); /** \brief This method applies (or modifies) the lookuptable for all types of images. */ - void ApplyLookuptable( mitk::BaseRenderer* renderer ); + void ApplyLookuptable( mitk::BaseRenderer* renderer, vtkFloatingPointType* bounds ); - /** \brief This method applies a color transfer function, if no LookuptableProperty is set. + /** \brief This method applies a color transfer function, if no LookuptableProperty is set. Internally, a vtkColorTransferFunction is used. This is usefull for coloring continous images (e.g. float) */ - void ApplyColorTransferFunction(mitk::BaseRenderer* renderer); + void ApplyColorTransferFunction(mitk::BaseRenderer* renderer); - /** \brief Set the color of the image/polydata */ - void ApplyColor( mitk::BaseRenderer* renderer ); + /** \brief Set the color of the image/polydata */ + void ApplyColor( mitk::BaseRenderer* renderer ); - /** \brief Set the opacity of the actor. */ - void ApplyOpacity( mitk::BaseRenderer* renderer ); + /** \brief Set the opacity of the actor. */ + void ApplyOpacity( mitk::BaseRenderer* renderer ); - /** + /** * \brief Calculates whether the given rendering geometry intersects the * given SlicedGeometry3D. * * This method checks if the given Geometry2D intersects the given * SlicedGeometry3D. It calculates the distance of the Geometry2D to all * 8 cornerpoints of the SlicedGeometry3D. If all distances have the same * sign (all positive or all negative) there is no intersection. * If the distances have different sign, there is an intersection. **/ - bool RenderingGeometryIntersectsImage( const Geometry2D* renderingGeometry, SlicedGeometry3D* imageGeometry ); - }; + bool RenderingGeometryIntersectsImage( const Geometry2D* renderingGeometry, SlicedGeometry3D* imageGeometry ); +}; } // namespace mitk #endif /* MITKIMAGEVTKMAPPER2D_H_HEADER_INCLUDED_C10E906E */ diff --git a/Core/Code/Rendering/mitkVolumeDataVtkMapper3D.cpp b/Core/Code/Rendering/mitkVolumeDataVtkMapper3D.cpp index 9dbc037819..b21d338bf5 100644 --- a/Core/Code/Rendering/mitkVolumeDataVtkMapper3D.cpp +++ b/Core/Code/Rendering/mitkVolumeDataVtkMapper3D.cpp @@ -1,706 +1,707 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; 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 ); } //This mapper used to set a default lut "LookupTable" for images. However, this will //overwrite the default lut of the 2D image mapper. Thus, this property here is renamed. + /* if((overwrite) || (node->GetProperty("Volume.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( "Volume.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().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/Rendering/vtkMitkApplyLevelWindowToRGBFilter.cpp b/Core/Code/Rendering/vtkMitkApplyLevelWindowToRGBFilter.cpp deleted file mode 100644 index 3658446ce7..0000000000 --- a/Core/Code/Rendering/vtkMitkApplyLevelWindowToRGBFilter.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#include "vtkMitkApplyLevelWindowToRGBFilter.h" -#include -#include -#include - -//used for acos etc. -#include - -//used for PI -#include - -static const double PI = itk::Math::pi; - -vtkMitkApplyLevelWindowToRGBFilter::vtkMitkApplyLevelWindowToRGBFilter():m_MinOqacity(0.0),m_MaxOpacity(255.0) -{ -} - -vtkMitkApplyLevelWindowToRGBFilter::~vtkMitkApplyLevelWindowToRGBFilter() -{ -} - -void vtkMitkApplyLevelWindowToRGBFilter::SetLookupTable(vtkScalarsToColors *lookupTable) -{ - m_LookupTable = lookupTable; -} - -vtkScalarsToColors* vtkMitkApplyLevelWindowToRGBFilter::GetLookupTable() -{ - return m_LookupTable; -} - -//This code was copied from the iil. The template works only for float and double. -//Internal method which should never be used anywhere else and should not be in th header. -// Convert color pixels from (R,G,B) to (H,S,I). -// Reference: "Digital Image Processing, 2nd. edition", R. Gonzalez and R. Woods. Prentice Hall, 2002. -template -void RGBtoHSI(T* RGB, T* HSI) -{ - T R = RGB[0], - G = RGB[1], - B = RGB[2], - nR = (R<0?0:(R>255?255:R))/255, - nG = (G<0?0:(G>255?255:G))/255, - nB = (B<0?0:(B>255?255:B))/255, - m = nR0) H = (nB<=nG)?theta:360-theta; - if (sum>0) S = 1 - 3/sum*m; - I = sum/3; - HSI[0] = (T)H; - HSI[1] = (T)S; - HSI[2] = (T)I; -} - -//This code was copied from the iil. The template works only for float and double. -//Internal method which should never be used anywhere else and should not be in th header. -// Convert color pixels from (H,S,I) to (R,G,B). -template -void HSItoRGB(T* HSI, T* RGB) -{ - T H = (T)HSI[0], - S = (T)HSI[1], - I = (T)HSI[2], - a = I*(1-S), - R = 0, G = 0, B = 0; - if (H<120) { - B = a; - R = (T)(I*(1+S*std::cos(H*PI/180)/std::cos((60-H)*PI/180))); - G = 3*I-(R+B); - } else if (H<240) { - H-=120; - R = a; - G = (T)(I*(1+S*std::cos(H*PI/180)/std::cos((60-H)*PI/180))); - B = 3*I-(R+G); - } else { - H-=240; - G = a; - B = (T)(I*(1+S*std::cos(H*PI/180)/std::cos((60-H)*PI/180))); - R = 3*I-(G+B); - } - R*=255; G*=255; B*=255; - RGB[0] = (T)(R<0?0:(R>255?255:R)); - RGB[1] = (T)(G<0?0:(G>255?255:G)); - RGB[2] = (T)(B<0?0:(B>255?255:B)); -} - -//Internal method which should never be used anywhere else and should not be in th header. -//---------------------------------------------------------------------------- -// This templated function executes the filter for any type of data. -template - void vtkCalculateIntensityFromLookupTable(vtkMitkApplyLevelWindowToRGBFilter *self, - vtkImageData *inData, - vtkImageData *outData, - int outExt[6], T *) -{ - vtkImageIterator inputIt(inData, outExt); - vtkImageIterator outputIt(outData, outExt); - vtkLookupTable* lookupTable; - int maxC; - int indexComponents = 3; //RGB case - double imgRange[2]; - double tableRange[2]; - - lookupTable = dynamic_cast(self->GetLookupTable()); - - lookupTable->GetTableRange(tableRange); - inData->GetScalarRange(imgRange); - - //parameters for RGB level window - double scale = (tableRange[1] -tableRange[0] > 0 ? 255.0 / (tableRange[1] - tableRange[0]) : 0.0); - double bias = tableRange[0] * scale; - - // find the region to loop over - maxC = inData->GetNumberOfScalarComponents(); - - //parameters for opaque level window - double scaleOpac = (self->GetMaxOpacity() -self->GetMinOpacity() > 0 ? 255.0 / (self->GetMaxOpacity() - self->GetMinOpacity()) : 0.0); - double biasOpac = self->GetMinOpacity() * scaleOpac; - - // Loop through ouput pixels - while (!outputIt.IsAtEnd()) - { - T* inputSI = inputIt.BeginSpan(); - T* outputSI = outputIt.BeginSpan(); - T* outputSIEnd = outputIt.EndSpan(); - while (outputSI != outputSIEnd) - { - double rgb[3], alpha, hsi[3]; - - // level/window mechanism for intensity in HSI space - rgb[0] = static_cast(*inputSI); inputSI++; - rgb[1] = static_cast(*inputSI); inputSI++; - rgb[2] = static_cast(*inputSI); inputSI++; - - RGBtoHSI(rgb,hsi); - hsi[2] = hsi[2] * 255.0 * scale - bias; - hsi[2] = (hsi[2] > 255.0 ? 255 : (hsi[2] < 0.0 ? 0 : hsi[2])); - hsi[2] /= 255.0; - HSItoRGB(hsi,rgb); - - *outputSI = static_cast(rgb[0]); outputSI++; - *outputSI = static_cast(rgb[1]); outputSI++; - *outputSI = static_cast(rgb[2]); outputSI++; - - //RGBA case - if(maxC >= 4) - { - indexComponents = 4; //now its the RGBA case - // level/window mechanism for opacity - alpha = static_cast(*inputSI); inputSI++; - alpha = alpha * scaleOpac - biasOpac; - if(alpha > 255.0) - { - alpha = 255.0; - } - else if(alpha < 0.0) - { - alpha = 0.0; - } - *outputSI = static_cast(alpha); outputSI++; - } - - for (int i = indexComponents; i < maxC; i++) - { - *outputSI++ = *inputSI++; - } - } - inputIt.NextSpan(); - outputIt.NextSpan(); - } -} - -void vtkMitkApplyLevelWindowToRGBFilter::ExecuteInformation() -{ - vtkImageData *input = this->GetInput(); - vtkImageData *output = this->GetOutput(); - - if (!input) - { - vtkErrorMacro(<< "Input not set."); - return; - } - output->CopyTypeSpecificInformation( input ); - - int extent[6]; - input->GetWholeExtent(extent); - output->SetExtent(extent); - output->SetWholeExtent(extent); - output->SetUpdateExtent(extent); - output->AllocateScalars(); - - switch (input->GetScalarType()) - { - vtkTemplateMacro( - vtkCalculateIntensityFromLookupTable( this, - input, - output, extent, - static_cast(0))); - default: - vtkErrorMacro(<< "Execute: Unknown ScalarType"); - return; - } -} - -//Method to run the filter in different threads. -void vtkMitkApplyLevelWindowToRGBFilter::ThreadedExecute(vtkImageData *inData, - vtkImageData *outData, - int extent[6], int /*id*/) -{ - switch (inData->GetScalarType()) - { - vtkTemplateMacro( - vtkCalculateIntensityFromLookupTable( this, - inData, - outData, - extent, - static_cast(0))); - default: - vtkErrorMacro(<< "Execute: Unknown ScalarType"); - return; - } -} - -void vtkMitkApplyLevelWindowToRGBFilter::ExecuteInformation( - vtkImageData *vtkNotUsed(inData), vtkImageData *vtkNotUsed(outData)) -{ -} - -void vtkMitkApplyLevelWindowToRGBFilter::SetMinOpacity(double minOpacity) -{ - m_MinOqacity = minOpacity; -} - -inline double vtkMitkApplyLevelWindowToRGBFilter::GetMinOpacity() const -{ - return m_MinOqacity; -} - -void vtkMitkApplyLevelWindowToRGBFilter::SetMaxOpacity(double maxOpacity) -{ - m_MaxOpacity = maxOpacity; -} - -inline double vtkMitkApplyLevelWindowToRGBFilter::GetMaxOpacity() const -{ - return m_MaxOpacity; -} diff --git a/Core/Code/Rendering/vtkMitkLevelWindowFilter.cpp b/Core/Code/Rendering/vtkMitkLevelWindowFilter.cpp new file mode 100644 index 0000000000..f63654f949 --- /dev/null +++ b/Core/Code/Rendering/vtkMitkLevelWindowFilter.cpp @@ -0,0 +1,493 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "vtkMitkLevelWindowFilter.h" +#include +#include +#include + +//used for acos etc. +#include + +//used for PI +#include + +#include + +static const double PI = itk::Math::pi; + +vtkMitkLevelWindowFilter::vtkMitkLevelWindowFilter():m_MinOpacity(0.0),m_MaxOpacity(255.0) +{ + //MITK_INFO << "mitk level/window filter uses " << GetNumberOfThreads() << " thread(s)"; +} + +vtkMitkLevelWindowFilter::~vtkMitkLevelWindowFilter() +{ +} + +unsigned long int vtkMitkLevelWindowFilter::GetMTime() +{ + unsigned long mTime=this->vtkObject::GetMTime(); + unsigned long time; + + if ( this->m_LookupTable != NULL ) + { + time = this->m_LookupTable->GetMTime(); + mTime = ( time > mTime ? time : mTime ); + } + + return mTime; +} + +void vtkMitkLevelWindowFilter::SetLookupTable(vtkScalarsToColors *lookupTable) +{ + if (m_LookupTable != lookupTable) + { + m_LookupTable = lookupTable; + this->Modified(); + } +} + +vtkScalarsToColors* vtkMitkLevelWindowFilter::GetLookupTable() +{ + return m_LookupTable; +} + +//This code was copied from the iil. The template works only for float and double. +//Internal method which should never be used anywhere else and should not be in th header. +// Convert color pixels from (R,G,B) to (H,S,I). +// Reference: "Digital Image Processing, 2nd. edition", R. Gonzalez and R. Woods. Prentice Hall, 2002. +template +void RGBtoHSI(T* RGB, T* HSI) +{ + T R = RGB[0], + G = RGB[1], + B = RGB[2], + nR = (R<0?0:(R>255?255:R))/255, + nG = (G<0?0:(G>255?255:G))/255, + nB = (B<0?0:(B>255?255:B))/255, + m = nR0) H = (nB<=nG)?theta:360-theta; + if (sum>0) S = 1 - 3/sum*m; + I = sum/3; + HSI[0] = (T)H; + HSI[1] = (T)S; + HSI[2] = (T)I; +} + +//This code was copied from the iil. The template works only for float and double. +//Internal method which should never be used anywhere else and should not be in th header. +// Convert color pixels from (H,S,I) to (R,G,B). +template +void HSItoRGB(T* HSI, T* RGB) +{ + T H = (T)HSI[0], + S = (T)HSI[1], + I = (T)HSI[2], + a = I*(1-S), + R = 0, G = 0, B = 0; + if (H<120) { + B = a; + R = (T)(I*(1+S*std::cos(H*PI/180)/std::cos((60-H)*PI/180))); + G = 3*I-(R+B); + } else if (H<240) { + H-=120; + R = a; + G = (T)(I*(1+S*std::cos(H*PI/180)/std::cos((60-H)*PI/180))); + B = 3*I-(R+G); + } else { + H-=240; + G = a; + B = (T)(I*(1+S*std::cos(H*PI/180)/std::cos((60-H)*PI/180))); + R = 3*I-(G+B); + } + R*=255; G*=255; B*=255; + RGB[0] = (T)(R<0?0:(R>255?255:R)); + RGB[1] = (T)(G<0?0:(G>255?255:G)); + RGB[2] = (T)(B<0?0:(B>255?255:B)); +} + + +//Internal method which should never be used anywhere else and should not be in th header. +//---------------------------------------------------------------------------- +// This templated function executes the filter for any type of data. +template +void vtkApplyLookupTableOnRGBA(vtkMitkLevelWindowFilter* self, + vtkImageData* inData, + vtkImageData* outData, + int outExt[6], + vtkFloatingPointType* clippingBounds, + T*) +{ + vtkImageIterator inputIt(inData, outExt); + vtkImageIterator outputIt(outData, outExt); + vtkLookupTable* lookupTable; + const int maxC = inData->GetNumberOfScalarComponents(); + + double tableRange[2]; + + lookupTable = dynamic_cast(self->GetLookupTable()); + + lookupTable->GetTableRange(tableRange); + + //parameters for RGB level window + double scale = (tableRange[1] -tableRange[0] > 0 ? 255.0 / (tableRange[1] - tableRange[0]) : 0.0); + double bias = tableRange[0] * scale; + + //parameters for opaque level window + double scaleOpac = (self->GetMaxOpacity() -self->GetMinOpacity() > 0 ? 255.0 / (self->GetMaxOpacity() - self->GetMinOpacity()) : 0.0); + double biasOpac = self->GetMinOpacity() * scaleOpac; + + int y = outExt[2]; + + // Loop through ouput pixels + while (!outputIt.IsAtEnd()) + { + T* inputSI = inputIt.BeginSpan(); + T* outputSI = outputIt.BeginSpan(); + T* outputSIEnd = outputIt.EndSpan(); + + if( y >= clippingBounds[2] && y < clippingBounds[3] ) + { + int x = outExt[0]; + + while (outputSI != outputSIEnd) + { + if ( x >= clippingBounds[0] && x < clippingBounds[1]) + { + double rgb[3], alpha, hsi[3]; + + // level/window mechanism for intensity in HSI space + rgb[0] = static_cast(*inputSI); inputSI++; + rgb[1] = static_cast(*inputSI); inputSI++; + rgb[2] = static_cast(*inputSI); inputSI++; + + RGBtoHSI(rgb,hsi); + hsi[2] = hsi[2] * 255.0 * scale - bias; + hsi[2] = (hsi[2] > 255.0 ? 255 : (hsi[2] < 0.0 ? 0 : hsi[2])); + hsi[2] /= 255.0; + HSItoRGB(hsi,rgb); + + *outputSI = static_cast(rgb[0]); outputSI++; + *outputSI = static_cast(rgb[1]); outputSI++; + *outputSI = static_cast(rgb[2]); outputSI++; + + unsigned char finalAlpha = 255; + + //RGBA case + if(maxC >= 4) + { + // level/window mechanism for opacity + alpha = static_cast(*inputSI); inputSI++; + alpha = alpha * scaleOpac - biasOpac; + if(alpha > 255.0) + { + alpha = 255.0; + } + else if(alpha < 0.0) + { + alpha = 0.0; + } + finalAlpha = static_cast(alpha); + + for( int c = 4; c < maxC; c++ ) + inputSI++; + + } + + *outputSI = static_cast(finalAlpha); outputSI++; + } + else + { + inputSI+=maxC; + *outputSI = 0; outputSI++; + *outputSI = 0; outputSI++; + *outputSI = 0; outputSI++; + *outputSI = 0; outputSI++; + } + + x++; + } + } + else + { + while (outputSI != outputSIEnd) + { + *outputSI = 0; outputSI++; + *outputSI = 0; outputSI++; + *outputSI = 0; outputSI++; + *outputSI = 0; outputSI++; + } + } + inputIt.NextSpan(); + outputIt.NextSpan(); + y++; + } +} + +//Internal method which should never be used anywhere else and should not be in th header. +//---------------------------------------------------------------------------- +// This templated function executes the filter for any type of data. +template +void vtkApplyLookupTableOnScalarsFast(vtkMitkLevelWindowFilter *self, + vtkImageData *inData, + vtkImageData *outData, + int outExt[6], + T *) +{ + vtkImageIterator inputIt(inData, outExt); + vtkImageIterator outputIt(outData, outExt); + + double tableRange[2]; + + // access vtkLookupTable + vtkLookupTable* lookupTable = dynamic_cast(self->GetLookupTable()); + lookupTable->GetTableRange(tableRange); + + // access elements of the vtkLookupTable + int * realLookupTable = reinterpret_cast(lookupTable->GetTable()->GetPointer(0)); + int maxIndex = lookupTable->GetNumberOfColors() - 1; + + + float scale = (tableRange[1] -tableRange[0] > 0 ? (maxIndex + 1) / (tableRange[1] - tableRange[0]) : 0.0); + // ensuring that starting point is zero + float bias = - tableRange[0] * scale; + // due to later conversion to int for rounding + bias += 0.5f; + + + // Loop through ouput pixels + while (!outputIt.IsAtEnd()) + { + unsigned char* outputSI = outputIt.BeginSpan(); + unsigned char* outputSIEnd = outputIt.EndSpan(); + + T* inputSI = inputIt.BeginSpan(); + + while (outputSI != outputSIEnd) + { + // map to an index + int idx = static_cast( *inputSI * scale + bias ); + + if (idx < 0) + idx = 0; + else if (idx > maxIndex) + idx = maxIndex; + + * reinterpret_cast(outputSI) = realLookupTable[idx]; + + inputSI++; + outputSI+=4; + } + + inputIt.NextSpan(); + outputIt.NextSpan(); + } +} + + + +//Internal method which should never be used anywhere else and should not be in th header. +//---------------------------------------------------------------------------- +// This templated function executes the filter for any type of data. +template +void vtkApplyLookupTableOnScalars(vtkMitkLevelWindowFilter *self, + vtkImageData *inData, + vtkImageData *outData, + int outExt[6], + vtkFloatingPointType* clippingBounds, + T *) +{ + vtkImageIterator inputIt(inData, outExt); + vtkImageIterator outputIt(outData, outExt); + vtkScalarsToColors* lookupTable = self->GetLookupTable(); + + int y = outExt[2]; + + // Loop through ouput pixels + while (!outputIt.IsAtEnd()) + { + unsigned char* outputSI = outputIt.BeginSpan(); + unsigned char* outputSIEnd = outputIt.EndSpan(); + + // do we iterate over the inner vertical clipping bounds + if( y >= clippingBounds[2] && y < clippingBounds[3] ) + { + T* inputSI = inputIt.BeginSpan(); + + int x= outExt[0]; + + while (outputSI != outputSIEnd) + { + // is this pixel within horizontal clipping bounds + if ( x >= clippingBounds[0] && x < clippingBounds[1]) + { + // fetching original value + double grayValue = static_cast(*inputSI); + // applying lookuptable - copy the 4 (RGBA) chars as a single int + *reinterpret_cast(outputSI) = *reinterpret_cast(lookupTable->MapValue( grayValue )); + } + else + { + // outer horizontal clipping bounds - write a transparent RGBA pixel as a single int + *reinterpret_cast(outputSI) = 0; + } + + inputSI++; + outputSI+=4; + x++; + } + + } + else + { + // outer vertical clipping bounds - write a transparent RGBA line as ints + while (outputSI != outputSIEnd) + { + *reinterpret_cast(outputSI) = 0; + outputSI+=4; + } + } + + inputIt.NextSpan(); + outputIt.NextSpan(); + y++; + } +} + + +void vtkMitkLevelWindowFilter::ExecuteInformation() +{ + vtkImageData *input = this->GetInput(); + vtkImageData *output = this->GetOutput(); + + if (!input) + { + vtkErrorMacro(<< "Input not set."); + return; + } + output->CopyTypeSpecificInformation( input ); + + // TODO make output RGBA + output->SetScalarTypeToUnsignedChar(); + output->SetNumberOfScalarComponents(4); + + int extent[6]; + input->GetWholeExtent(extent); + output->SetExtent(extent); + output->SetWholeExtent(extent); + output->SetUpdateExtent(extent); + output->AllocateScalars(); +} + +//Method to run the filter in different threads. +void vtkMitkLevelWindowFilter::ThreadedExecute(vtkImageData *inData, + vtkImageData *outData, + int extent[6], int /*id*/) +{ + if(inData->GetNumberOfScalarComponents() > 2) + { + switch (inData->GetScalarType()) + { + vtkTemplateMacro( + vtkApplyLookupTableOnRGBA( this, + inData, + outData, + extent, + m_ClippingBounds, + static_cast(0))); + default: + vtkErrorMacro(<< "Execute: Unknown ScalarType"); + return; + } + } + else + { + bool dontClip = + extent[2] >= m_ClippingBounds[2] + && extent[3] <= m_ClippingBounds[3] + && extent[0] >= m_ClippingBounds[0] + && extent[1] <= m_ClippingBounds[1]; + + vtkLookupTable *vlt = dynamic_cast(this->GetLookupTable()); + + bool linearLookupTable = vlt && vlt->GetScale() == VTK_SCALE_LINEAR; + + bool useFast = dontClip && linearLookupTable; + + if(useFast) + switch (inData->GetScalarType()) + { + vtkTemplateMacro( + vtkApplyLookupTableOnScalarsFast( this, + inData, + outData, + extent, + static_cast(0))); + default: + vtkErrorMacro(<< "Execute: Unknown ScalarType"); + return; + } + else + switch (inData->GetScalarType()) + { + vtkTemplateMacro( + vtkApplyLookupTableOnScalars( this, + inData, + outData, + extent, + m_ClippingBounds, + static_cast(0))); + default: + vtkErrorMacro(<< "Execute: Unknown ScalarType"); + return; + } + } +} + +void vtkMitkLevelWindowFilter::ExecuteInformation( + vtkImageData *vtkNotUsed(inData), vtkImageData *vtkNotUsed(outData)) +{ +} + +void vtkMitkLevelWindowFilter::SetMinOpacity(double minOpacity) +{ + m_MinOpacity = minOpacity; +} + +inline double vtkMitkLevelWindowFilter::GetMinOpacity() const +{ + return m_MinOpacity; +} + +void vtkMitkLevelWindowFilter::SetMaxOpacity(double maxOpacity) +{ + m_MaxOpacity = maxOpacity; +} + +inline double vtkMitkLevelWindowFilter::GetMaxOpacity() const +{ + return m_MaxOpacity; +} + +void vtkMitkLevelWindowFilter::SetClippingBounds(vtkFloatingPointType* bounds) // TODO does vtkFloatingPointType[4] work?? +{ + for (unsigned int i = 0 ; i < 4; ++i) + m_ClippingBounds[i] = bounds[i]; +} diff --git a/Core/Code/Rendering/vtkMitkApplyLevelWindowToRGBFilter.h b/Core/Code/Rendering/vtkMitkLevelWindowFilter.h similarity index 74% rename from Core/Code/Rendering/vtkMitkApplyLevelWindowToRGBFilter.h rename to Core/Code/Rendering/vtkMitkLevelWindowFilter.h index 3636b332ba..723b6f8d0c 100644 --- a/Core/Code/Rendering/vtkMitkApplyLevelWindowToRGBFilter.h +++ b/Core/Code/Rendering/vtkMitkLevelWindowFilter.h @@ -1,80 +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. ===================================================================*/ -#ifndef __vtkMitkApplyLevelWindowToRGBFilter_h -#define __vtkMitkApplyLevelWindowToRGBFilter_h +#ifndef __vtkMitkLevelWindowFilter_h +#define __vtkMitkLevelWindowFilter_h class vtkScalarsToColors; #include #include #include /** Documentation -* \brief Applies the color and opacity level window to RGB(A) images. +* \brief Applies the grayvalue or color/opacity level window to scalar or RGB(A) images. * -* This filter is used to apply the color level window to RBG images (e.g. +* This filter is used to apply the color level window to RGB images (e.g. * diffusion tensor images). Therefore, the RGB channels are converted to * the HSI color space, where the level window can be applied. Afterwards, * the HSI values transformed back to the RGB space. * * The filter is also able to apply an opacity level window to RGBA images. * * \ingroup Renderer */ -class MITK_CORE_EXPORT vtkMitkApplyLevelWindowToRGBFilter : public vtkImageToImageFilter +class MITK_CORE_EXPORT vtkMitkLevelWindowFilter : public vtkImageToImageFilter { public: + virtual unsigned long int GetMTime(); /** \brief Get the lookup table for the RGB level window */ vtkScalarsToColors* GetLookupTable(); /** \brief Set the lookup table for the RGB level window */ void SetLookupTable(vtkScalarsToColors *lookupTable); /** \brief Get/Set the lower window opacity for the alpha level window */ void SetMinOpacity(double minOpacity); inline double GetMinOpacity() const; /** \brief Get/Set the upper window opacity for the alpha level window */ void SetMaxOpacity(double maxOpacity); inline double GetMaxOpacity() const; + /** \brief Set clipping bounds for the opaque part of the resliced 2d image */ + void SetClippingBounds(vtkFloatingPointType*); + /** Default constructor. */ - vtkMitkApplyLevelWindowToRGBFilter(); + vtkMitkLevelWindowFilter(); /** Default deconstructor. */ - ~vtkMitkApplyLevelWindowToRGBFilter(); + ~vtkMitkLevelWindowFilter(); protected: /** \brief Method for threaded execution of the filter. * \param *inData: The input. * \param *outData: The output of the filter. - * \param extent: Array[6] specifies the region of the image to be updated inside this thread. + * \param extent: Specifies the region of the image to be updated inside this thread. * It is a six-component array of the form (xmin, xmax, ymin, ymax, zmin, zmax). * \param id: The thread id. */ void ThreadedExecute(vtkImageData *inData, vtkImageData *outData,int extent[6], int id); /** Standard VTK filter method to apply the filter. See VTK documentation.*/ void ExecuteInformation(); /** Standard VTK filter method to apply the filter. See VTK documentation. Not used at the moment.*/ void ExecuteInformation(vtkImageData *vtkNotUsed(inData), vtkImageData *vtkNotUsed(outData)); private: /** m_LookupTable contains the lookup table for the RGB level window.*/ vtkScalarsToColors* m_LookupTable; - /** m_MinOqacity contains the lower bound for the alpha level window.*/ - double m_MinOqacity; - /** m_MinOqacity contains the upper bound for the alpha level window.*/ + /** m_MinOpacity contains the lower bound for the alpha level window.*/ + double m_MinOpacity; + /** m_MaxOpacity contains the upper bound for the alpha level window.*/ double m_MaxOpacity; + + vtkFloatingPointType m_ClippingBounds[4]; }; #endif diff --git a/Core/Code/Rendering/vtkNeverTranslucentTexture.cpp b/Core/Code/Rendering/vtkNeverTranslucentTexture.cpp new file mode 100644 index 0000000000..ad658706c4 --- /dev/null +++ b/Core/Code/Rendering/vtkNeverTranslucentTexture.cpp @@ -0,0 +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 "vtkNeverTranslucentTexture.h" + +#include "vtkVersion.h" + +// Replacement texture code ------------------------------------------------------------- + +vtkStandardNewMacro(vtkNeverTranslucentTexture); + +vtkNeverTranslucentTexture::vtkNeverTranslucentTexture() +:vtkOpenGLTexture() +{ +} + + +int vtkNeverTranslucentTexture::IsTranslucent() +{ + return 0; // THE speedup +} + + +void vtkNeverTranslucentTexture::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); + os << indent << "Translucent: NEVER\n"; + +} + +// Factory code ------------------------------------------------------------- + +VTK_CREATE_CREATE_FUNCTION(vtkNeverTranslucentTexture); + +vtkNeverTranslucentTextureFactory::vtkNeverTranslucentTextureFactory() +{ + this->RegisterOverride("vtkTexture", + "vtkNeverTranslucentTextureFactory", + "less translucent texture", + 1, + vtkObjectFactoryCreatevtkNeverTranslucentTexture); +} + +vtkNeverTranslucentTextureFactory* vtkNeverTranslucentTextureFactory::New() +{ + return new vtkNeverTranslucentTextureFactory; +} + +const char* vtkNeverTranslucentTextureFactory::GetVTKSourceVersion() +{ + return VTK_SOURCE_VERSION; +} + +const char* vtkNeverTranslucentTextureFactory::GetDescription() +{ + return "Factory for a quickly decided, never translucent, texture"; +} diff --git a/Core/Code/Rendering/vtkNeverTranslucentTexture.h b/Core/Code/Rendering/vtkNeverTranslucentTexture.h new file mode 100644 index 0000000000..59524ce56a --- /dev/null +++ b/Core/Code/Rendering/vtkNeverTranslucentTexture.h @@ -0,0 +1,107 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkNeverTranslucentTexture_h +#define mitkNeverTranslucentTexture_h + +#include + +#include + +#include + +/** + \brief VTK Fix to speed up our image rendering. + + The way we render images while changing the contrast via level/window + extremely slows down rendering. + + The cause of this slowdown is that VTK asks a texture + (via a call to IsTranslucent) if it is translucent. + When the texture refers to a lookup table this question + is answered in a most expensive way: pushing every pixel + through the lookup table to see whether it would render + translucent. + + We can speed this up extremely by always answering NO. + 2D Image rendering in the context of MITK is still correct. + + This class is injected into the VTK system by registering + it with vtkObjectFactory as a replacement for vtkTexture. + + We chose vtkOpenGLTexture as super class, because it seems + that the other texture super class is deprecated: + http://www.cmake.org/Wiki/VTK:How_I_mangled_Mesa + + \sa ImageVtkMapper2D +*/ +/* NOT exported, this is a 2D image mapper helper */ + +class vtkNeverTranslucentTexture : public vtkOpenGLTexture +{ +public: + + static vtkNeverTranslucentTexture* New(); + vtkTypeMacro(vtkNeverTranslucentTexture, vtkTexture); + void PrintSelf(ostream& os, vtkIndent indent); + + /** + \brief The FIX (see class description). + + VTK Description: Is this Texture Translucent? + + Returns false (0) if the texture is either fully opaque or has + only fully transparent pixels and fully opaque pixels and the + Interpolate flag is turn off. + */ + virtual int IsTranslucent(); + +protected: + + vtkNeverTranslucentTexture(); + +private: + + vtkNeverTranslucentTexture(const vtkNeverTranslucentTexture&); // Not implemented. + void operator=(const vtkNeverTranslucentTexture&); // Not implemented. +}; + +/** + \brief Factory for vtkNeverTranslucentTexture (see this class!). + + Registered in CoreActivator to replace all instances of vtkTexture + with vtkNeverTranslucentTexture. + + Required to make rendering of images during level/window operations + acceptably fast. +*/ +class vtkNeverTranslucentTextureFactory : public vtkObjectFactory +{ + public: + + vtkNeverTranslucentTextureFactory(); + + static vtkNeverTranslucentTextureFactory* New(); + virtual const char* GetVTKSourceVersion(); + const char* GetDescription(); + + protected: + vtkNeverTranslucentTextureFactory(const vtkNeverTranslucentTextureFactory&); + void operator=(const vtkNeverTranslucentTextureFactory&); +}; + + +#endif diff --git a/Core/Code/Testing/mitkDispatcherTest.cpp b/Core/Code/Testing/mitkDispatcherTest.cpp index 4b1069543a..7f9f49cc66 100644 --- a/Core/Code/Testing/mitkDispatcherTest.cpp +++ b/Core/Code/Testing/mitkDispatcherTest.cpp @@ -1,119 +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. ===================================================================*/ #include "mitkStandaloneDataStorage.h" #include "mitkDataNode.h" #include "mitkInteractor.h" #include "mitkDataInteractor.h" #include "mitkVtkPropRenderer.h" +#include "mitkBaseRenderer.h" #include "mitkTestingMacros.h" #include "mitkGlobalInteraction.h" +#include "itkLightObject.h" +#include "mitkDispatcher.h" int mitkDispatcherTest(int /*argc*/, char* /*argv*/[]) { MITK_TEST_BEGIN("Dispatcher") /* * Tests the process of creating Interactors and assigning DataNodes to them. * Test checks if these Interactors are added to the Dispatcher under different conditions, * and in different call order. */ // Global interaction must(!) be initialized if used mitk ::GlobalInteraction::GetInstance()->Initialize("global"); // Here BindDispatcherInteractor and Dispatcher should be created automatically vtkRenderWindow* renWin = vtkRenderWindow::New(); mitk::VtkPropRenderer::Pointer renderer = mitk::VtkPropRenderer::New( "ContourRenderer",renWin, mitk::RenderingManager::GetInstance() ); mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); mitk::DataNode::Pointer dn = mitk::DataNode::New(); mitk::DataNode::Pointer dn2 = mitk::DataNode::New(); mitk::DataInteractor::Pointer ei = mitk::DataInteractor::New(); mitk::DataInteractor::Pointer ei2 = mitk::DataInteractor::New(); MITK_TEST_CONDITION_REQUIRED( renderer->GetDispatcher()->GetNumberOfInteractors() == 0 , "01 Check Existence of Dispatcher." ); ei->SetDataNode(dn); renderer->SetDataStorage(ds); ds->Add(dn); int num = renderer->GetDispatcher()->GetNumberOfInteractors(); MITK_TEST_CONDITION_REQUIRED( num == 1 , "02 Number of registered Interactors " << num << " , expected 1" ); // This _must not_ result in additionally registered interactors. ei->SetDataNode(dn); ei->SetDataNode(dn); num = renderer->GetDispatcher()->GetNumberOfInteractors(); MITK_TEST_CONDITION_REQUIRED( num == 1 , "03 Number of registered Interactors " << num << " , expected 1" ); // Switching the DataNode of an Interactor also must not result in extra registered Interactors in Dispatcher // since dn2 is not connected to DataStorage // ei will be dropped from dispatcher ei->SetDataNode(dn2); num = renderer->GetDispatcher()->GetNumberOfInteractors(); MITK_TEST_CONDITION_REQUIRED( num == 0 , "04 Number of registered Interactors " << num << " , expected 0" ); // DataNode Added to DataStorage, now Interactor entry in Dispatcher should be replaced, // hence we restore Interactor in the Dispatcher ds->Add(dn2); num = renderer->GetDispatcher()->GetNumberOfInteractors(); MITK_TEST_CONDITION_REQUIRED( num == 1 , "05 Number of registered Interactors " << num << " , expected 1" ); // New DataNode and new interactor, this should result in additional Interactor in the Dispatcher. ei2->SetDataNode(dn); num = renderer->GetDispatcher()->GetNumberOfInteractors(); MITK_TEST_CONDITION_REQUIRED( num == 2 , "06 Number of registered Interactors " << num << " , expected 2" ); // Here ei and ei2 point to the same dn2; dn2 now only points to ei2, so ei is abandoned, // therefore ei1 is expected to be removed ei2->SetDataNode(dn2); num = renderer->GetDispatcher()->GetNumberOfInteractors(); MITK_TEST_CONDITION_REQUIRED( num == 1 , "07 Number of registered Interactors " << num << " , expected 1" ); // Setting DataNode in Interactor to NULL, should remove Interactor from Dispatcher ei2->SetDataNode(NULL); num = renderer->GetDispatcher()->GetNumberOfInteractors(); MITK_TEST_CONDITION_REQUIRED( num == 0 , "08 Number of registered Interactors " << num << " , expected 0" ); renWin->Delete(); // always end with this! MITK_TEST_END() } diff --git a/Core/Code/files.cmake b/Core/Code/files.cmake index 49ddb9419e..ea68d73a03 100644 --- a/Core/Code/files.cmake +++ b/Core/Code/files.cmake @@ -1,355 +1,357 @@ set(H_FILES Algorithms/itkImportMitkImageContainer.h Algorithms/itkImportMitkImageContainer.txx Algorithms/itkLocalVariationImageFilter.h Algorithms/itkLocalVariationImageFilter.txx Algorithms/itkMITKScalarImageToHistogramGenerator.h Algorithms/itkMITKScalarImageToHistogramGenerator.txx Algorithms/itkTotalVariationDenoisingImageFilter.h Algorithms/itkTotalVariationDenoisingImageFilter.txx Algorithms/itkTotalVariationSingleIterationImageFilter.h Algorithms/itkTotalVariationSingleIterationImageFilter.txx Algorithms/mitkBilateralFilter.h Algorithms/mitkBilateralFilter.cpp Algorithms/mitkInstantiateAccessFunctions.h Algorithms/mitkPixelTypeList.h # Preprocessor macros taken from Boost Algorithms/mitkPPArithmeticDec.h Algorithms/mitkPPArgCount.h Algorithms/mitkPPCat.h Algorithms/mitkPPConfig.h Algorithms/mitkPPControlExprIIf.h Algorithms/mitkPPControlIf.h Algorithms/mitkPPControlIIf.h Algorithms/mitkPPDebugError.h Algorithms/mitkPPDetailAutoRec.h Algorithms/mitkPPDetailDMCAutoRec.h Algorithms/mitkPPExpand.h Algorithms/mitkPPFacilitiesEmpty.h Algorithms/mitkPPFacilitiesExpand.h Algorithms/mitkPPLogicalBool.h Algorithms/mitkPPRepetitionDetailDMCFor.h Algorithms/mitkPPRepetitionDetailEDGFor.h Algorithms/mitkPPRepetitionDetailFor.h Algorithms/mitkPPRepetitionDetailMSVCFor.h Algorithms/mitkPPRepetitionFor.h Algorithms/mitkPPSeqElem.h Algorithms/mitkPPSeqForEach.h Algorithms/mitkPPSeqForEachProduct.h Algorithms/mitkPPSeq.h Algorithms/mitkPPSeqEnum.h Algorithms/mitkPPSeqSize.h Algorithms/mitkPPSeqToTuple.h Algorithms/mitkPPStringize.h Algorithms/mitkPPTupleEat.h Algorithms/mitkPPTupleElem.h Algorithms/mitkPPTupleRem.h Algorithms/mitkClippedSurfaceBoundsCalculator.h Algorithms/mitkExtractSliceFilter.h Algorithms/mitkConvert2Dto3DImageFilter.h + Algorithms/mitkPlaneClipping.h Common/mitkExceptionMacro.h Common/mitkServiceBaseObject.h Common/mitkTestingMacros.h DataManagement/mitkImageAccessByItk.h DataManagement/mitkImageCast.h DataManagement/mitkImagePixelAccessor.h DataManagement/mitkImagePixelReadAccessor.h DataManagement/mitkImagePixelWriteAccessor.h DataManagement/mitkImageReadAccessor.h DataManagement/mitkImageWriteAccessor.h DataManagement/mitkITKImageImport.h DataManagement/mitkITKImageImport.txx DataManagement/mitkImageToItk.h DataManagement/mitkImageToItk.txx Interactions/mitkEventMapperAddOn.h Interfaces/mitkIDataNodeReader.h IO/mitkPixelTypeTraits.h ) set(CPP_FILES Algorithms/mitkBaseDataSource.cpp Algorithms/mitkBaseProcess.cpp Algorithms/mitkDataNodeSource.cpp Algorithms/mitkGeometry2DDataToSurfaceFilter.cpp Algorithms/mitkHistogramGenerator.cpp Algorithms/mitkImageChannelSelector.cpp Algorithms/mitkImageSliceSelector.cpp Algorithms/mitkImageSource.cpp Algorithms/mitkImageTimeSelector.cpp Algorithms/mitkImageToImageFilter.cpp Algorithms/mitkPointSetSource.cpp Algorithms/mitkPointSetToPointSetFilter.cpp Algorithms/mitkRGBToRGBACastImageFilter.cpp Algorithms/mitkSubImageSelector.cpp Algorithms/mitkSurfaceSource.cpp Algorithms/mitkSurfaceToSurfaceFilter.cpp Algorithms/mitkUIDGenerator.cpp Algorithms/mitkVolumeCalculator.cpp Algorithms/mitkClippedSurfaceBoundsCalculator.cpp Algorithms/mitkExtractSliceFilter.cpp Algorithms/mitkConvert2Dto3DImageFilter.cpp Controllers/mitkBaseController.cpp Controllers/mitkCallbackFromGUIThread.cpp Controllers/mitkCameraController.cpp Controllers/mitkCameraRotationController.cpp Controllers/mitkCoreActivator.cpp Controllers/mitkFocusManager.cpp Controllers/mitkLimitedLinearUndo.cpp Controllers/mitkOperationEvent.cpp Controllers/mitkPlanePositionManager.cpp Controllers/mitkProgressBar.cpp Controllers/mitkRenderingManager.cpp Controllers/mitkSliceNavigationController.cpp Controllers/mitkSlicesCoordinator.cpp Controllers/mitkSlicesRotator.cpp Controllers/mitkSlicesSwiveller.cpp Controllers/mitkStatusBar.cpp Controllers/mitkStepper.cpp Controllers/mitkTestManager.cpp Controllers/mitkUndoController.cpp Controllers/mitkVerboseLimitedLinearUndo.cpp Controllers/mitkVtkInteractorCameraController.cpp Controllers/mitkVtkLayerController.cpp DataManagement/mitkAbstractTransformGeometry.cpp DataManagement/mitkAnnotationProperty.cpp DataManagement/mitkApplicationCursor.cpp DataManagement/mitkBaseData.cpp DataManagement/mitkBaseProperty.cpp DataManagement/mitkClippingProperty.cpp DataManagement/mitkChannelDescriptor.cpp DataManagement/mitkColorProperty.cpp DataManagement/mitkDataStorage.cpp #DataManagement/mitkDataTree.cpp DataManagement/mitkDataNode.cpp DataManagement/mitkDataNodeFactory.cpp #DataManagement/mitkDataTreeStorage.cpp DataManagement/mitkDisplayGeometry.cpp DataManagement/mitkEnumerationProperty.cpp DataManagement/mitkGeometry2D.cpp DataManagement/mitkGeometry2DData.cpp DataManagement/mitkGeometry3D.cpp DataManagement/mitkGeometryData.cpp DataManagement/mitkGroupTagProperty.cpp DataManagement/mitkImage.cpp DataManagement/mitkImageAccessorBase.cpp DataManagement/mitkImageCaster.cpp DataManagement/mitkImageCastPart1.cpp DataManagement/mitkImageCastPart2.cpp DataManagement/mitkImageCastPart3.cpp DataManagement/mitkImageCastPart4.cpp DataManagement/mitkImageDataItem.cpp DataManagement/mitkImageDescriptor.cpp DataManagement/mitkImageVtkAccessor.cpp DataManagement/mitkImageStatisticsHolder.cpp DataManagement/mitkLandmarkBasedCurvedGeometry.cpp DataManagement/mitkLandmarkProjectorBasedCurvedGeometry.cpp DataManagement/mitkLandmarkProjector.cpp DataManagement/mitkLevelWindow.cpp DataManagement/mitkLevelWindowManager.cpp DataManagement/mitkLevelWindowPreset.cpp DataManagement/mitkLevelWindowProperty.cpp DataManagement/mitkLookupTable.cpp DataManagement/mitkLookupTables.cpp # specializations of GenericLookupTable DataManagement/mitkMemoryUtilities.cpp DataManagement/mitkModalityProperty.cpp DataManagement/mitkModeOperation.cpp DataManagement/mitkNodePredicateAnd.cpp DataManagement/mitkNodePredicateBase.cpp DataManagement/mitkNodePredicateCompositeBase.cpp DataManagement/mitkNodePredicateData.cpp DataManagement/mitkNodePredicateDataType.cpp DataManagement/mitkNodePredicateDimension.cpp DataManagement/mitkNodePredicateFirstLevel.cpp DataManagement/mitkNodePredicateNot.cpp DataManagement/mitkNodePredicateOr.cpp DataManagement/mitkNodePredicateProperty.cpp DataManagement/mitkNodePredicateSource.cpp DataManagement/mitkPlaneOrientationProperty.cpp DataManagement/mitkPlaneGeometry.cpp DataManagement/mitkPlaneOperation.cpp DataManagement/mitkPointOperation.cpp DataManagement/mitkPointSet.cpp DataManagement/mitkProperties.cpp DataManagement/mitkPropertyList.cpp DataManagement/mitkRestorePlanePositionOperation.cpp DataManagement/mitkRotationOperation.cpp DataManagement/mitkSlicedData.cpp DataManagement/mitkSlicedGeometry3D.cpp DataManagement/mitkSmartPointerProperty.cpp DataManagement/mitkStandaloneDataStorage.cpp DataManagement/mitkStateTransitionOperation.cpp DataManagement/mitkStringProperty.cpp DataManagement/mitkSurface.cpp DataManagement/mitkSurfaceOperation.cpp DataManagement/mitkThinPlateSplineCurvedGeometry.cpp DataManagement/mitkTimeSlicedGeometry.cpp DataManagement/mitkTransferFunction.cpp DataManagement/mitkTransferFunctionProperty.cpp DataManagement/mitkTransferFunctionInitializer.cpp DataManagement/mitkVector.cpp DataManagement/mitkVtkInterpolationProperty.cpp DataManagement/mitkVtkRepresentationProperty.cpp DataManagement/mitkVtkResliceInterpolationProperty.cpp DataManagement/mitkVtkScalarModeProperty.cpp DataManagement/mitkVtkVolumeRenderingProperty.cpp DataManagement/mitkWeakPointerProperty.cpp DataManagement/mitkShaderProperty.cpp DataManagement/mitkResliceMethodProperty.cpp DataManagement/mitkMaterial.cpp Interactions/mitkAction.cpp Interactions/mitkAffineInteractor.cpp Interactions/mitkBindDispatcherInteractor.cpp Interactions/mitkCoordinateSupplier.cpp Interactions/mitkDataInteractor.cpp Interactions/mitkDispatcher.cpp Interactions/mitkDisplayCoordinateOperation.cpp Interactions/mitkDisplayInteractor.cpp Interactions/mitkDisplayPositionEvent.cpp # Interactions/mitkDisplayVectorInteractorLevelWindow.cpp # legacy, prob even now unneeded # Interactions/mitkDisplayVectorInteractorScroll.cpp Interactions/mitkEvent.cpp Interactions/mitkEventConfig.cpp Interactions/mitkEventDescription.cpp Interactions/mitkEventFactory.cpp Interactions/mitkInteractionEventHandler.cpp Interactions/mitkEventMapper.cpp Interactions/mitkEventStateMachine.cpp Interactions/mitkGlobalInteraction.cpp Interactions/mitkInteractor.cpp Interactions/mitkInternalEvent.cpp Interactions/mitkInteractionEvent.cpp Interactions/mitkInteractionPositionEvent.cpp Interactions/mitkInteractionKeyEvent.cpp Interactions/mitkMousePressEvent.cpp Interactions/mitkMouseMoveEvent.cpp Interactions/mitkMouseReleaseEvent.cpp Interactions/mitkMouseWheelEvent.cpp Interactions/mitkMouseModeSwitcher.cpp Interactions/mitkMouseMovePointSetInteractor.cpp Interactions/mitkMoveBaseDataInteractor.cpp Interactions/mitkNodeDepententPointSetInteractor.cpp Interactions/mitkPointSetDataInteractor.cpp Interactions/mitkPointSetInteractor.cpp Interactions/mitkPositionEvent.cpp Interactions/mitkPositionTracker.cpp Interactions/mitkStateMachineAction.cpp Interactions/mitkStateMachineState.cpp Interactions/mitkStateMachineTransition.cpp Interactions/mitkState.cpp Interactions/mitkStateMachineContainer.cpp Interactions/mitkStateEvent.cpp Interactions/mitkStateMachine.cpp Interactions/mitkStateMachineFactory.cpp Interactions/mitkTransition.cpp Interactions/mitkWheelEvent.cpp Interactions/mitkKeyEvent.cpp Interactions/mitkVtkEventAdapter.cpp Interactions/mitkVtkInteractorStyle.cxx Interactions/mitkCrosshairPositionEvent.cpp Interfaces/mitkInteractionEventObserver.cpp IO/mitkBaseDataIOFactory.cpp IO/mitkCoreDataNodeReader.cpp IO/mitkDicomSeriesReader.cpp IO/mitkFileReader.cpp IO/mitkFileSeriesReader.cpp IO/mitkFileWriter.cpp #IO/mitkIpPicGet.c IO/mitkImageGenerator.cpp IO/mitkImageWriter.cpp IO/mitkImageWriterFactory.cpp IO/mitkItkImageFileIOFactory.cpp IO/mitkItkImageFileReader.cpp IO/mitkItkLoggingAdapter.cpp IO/mitkItkPictureWrite.cpp IO/mitkIOUtil.cpp IO/mitkLookupTableProperty.cpp IO/mitkOperation.cpp #IO/mitkPicFileIOFactory.cpp #IO/mitkPicFileReader.cpp #IO/mitkPicFileWriter.cpp #IO/mitkPicHelper.cpp #IO/mitkPicVolumeTimeSeriesIOFactory.cpp #IO/mitkPicVolumeTimeSeriesReader.cpp IO/mitkPixelType.cpp IO/mitkPointSetIOFactory.cpp IO/mitkPointSetReader.cpp IO/mitkPointSetWriter.cpp IO/mitkPointSetWriterFactory.cpp IO/mitkRawImageFileReader.cpp IO/mitkStandardFileLocations.cpp IO/mitkSTLFileIOFactory.cpp IO/mitkSTLFileReader.cpp IO/mitkSurfaceVtkWriter.cpp IO/mitkSurfaceVtkWriterFactory.cpp IO/mitkVtkLoggingAdapter.cpp IO/mitkVtiFileIOFactory.cpp IO/mitkVtiFileReader.cpp IO/mitkVtkImageIOFactory.cpp IO/mitkVtkImageReader.cpp IO/mitkVtkSurfaceIOFactory.cpp IO/mitkVtkSurfaceReader.cpp IO/vtkPointSetXMLParser.cpp IO/mitkLog.cpp Rendering/mitkBaseRenderer.cpp Rendering/mitkVtkMapper2D.cpp Rendering/mitkVtkMapper3D.cpp Rendering/mitkRenderWindowFrame.cpp Rendering/mitkGeometry2DDataMapper2D.cpp Rendering/mitkGeometry2DDataVtkMapper3D.cpp Rendering/mitkGLMapper2D.cpp Rendering/mitkGradientBackground.cpp Rendering/mitkManufacturerLogo.cpp Rendering/mitkMapper2D.cpp Rendering/mitkMapper3D.cpp Rendering/mitkMapper.cpp Rendering/mitkPointSetGLMapper2D.cpp Rendering/mitkPointSetVtkMapper3D.cpp Rendering/mitkPolyDataGLMapper2D.cpp Rendering/mitkSurfaceGLMapper2D.cpp Rendering/mitkSurfaceVtkMapper3D.cpp Rendering/mitkVolumeDataVtkMapper3D.cpp Rendering/mitkVtkPropRenderer.cpp Rendering/mitkVtkWidgetRendering.cpp Rendering/vtkMitkRectangleProp.cpp Rendering/vtkMitkRenderProp.cpp Rendering/mitkVtkEventProvider.cpp Rendering/mitkRenderWindow.cpp Rendering/mitkRenderWindowBase.cpp Rendering/mitkShaderRepository.cpp Rendering/mitkImageVtkMapper2D.cpp Rendering/vtkMitkThickSlicesFilter.cpp - Rendering/vtkMitkApplyLevelWindowToRGBFilter.cpp + Rendering/vtkMitkLevelWindowFilter.cpp + Rendering/vtkNeverTranslucentTexture.cpp Common/mitkException.cpp Common/mitkCommon.h Common/mitkCoreObjectFactoryBase.cpp Common/mitkCoreObjectFactory.cpp ) list(APPEND CPP_FILES ${CppMicroServices_SOURCES}) set(RESOURCE_FILES Interactions/globalConfig.xml Interactions/DisplayInteraction.xml Interactions/DisplayConfig.xml Interactions/DisplayConfigPACS.xml Interactions/DisplayConfigPACSPan.xml Interactions/DisplayConfigPACSScroll.xml Interactions/DisplayConfigPACSZoom.xml Interactions/DisplayConfigPACSLevelWindow.xml Interactions/DisplayConfigMITK.xml Interactions/PointSet.xml Interactions/Legacy/StateMachine.xml Interactions/PointSetConfig.xml Interactions/Tests/AddAndRemovePoints.xml Interactions/Tests/globalConfig.xml Interactions/Tests/StatemachineTest.xml Interactions/Tests/StatemachineConfigTest.xml ) diff --git a/Core/Documentation/Doxygen/Concepts/Concepts.dox b/Core/Documentation/Doxygen/Concepts/Concepts.dox index 2665de8898..b435bffaa9 100644 --- a/Core/Documentation/Doxygen/Concepts/Concepts.dox +++ b/Core/Documentation/Doxygen/Concepts/Concepts.dox @@ -1,32 +1,29 @@ /** \page Concepts MITK Concepts The following items describe some issues about MITK on a more abstract level. -# \subpage OverviewPage -# \subpage CodingPage "Coding Concepts" -# \ref CodingPageGeneral -# \ref CodingPageStyle -# \ref CodingPageMITKMacros -# \subpage MicroServices_Overview -# Data Concepts -# \subpage DataManagementPage -# \subpage MitkImagePage -# \subpage PropertiesPage -# \subpage GeometryOverviewPage -# \subpage PipelineingConceptPage -# \subpage QVTKRendering -# Interaction -# \subpage DataInteractionPage -# \subpage InteractionPage -# \subpage LoggingPage -# \subpage ExceptionPage --# Testing Concept - -# \subpage GeneralTests - -# \subpage RenderingTests -# \subpage ModularizationPage "Modularization Concept" -# \ref ModularizationPageOverview -# \ref ModularizationPageHowTo If you want to start using MITK, you also want to see the chapter \ref Development. */ diff --git a/Core/Documentation/Doxygen/Concepts/DataInteraction.dox b/Core/Documentation/Doxygen/Concepts/DataInteraction.dox index 30a9923e61..6c74c6b905 100644 --- a/Core/Documentation/Doxygen/Concepts/DataInteraction.dox +++ b/Core/Documentation/Doxygen/Concepts/DataInteraction.dox @@ -1,204 +1,204 @@ /** \page DataInteractionPage Interaction Concepts \tableofcontents \section InteractionPage_Introduction Introduction to Interaction in MITK Interaction is a very important task in medical image processing software. Therefore MITK provides a special interaction concept that provides the developer with an easy way to develop and maintain user interaction separately from the algorithms processing the input. This allows e.g. for common interaction schemes to be re-used in different contexts. The core of the interaction concept is based on entities called \b DataInteractors that listen for certain pre-defined events and execute actions when such an event is triggered.\n In the following the different components of the interaction concept are explained. First a a high-level overview about how the different components interact is given, then some parts are explained in more detail. \subsection FurtherReadingInteraction Topics related to interaction - further information: See the \ref DataInteractionTechnicalPage page for a more technical explanation. \n Consult \ref HowToUseDataInteractor for usage information.\n See \ref SectionImplementationDataInteractor for an example on how to implement a new DataInteractor \n for information about how to create new events refer to ImplementNewEventsPage.\n The documentation of the depricated former concept can be found at \ref InteractionPage. \section HandlingSection Event Handling & Window Manager Abstraction The following sequence diagram gives an examplary overview of the process from creating an event until executing an action in the DataInteractor. This diagram assumes the usage of the Qt framework, but also shows that the interaction concept itself is implemented independent of any specific window manager. \image html event_handling.png
  1. a user event is triggered and send to MITK
  2. this layler serves as an adapter from window manager (here Qt) events to MITK internal events (later refered to as InteractionEvents).
  3. once the event is adapted it is send to a Dispatcher, which is linked to a render window, to be handled.
  4. on Dispatcher level all objects are known that can react to incoming events (DataInteractors)
  5. a DataInteractor is offered an event and checks its EventConfig object, which returns if a variant if this event has been defined for this DataInteractor.
  6. if the DataInteractor has a variant for the event, it consults its state machine to check if the input can be handled in the current state
  7. the actions asociated with a state change (transition) are executed and the event is successfully handled.
\section EventPage Events Events can describe any sort of user input, such as key strokes, mouse clicks or touch gestures. These events are mapped from an UI framework like Qt to an MITK internal representation and send to the Dispatcher which in turn deals with further processing of the event. These events are not limited to classical input devices but can be extened at will, by introducing new classes which e.g. describe -events from tracking devices, etc. Refer to \ref ImplementNewEventsPage to see how new events and thereby input devices can be integrated. -For an overview of available Events see mitk::InteractionEvent, for on overview of parameters see the \ref DataInteractionTechnicalPage. +events from tracking devices, etc. Refer to \subpage ImplementNewEventsPage to see how new events and thereby input devices can be integrated. +For an overview of available Events see mitk::InteractionEvent, for on overview of parameters see the \subpage DataInteractionTechnicalPage. \section InteractionEventHandlerSection InteractionEventHandler Is the term describing objects in general that can handle events. These objects can be devided into two groups, namely DataInteractors and InteractionEventObserver. Their difference is that DataInteractors are linked with a DataNode which they manipulate, whereas InteractionEventObserver do not have a DataNode and therefore are not supposed to manipulate any data. \dot digraph linker_deps { node [shape=record, fontname=Helvetica, fontsize=10]; a [ label="InteractionEventHandler" ]; d [ label="{StateMachine|HandleEvent()}" ]; b [ label="{DataInteractor|HandleEvent()}" ]; c [ label="{InteractionEventObserver|Notify()}" ]; a -> d; d -> b; d -> c; } \enddot \subsection DataInteractorsSection DataInteractors DataInteractors are specialized InteractionEventHandler which handle events for one spefific DataNode. They are implemented following a concept called state machines (see e.g. Wikipedia ). \subsubsection StateMachinesSection StateMachines A specific events action is usually desired to dependent on the content of the data object the state of the interaction. For example if the when adding a line by clicking with the mouse, the first to clicks are supposed to add a point. But the second click should additionally finish the interaction and a subsequent third click should be ignored. State machines provide a great way to model such interaction in which the same user interaction can trigger different actions depending on the current state. Therefore DataInteractors work with so called state machine patterns. The basic idea here is that each interaction can be described by states and transitions which in turn trigger actions. These patterns define a workflow and different patterns can be applied to the same DataInteractor and cause this DataInteractor to perform different user interactions. This principle is best described by an example. Imagine a DataInteractor with the functionality (1) to add Points at a given mouse position and connect them by a line and (2) check if two points are on the same position. Using this DataInteractor, different StateMachine patterns/descriptions can be given which each cause the DataInteractor to perform different interaction schemes. State machine pattern 1: We want the user to draw a line. A simple state machine could express this by three states like this: \dot digraph linker_deps { node [shape=circle, fontname=Helvetica, fontsize=10]; a [ label="NoPoints" ]; b [ label="OnePoint" ]; c [ label="TwoPoints" ]; a -> b [label="MousePress/AddPoint",fontname=Helvetica, fontsize=10]; b -> c [label="MousePress/AddPoint",fontname=Helvetica, fontsize=10]; { rank=same; a b c } } \enddot With each MousePress event the AddPoint function is called and adds a point at the mouse position, unless two points already exist. State machine pattern 2: The same DataInteractor can also operate after the following state machine, which models the interaction to input a closed contour. The DataInteractor can detect an AddPoint event on an already existing point and will trigger a PointsMatch event. \dot digraph { node [shape=circle, fontname=Helvetica, fontsize=10]; a [ label="StartState" ]; b [ label="ClosedContour"]; a -> a [label="MousePress/AddPoint",fontname=Helvetica, fontsize=10]; a -> b [label="PointsMatch/AddPoint",fontname=Helvetica, fontsize=10]; } \enddot In this way state machines provide both, a nice and structured way to represent interaction tasks and description of the interaction which is separated from the code. One DataInteractor can be re-used for different tasks by simply exchanging the state machine pattern. These patterns are described in XML files. \subsubsection DefinitionStateMachine Definition of a State Machine The definition is made up out of three components.
  • States - represent the current status of the interaction
  • Transitions - describe the events needed to change from one state to another
  • Actions - are executed, when a transition is taken
Each state machine needs exactly one designated start state into which the state machine is set in the beginning. An example of a state machine describing the interaction of example 2 looks like this: \code \endcode Example 1: State machine pattern, that describes adding points to a contour until the PointsMatch event is triggered. For a more detailed desciption of state machine patterns see here. \subsection InteractionEventObserverSection InteractionEventObserver InteractionEventObserver are objects which will receive all user input and are intented for observation only, they should never modify any DataNodes. For InteractionEventObserver it is optional to use the state machine functionality, the default is without. How to use the state machine functionality is described in the documentation of mitk::InteractionEventObserver::Notify. \subsection ConfigurationSection Configuration In a lot of cases it is preferable to implement interactions independent of a specific event (e.g. left click with mouse), such that is it possible to easily change this. This is achieved through configuration of InteractionEventHandlers. This allows to change the behavior at runtime. The InteractionEventHandler provides an interface to easily modify the user input that triggers an action by loading a different configuration, this allows to implement user-specific behavior of the software on an abstract level and to switch in at runtime. This is achieved through XML files describing a configuration. These files can be loaded by the InteractionEventHandler and will lead to an internal mapping from specific user input to an absract description of the event given in the config file. In order to do this we distinguish between a spefic event and an event variant. A specific event is described by its event class, which determines the category of an event, e.g. the class MousePressEvent, and its parameter which make this event unique, e.g. LeftMouseButton pressed and no modifier keys pressed. The event variant is a name that is assigned to a spefific event, and to which an InteractionEventHandler listens. To illustrate this, an example is given here for two different configuration files. We assume an InteractionEventHandler that listens to the event variant 'AddPoint', two possible config files could then look like this: \code \endcode Example 2: Event description of a left click with the mouse and \code \endcode Example 3: Event description of a left click with the mouse while pressing the shift-key If the InteractionEventHandler is loaded with the first configuration the event variant 'MousePress' is triggered when the user performs a mouse click, while when the second configuration is loaded 'MousePress' is triggered when the user performs a right click while pressing the shift button. In this way all objects derived by InteractionEventHandler can be configured. For a detailed description about how to create the XML file see \ref ConfigurationTechnical . \section DispatcherSection Dispatcher This unit receives all events and distributes them to the DataInteractors. This is done by ordering the DataInteractors according to the layer of their DataNode in descending order. Then the event is offered to the first DataInteractor, which in turn checks if it can handle the event. This is done for each DataInteractor until the first processes the event, after this the other DataInteractors are skipped and all InteractionEventObservers are notified. */ diff --git a/Documentation/Doxygen/Modules/CMakeLists.txt b/Documentation/Doxygen/API/Groups/CMakeLists.txt similarity index 100% rename from Documentation/Doxygen/Modules/CMakeLists.txt rename to Documentation/Doxygen/API/Groups/CMakeLists.txt diff --git a/Documentation/Doxygen/Modules/ModuleAdaptors.dox b/Documentation/Doxygen/API/Groups/ModuleAdaptors.dox similarity index 99% rename from Documentation/Doxygen/Modules/ModuleAdaptors.dox rename to Documentation/Doxygen/API/Groups/ModuleAdaptors.dox index c00107bc16..87c36285cf 100644 --- a/Documentation/Doxygen/Modules/ModuleAdaptors.dox +++ b/Documentation/Doxygen/API/Groups/ModuleAdaptors.dox @@ -1,142 +1,142 @@ namespace mitk { /** \defgroup Adaptor Adaptor Classes \ingroup ProcessAdaptor -\brief This subcategory includes adaptor classes for the integration of algorithms from +\brief This subcategory includes adaptor classes for the integration of algorithms from other toolkits, especially ITK. The task of most of the classes in this category is to deal with the conversion between the (templated) itk::Image and the (not-templated) mitk::Image. Methods for conversion are provided for both directions: \li \ref MitkToItk \li \ref ItkToMitk Care has to be taken regarding the involved coordinate systems, see \ref ItkToMitkCoordinateSystems. For limitations on ITK-type conversion see the section \ref ModuleAdaptorLimitations. VTK-based access to MITK images is straightforward: simply ask your mitk::Image for a -\a vtkImageData by calling Image:GetVtkImageData. Similarily, to get a \a vtkPolyData +\a vtkImageData by calling Image:GetVtkImageData. Similarily, to get a \a vtkPolyData from the MITK class for storing surfaces, mitk::Surface, call Surface::GetVtkPolyData. \section MitkToItk MITK to ITK adaptors Pixel type and dimension of MITK images can be specified at run time whereas ITK images are templated over the pixel type and the dimension, thus in ITK both need to be specified at compile time. There two different situations, which are covered in the following sub-sections: \li Either you know the pixel type/dimension the ITK image should have at compile time for some reason (e.g., you always create MITK images of a specific pixel type/dimension) \li or the pixel type/dimension of an MITK image is really unkown and the ITK image should have the same (unkown) type. \subsection MitkToFixedItk Converting MITK images to ITK images with known type If you know the type (pixel type and dimension) of the MITK image you have two options: \li mitk::ImageToItk: is a process class that takes an mitk::Image as input and produces an itk::Image of the given type \a TOutputImage as output (to be accessed using \a GetOutput()). In case the MITK image does not have the same type as \a TOutputImage an exception will be thrown. \li mitk::CastToItkImage: this function has two parameters, the mitk::Image (input) and a smartpointer to an itk::Image (output, does not need to be initialized). In case the - MITK image does not have the same type as the ITK image it will be casted + MITK image does not have the same type as the ITK image it will be casted (if possible; done via itk::CastImageFilter). Thus, mitk::CastToItkImage is the more powerful variant: here it is sufficient that you know what you want to have (the ITK data type), to which the MITK image will be casted, if needed. \subsection MitkToUnkownItk Accessing an MITK image as an ITK image (type unkown) If you do not know the pixel type/dimension of an MITK image in advance and the ITK image should have the same (unkown) type, e.g., to run a filter on the MITK image data, we cannot really convert to one ITK image. This is simply, because we cannot instantiate an itk::Image object with unkown pixel type/dimension. Nevertheless, MITK provides a way to access an MITK image as if it was an ITK image of unkown type. To do so, first define an access method, which is templated as an ITK image is: \code template MyAccessMethod(itk::Image* itkImage) { ... } \endcode If you don't understand this template syntax, we need to refer you to an C++ text book. Understanding template syntax is crucial to successfully using ITK. To call this templated method with an (untemplated) mitk::Image, you can use the #AccessByItk macro (or one of its variants) from mitkImageAccessByItk.h. This macro checks for the actual image type of the mitk::Image and does any neccessary conversions. This works for all configured pixel types (default is char, unsigned char, short, unsigned short, int, unsigned int, float, and double) and dimensions (default is 2 and 3). You can change the considered default pixel types and dimensions by modifying the CMake variables MITK_ACCESSBYITK_*. \code AccessByItk(mitkImage, MyAccessMethod) \endcode An example is given in \ref Step6Page. The AccessBy... macros create quite a lot of code: the user defined access method has to be compiled for all considered pixel types \em times the supported dimensions (default is 2 and 3). Therefore, depending on the complexity of the access method, some compilers may run into problems with memory. One workaround is to use explicit instantiation and distribute it on multiple files. The macro #InstantiateAccessFunction and its variants are for this purpose. An example is again given in \ref Step6Page. Another workaround is to reduce the created code by fixing either the type (#AccessFixedTypeByItk) or dimension (#AccessFixedDimensionByItk). There is one variant of AccessByItk... for passing additional parameters to the access-function, called #AccessFixedTypeByItk_n. \link mitkImage.h \endlink \link mitkImageCast.h \endlink \link mitkImageToItk.h \endlink \link mitkITKImageImport.h \endlink \section ItkToMitk ITK to MITK adaptors Converting ITK images to MITK is easier than the other way round. Basically, you have three options: \li mitk::ITKImageImport: is a process class that takes an itk::Image of the given type \a TOutputImage as input and produces an mitk::Image as output (to be accessed using \a GetOutput()). The image data contained in the itk::Image is referenced, not copied. \li mitk::ImportItkImage: this function takes the itk::Image as input and returns an mitk::Image. Internally, it uses the class just described. So again, the image data contained in the itk::Image is referenced, not copied. \li mitk::CastToMitkImage: this function has two parameters, the itk::Image (input) and a smartpointer to an mitk::Image (output, does not need to be initialized). In contrast to the other described methods, this function copies the image data! \section ItkToMitkCoordinateSystems ITK image vs MITK coordinate systems Converting coordinates from the ITK physical coordinate system (which does not support rotated images) to the MITK world coordinate system should be performed via the Geometry3D of the Image, see mitk::Geometry3D::WorldToItkPhysicalPoint. \section ModuleAdaptorLimitations Limitations The \ref MitkToItk for unspecified types have to do type multiplexing at compile time. This is done for a limited number of pixel types and dimensions, defined during the CMake configuration process. Especially, color image types are not multiplexed. This is because many algorithms do not support color images (e.g. with data type itk::RGBPixel) because they do not have a scalar data type. If your algorithm do support color and you want to multiplex over all scalar as well as the color data type, try the following: \code try { AccessFixedPixelTypeByItk(myMitkImageThatMaybeColor, // The MITK image which may be a color image myAlgorithmFunction, // The template method being able to handle color MITK_ACCESSBYITK_PIXEL_TYPES_SEQ // The default pixel type sequence (itk::RGBPixel) // The additional type sequence ) } catch(const mitk::AccessByItkException& e) { // add error handling here } \endcode */ } diff --git a/Documentation/Doxygen/Modules/ModuleGeometry.dox b/Documentation/Doxygen/API/Groups/ModuleGeometry.dox similarity index 97% rename from Documentation/Doxygen/Modules/ModuleGeometry.dox rename to Documentation/Doxygen/API/Groups/ModuleGeometry.dox index 212dd043a4..aa6ca16d8f 100644 --- a/Documentation/Doxygen/Modules/ModuleGeometry.dox +++ b/Documentation/Doxygen/API/Groups/ModuleGeometry.dox @@ -1,47 +1,47 @@ namespace mitk { /** \defgroup Geometry Geometry Classes \ingroup DataManagement -\brief This subcategory includes the geometry classes, which describe the geometry of the +\brief This subcategory includes the geometry classes, which describe the geometry of the data in space and time. The Geometry3D class holds (see figure) \li a bounding box which is axes-parallel in intrinsic coordinates (often integer indices of pixels), to be accessed by Geometry3D::GetBoundingBox() \li a transform to convert intrinsic coordinates into a world-coordinate system with coordinates in millimeters and milliseconds (floating point values), to be accessed by Geometry3D::GetIndexToWorldTransform() \li a life span, i.e. a bounding box in time in ms (with start and end time), to be accessed by Geometry3D::GetTimeBounds(). The default is minus infinity to plus infinity. \image html ModuleGeometryFig1.png "Geometry: Bounding box and transform" Geometry3D and its sub-classes allow converting between intrinsic coordinates (called index or unit coordinates) and word-coordinates (called world or mm coordinates), e.g. Geometry3D::WorldToIndex. Every data object (sub-)class of BaseData has a Geometry3D, to be more specific, a TimeSlicedGeometry, to be accessed by BaseData::Get TimeSlicedGeometry(). This is because data objects are objects in space and time. The data values are often stored in intrinsic coordinates, e.g., integer pixel/voxel or time indices. The information required to convert these intrinsic coordinates into a physical world coordinate system, with coordinates in millimeters and milliseconds, is stored in Geometry3D class and its sub-classes. -TimeSlicedGeometry describes a geometry consisting of several geometries which exist at different times. It contains a list of Geometry3D instances to be accessed by TimeSlicedGeometry::GetGeometry3D(t), with t between 0 and TimeSlicedGeometry::GetTimeSteps().To convert between world-time in milliseconds and the integer timestep-number use mitk:TimeSlicedGeometry:: MSToTimeStep, for conversion in the opposite direction mitk:TimeSlicedGeometry:: TimeStepToMS. +TimeSlicedGeometry describes a geometry consisting of several geometries which exist at different times. It contains a list of Geometry3D instances to be accessed by TimeSlicedGeometry::GetGeometry3D(t), with t between 0 and TimeSlicedGeometry::GetTimeSteps().To convert between world-time in milliseconds and the integer timestep-number use mitk:TimeSlicedGeometry:: MSToTimeStep, for conversion in the opposite direction mitk:TimeSlicedGeometry:: TimeStepToMS. Often all Geometry3D instances contained in a TimeSlicedGeometry have the same duration of life. The initialization for this case can be done using TimeSlicedGeometry::InitializeEvenlyTimed(Geometry3D *geometry3D, unsigned int timeSteps). The Geometry3D parameter must have a limited life span set by Geometry3D::SetTimeBounds(). It is used as the first Geometry3D contained in the TimeSlicedGeometry (thus returned by TimeSlicedGeometry:: GetGeometry3D(0)). The next one will start to live immediately at the end of life of the first. The bounding boxes and transformations are copied. The instance of Geometry3D provided to TimeSlicedGeometry::InitializeEvenlyTimed is referenced, not copied! -TimeSlicedGeometry is a Geometry3D itself. Its bounding box and transformation is usually the same as the bounding box and transformations of the contained Geometry3D instances. Its life span (to be accessed by TimeSlicedGeometry::GetTimeBounds()) is the span from the beginning of the first contained Geometry3D to the end of the last contained Geometry3D. +TimeSlicedGeometry is a Geometry3D itself. Its bounding box and transformation is usually the same as the bounding box and transformations of the contained Geometry3D instances. Its life span (to be accessed by TimeSlicedGeometry::GetTimeBounds()) is the span from the beginning of the first contained Geometry3D to the end of the last contained Geometry3D. TimeSlicedGeometry can also contain Geometry3D instances that do not have the same bounding box and transformation. In this case, TimeSlicedGeometry::GetEvenlyTimed() has to be \a false. SlicedGeometry3D is a sub-class of Geometry3D, which descibes data objects consisting of slices, e.g., objects of type Image (or SlicedData, which is the super-class of Image). Therefore, Image::Get TimeSlicedGeometry() will contain a list of SlicedGeometry3D instances. There is a special method SlicedData::GetSlicedGeometry(t) which directly returns a SlicedGeometry3D to avoid the need of casting. Geometry instances referring to images need a slightly different definition of corners, see Geometry3D::SetImageGeometry. This is usualy automatically called by Image. -Comparable to TimeSlicedGeometry the class SlicedGeometry3D contains a list of Geometry2D objects describing the slices in the data object. Instead of time steps we have spatial steps here from 0 to GetSlices(). SlicedGeometry3D::InitializeEvenlySpaced (Geometry2D *geometry2D, unsigned int slices) initializes a stack of slices with the same thickness, one starting at the position where the previous one ends. +Comparable to TimeSlicedGeometry the class SlicedGeometry3D contains a list of Geometry2D objects describing the slices in the data object. Instead of time steps we have spatial steps here from 0 to GetSlices(). SlicedGeometry3D::InitializeEvenlySpaced (Geometry2D *geometry2D, unsigned int slices) initializes a stack of slices with the same thickness, one starting at the position where the previous one ends. Geometry2D provides methods for working with 2D manifolds (i.e., simply spoken, an object that can be described using a 2D coordinate-system) in 3D space. For example it allows mapping a 3D point on the 2D manifold using Geometry2D::Map. The most important sub-class is PlaneGeometry2D, which describes a planar rectangle. \section ExampleForImage Putting it together for Image Image has a TimeSlicedGeometry, which contains one or more SlicedGeometry3D instances (one for each time step), all of which contain one or more instances of (sub-classes of) Geometry2D (usually PlaneGeometry2D). \deprecated For ITK rev. 3.8 and earlier: Converting coordinates from the ITK physical coordinate system (which did not support rotated images for ITK v3.8 and earlier) to the MITK world coordinate system should be performed via the Geometry3D of the Image, see Geometry3D::WorldToItkPhysicalPoint. As a reminder: Geometry instances referring to images need a slightly different definition of corners, see Geometry3D::SetImageGeometry. This is usualy automatically called by Image. */ //\f$-\infty\f$ to \f$+\infty\f$. } diff --git a/Documentation/Doxygen/Modules/ModuleGeometryFig1.png b/Documentation/Doxygen/API/Groups/ModuleGeometryFig1.png similarity index 100% rename from Documentation/Doxygen/Modules/ModuleGeometryFig1.png rename to Documentation/Doxygen/API/Groups/ModuleGeometryFig1.png diff --git a/Documentation/Doxygen/Modules/ModuleMicroServices.dox b/Documentation/Doxygen/API/Groups/ModuleMicroServices.dox similarity index 99% rename from Documentation/Doxygen/Modules/ModuleMicroServices.dox rename to Documentation/Doxygen/API/Groups/ModuleMicroServices.dox index e3e6869d38..0e5d618203 100644 --- a/Documentation/Doxygen/Modules/ModuleMicroServices.dox +++ b/Documentation/Doxygen/API/Groups/ModuleMicroServices.dox @@ -1,30 +1,29 @@ /** \addtogroup MicroServices \ingroup Core */ /** \addtogroup MicroServicesUtils \ingroup Core */ /** \defgroup MicroServices_Interfaces Micro Services Interfaces \ingroup Core \brief Classes (interfaces) in this category are explicitely designed for usage with the MITK Micro Services. All classes in this category are structs with no non-static members and only pure virtual functions (except for an inlined virtual destructor). Such a class will be called a \e interface. These interfaces are meant to be implemented by MITK module developers to enhance or overwrite certain aspects of the MITK toolkit. All implementations must be registered in the implementing module's \e activator (see mitk::ModuleActivator) using the module's mitk::ModuleContext instance. */ - diff --git a/Documentation/Doxygen/Modules/ModuleVisualization.dox b/Documentation/Doxygen/API/Groups/ModuleVisualization.dox similarity index 80% rename from Documentation/Doxygen/Modules/ModuleVisualization.dox rename to Documentation/Doxygen/API/Groups/ModuleVisualization.dox index b63b43f940..72fb312d85 100644 --- a/Documentation/Doxygen/Modules/ModuleVisualization.dox +++ b/Documentation/Doxygen/API/Groups/ModuleVisualization.dox @@ -1,45 +1,45 @@ /** \defgroup Visualization Visualization and Visualization Organization Classes \ingroup Core -\brief This category includes renderwindows (currently one for OpenGL), renderers (currently only one, +\brief This category includes renderwindows (currently one for OpenGL), renderers (currently only one, for OpenGL-based renderwindows), mappers and classes for navigating in the data. \section overviewVisualization Rationale and overview -Mappers visualize data objects of a specific classes by creating rendering primitives that -interface to the graphics library (e.g., OpenGL, vtk). -Renderers organize the rendering process. A Renderer contains a reference to a (sub-) data tree +Mappers visualize data objects of a specific classes by creating rendering primitives that +interface to the graphics library (e.g., OpenGL, vtk). +Renderers organize the rendering process. A Renderer contains a reference to a (sub-) data tree and asks the mappers of the data objects to render the data into the renderwindow it is associated to. -More details can be found in the section on \ref Rendering. +More details can be found in the section on \ref Rendering. -\subsection inthisgroupVisualization What belongs into this group +\subsection inthisgroupVisualization What belongs into this group \section implementVisualization Practical issues -\section futureVisualization Plans for the future +\section futureVisualization Plans for the future - Abort mechanism - level-of-detail rendering mechanism - allow multiple renderers per renderwindow -- modified detection mechanism: +- modified detection mechanism: - allow to detect whether a modification of data/property/dislaygeometry /camera requires to re-render. E.g., mark whether a property effects the rendering. - analyze which type of modification requires which kind of action, e.g.: - if the displaygeometry or the color has changed, we do not need to - resample an image, but we do need to redraw. The first step is to + if the displaygeometry or the color has changed, we do not need to + resample an image, but we do need to redraw. The first step is to analyze which types of modifications (e.g., displaygeometry changed, properties changed; can we group these?) and actions exist. -- improved design of navigation controllers, probably more focused on +- improved design of navigation controllers, probably more focused on steppers (then on BaseController). Have in mind: - rotatable slices - - dependent views: e.g., sequence of renderers showing series of - consecutive slices (maybe realized as master stepper and + - dependent views: e.g., sequence of renderers showing series of + consecutive slices (maybe realized as master stepper and dependent offset steppers) - consider time vs. slice stepping - use stepper mechanism for additional purposes, e.g., for animating transfer functions */ diff --git a/Documentation/Doxygen/Modules/ModuleVisualizationMapper.dox b/Documentation/Doxygen/API/Groups/ModuleVisualizationMapper.dox similarity index 98% rename from Documentation/Doxygen/Modules/ModuleVisualizationMapper.dox rename to Documentation/Doxygen/API/Groups/ModuleVisualizationMapper.dox index a7a9dc1a2f..8f6a285c77 100644 --- a/Documentation/Doxygen/Modules/ModuleVisualizationMapper.dox +++ b/Documentation/Doxygen/API/Groups/ModuleVisualizationMapper.dox @@ -1,25 +1,25 @@ /** \defgroup Mapper Mapper Classes \ingroup Visualization \brief In the MITK rendering concept, Mappers are responsible for actually rendering data onto the screen. \section overviewVisualizationMapper Overview Mappers differ in the type of data they are capable of rendering (e.g. volume data, polygonal data) and the mode of how data is rendered (e.g. 2D or 3D). For example, the ImageMapperGL2D renders volume data in a 2D view, i.e. it extracts a slice of the volume (as determined by the Geometry of the associated Renderer) and displays it as a 2D plane. All Mapper classes are arranged in a class hierarchy according to these criterions. \section integrationVisualizationMapper Integration into the rendering process Mapper objects are owned by the DataNode which contains the data they have to render. An overview over this composition is given in the section \ref Renderer. Each DataNode can have (and usually has) multiple Mappers attached, each responsible for different modes of rendering. In most cases this would be one 2D Mapper and one 3D Mapper, but other Mappers are possible, too. -Which Mapper of a DataNode to use is determined by an ID; the Renderer of a 2D window would for example ask the DataNode to return an appropriate 2D Mapper. +Which Mapper of a DataNode to use is determined by an ID; the Renderer of a 2D window would for example ask the DataNode to return an appropriate 2D Mapper. More details can be found in the section on \ref Rendering. \section todoVisualizationMapper Future plans The need to Update() a Mapper can be justified by property changes in the associated data items. However, property changes are not uniformly taken into account when deciding on whether to execute Update() or not. The changes are data specific and difficult to generalize. As an effect, many Update() calls are not really necessary and might slow down the rendering process significantly. One solution to this problem might be a mechanism which allows Mappers to register themselves to relevant data properties, so as to be notified whenever a change occurs. If no modification did occur since the last Update(), and the data itself has remained unchanged, no re-initialization (of the rendering pipeline for example) needs to be performed. */ diff --git a/Documentation/Doxygen/Modules/ModuleVisualizationNavigationControl.dox b/Documentation/Doxygen/API/Groups/ModuleVisualizationNavigationControl.dox similarity index 87% rename from Documentation/Doxygen/Modules/ModuleVisualizationNavigationControl.dox rename to Documentation/Doxygen/API/Groups/ModuleVisualizationNavigationControl.dox index 8543bfbee3..5e6a5b828a 100644 --- a/Documentation/Doxygen/Modules/ModuleVisualizationNavigationControl.dox +++ b/Documentation/Doxygen/API/Groups/ModuleVisualizationNavigationControl.dox @@ -1,15 +1,15 @@ /** \defgroup NavigationControl Navigation Control Classes \ingroup Visualization -\brief The classes in this category tell the render (subclass of mitk::BaseRenderer) which +\brief The classes in this category tell the render (subclass of mitk::BaseRenderer) which slice (subclass mitk::SliceNavigationController) or from which direction (subclass mitk::CameraController) it has to render. -Contains two Stepper for stepping through the slices or through different camera views (e.g., +Contains two Stepper for stepping through the slices or through different camera views (e.g., for the creation of a movie around the data), respectively, and through time, if there is 3D+t data. */ \ No newline at end of file diff --git a/Documentation/Doxygen/Modules/ModuleVisualizationRenderer.dox b/Documentation/Doxygen/API/Groups/ModuleVisualizationRenderer.dox similarity index 99% rename from Documentation/Doxygen/Modules/ModuleVisualizationRenderer.dox rename to Documentation/Doxygen/API/Groups/ModuleVisualizationRenderer.dox index ade1036bad..e1e2428197 100644 --- a/Documentation/Doxygen/Modules/ModuleVisualizationRenderer.dox +++ b/Documentation/Doxygen/API/Groups/ModuleVisualizationRenderer.dox @@ -1,42 +1,42 @@ /** \defgroup Renderer Renderer and RenderWindow Classes \ingroup Visualization \brief The MITK rendering model resembles the mechisms found in VTK. This section describes the core components for coordinating rendering processes and render windows. \section overviewVisualizationRenderer Overview To visualize a dataset it needs to be stored in the DataTree. Depending on the application, the whole DataTree may be displayed, or merely parts of it. The rendering of individual data items (e.g. volumes or polygon models) is conducted by specific Mappers: each kind of visualizable data has its own corresponding Mapper implementation (see \ref Mapper). MITK is designed to intrinsically provide different views on data. For example, a volume dataset is volume rendered in a 3D view, and displayed slice-wise in a 2D view. A polygon model would be displayed as a contour in 2D (i.e., the intersection of the 3D model and the respective 2D plane). This principle applies to all kinds of data, thereby ensuring a consistent visual representation regardless of the view type. It is realized by providing Mappers for each combination of data type and view type. Every item of the DataTree is associated with a list of Mappers, each capable of rendering the data item in a specific view. RenderWindows represent the rendering target: an area of the user interface into which data is rendered. The actual rendering process is controlled by Renderers, specifically by mitkVtkPropRenderer, which is a concrete implementation BaseRenderer and iterates over the elements of the DataTree to render each using the associated Mapper. Eeach data item of the DataTree has Geometry objects attached to it which describe the geometry of the data (e.g. its bounding box, location, or spatial conversion hints). \section vtkVisualizationRenderer Encapsulating VTK Rendering Mechanisms As a framework, MITK aims at making use of the visualization capabilities of VTK as much as possible. For the application developer building on top of MITK, the way of how to utilize specific VTK features should be straightforward and familiar. Therefore, most of the MITK rendering components closely resemble or integrate corresponding VTK components. Just like VTK, MITK defines Renderers and Mappers. These classes do not derive from their VTK counterparts, but integrate them and have similar scopes of responsibility. While the VTK rendering mechanism is mainly focused on establishing a pipeline of rendering components (data, filters, mappers, and renderers), MITK has a central DataTree and provides convenient ways of rendering different items of the tree according to their type. Internally, the VTK rendering pipeline is used, though it is more hidden from the application developer who merely makes use of existing rendering capabilities. As of MITK 0.8, the class vtkMitkRenderProp (a derivation of vtkProp) represents the single prop object in the VTK rendering pipeline responsible for coordinating the rendering of all objects in MITK's DataTree. The advantage of this approach is that all rendering management is done in the usual VTK rendering pipeline style, while the control of how data is actually rendered is entirely on MITK side. For example, MITK Mapper classes may either use VTK classes for rendering (actors, properties, ...), or do their rendering entirely in OpenGL where appropriate (e.g. in 2D Mapper classes). For further details refer to the page \ref Rendering. \section renderingManagerVisualizationRenderer Controlling it All: RenderingManager On a higher level, all rendering in MITK is managed and supervised by the RenderingManager. Its main task is to provide a central instance where any part of the application can request a repaint of a particular RenderWindow. Thereby, requests can be issued from multiple independent subroutines at one time, and only result in one repainting call, rather than induce many unnecessary rendering passes. Another task is the supervision of ongoing rendering activities. For large datasets, high quality rendering might become very slow and thus impede smooth user interactions. To alleviate this, level-of-detail rendering and abort-mechanisms are introduced and controlled by the RenderingManager to achieve interactive frame rate and response times. Note that these features are not yet available but currently under development. The rendering process could be further simplified by making the DataTree automatically detect data changes that require the data to be re-drawn. The fundamentals for such a mechanism already exist but still for many modifications a repainting request has to be issued by the entity causing it. \section implementationManagerVisualizationRenderer Platform-Specific Implementation -MITK tries to integrate seamlessly into the normal VTK rendering pipeline. The whole MITK data(tree) is capsuled into one customized vtkProp, the so-called vtkMitkRenderProp which is then integrated into VTK pipeline. +MITK tries to integrate seamlessly into the normal VTK rendering pipeline. The whole MITK data(tree) is capsuled into one customized vtkProp, the so-called vtkMitkRenderProp which is then integrated into VTK pipeline. The VTK integration into GUI systems, like e.g. QT, is therefore equal to normal VTK usage. As an example, the MITK MainApp requires the QT-VTK widget (provided by VTK) for integration of renderWindows into GUI. Further information on this can be found in section "Related Pages" "Rendering in MITK by means of the QT-VTK widget". */ \ No newline at end of file diff --git a/Documentation/Doxygen/Modules/Modules.dox b/Documentation/Doxygen/API/Groups/Modules.dox similarity index 100% rename from Documentation/Doxygen/Modules/Modules.dox rename to Documentation/Doxygen/API/Groups/Modules.dox diff --git a/Documentation/Doxygen/Modules/RenderingSequence.png b/Documentation/Doxygen/API/Groups/RenderingSequence.png similarity index 100% rename from Documentation/Doxygen/Modules/RenderingSequence.png rename to Documentation/Doxygen/API/Groups/RenderingSequence.png diff --git a/Documentation/Doxygen/Modules/RenderingSequence.vsd b/Documentation/Doxygen/API/Groups/RenderingSequence.vsd similarity index 100% rename from Documentation/Doxygen/Modules/RenderingSequence.vsd rename to Documentation/Doxygen/API/Groups/RenderingSequence.vsd diff --git a/Documentation/Doxygen/Modules/dialogbarSlicer.png b/Documentation/Doxygen/API/Groups/dialogbarSlicer.png similarity index 100% rename from Documentation/Doxygen/Modules/dialogbarSlicer.png rename to Documentation/Doxygen/API/Groups/dialogbarSlicer.png diff --git a/Documentation/Doxygen/Modules/dialogbarStandardViews.png b/Documentation/Doxygen/API/Groups/dialogbarStandardViews.png similarity index 100% rename from Documentation/Doxygen/Modules/dialogbarStandardViews.png rename to Documentation/Doxygen/API/Groups/dialogbarStandardViews.png diff --git a/Documentation/Doxygen/Modules/dialogbarStereoOptions.png b/Documentation/Doxygen/API/Groups/dialogbarStereoOptions.png similarity index 100% rename from Documentation/Doxygen/Modules/dialogbarStereoOptions.png rename to Documentation/Doxygen/API/Groups/dialogbarStereoOptions.png diff --git a/Documentation/Doxygen/Modules/dialogbarbuttons.png b/Documentation/Doxygen/API/Groups/dialogbarbuttons.png similarity index 100% rename from Documentation/Doxygen/Modules/dialogbarbuttons.png rename to Documentation/Doxygen/API/Groups/dialogbarbuttons.png diff --git a/Documentation/Doxygen/Modules/functionalityButtons.png b/Documentation/Doxygen/API/Groups/functionalityButtons.png similarity index 100% rename from Documentation/Doxygen/Modules/functionalityButtons.png rename to Documentation/Doxygen/API/Groups/functionalityButtons.png diff --git a/Documentation/Doxygen/Modules/renderwindowOptions.png b/Documentation/Doxygen/API/Groups/renderwindowOptions.png similarity index 100% rename from Documentation/Doxygen/Modules/renderwindowOptions.png rename to Documentation/Doxygen/API/Groups/renderwindowOptions.png diff --git a/Documentation/Doxygen/Modules/renderwindows.png b/Documentation/Doxygen/API/Groups/renderwindows.png similarity index 100% rename from Documentation/Doxygen/Modules/renderwindows.png rename to Documentation/Doxygen/API/Groups/renderwindows.png diff --git a/Documentation/Doxygen/Modules/undoredobutton.png b/Documentation/Doxygen/API/Groups/undoredobutton.png similarity index 100% rename from Documentation/Doxygen/Modules/undoredobutton.png rename to Documentation/Doxygen/API/Groups/undoredobutton.png diff --git a/Documentation/Doxygen/BlueBerry/BlueBerryExampleLauncherDialog.png b/Documentation/Doxygen/DeveloperManual/Application/BlueBerry/BlueBerryExampleLauncherDialog.png similarity index 100% rename from Documentation/Doxygen/BlueBerry/BlueBerryExampleLauncherDialog.png rename to Documentation/Doxygen/DeveloperManual/Application/BlueBerry/BlueBerryExampleLauncherDialog.png diff --git a/Documentation/Doxygen/BlueBerry/BlueBerryExamples.dox b/Documentation/Doxygen/DeveloperManual/Application/BlueBerry/BlueBerryExamples.dox similarity index 100% rename from Documentation/Doxygen/BlueBerry/BlueBerryExamples.dox rename to Documentation/Doxygen/DeveloperManual/Application/BlueBerry/BlueBerryExamples.dox diff --git a/Documentation/Doxygen/BlueBerry/BlueBerryExtensionPointsIntro.dox b/Documentation/Doxygen/DeveloperManual/Application/BlueBerry/BlueBerryExtensionPointsIntro.dox similarity index 100% rename from Documentation/Doxygen/BlueBerry/BlueBerryExtensionPointsIntro.dox rename to Documentation/Doxygen/DeveloperManual/Application/BlueBerry/BlueBerryExtensionPointsIntro.dox diff --git a/Documentation/Doxygen/BlueBerry/BlueBerryIntro.dox b/Documentation/Doxygen/DeveloperManual/Application/BlueBerry/BlueBerryIntro.dox similarity index 100% rename from Documentation/Doxygen/BlueBerry/BlueBerryIntro.dox rename to Documentation/Doxygen/DeveloperManual/Application/BlueBerry/BlueBerryIntro.dox diff --git a/Documentation/Doxygen/BlueBerry/BlueBerrySelectionServiceIntro.dox b/Documentation/Doxygen/DeveloperManual/Application/BlueBerry/BlueBerrySelectionServiceIntro.dox similarity index 100% rename from Documentation/Doxygen/BlueBerry/BlueBerrySelectionServiceIntro.dox rename to Documentation/Doxygen/DeveloperManual/Application/BlueBerry/BlueBerrySelectionServiceIntro.dox diff --git a/Documentation/Doxygen/BlueBerry/ExtensionPointEx.png b/Documentation/Doxygen/DeveloperManual/Application/BlueBerry/ExtensionPointEx.png similarity index 100% rename from Documentation/Doxygen/BlueBerry/ExtensionPointEx.png rename to Documentation/Doxygen/DeveloperManual/Application/BlueBerry/ExtensionPointEx.png diff --git a/Documentation/Doxygen/BlueBerry/ExtensionPoints.png b/Documentation/Doxygen/DeveloperManual/Application/BlueBerry/ExtensionPoints.png similarity index 100% rename from Documentation/Doxygen/BlueBerry/ExtensionPoints.png rename to Documentation/Doxygen/DeveloperManual/Application/BlueBerry/ExtensionPoints.png diff --git a/Documentation/Doxygen/BlueBerry/MitkSelectionService.png b/Documentation/Doxygen/DeveloperManual/Application/BlueBerry/MitkSelectionService.png similarity index 100% rename from Documentation/Doxygen/BlueBerry/MitkSelectionService.png rename to Documentation/Doxygen/DeveloperManual/Application/BlueBerry/MitkSelectionService.png diff --git a/Documentation/Doxygen/BlueBerry/SelectionServiceDiagram.png b/Documentation/Doxygen/DeveloperManual/Application/BlueBerry/SelectionServiceDiagram.png similarity index 100% rename from Documentation/Doxygen/BlueBerry/SelectionServiceDiagram.png rename to Documentation/Doxygen/DeveloperManual/Application/BlueBerry/SelectionServiceDiagram.png diff --git a/Documentation/Doxygen/BlueBerry/SelectionServiceDiagram.xcf b/Documentation/Doxygen/DeveloperManual/Application/BlueBerry/SelectionServiceDiagram.xcf similarity index 100% rename from Documentation/Doxygen/BlueBerry/SelectionServiceDiagram.xcf rename to Documentation/Doxygen/DeveloperManual/Application/BlueBerry/SelectionServiceDiagram.xcf diff --git a/Documentation/Doxygen/BlueBerry/application-window.jpg b/Documentation/Doxygen/DeveloperManual/Application/BlueBerry/application-window.jpg similarity index 100% rename from Documentation/Doxygen/BlueBerry/application-window.jpg rename to Documentation/Doxygen/DeveloperManual/Application/BlueBerry/application-window.jpg diff --git a/Documentation/Doxygen/BlueBerry/workbench-class-diagram.jpg b/Documentation/Doxygen/DeveloperManual/Application/BlueBerry/workbench-class-diagram.jpg similarity index 100% rename from Documentation/Doxygen/BlueBerry/workbench-class-diagram.jpg rename to Documentation/Doxygen/DeveloperManual/Application/BlueBerry/workbench-class-diagram.jpg diff --git a/Documentation/Doxygen/BlueBerry/workbench-page.jpg b/Documentation/Doxygen/DeveloperManual/Application/BlueBerry/workbench-page.jpg similarity index 100% rename from Documentation/Doxygen/BlueBerry/workbench-page.jpg rename to Documentation/Doxygen/DeveloperManual/Application/BlueBerry/workbench-page.jpg diff --git a/Documentation/Doxygen/BlueBerry/workbench-window-editor-area.png b/Documentation/Doxygen/DeveloperManual/Application/BlueBerry/workbench-window-editor-area.png similarity index 100% rename from Documentation/Doxygen/BlueBerry/workbench-window-editor-area.png rename to Documentation/Doxygen/DeveloperManual/Application/BlueBerry/workbench-window-editor-area.png diff --git a/Documentation/Doxygen/BlueBerry/workbench-window-editor-area.xcf b/Documentation/Doxygen/DeveloperManual/Application/BlueBerry/workbench-window-editor-area.xcf similarity index 100% rename from Documentation/Doxygen/BlueBerry/workbench-window-editor-area.xcf rename to Documentation/Doxygen/DeveloperManual/Application/BlueBerry/workbench-window-editor-area.xcf diff --git a/Documentation/Doxygen/BlueBerry/workbench-window-perspective.png b/Documentation/Doxygen/DeveloperManual/Application/BlueBerry/workbench-window-perspective.png similarity index 100% rename from Documentation/Doxygen/BlueBerry/workbench-window-perspective.png rename to Documentation/Doxygen/DeveloperManual/Application/BlueBerry/workbench-window-perspective.png diff --git a/Documentation/Doxygen/BlueBerry/workbench-window-perspective.xcf b/Documentation/Doxygen/DeveloperManual/Application/BlueBerry/workbench-window-perspective.xcf similarity index 100% rename from Documentation/Doxygen/BlueBerry/workbench-window-perspective.xcf rename to Documentation/Doxygen/DeveloperManual/Application/BlueBerry/workbench-window-perspective.xcf diff --git a/Documentation/Doxygen/BlueBerry/workbench-window-views.png b/Documentation/Doxygen/DeveloperManual/Application/BlueBerry/workbench-window-views.png similarity index 100% rename from Documentation/Doxygen/BlueBerry/workbench-window-views.png rename to Documentation/Doxygen/DeveloperManual/Application/BlueBerry/workbench-window-views.png diff --git a/Documentation/Doxygen/BlueBerry/workbench-window-views.xcf b/Documentation/Doxygen/DeveloperManual/Application/BlueBerry/workbench-window-views.xcf similarity index 100% rename from Documentation/Doxygen/BlueBerry/workbench-window-views.xcf rename to Documentation/Doxygen/DeveloperManual/Application/BlueBerry/workbench-window-views.xcf diff --git a/Documentation/Doxygen/BlueBerry/workbench-window.jpg b/Documentation/Doxygen/DeveloperManual/Application/BlueBerry/workbench-window.jpg similarity index 100% rename from Documentation/Doxygen/BlueBerry/workbench-window.jpg rename to Documentation/Doxygen/DeveloperManual/Application/BlueBerry/workbench-window.jpg diff --git a/Documentation/Doxygen/BlueBerry/workbench.jpg b/Documentation/Doxygen/DeveloperManual/Application/BlueBerry/workbench.jpg similarity index 100% rename from Documentation/Doxygen/BlueBerry/workbench.jpg rename to Documentation/Doxygen/DeveloperManual/Application/BlueBerry/workbench.jpg diff --git a/Documentation/Doxygen/DeveloperManual/Deployment.dox b/Documentation/Doxygen/DeveloperManual/Application/Deployment.dox similarity index 98% rename from Documentation/Doxygen/DeveloperManual/Deployment.dox rename to Documentation/Doxygen/DeveloperManual/Application/Deployment.dox index ea81e022c7..71408502a3 100644 --- a/Documentation/Doxygen/DeveloperManual/Deployment.dox +++ b/Documentation/Doxygen/DeveloperManual/Application/Deployment.dox @@ -1,46 +1,46 @@ /** -\page DeploymentPage Deployment +\page DeploymentPage Deploying MITK \section DeploymentPageIntroduction Introduction
  • easily create portable or installable versions of your MITK-based applications.
  • created packages include all MITK and 3rd party libraries necessary for running the application on other systems
  • distribute your binary application to other people without giving them your source code or putting them in the need for setting up a development environment themselves, eg for evaluation of your tool.
\note This does not install the MITK headers (like an SDK). If you want to develop applications based on MITK you still have to compile MITK yourself. \section DeploymentPagePlatform Platform specific notes \subsection DeploymentPagePlatformLinux Linux You can create a tarball (.tar.gz) of your MITK application which includes all necessary non-system libraries by following these steps:
  • Set the %CMake Variable CMAKE_BUILD_TYPE to either "Debug" or "Release". Any other type (or leaving the variable empty) will not work.
  • If you are using third-pary libraries not shipped with MITK, you might need to add the paths to the third-party libs to your LD_LIBRARY_PATH environment variable (not necessary if you use RPATH in your shared libraries).
  • Type "make package" in your build-tree. This will create a tarball in your build-tree directory.
\note Libraries in system locations (/lib/, /lib32/, /lib64/, /usr/lib/, /usr/lib32/,/usr/lib64/, and /usr/X11R6/) will not be included in the tarball. If you want to distribute Qt (for example), you have to do a custom Qt installation outside of these directories. \subsection DeploymentPagePlatformWindows Windows You can create a Zip file (.zip) or an NSIS installer (needs an installation of NSIS) for Windows platforms. Only "Release" builds are supported during packaging, the results of trying to package "Debug" builds are undefined. \note Building installers based on MinGW is not supported.
  • In Visual Studio, build the "PACKAGE" project, this will create a .zip file and a .exe NSIS installer (if NSIS is installed).
On some systems, it might still be necessary to install the Microsoft Visual C++ Redistributable Package to start the installed application successfully. \subsection DeploymentPagePlatformMacOS MacOS You can create a drag'n drop disk image (.dmg) file for MacOS. The procedure is pretty much the same as for Linux. \note On MacOS, libraries in system locations as pointed out in the Linux section \b and libraries located in /System/Library will not be copied. If you want to distribute any libraries from these locations, you have to install them somewhere else prior to configuring your MITK build. */ \ No newline at end of file diff --git a/Documentation/Doxygen/DeveloperManual/Application/DevelopmentApplication.dox b/Documentation/Doxygen/DeveloperManual/Application/DevelopmentApplication.dox new file mode 100644 index 0000000000..1bcb321658 --- /dev/null +++ b/Documentation/Doxygen/DeveloperManual/Application/DevelopmentApplication.dox @@ -0,0 +1,16 @@ +/** + +\page DevelopmentApplication Developing with the MITK Application Framework + +MITK offers a powerful application featuring a plugin system and many predefined plugins. You can configure this application to offer a set of functionality to the user and easily create an installer. +Working with the application, you will have to learn about extension points and the Blueberry framework itself. If you are new to the matter, please also consult \ref Architecture and \ref FirstSteps. + +
    +
  • \subpage BlueBerryIntro
  • +
  • \subpage BlueBerryExamples
  • +
  • \subpage mitkExtPointsIndex
  • +
  • \subpage DeploymentPage
  • +
+ + +*/ diff --git a/Core/Documentation/Doxygen/extension-points/mitkExtPointsIndex.dox b/Documentation/Doxygen/DeveloperManual/Application/ExtensionPointReference.dox similarity index 100% rename from Core/Documentation/Doxygen/extension-points/mitkExtPointsIndex.dox rename to Documentation/Doxygen/DeveloperManual/Application/ExtensionPointReference.dox diff --git a/Documentation/Doxygen/DeveloperManual/DeveloperManualPortal.dox b/Documentation/Doxygen/DeveloperManual/DeveloperManualPortal.dox new file mode 100644 index 0000000000..ec44916cba --- /dev/null +++ b/Documentation/Doxygen/DeveloperManual/DeveloperManualPortal.dox @@ -0,0 +1,33 @@ +/** +\page DeveloperManualPortal MITK: Developer Manual + +Development with MITK can happen under several disctinct conditions. Depending on whether you are using the Toolkit or the entire application, different sections may apply to you. In case you are unsure about what you need, please refer to \link Architecture The Architecture of MITK text\endlink. An extensive Introduction to MITK is available under \link StartingDevelopment Starting your MITK Development\endlink. + +Depending on whether you are working with the \link DevelopmentToolkit Toolkit\endlink or the \link DevelopmentApplication Application\endlink, you can refer to their respective pages. Generated API-Documentation can be found \link DevelopmentAPI here\endlink. + +\section DeveloperManualStarting Starting your MITK Development + +
    +
  • \subpage StartingDevelopment
  • +
      +
    • \ref Architecture
    • +
    • \ref SettingUpMITK
    • +
    • \ref GettingToKnowMITK
    • +
    • \ref FirstSteps
    • +
    • \ref AboutTestingPage
    • +
    +
  • \subpage DevelopmentToolkit
  • +
      +
    • \ref Concepts
    • +
    • \ref MITKModuleManualsListPage
    • +
    +
  • \subpage DevelopmentApplication
  • +
      +
    • \ref mitkExtPointsIndex
    • +
    • \ref DeploymentPage
    • +
    • \ref BlueBerryExamples
    • +
    • \ref BlueBerryIntro
    • +
    +
+ +*/ diff --git a/Documentation/Doxygen/DeveloperManual/Development.dox b/Documentation/Doxygen/DeveloperManual/Development.dox deleted file mode 100644 index 5e1997f33c..0000000000 --- a/Documentation/Doxygen/DeveloperManual/Development.dox +++ /dev/null @@ -1,50 +0,0 @@ -/** -\page Development Development with MITK - -The following items are concerned with the practical use of the MITK library for software development. - -Some abstract concepts of MITK are described in \ref Concepts - -\section DevelopmentSetup Setting Up MITK - -\li \subpage SupportedPlatformsPage -\li \subpage BuildInstructionsPage -\li \subpage thirdpartylibs -\li \ref HowToNewProject - -\section DevelopmentGettingToKnow Getting To Know MITK - -\li \subpage DirectoryStructurePage -\li \subpage TutorialPage - -\section DevelopmentWith Developing With MITK - -\li \subpage CMAKE_FAQ -\li \subpage DICOMTesting -\li \subpage NewPluginPage -\li \subpage StatemachineEditor -\li \subpage mitkExtPointsIndex -\li \subpage DeploymentPage -\li \subpage KnownProblemsPage - -\section DevelopmentContributing Contributing To MITK - -\li \subpage DocumentationGuide -\li \subpage StyleGuideAndNotesPage - -\section DevelopmentGettingToKnowBlueberry Getting To Know BlueBerry - -\li \subpage BlueBerryExamples - -\section DevelopmentFurtherInfo Further Information - -This section lists some ressources you might want to look at if you could not find what you need in -the \ref Development or \ref Concepts sections. - -We hold regular internal seminars which may or may not have something to do with MITK directly. The slides can be found -here. - -If you have some problems with MITK you might want to take a look at the FAQ. - -If the above does not prove sufficient you can contact the Mailinglist. -*/ diff --git a/Documentation/Doxygen/DeveloperManual/Starting/AboutTesting/AboutTestingPage.dox b/Documentation/Doxygen/DeveloperManual/Starting/AboutTesting/AboutTestingPage.dox new file mode 100644 index 0000000000..a0231fc98d --- /dev/null +++ b/Documentation/Doxygen/DeveloperManual/Starting/AboutTesting/AboutTestingPage.dox @@ -0,0 +1,9 @@ +/** +\page AboutTestingPage Testing + +TODO +\subpage GeneralTests +\subpage RenderingTests +\subpage DICOMTesting + +*/ diff --git a/Core/Documentation/Doxygen/Concepts/Overview.dox b/Documentation/Doxygen/DeveloperManual/Starting/Architecture.dox similarity index 96% rename from Core/Documentation/Doxygen/Concepts/Overview.dox rename to Documentation/Doxygen/DeveloperManual/Starting/Architecture.dox index f5def8bb90..c1553fe018 100644 --- a/Core/Documentation/Doxygen/Concepts/Overview.dox +++ b/Documentation/Doxygen/DeveloperManual/Starting/Architecture.dox @@ -1,47 +1,47 @@ /** -\page OverviewPage Introduction: Overview on the Medical Imaging Interaction Toolkit (MITK) +\page Architecture The Architecture of MITK MITK is an open source software toolkit for medical image processing, subsequent data analysis and integration of medical hardware. It is designed with the aim of providing a modular and heavily reusable code base to enable rapid development of new features. Following this design philosophy MITK includes many different specialized modules e.g. the Segmentation Module. This document is aimed at giving an overview of the general structure of MITK. Furthermore it will give an introduction into the coding and design concepts behind this toolkit. \section OverviewPage_DesignOverview Design Overview MITK is designed to be used as a pure software library or as a complete application framework. Thus, a user of MITK can decide if he simply wants to add a new plug-in to the existing application framework or if he needs to implement his own application and wants to use MITK as a software library. Depending on the type of use MITK uses different software libraries, which is shown in the next figure for overview. \image html MitkOverview.png "Overview of MITK" Like shown above, MITK uses the following libraries. These are the main libraries MITK is based on. For further functionality you can optionally include others, a list can be found \ref thirdpartylibs "here" . Based on these libraries, MITK includes the following features:
  • High level interactions with data.
  • Specialized medical imaging algorithms (e.g. segmentation)
  • Support of 3D + t data.
  • Complete application framework, expandable by plug-ins
  • Standard tools for medical imaging as default plug-ins (e.g. measurement, segmentation)
  • Many specialized module for different topics on medical imaging (e.g. diffusion imaging, image guided therapy, live image/ultrasound data processing)
*/ diff --git a/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/FirstSteps.dox b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/FirstSteps.dox new file mode 100644 index 0000000000..72d5728de0 --- /dev/null +++ b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/FirstSteps.dox @@ -0,0 +1,13 @@ +/** +\page FirstSteps First steps in Development + +TODO + +
    +
  • \subpage NewPluginPage
  • +
  • \subpage NewModulePage
  • +
  • \subpage CMAKE_FAQ
  • +
  • \subpage StatemachineEditor
  • +
+ +*/ diff --git a/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/NewModule.dox b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/NewModule.dox new file mode 100644 index 0000000000..ac64bbafbe --- /dev/null +++ b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/NewModule.dox @@ -0,0 +1,4 @@ +/** +\page NewModulePage How to create a new MITK Module + +*/ diff --git a/Documentation/Doxygen/DeveloperManual/NewPlugin.dox b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/NewPlugin.dox similarity index 100% rename from Documentation/Doxygen/DeveloperManual/NewPlugin.dox rename to Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/NewPlugin.dox diff --git a/Documentation/Doxygen/StatemachineEditor/StatemachineEditor.dox b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/StatemachineEditor.dox similarity index 100% rename from Documentation/Doxygen/StatemachineEditor/StatemachineEditor.dox rename to Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/StatemachineEditor.dox diff --git a/Documentation/Doxygen/StatemachineEditor/images/BuildPath.PNG b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/BuildPath.PNG similarity index 100% rename from Documentation/Doxygen/StatemachineEditor/images/BuildPath.PNG rename to Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/BuildPath.PNG diff --git a/Documentation/Doxygen/StatemachineEditor/images/CreateJavaProject.PNG b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/CreateJavaProject.PNG similarity index 100% rename from Documentation/Doxygen/StatemachineEditor/images/CreateJavaProject.PNG rename to Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/CreateJavaProject.PNG diff --git a/Documentation/Doxygen/StatemachineEditor/images/Import.PNG b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/Import.PNG similarity index 100% rename from Documentation/Doxygen/StatemachineEditor/images/Import.PNG rename to Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/Import.PNG diff --git a/Documentation/Doxygen/StatemachineEditor/images/Import2.PNG b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/Import2.PNG similarity index 100% rename from Documentation/Doxygen/StatemachineEditor/images/Import2.PNG rename to Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/Import2.PNG diff --git a/Documentation/Doxygen/StatemachineEditor/images/Import3.PNG b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/Import3.PNG similarity index 100% rename from Documentation/Doxygen/StatemachineEditor/images/Import3.PNG rename to Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/Import3.PNG diff --git a/Documentation/Doxygen/StatemachineEditor/images/Import4.PNG b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/Import4.PNG similarity index 100% rename from Documentation/Doxygen/StatemachineEditor/images/Import4.PNG rename to Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/Import4.PNG diff --git a/Documentation/Doxygen/StatemachineEditor/images/NewStatemachine.PNG b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/NewStatemachine.PNG similarity index 100% rename from Documentation/Doxygen/StatemachineEditor/images/NewStatemachine.PNG rename to Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/NewStatemachine.PNG diff --git a/Documentation/Doxygen/StatemachineEditor/images/NewStatemachine1.PNG b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/NewStatemachine1.PNG similarity index 100% rename from Documentation/Doxygen/StatemachineEditor/images/NewStatemachine1.PNG rename to Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/NewStatemachine1.PNG diff --git a/Documentation/Doxygen/StatemachineEditor/images/NewStatemachine2.PNG b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/NewStatemachine2.PNG similarity index 100% rename from Documentation/Doxygen/StatemachineEditor/images/NewStatemachine2.PNG rename to Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/NewStatemachine2.PNG diff --git a/Documentation/Doxygen/StatemachineEditor/images/NewStatemachine3.PNG b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/NewStatemachine3.PNG similarity index 100% rename from Documentation/Doxygen/StatemachineEditor/images/NewStatemachine3.PNG rename to Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/NewStatemachine3.PNG diff --git a/Documentation/Doxygen/StatemachineEditor/images/Runas.png b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/Runas.png similarity index 100% rename from Documentation/Doxygen/StatemachineEditor/images/Runas.png rename to Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/Runas.png diff --git a/Documentation/Doxygen/StatemachineEditor/images/addAction.PNG b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/addAction.PNG similarity index 100% rename from Documentation/Doxygen/StatemachineEditor/images/addAction.PNG rename to Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/addAction.PNG diff --git a/Documentation/Doxygen/StatemachineEditor/images/application.PNG b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/application.PNG similarity index 100% rename from Documentation/Doxygen/StatemachineEditor/images/application.PNG rename to Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/application.PNG diff --git a/Documentation/Doxygen/StatemachineEditor/images/application1.PNG b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/application1.PNG similarity index 100% rename from Documentation/Doxygen/StatemachineEditor/images/application1.PNG rename to Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/application1.PNG diff --git a/Documentation/Doxygen/StatemachineEditor/images/changeEvent.PNG b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/changeEvent.PNG similarity index 100% rename from Documentation/Doxygen/StatemachineEditor/images/changeEvent.PNG rename to Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/changeEvent.PNG diff --git a/Documentation/Doxygen/StatemachineEditor/images/openPropertiesView.PNG b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/openPropertiesView.PNG similarity index 100% rename from Documentation/Doxygen/StatemachineEditor/images/openPropertiesView.PNG rename to Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/openPropertiesView.PNG diff --git a/Documentation/Doxygen/StatemachineEditor/images/openstatemachinexml.png b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/openstatemachinexml.png similarity index 100% rename from Documentation/Doxygen/StatemachineEditor/images/openstatemachinexml.png rename to Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/openstatemachinexml.png diff --git a/Documentation/Doxygen/StatemachineEditor/images/specifycontainer.png b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/specifycontainer.png similarity index 100% rename from Documentation/Doxygen/StatemachineEditor/images/specifycontainer.png rename to Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/specifycontainer.png diff --git a/Documentation/Doxygen/StatemachineEditor/images/specifycontainer2.png b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/specifycontainer2.png similarity index 100% rename from Documentation/Doxygen/StatemachineEditor/images/specifycontainer2.png rename to Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/specifycontainer2.png diff --git a/Documentation/Doxygen/StatemachineEditor/images/specifycontainer3.png b/Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/specifycontainer3.png similarity index 100% rename from Documentation/Doxygen/StatemachineEditor/images/specifycontainer3.png rename to Documentation/Doxygen/DeveloperManual/Starting/FirstSteps/StatemachineEditor/images/specifycontainer3.png diff --git a/Documentation/Doxygen/DeveloperManual/CMakeFAQ.dox b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/CMakeFAQ.dox similarity index 98% rename from Documentation/Doxygen/DeveloperManual/CMakeFAQ.dox rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/CMakeFAQ.dox index 2486bfc14e..a0495ae8a6 100644 --- a/Documentation/Doxygen/DeveloperManual/CMakeFAQ.dox +++ b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/CMakeFAQ.dox @@ -1,38 +1,38 @@ /** -\page CMAKE_FAQ %CMake FAQ +\page CMAKE_FAQ CMake FAQ \section CMAKE_FAQ_General A general comment MITK uses %CMake for configuration. If you want to develop either using MITK as a toolkit or by extending the capabilities of the applications provided by us we recommend using %CMake for your own prject as well. While it might be possible to use MITK in conjunction with other options, such as QMake or setting up your own project manually it will invariably use a lot of work and probably hacks as well. As we have no experience in this we will not be able to help you, so be prepared to have to do a lot of tweaking on your own. This guide does not try to give a general introduction to Cmake, instead it tries to answer some basic questions that might arise for those new to %CMake, to help you get started on MITK. For a more comprehensive introduction on %CMake see here. We will assume in this guide, that the path to your source is /MITK/. \section CMAKE_FAQ_Question Basic Questions \subsection CMAKE_FAQ_Question_WhereGetIt Where do I get CMake and what version do I need? See \ref BuildInstructions_Prerequisites. \subsection CMAKE_FAQ_Question_NewPluginNothing I coded a new plugin for the Workbench and nothing happened. Why? The correct way to create a new plugin is described in \ref NewPluginOnly. Do note that you need to move the source to the MITK/Plugins directory and you will have to add the plugin to the config file (most likely MITK/Plugins/Plugins.cmake). After that see \ref CMAKE_FAQ_Question_HowDoIActivatePlugin. \subsection CMAKE_FAQ_Question_HowDoIActivatePlugin I want to use a plugin, how do I activate it?
  1. Start %CMake
  2. Configure
  3. Set the variable MITK_BUILD_ to TRUE
  4. Configure again
  5. Generate
  6. Start a build using your development environment
\subsection CMAKE_FAQ_Question_HowDoIActivateModule I want to use a module, how do I activate it? Modules are build automatically if a plugin that requires them is activated. See \ref CMAKE_FAQ_Question_HowDoIActivatePlugin. \subsection CMAKE_FAQ_Question_HowOwnToolkits MITK always downloads the toolkits, but I want to use my own. This is covered in \ref HowToNewProjectCustomizingMITKConfigure. \subsection CMAKE_FAQ_Question_HowOwnProjectMITK I want to use an MITK plugin in my own project but I can not find it. See \ref HowToNewProjectAddingMITKFunctionality. */ \ No newline at end of file diff --git a/Core/Documentation/Doxygen/Concepts/CodingGeneral.dox b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Coding.dox similarity index 100% rename from Core/Documentation/Doxygen/Concepts/CodingGeneral.dox rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Coding.dox diff --git a/Documentation/Doxygen/DeveloperManual/DirectoryStructure.dox b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/DirectoryStructure.dox similarity index 100% rename from Documentation/Doxygen/DeveloperManual/DirectoryStructure.dox rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/DirectoryStructure.dox diff --git a/Documentation/Doxygen/DeveloperManual/DocumentationExample.dox b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/DocumentationExample.dox similarity index 100% rename from Documentation/Doxygen/DeveloperManual/DocumentationExample.dox rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/DocumentationExample.dox diff --git a/Documentation/Doxygen/DeveloperManual/DocumentationGuide.dox b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/DocumentationGuide.dox similarity index 100% rename from Documentation/Doxygen/DeveloperManual/DocumentationGuide.dox rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/DocumentationGuide.dox diff --git a/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/GettingToKnowMITK.dox b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/GettingToKnowMITK.dox new file mode 100644 index 0000000000..e418a0b301 --- /dev/null +++ b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/GettingToKnowMITK.dox @@ -0,0 +1,14 @@ +/** +\page GettingToKnowMITK Getting to know MITK + +TODO +
    +
  • \subpage DirectoryStructurePage
  • +
  • \subpage TutorialPage
  • +
  • \subpage CMAKE_FAQ
  • +
  • \subpage StyleGuideAndNotesPage
  • +
  • \subpage DocumentationGuide
  • +
  • \subpage CodingPage
  • +
  • \subpage KnownProblemsPage
  • +
+*/ diff --git a/Documentation/Doxygen/DeveloperManual/KnownProblems.dox b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/KnownProblems.dox similarity index 100% rename from Documentation/Doxygen/DeveloperManual/KnownProblems.dox rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/KnownProblems.dox diff --git a/Documentation/Doxygen/DeveloperManual/StyleGuideAndNotes.dox b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/StyleGuideAndNotes.dox similarity index 100% rename from Documentation/Doxygen/DeveloperManual/StyleGuideAndNotes.dox rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/StyleGuideAndNotes.dox diff --git a/Documentation/Doxygen/Tutorial/CMakeLists.txt b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/CMakeLists.txt similarity index 100% rename from Documentation/Doxygen/Tutorial/CMakeLists.txt rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/CMakeLists.txt diff --git a/Documentation/Doxygen/Tutorial/Step00.dox b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step00.dox similarity index 100% rename from Documentation/Doxygen/Tutorial/Step00.dox rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step00.dox diff --git a/Documentation/Doxygen/Tutorial/Step01.dox b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step01.dox similarity index 100% rename from Documentation/Doxygen/Tutorial/Step01.dox rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step01.dox diff --git a/Documentation/Doxygen/Tutorial/Step02.dox b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step02.dox similarity index 100% rename from Documentation/Doxygen/Tutorial/Step02.dox rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step02.dox diff --git a/Documentation/Doxygen/Tutorial/Step03.dox b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step03.dox similarity index 100% rename from Documentation/Doxygen/Tutorial/Step03.dox rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step03.dox diff --git a/Documentation/Doxygen/Tutorial/Step04.dox b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step04.dox similarity index 100% rename from Documentation/Doxygen/Tutorial/Step04.dox rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step04.dox diff --git a/Documentation/Doxygen/Tutorial/Step05.dox b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step05.dox similarity index 100% rename from Documentation/Doxygen/Tutorial/Step05.dox rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step05.dox diff --git a/Documentation/Doxygen/Tutorial/Step06.dox b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step06.dox similarity index 100% rename from Documentation/Doxygen/Tutorial/Step06.dox rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step06.dox diff --git a/Documentation/Doxygen/Tutorial/Step07.dox b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step07.dox similarity index 100% rename from Documentation/Doxygen/Tutorial/Step07.dox rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step07.dox diff --git a/Documentation/Doxygen/Tutorial/Step08.dox b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step08.dox similarity index 100% rename from Documentation/Doxygen/Tutorial/Step08.dox rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step08.dox diff --git a/Documentation/Doxygen/Tutorial/Step09.dox b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step09.dox similarity index 100% rename from Documentation/Doxygen/Tutorial/Step09.dox rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step09.dox diff --git a/Documentation/Doxygen/Tutorial/Step10.dox b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step10.dox similarity index 100% rename from Documentation/Doxygen/Tutorial/Step10.dox rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step10.dox diff --git a/Documentation/Doxygen/Tutorial/Tutorial.dox b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Tutorial.dox similarity index 100% rename from Documentation/Doxygen/Tutorial/Tutorial.dox rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Tutorial.dox diff --git a/Documentation/Doxygen/Tutorial/configureCMake.PNG b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/configureCMake.PNG similarity index 100% rename from Documentation/Doxygen/Tutorial/configureCMake.PNG rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/configureCMake.PNG diff --git a/Documentation/Doxygen/Tutorial/configureVisualStudioProperties.png b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/configureVisualStudioProperties.png similarity index 100% rename from Documentation/Doxygen/Tutorial/configureVisualStudioProperties.png rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/configureVisualStudioProperties.png diff --git a/Documentation/Doxygen/Tutorial/step10_result.png b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/step10_result.png similarity index 100% rename from Documentation/Doxygen/Tutorial/step10_result.png rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/step10_result.png diff --git a/Documentation/Doxygen/Tutorial/step1_result.png b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/step1_result.png similarity index 100% rename from Documentation/Doxygen/Tutorial/step1_result.png rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/step1_result.png diff --git a/Documentation/Doxygen/Tutorial/step2_result.png b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/step2_result.png similarity index 100% rename from Documentation/Doxygen/Tutorial/step2_result.png rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/step2_result.png diff --git a/Documentation/Doxygen/Tutorial/step3a_result.png b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/step3a_result.png similarity index 100% rename from Documentation/Doxygen/Tutorial/step3a_result.png rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/step3a_result.png diff --git a/Documentation/Doxygen/Tutorial/step3b_result.png b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/step3b_result.png similarity index 100% rename from Documentation/Doxygen/Tutorial/step3b_result.png rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/step3b_result.png diff --git a/Documentation/Doxygen/Tutorial/step4a_result.png b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/step4a_result.png similarity index 100% rename from Documentation/Doxygen/Tutorial/step4a_result.png rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/step4a_result.png diff --git a/Documentation/Doxygen/Tutorial/step4b_result.png b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/step4b_result.png similarity index 100% rename from Documentation/Doxygen/Tutorial/step4b_result.png rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/step4b_result.png diff --git a/Documentation/Doxygen/Tutorial/step5_result.png b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/step5_result.png similarity index 100% rename from Documentation/Doxygen/Tutorial/step5_result.png rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/step5_result.png diff --git a/Documentation/Doxygen/Tutorial/step6_result.png b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/step6_result.png similarity index 100% rename from Documentation/Doxygen/Tutorial/step6_result.png rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/step6_result.png diff --git a/Documentation/Doxygen/Tutorial/step8_result.png b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/step8_result.png similarity index 100% rename from Documentation/Doxygen/Tutorial/step8_result.png rename to Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/step8_result.png diff --git a/Documentation/Doxygen/DeveloperManual/BuildInstructions.dox b/Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/BuildInstructions.dox similarity index 100% rename from Documentation/Doxygen/DeveloperManual/BuildInstructions.dox rename to Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/BuildInstructions.dox diff --git a/Documentation/Doxygen/DeveloperManual/BuildToolkits.dox b/Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/BuildToolkits.dox similarity index 100% rename from Documentation/Doxygen/DeveloperManual/BuildToolkits.dox rename to Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/BuildToolkits.dox diff --git a/Documentation/Doxygen/DeveloperManual/HowToNewProject-MyProjectLayout.png b/Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/HowToNewProject-MyProjectLayout.png similarity index 100% rename from Documentation/Doxygen/DeveloperManual/HowToNewProject-MyProjectLayout.png rename to Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/HowToNewProject-MyProjectLayout.png diff --git a/Documentation/Doxygen/DeveloperManual/HowToNewProject.dox b/Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/HowToNewProject.dox similarity index 99% rename from Documentation/Doxygen/DeveloperManual/HowToNewProject.dox rename to Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/HowToNewProject.dox index d961d9c9e4..f9b4cdeaa7 100644 --- a/Documentation/Doxygen/DeveloperManual/HowToNewProject.dox +++ b/Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/HowToNewProject.dox @@ -1,161 +1,161 @@ /** \page HowToNewProject Creating a new MITK project This page is intended to give a comprehensive guide to setting up your own MITK based project. It will use the application framework provided by MITK and is probably the preferred way for most users. The first part of this document is a tutorial aimed at newcomers to MITK and possibly %CMake and tries to give as much help as possible on setting up your own project. If you are looking for more technical information about customizing MITK, the structure of the superbuild or packaging you might want to read the \ref HowToNewProjectAdvancedInformation. If you have set up your MITK project already and want to start developing you could take a look at \ref TutorialPage. \section HowToNewProjectGettingStarted Getting Started To bootstrap your project MITK offers two convenient options:
  1. Use the MITK Plugin Generator, a command line tool used to generate a customized MITK project and/or MITK plug-ins (available for download here).
  2. Use the MITK project template as an example project.
Both options will provide you with a project which contains a "superbuild" mechanism to automatically download, configure, and build MITK as a dependency of your own project. The MITK Plugin Generator generates code using the supplied command line arguments, whereas the MITK project template needs immediate modifications to customize it to your naming schemes. However, the project template will potentially contain more code demonstrating features of MITK. \note Using the MITK Plugin Generator is recommended for beginners. \section HowToNewProjectPrerequisites Prerequisites What ever option you choose, a MITK-based project needs essentially the same prerequisites as MITK itself. Please see \ref BuildInstructions_Prerequisites for details. \note If you use one of the two options above you will \b not \b need to build MITK yourself. This will be done automatically. \section HowToNewProjectCreatingSourceDir Preparing your source directory In order to start developing with MITK, you first have to set up the source directory for your project. \subsection HowToNewProjectSourceUsingGenerator Using the MITK Plugin Generator The usage of the Plugin Generator for creating a new project is described in \ref NewPluginWithProject, please have a look there. \subsection HowToNewProjectSourceUsingTemplate Using the MITK Project Template Download the project as a tarball or zipball and extract it to your desired source directory. \note This is a \b template \b. You must modify it such that it fits the needs of your particular project. Especially you should do a global search and replace for the string "awesome" to rename the template application and plug-in. You may want to rename some files too. \section HowToNewProjectGeneratingCMake Generating your binary with CMake After you have set up your source directory you can proceed to generate your binary directory using %CMake. Depending on your operating system and preferences you might want to use "cmake-gui" or "ccmake" (shell). This document assumes you are using cmake-gui.
  1. Start "cmake-gui" and enter your source (e.g. "D:\AwesomeProject") and binary directory (e.g. "D:\AwesomeProject-superbuild").
  2. Upon first pressing "Configure" you will be prompted to select your generator. This determines what project files will be generated by %CMake. Set this to the development tool you are intending to use (e.g. "Visual Studio 2010 64Bit" or "linux makefiles".
  3. Press "Configure" until no new variables appear and then "Generate". Now all project files have been generated into your binary directory.
  4. Double-check that the right Qt version is used.
Now you are ready to compile your code. Depending on your choice of tool this will be done differently, we cover two possibilities here. \subsection HowToNewProjectCompilingLinuxMakefiles Compiling using linux makefiles
  1. In the shell, switch to your binary directory.
  2. type "make" and hit enter
\subsection HowToNewProjectCompilingVisualStudio Compiling using visual studio We assume your application is called "AwesomeApp" and your project "AwesomeProject" and your binary directory is "D:\AwesomeProject-superbuild\". Replace names and paths accordingly.
  1. Close %CMake and open "D:\AwesomeProject-superbuild\AwesomeProject-superbuild.sln" . Your Visual Studio should appear and by pressing F7 you start the compilation. This will clone the MITK source code, build it, and then start building your own project.
  2. After the superbuild compilation has finished, close the solution file and start the batch file "D:\AwesomeProject-superbuild\AwesomeProject-build\StartVS_debug.bat" (or _release.bat if you built in Release mode) which opens the "D:\AwesomeProject-superbuild\AweseomeProject-build\AwesomeProject.sln" solution.
  3. Set the "AwesomeApp" project as start-up project (right click > "Set as StartUp Project") and press "F5" to start your MITK AwesomeApp.
\note Just opening AwesomeProject.sln from your explorer by double-cliking won`t allow you to start or debug your application because the required environment variables would be missing. Use the supplied batch files or set your PATH variable accordingly. \section HowToNewProjectAddingMITKFunctionality I want to use some MITK plugin but it is not available Due to the sheer number of MITK plugins not every plugin is activated by default. To activate a specific plugin (again replace paths as needed):
  1. Start "cmake-gui" and set the binary directory to "D:\AwesomeProject-superbuild\MITK-superbuild\MITK-build\", the source will adjust automatically and you will see new settings appear.
  2. Navigate to the plugin you want to use (e.g. "MITK_BUILD_org.mitk.gui.qt.segmentation") and tick the checkbox behind it
  3. Press "Configure" until no new variables appear and then "Generate".
  4. Build MITK using your development tool (as in \ref HowToNewProjectCompilingLinuxMakefiles or \ref HowToNewProjectCompilingVisualStudio only in the "D:\AwesomeProject-superbuild\MITK-superbuild\MITK-build\" directory )
  5. Start "cmake-gui" and set the binary directory to "D:\AwesomeProject-superbuild\AwesomeProject-build\", the source will adjust automatically and you will see new settings appear.
  6. Press "Configure" until no new variables appear and then "Generate".
  7. Build your project
  8. Start your application
\note If you want to use an application provided by MITK (e.g. MITK Workbench) you have to tick the appropriate checkbox as well (in this case MITK_BUILD_APP_mitkWorkbench ) and build MITK. Do note, that this application will be located in the bin directory of the "D:\AwesomeProject-superbuild\MITK-superbuild\MITK-build\" folder. -\section HowToNewProjectAdvancedInformation Information for avanced users +\section HowToNewProjectAdvancedInformation Information for advanced users \subsection HowToNewProjectCustomizingMITK Customizing MITK The %CMake scripts from the Plugin Generator of the project template provide some handy options which allow you to customize the MITK build used in your project. You can either inject an already build MITK to be used by your project or configure some MITK options directly in your project's superbuild configuration if MITK is going to be build inside your project. \subsubsection HowToNewProjectCustomizingMITKInjectMITK Inject a MITK build By setting the \b EXTERNAL_MITK_DIR \b variable in your project's superbuild %CMake configuration to a MITK build directory (containing the MITKConfig.cmake) you can skip the MITK build process. If MITK is the only external project in your project, you might want to disable the superbuild of your project completely (set _USE_SUPERBUILD to OFF or edit your CMakeLists.txt file to set it to OFF by default) and set the \b MITK_DIR \b %CMake variable to your MITK build directory. \subsubsection HowToNewProjectCustomizingMITKConfigure Configure the MITK superbuild If MITK is being build inside your project's superbuild process, you can enable the use of certain third-party libraries inside of MITK. The following variables control the MITK configuration:
  • \b MITK_USE_BLUEBERRY Enable the use of the BlueBerry application framework
  • \b MITK_USE_Boost Download and use Boost in MITK
  • \b MITK_USE_CTK Download, compile, and use CTK in MITK
  • \b MITK_USE_DCMTK Download, compile, and use DCMTK in MITK
  • \b MITK_USE_OpenCV Download, compile, and use OpenCV in MITK
  • \b MITK_USE_Python Download and compile 1CableSwig and enable Python wrapping in ITK, VTK, OpenCV, and MITK
  • \b MITK_USE_QT Use the Qt framework in MITK
You can also inject already build third-party libraries from inside your project's superbuild in the MITK superbuild by using any of the following %CMake variables:
  • \b MITK_CTK_DIR Reuse a CTK build directory in MITK.
  • \b MITK_CableSwig_DIR Reuse a 1CableSwig build directory in MITK.
  • \b MITK_DCMTK_DIR Reuse a DCMKT build directory in MITK.
  • \b MITK_GDCM_DIR Reuse a GDCM build directory in MITK.
  • \b MITK_ITK_DIR Reuse a ITK build directory in MITK.
  • \b MITK_OpenCV_DIR Reuse a OpenCV build directory in MITK.
  • \b MITK_VTK_DIR Reuse a VTK build directory in MITK.
If the corresponding \b MITK_USE_ \b option is set to on, the MITK superbuild will use the provided build directory instead of building the project itself. You can also control the source code location for MITK in your project's superbuild configuration by using the following %CMake variables:
  • \b MITK_SOURCE_DIR The path to the MITK source directory. If the value for this variable is non-empty, the variables below are ignored.
  • \b MITK_GIT_REPOSITORY The Git repository containing the MITK source code.
  • \b MITK_GIT_TAG The hash id, tag or branch name used for a checkout from MITK_GIT_REPOSITORY.
\subsubsection HowToNewProjectProjectStructure Project Structure If you are using the superbuild feature of the generated project (the default), you might want to familiarise yourself with the layout of your build tree. The top-level build directory which you specified in %CMake when configuring your project will contain all the required dependencies. Suppose we call our project MyProject and the build directory is "C:\MyProject-superbuild". Then the layout looks something like this: MyProjectLayout.png The top-level directory contains the source code and the build directories from the dependencies of your project. In the current case, the only dependency of MyProject is MITK, which in turn has downloaded and built its own dependencies (CTK, DCMTK, ITK, etc.). The "real" build tree for your project is located in MyProject-superbuild/MyProject-build, so point the %CMake-GUI to this build directory if you want to change the set of enabled plug-ins for example. Further, you should open the MyProject.sln solution file (for Visual Studio) or execute "make" in the MyProject-superbuild/MyProject-build/ directory. Only for the very first time or if you want to update and newly build the project's dependencies should you use the project files in the MyProject-superbuild directory directly. The same applies for the MyProject-superbuild/MITK-superbuild directory. This directory contains the MITK superbuild, nested inside your project's superbuild. If you want to change %CMake options for MITK, use the MyProject-superbuild/MITK-superbuild/MITK-build build directory. \image html HowToNewProject-MyProjectLayout.png "Layout of MyProject" \subsubsection HowToNewProjectPackaging Packaging The project template and the generated projects by the Plugin Generator come with full packaging support. You can create deployable packages of your project for all supported operating systems my building the PACKAGE target. On Linux, this will create a tarball, on MacOS a .dmg file, and on Windows a zipball and an NSIS installer (if NSIS is installed and found). You can read more about deployment \ref DeploymentPage "here". */ \ No newline at end of file diff --git a/Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/SettingUpMITK.dox b/Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/SettingUpMITK.dox new file mode 100644 index 0000000000..5b67763c66 --- /dev/null +++ b/Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/SettingUpMITK.dox @@ -0,0 +1,14 @@ +/** +\page SettingUpMITK Setting Up Mitk + +TODO + +
    +
  • \subpage SupportedPlatformsPage
  • +
  • \subpage BuildInstructionsPage
  • +
  • \subpage thirdpartylibs
  • +
  • \subpage HowToNewProject
  • +
  • \subpage Testing
  • +
+ +*/ diff --git a/Documentation/Doxygen/DeveloperManual/SupportedPlatforms.md b/Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/SupportedPlatforms.md similarity index 100% rename from Documentation/Doxygen/DeveloperManual/SupportedPlatforms.md rename to Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/SupportedPlatforms.md diff --git a/Documentation/Doxygen/DeveloperManual/ThirdPartyLibs.dox b/Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/ThirdPartyLibs.dox similarity index 100% rename from Documentation/Doxygen/DeveloperManual/ThirdPartyLibs.dox rename to Documentation/Doxygen/DeveloperManual/Starting/SettingUpMITK/ThirdPartyLibs.dox diff --git a/Documentation/Doxygen/DeveloperManual/Starting/Starting.dox b/Documentation/Doxygen/DeveloperManual/Starting/Starting.dox new file mode 100644 index 0000000000..fa78a1bb8d --- /dev/null +++ b/Documentation/Doxygen/DeveloperManual/Starting/Starting.dox @@ -0,0 +1,37 @@ +/** + +\page StartingDevelopment Starting your MITK Development + +This Introduction will acquaint you with the most important workflows to get you started with your MITK Development. + +
    +
  • \subpage Architecture
  • +
  • \subpage SettingUpMITK
  • +
      +
    • \ref SupportedPlatformsPage
    • +
    • \ref BuildInstructionsPage
    • +
    • \ref thirdpartylibs
    • +
    • \ref HowToNewProject
    • +
    +
  • \subpage GettingToKnowMITK
  • +
      +
    • \ref DirectoryStructurePage
    • +
    • \ref TutorialPage
    • +
    • \ref CMAKE_FAQ
    • +
    • \ref StyleGuideAndNotesPage
    • +
    • \ref DocumentationGuide
    • +
    • \ref CodingPage
    • +
    • \ref KnownProblemsPage
    • +
    +
  • \subpage FirstSteps
  • +
      +
    • \ref NewPluginPage
    • +
    • \ref NewModulePage
    • +
    • \ref StatemachineEditor
    • +
    +
  • \subpage AboutTestingPage
  • +
+ + + +*/ diff --git a/Documentation/Doxygen/DeveloperManual/Toolkit/DevelopmentToolkit.dox b/Documentation/Doxygen/DeveloperManual/Toolkit/DevelopmentToolkit.dox new file mode 100644 index 0000000000..ae77b729ea --- /dev/null +++ b/Documentation/Doxygen/DeveloperManual/Toolkit/DevelopmentToolkit.dox @@ -0,0 +1,13 @@ +/** + +\page DevelopmentToolkit Developing with the MITK Toolkit + +Todo + +
    +
  • \subpage Concepts
  • +
  • \subpage MITKModuleManualsListPage
  • +
+ + +*/ diff --git a/Documentation/Doxygen/UserManual/MITKModuleManualsList.dox b/Documentation/Doxygen/DeveloperManual/Toolkit/ModuleManuals/MITKModuleManualsList.dox similarity index 93% rename from Documentation/Doxygen/UserManual/MITKModuleManualsList.dox rename to Documentation/Doxygen/DeveloperManual/Toolkit/ModuleManuals/MITKModuleManualsList.dox index 1cd4e1e54e..6dfede77e3 100644 --- a/Documentation/Doxygen/UserManual/MITKModuleManualsList.dox +++ b/Documentation/Doxygen/DeveloperManual/Toolkit/ModuleManuals/MITKModuleManualsList.dox @@ -1,20 +1,21 @@ /** \page MITKModuleManualsListPage MITK Module Manuals \section MITKModuleManualsListPageOverview Overview The modules are shared libraries that provide functionality that can be used by developers. \section MITKModuleManualsListPageModuleManualList List of Module Manuals \li \subpage IGTGeneralModulePage \li \subpage MitkOpenCL_Overview \li \subpage SimulationManualPage + \li \subpage GeneratingDeviceModulesPage \section MITKModuleManualsListPageAdditionalInformation Additional Information on Certain Modules \li \ref PlanarPropertiesPage \li \subpage DiffusionImagingPropertiesPage \li \subpage ConnectomicsRenderingPropertiesPage */ diff --git a/Core/Documentation/Doxygen/Concepts/images/introduction/MitkOverview.png b/Documentation/Doxygen/DeveloperManual/images/MitkOverview.png similarity index 100% rename from Core/Documentation/Doxygen/Concepts/images/introduction/MitkOverview.png rename to Documentation/Doxygen/DeveloperManual/images/MitkOverview.png diff --git a/Documentation/Doxygen/MainPage.dox.in b/Documentation/Doxygen/MainPage.dox.in index 05d7565451..ed93fcfd62 100644 --- a/Documentation/Doxygen/MainPage.dox.in +++ b/Documentation/Doxygen/MainPage.dox.in @@ -1,57 +1,17 @@ /** -\mainpage Medical Imaging Interaction Toolkit +\mainpage Medical Imaging Interaction Toolkit - Documentation Portal \image html mitkLogo.jpg -\section intro Introduction +This page acts as a portal to the three different parts of the MITK-Documentation. -Welcome to the Medical Imaging Interaction Toolkit (MITK). -Currently under active development, MITK aims at supporting the -development of leading-edge medical imaging software -with a high degree of interaction. It combines VTK, -ITK and the pic-based-libraries of the -Div. Medical and Biological Informatics -of the DKFZ and adds those features that are most important -for developing interactive medical imaging software covered neither by VTK nor ITK, i.e: -\li multiple, consistent views on the same data. For example, when you have three orthogonal -2D-views and a 3D view and data consisting of a green surface, the surface will be visible and green -in all views (as contour lines in 2D, as a surface in 3D), and when you move the surface, it will -move in all views. When you try to implement this with basic VTK, you will need to coordinate the -position/orientation/color/... of all the views somewhere in your program - exactly this can MITK -do for you. -\li interactions that create and/or modify data (not only actors as in basic VTK) -\li complex interactions with multiple states, e.g., for interaction with active contours -\li undo/redo of interactions -\li organization of data objects in a tree at run-time, e.g., to represent logical dependencies (e.g., -a heart cavity is a part of the heart) or to control the rendering process -\li additional properties of arbitrary type can be assigned to data objects contained in the data tree -\li visualization and interaction with 3D+t data (basic VTK can handle only 3D data and ITK is not -for visualization and interaction) -\li although MITK is mainly a toolkit and not an application, it offers some support on the -application-level, e.g, for structured combination of modules (so-called functionalities), e.g., for -combining and switching between one functionality for segmentation and another for registration. +If this is your first time around here and you are interested in learning more about MITK, please read \subpage Overview -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 the features outlined above. +If you are a MITK end-user, please refer to the \subpage UserManualPortal -\section FurtherReading Further Reading +If you are a developer looking for a developer's guide, please see \subpage DeveloperManualPortal -\subpage ShortIntroductionToMITK - -\ref Concepts - -\ref Development - -\ref HowToNewProject "A comprehensive newcomers guide to setting up your own MITK project" - -@MITK_XP_LINK@ - -@BLUEBERRY_DOXYGEN_LINK@ - -\ref thirdpartylibs - - */ diff --git a/Documentation/Doxygen/Modules/ModuleGeometryFigures.zip b/Documentation/Doxygen/Modules/ModuleGeometryFigures.zip deleted file mode 100644 index 434c701fb9..0000000000 Binary files a/Documentation/Doxygen/Modules/ModuleGeometryFigures.zip and /dev/null differ diff --git a/Documentation/Doxygen/DeveloperManual/ShortIntroductionToMITK.dox b/Documentation/Doxygen/Overview/Overview.dox similarity index 96% rename from Documentation/Doxygen/DeveloperManual/ShortIntroductionToMITK.dox rename to Documentation/Doxygen/Overview/Overview.dox index 9b03af2ba5..565f32e6f2 100644 --- a/Documentation/Doxygen/DeveloperManual/ShortIntroductionToMITK.dox +++ b/Documentation/Doxygen/Overview/Overview.dox @@ -1,29 +1,29 @@ /** -\page ShortIntroductionToMITK A short introduction to MITK +\page Overview MITK: An Overview The Medical Imaging Interaction Toolkit (MITK) can be used in several different ways. If you are a new user to MITK the first question is in what manner you intend to use it. The following options are simplified and condensed versions of the most common usage scenarios. \tableofcontents \section ShortIntroductionToMITKAsToolkit I want to develop my own software framework, but use some of MITK's data structures and algorithms You will use MITK as a toolkit and probably benefit most from the \ref BuildInstructionsPage and MITK API Documentation. \section ShortIntroductionToMITKAsFramework I want to use the MITK and BlueBerry software framework to develop my own software Here you have again two options. \subsection ShortIntroductionToMITKAsFrameworkExtendingWorkbench I want use the MITK Workbench and extend its capabilities You are using MITK as software framework and writing your own modules and plugins for MITK. You want to read the \ref BuildInstructionsPage and further on \ref Development. Also you might want to take a look at our \ref CMAKE_FAQ. \subsection ShortIntroductionToMITKAsFrameworkExternalProject I want to create my own application based on MITK but with major customizations and changes This is probably the most common way to use MITK. You are using MITK as software framework and building your own project and application using MITK. You want to read \ref HowToNewProject and the general information in \ref Development. Also you might want to take a look at our \ref CMAKE_FAQ. \section ShortIntroductionToMITKAsFrameworkEndUser I want to use the MITK Workbench to do image processing You are using MITK and the MITK Workbench as an end user and will find user manuals in \ref MITKUserManualPage and \ref PluginListPage. */ \ No newline at end of file diff --git a/Documentation/Doxygen/UserManual/Applications.dox b/Documentation/Doxygen/UserManual/Applications.dox index 2a6b7db404..7620fc8046 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 PluginListPage . -The basic usage information on MITK can be found in \subpage MITKUserManualPage . +The basic usage information on MITK can be found in \ref MITKUserManualPage . \section ApplicationsPageApplications What are Applications? Applications are executables, which contain a certain configuration of views and perspectives. Usually they are aimed at a selective audience or solving a particular problem. As such they focus on certain capabilities of MITK, while ignoring others. The main reason for this is to supply the users of the application with the power of MITK for solving their tasks, without daunting them with an overwhelming number of menus and options. At the same time, this allows, together with the use of perspectives, the creation of sleek and elegant workflows, which are easily comprehensible. A typical example of this would be an application which contains only views related to the analysis of the human brain (particular question) or one which contains only what is necessary for displaying medical data in the classroom (specific audience). \section ApplicationsPageApplicationsList List of Applications If you are interested in using a specific application, currently developed by the MITK team you might want to take a look first at the \ref MITKUserManualPage . Further information on any application can be found here:
  • \subpage org_mitkworkbench
  • \subpage org_dti_atlas_application
  • \subpage org_mitk_gui_qt_diffusionimagingapp
*/ \ No newline at end of file diff --git a/Documentation/Doxygen/UserManual/MITKPluginManualsList.dox b/Documentation/Doxygen/UserManual/MITKPluginManualsList.dox index 26c53b8a28..7c28abd755 100644 --- a/Documentation/Doxygen/UserManual/MITKPluginManualsList.dox +++ b/Documentation/Doxygen/UserManual/MITKPluginManualsList.dox @@ -1,37 +1,39 @@ /** \page PluginListPage MITK Plugin Manuals \section PluginListPageOverview Overview The plugins and bundles provide much of the extended functionality of MITK. Each encapsulates a solution to a problem and associated features. This way one can easily assemble the necessary capabilites for a workflow without adding a lot of bloat, by combining plugins as needed. The distinction between developer and end user use is for convenience only and mainly distinguishes which group a plugin is primarily aimed at. \section PluginListPageEndUserPluginList List of Plugins for End User Use \li \subpage org_mitk_views_basicimageprocessing \li \subpage org_mitk_views_datamanager \li \subpage org_mitk_gui_qt_diffusionimaging \li \subpage org_mitk_views_imagecropper \li \subpage org_mitk_views_imagenavigator \li \subpage org_mitk_gui_qt_measurementtoolbox \li \subpage org_mitk_views_moviemaker \li \subpage org_mitk_views_meshdecimation \li \subpage org_mitk_views_pointsetinteraction \li \subpage org_mitk_gui_qt_registration \li \subpage org_mitk_views_segmentation \li \subpage org_mitk_views_volumevisualization \li \subpage org_mitk_gui_qt_dicom \li \subpage org_mitk_gui_qt_ultrasound + \li \subpage org_mitk_views_fiberfoxview \section PluginListPageDevPluginList List of Plugins for Developer Use and Examples \li \subpage org_surfacematerialeditor \li \subpage org_toftutorial \li \subpage org_mitk_gui_qt_examples \li \subpage org_mitkexamplesopencv \li \ref org_mitk_gui_qt_igtexample \li \ref org_mitk_gui_qt_igttracking + \li \subpage org_mitk_gui_InteractionTests */ diff --git a/Documentation/Doxygen/UserManual/UserManualPortal.dox b/Documentation/Doxygen/UserManual/UserManualPortal.dox new file mode 100644 index 0000000000..83d3a73e5b --- /dev/null +++ b/Documentation/Doxygen/UserManual/UserManualPortal.dox @@ -0,0 +1,9 @@ +/** +\page UserManualPortal MITK: User Manual + +
    +
  • \subpage ApplicationsPage
  • +
  • \subpage MITKUserManualPage
  • +
  • \subpage PluginListPage
  • +
+*/ \ No newline at end of file diff --git a/Documentation/MITKDoxygenLayout.xml b/Documentation/MITKDoxygenLayout.xml index 19afb000f9..78f4ebf655 100644 --- a/Documentation/MITKDoxygenLayout.xml +++ b/Documentation/MITKDoxygenLayout.xml @@ -1,188 +1,195 @@ - + - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - diff --git a/Documentation/Doxygen/ExampleCode/DocumentationExample.h b/Examples/DocumentationExample.h similarity index 100% rename from Documentation/Doxygen/ExampleCode/DocumentationExample.h rename to Examples/DocumentationExample.h diff --git a/Examples/QtFreeRender/QtFreeRender.cpp b/Examples/QtFreeRender/QtFreeRender.cpp index 421c89fa8e..3149c7cbb4 100644 --- a/Examples/QtFreeRender/QtFreeRender.cpp +++ b/Examples/QtFreeRender/QtFreeRender.cpp @@ -1,385 +1,373 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "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 "mitkDisplayInteractor.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" // us #include "mitkGetModuleContext.h" #include "mitkModule.h" #include "mitkModuleRegistry.h" -#include "mitkInformer.h" +#include "mitkInteractionEventObserver.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::DisplayInteractor::Pointer m_DisplayInteractor; 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* 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; void InitializeWindows() { // Set default view directions for SNCs mitkWidget1->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); mitkWidget2->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); mitkWidget3->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Frontal); mitkWidget4->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Original); //initialize m_TimeNavigationController: send time via sliceNavigationControllers 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())); //reverse connection between sliceNavigationControllers and m_TimeNavigationController mitkWidget1->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController, false); mitkWidget2->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController, false); mitkWidget3->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController, false); mitkWidget4->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController, false); // 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; 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(); // 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 // legacy because window manager relies still on existence if global interaction mitk::GlobalInteraction::GetInstance()->Initialize("global"); //mitk::GlobalInteraction::GetInstance()->AddListener(m_DisplayInteractor); // 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()); // instantiate display interactor if (m_DisplayInteractor.IsNull()) { m_DisplayInteractor = mitk::DisplayInteractor::New(); m_DisplayInteractor->LoadStateMachine("DisplayInteraction.xml"); m_DisplayInteractor->LoadEventConfig("DisplayConfigMITK.xml"); - // Register as listener + // Register as listener via micro services + mitk::ModuleContext* context = mitk::ModuleRegistry::GetModule(1)->GetModuleContext(); - if (context != NULL) - { - mitk::ServiceReference serviceRef = context->GetServiceReference(); - mitk::InformerService* service = dynamic_cast(context->GetService(serviceRef)); - if (serviceRef != NULL) - { - service->RegisterObserver(m_DisplayInteractor.GetPointer()); - } else { - MITK_ERROR << "Service not registered."; - } - } - else - { - MITK_ERROR<< "Invalid Module context."; - } + context->RegisterService( + m_DisplayInteractor.GetPointer()); } // 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/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp index 3a6f40cecb..66891575b5 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp @@ -1,624 +1,631 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "itkTractsToDWIImageFilter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace itk { TractsToDWIImageFilter::TractsToDWIImageFilter() : m_CircleDummy(false) , m_VolumeAccuracy(10) , m_Upsampling(1) , m_NumberOfRepetitions(1) , m_EnforcePureFiberVoxels(true) + , m_InterpolationShrink(5) { m_Spacing.Fill(2.5); m_Origin.Fill(0.0); m_DirectionMatrix.SetIdentity(); m_ImageRegion.SetSize(0, 10); m_ImageRegion.SetSize(1, 10); m_ImageRegion.SetSize(2, 10); } TractsToDWIImageFilter::~TractsToDWIImageFilter() { } std::vector< TractsToDWIImageFilter::DoubleDwiType::Pointer > TractsToDWIImageFilter::AddKspaceArtifacts( std::vector< DoubleDwiType::Pointer >& images ) { // create slice object SliceType::Pointer slice = SliceType::New(); ImageRegion<2> region; region.SetSize(0, m_UpsampledImageRegion.GetSize()[0]); region.SetSize(1, m_UpsampledImageRegion.GetSize()[1]); slice->SetLargestPossibleRegion( region ); slice->SetBufferedRegion( region ); slice->SetRequestedRegion( region ); slice->Allocate(); boost::progress_display disp(images.size()*images[0]->GetVectorLength()*images[0]->GetLargestPossibleRegion().GetSize(2)); std::vector< DoubleDwiType::Pointer > outImages; for (int i=0; iSetSpacing( m_Spacing ); newImage->SetOrigin( m_Origin ); newImage->SetDirection( m_DirectionMatrix ); newImage->SetLargestPossibleRegion( m_ImageRegion ); newImage->SetBufferedRegion( m_ImageRegion ); newImage->SetRequestedRegion( m_ImageRegion ); newImage->SetVectorLength( image->GetVectorLength() ); newImage->Allocate(); DiffusionSignalModel* signalModel; if (iGetVectorLength(); g++) for (int z=0; zGetLargestPossibleRegion().GetSize(2); z++) { ++disp; // extract slice from channel g for (int y=0; yGetLargestPossibleRegion().GetSize(1); y++) for (int x=0; xGetLargestPossibleRegion().GetSize(0); x++) { SliceType::IndexType index2D; index2D[0]=x; index2D[1]=y; DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; SliceType::PixelType pix2D = image->GetPixel(index3D)[g]; slice->SetPixel(index2D, pix2D); } // fourier transform slice itk::FFTRealToComplexConjugateImageFilter< SliceType::PixelType, 2 >::Pointer fft = itk::FFTRealToComplexConjugateImageFilter< SliceType::PixelType, 2 >::New(); fft->SetInput(slice); fft->Update(); ComplexSliceType::Pointer fSlice = fft->GetOutput(); fSlice = RearrangeSlice(fSlice); // add artifacts for (int a=0; aSetRelaxationT2(signalModel->GetRelaxationT2()); fSlice = m_KspaceArtifacts.at(a)->AddArtifact(fSlice); } // save k-space slice of s0 image if (g==0) for (int y=0; yGetLargestPossibleRegion().GetSize(1); y++) for (int x=0; xGetLargestPossibleRegion().GetSize(0); x++) { DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; SliceType::IndexType index2D; index2D[0]=x; index2D[1]=y; double kpix = sqrt(fSlice->GetPixel(index2D).real()*fSlice->GetPixel(index2D).real()+fSlice->GetPixel(index2D).imag()*fSlice->GetPixel(index2D).imag()); m_KspaceImage->SetPixel(index3D, kpix); } // inverse fourier transform slice SliceType::Pointer newSlice; itk::FFTComplexConjugateToRealImageFilter< SliceType::PixelType, 2 >::Pointer ifft = itk::FFTComplexConjugateToRealImageFilter< SliceType::PixelType, 2 >::New(); ifft->SetInput(fSlice); ifft->Update(); newSlice = ifft->GetOutput(); // put slice back into channel g for (int y=0; yGetLargestPossibleRegion().GetSize(1); y++) for (int x=0; xGetLargestPossibleRegion().GetSize(0); x++) { DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; DoubleDwiType::PixelType pix3D = newImage->GetPixel(index3D); SliceType::IndexType index2D; index2D[0]=x; index2D[1]=y; pix3D[g] = newSlice->GetPixel(index2D); newImage->SetPixel(index3D, pix3D); } } outImages.push_back(newImage); } return outImages; } TractsToDWIImageFilter::ComplexSliceType::Pointer TractsToDWIImageFilter::RearrangeSlice(ComplexSliceType::Pointer slice) { ImageRegion<2> region = slice->GetLargestPossibleRegion(); ComplexSliceType::Pointer rearrangedSlice = ComplexSliceType::New(); rearrangedSlice->SetLargestPossibleRegion( region ); rearrangedSlice->SetBufferedRegion( region ); rearrangedSlice->SetRequestedRegion( region ); rearrangedSlice->Allocate(); int xHalf = region.GetSize(0)/2; int yHalf = region.GetSize(1)/2; for (int y=0; y pix = slice->GetPixel(idx); if( idx[0] < xHalf ) idx[0] = idx[0] + xHalf; else idx[0] = idx[0] - xHalf; if( idx[1] < yHalf ) idx[1] = idx[1] + yHalf; else idx[1] = idx[1] - yHalf; rearrangedSlice->SetPixel(idx, pix); } return rearrangedSlice; } void TractsToDWIImageFilter::GenerateData() { // check input data if (m_FiberBundle.IsNull()) itkExceptionMacro("Input fiber bundle is NULL!"); int numFibers = m_FiberBundle->GetNumFibers(); if (numFibers<=0) itkExceptionMacro("Input fiber bundle contains no fibers!"); if (m_FiberModels.empty()) itkExceptionMacro("No diffusion model for fiber compartments defined!"); if (m_NonFiberModels.empty()) itkExceptionMacro("No diffusion model for non-fiber compartments defined!"); int baselineIndex = m_FiberModels[0]->GetFirstBaselineIndex(); if (baselineIndex<0) itkExceptionMacro("No baseline index found!"); // determine k-space undersampling for (int i=0; i*>(m_KspaceArtifacts.at(i)) ) m_Upsampling = dynamic_cast*>(m_KspaceArtifacts.at(i))->GetKspaceCropping(); if (m_Upsampling<1) m_Upsampling = 1; if (m_TissueMask.IsNotNull()) { // use input tissue mask m_Spacing = m_TissueMask->GetSpacing(); m_Origin = m_TissueMask->GetOrigin(); m_DirectionMatrix = m_TissueMask->GetDirection(); m_ImageRegion = m_TissueMask->GetLargestPossibleRegion(); if (m_Upsampling>1) { ImageRegion<3> region = m_ImageRegion; region.SetSize(0, m_ImageRegion.GetSize(0)*m_Upsampling); region.SetSize(1, m_ImageRegion.GetSize(1)*m_Upsampling); mitk::Vector3D spacing = m_Spacing; spacing[0] /= m_Upsampling; spacing[1] /= m_Upsampling; itk::RescaleIntensityImageFilter::Pointer rescaler = itk::RescaleIntensityImageFilter::New(); rescaler->SetInput(0,m_TissueMask); rescaler->SetOutputMaximum(100); rescaler->SetOutputMinimum(0); rescaler->Update(); itk::ResampleImageFilter::Pointer resampler = itk::ResampleImageFilter::New(); resampler->SetInput(rescaler->GetOutput()); resampler->SetOutputParametersFromImage(m_TissueMask); resampler->SetSize(region.GetSize()); resampler->SetOutputSpacing(spacing); resampler->Update(); m_TissueMask = resampler->GetOutput(); } MITK_INFO << "Using tissue mask"; } // initialize output dwi image OutputImageType::Pointer outImage = OutputImageType::New(); outImage->SetSpacing( m_Spacing ); outImage->SetOrigin( m_Origin ); outImage->SetDirection( m_DirectionMatrix ); outImage->SetLargestPossibleRegion( m_ImageRegion ); outImage->SetBufferedRegion( m_ImageRegion ); outImage->SetRequestedRegion( m_ImageRegion ); outImage->SetVectorLength( m_FiberModels[0]->GetNumGradients() ); outImage->Allocate(); OutputImageType::PixelType temp; temp.SetSize(m_FiberModels[0]->GetNumGradients()); temp.Fill(0.0); outImage->FillBuffer(temp); // is input slize size a power of two? int x=2; int y=2; while (x " << x; m_ImageRegion.SetSize(0, x); } if (y!=m_ImageRegion.GetSize(1)) { MITK_INFO << "Adjusting image height: " << m_ImageRegion.GetSize(1) << " --> " << y; m_ImageRegion.SetSize(1, y); } // initialize k-space image m_KspaceImage = ItkDoubleImgType::New(); m_KspaceImage->SetSpacing( m_Spacing ); m_KspaceImage->SetOrigin( m_Origin ); m_KspaceImage->SetDirection( m_DirectionMatrix ); m_KspaceImage->SetLargestPossibleRegion( m_ImageRegion ); m_KspaceImage->SetBufferedRegion( m_ImageRegion ); m_KspaceImage->SetRequestedRegion( m_ImageRegion ); m_KspaceImage->Allocate(); m_KspaceImage->FillBuffer(0); // apply undersampling to image parameters m_UpsampledSpacing = m_Spacing; m_UpsampledImageRegion = m_ImageRegion; m_UpsampledSpacing[0] /= m_Upsampling; m_UpsampledSpacing[1] /= m_Upsampling; m_UpsampledImageRegion.SetSize(0, m_ImageRegion.GetSize()[0]*m_Upsampling); m_UpsampledImageRegion.SetSize(1, m_ImageRegion.GetSize()[1]*m_Upsampling); // everything from here on is using the upsampled image parameters!!! if (m_TissueMask.IsNull()) { m_TissueMask = ItkUcharImgType::New(); m_TissueMask->SetSpacing( m_UpsampledSpacing ); m_TissueMask->SetOrigin( m_Origin ); m_TissueMask->SetDirection( m_DirectionMatrix ); m_TissueMask->SetLargestPossibleRegion( m_UpsampledImageRegion ); m_TissueMask->SetBufferedRegion( m_UpsampledImageRegion ); m_TissueMask->SetRequestedRegion( m_UpsampledImageRegion ); m_TissueMask->Allocate(); m_TissueMask->FillBuffer(1); } // resample fiber bundle for sufficient voxel coverage float minSpacing = 1; if(m_UpsampledSpacing[0]GetFiberSampling()<=0 || 10/m_FiberBundle->GetFiberSampling()>minSpacing*0.5/m_VolumeAccuracy) { fiberBundle = m_FiberBundle->GetDeepCopy(); fiberBundle->ResampleFibers(minSpacing/m_VolumeAccuracy); } // generate double images to wokr with because we don't want to lose precision // we use a separate image for each compartment model std::vector< DoubleDwiType::Pointer > compartments; for (int i=0; iSetSpacing( m_UpsampledSpacing ); doubleDwi->SetOrigin( m_Origin ); doubleDwi->SetDirection( m_DirectionMatrix ); doubleDwi->SetLargestPossibleRegion( m_UpsampledImageRegion ); doubleDwi->SetBufferedRegion( m_UpsampledImageRegion ); doubleDwi->SetRequestedRegion( m_UpsampledImageRegion ); doubleDwi->SetVectorLength( m_FiberModels[0]->GetNumGradients() ); doubleDwi->Allocate(); DoubleDwiType::PixelType pix; pix.SetSize(m_FiberModels[0]->GetNumGradients()); pix.Fill(0.0); doubleDwi->FillBuffer(pix); compartments.push_back(doubleDwi); } if (m_CircleDummy) { for (int i=0; iGetNumGradients()); pix.Fill(1); DoubleDwiType::Pointer doubleDwi = compartments.at(i); ImageRegion<3> region = doubleDwi->GetLargestPossibleRegion(); ImageRegionIterator it(doubleDwi, region); while(!it.IsAtEnd()) { DoubleDwiType::IndexType index = it.GetIndex(); double t = region.GetSize(0)/2; double d1 = index[0]-t+0.5; t = region.GetSize(1)/2; double d2 = index[1]-t+0.5; if (sqrt(d1*d1+d2*d2)<20*m_Upsampling) it.Set(pix); ++it; } } } else { + double interpFact = 2*atan(-0.5*m_InterpolationShrink); + vtkSmartPointer fiberPolyData = fiberBundle->GetFiberPolyData(); vtkSmartPointer vLines = fiberPolyData->GetLines(); vLines->InitTraversal(); MITK_INFO << "Generating signal of " << m_FiberModels.size() << " fiber compartments"; double maxFiberDensity = 0; boost::progress_display disp(numFibers); for( int i=0; iGetNextCell ( numPoints, points ); if (numPoints<2) continue; for( int j=0; jGetPoint(points[j]); itk::Point vertex = GetItkPoint(temp); itk::Vector v = GetItkVector(temp); itk::Vector dir(3); if (jGetPoint(points[j+1]))-v; else dir = v-GetItkVector(fiberPolyData->GetPoint(points[j-1])); itk::Index<3> idx; itk::ContinuousIndex contIndex; m_TissueMask->TransformPhysicalPointToIndex(vertex, idx); m_TissueMask->TransformPhysicalPointToContinuousIndex(vertex, contIndex); double frac_x = contIndex[0] - idx[0]; double frac_y = contIndex[1] - idx[1]; double frac_z = contIndex[2] - idx[2]; if (frac_x<0) { idx[0] -= 1; frac_x += 1; } if (frac_y<0) { idx[1] -= 1; frac_y += 1; } if (frac_z<0) { idx[2] -= 1; frac_z += 1; } + frac_x = atan((0.5-frac_x)*m_InterpolationShrink)/interpFact + 0.5; + frac_y = atan((0.5-frac_y)*m_InterpolationShrink)/interpFact + 0.5; + frac_z = atan((0.5-frac_z)*m_InterpolationShrink)/interpFact + 0.5; + // use trilinear interpolation itk::Index<3> newIdx; for (int x=0; x<2; x++) { frac_x = 1-frac_x; for (int y=0; y<2; y++) { frac_y = 1-frac_y; for (int z=0; z<2; z++) { frac_z = 1-frac_z; newIdx[0] = idx[0]+x; newIdx[1] = idx[1]+y; newIdx[2] = idx[2]+z; double frac = frac_x*frac_y*frac_z; // is position valid? if (!m_TissueMask->GetLargestPossibleRegion().IsInside(newIdx) || m_TissueMask->GetPixel(newIdx)<=0) continue; // generate signal for each fiber compartment for (int k=0; kSetFiberDirection(dir); doubleDwi->SetPixel(newIdx, doubleDwi->GetPixel(newIdx) + frac*m_FiberModels[k]->SimulateMeasurement()); DoubleDwiType::PixelType pix = doubleDwi->GetPixel(newIdx); if (pix[baselineIndex]>maxFiberDensity) maxFiberDensity = pix[baselineIndex]; } } } } } } MITK_INFO << "Generating signal of " << m_NonFiberModels.size() << " non-fiber compartments"; boost::progress_display disp2(m_NonFiberModels.size()*compartments.at(0)->GetLargestPossibleRegion().GetNumberOfPixels()); for (int i=0; i it(doubleDwi, doubleDwi->GetLargestPossibleRegion()); while(!it.IsAtEnd()) { ++disp2; DoubleDwiType::IndexType index = it.GetIndex(); if (m_TissueMask->GetLargestPossibleRegion().IsInside(index) && m_TissueMask->GetPixel(index)>0) doubleDwi->SetPixel(index, doubleDwi->GetPixel(index) + m_NonFiberModels[i]->SimulateMeasurement()); ++it; } } MITK_INFO << "Adjusting compartment signal intensities according to volume fraction"; ImageRegionIterator it3(m_TissueMask, m_TissueMask->GetLargestPossibleRegion()); boost::progress_display disp3(m_TissueMask->GetLargestPossibleRegion().GetNumberOfPixels()); while(!it3.IsAtEnd()) { ++disp3; DoubleDwiType::IndexType index = it3.GetIndex(); if (it3.Get()>0) { // compartment weights are calculated according to fiber density double w = compartments.at(0)->GetPixel(index)[baselineIndex]/maxFiberDensity; if (m_EnforcePureFiberVoxels && w>0) w = 1; // adjust fiber signal for (int i=0; iGetPixel(index); if (pix[baselineIndex]>0) pix /= pix[baselineIndex]; pix *= w/m_FiberModels.size(); doubleDwi->SetPixel(index, pix); } // adjust non-fiber signal for (int i=0; iGetPixel(index); if (pix[baselineIndex]>0) pix /= pix[baselineIndex]; pix *= (1-w)/m_NonFiberModels.size(); doubleDwi->SetPixel(index, pix); } } ++it3; } } // do k-space stuff if (!m_KspaceArtifacts.empty()) MITK_INFO << "Generating k-space artifacts"; else MITK_INFO << "Generating k-space image"; compartments = AddKspaceArtifacts(compartments); MITK_INFO << "Summing compartments and adding noise"; double correction = m_Upsampling*m_Upsampling; ImageRegionIterator it4 (outImage, outImage->GetLargestPossibleRegion()); DoubleDwiType::PixelType signal; signal.SetSize(m_FiberModels[0]->GetNumGradients()); boost::progress_display disp4(outImage->GetLargestPossibleRegion().GetNumberOfPixels()); while(!it4.IsAtEnd()) { ++disp4; DWIImageType::IndexType index = it4.GetIndex(); signal.Fill(0.0); // adjust fiber signal for (int i=0; iGetSignalScale()/correction; signal += compartments.at(i)->GetPixel(index)*s; } // adjust non-fiber signal for (int i=0; iGetSignalScale()/correction; signal += compartments.at(m_FiberModels.size()+i)->GetPixel(index)*s; } DoubleDwiType::PixelType accu = signal; accu.Fill(0.0); for (int i=0; iAddNoise(temp); accu += temp; } signal = accu/m_NumberOfRepetitions; for (int i=0; i0) signal[i] = floor(signal[i]+0.5); else signal[i] = ceil(signal[i]-0.5); } it4.Set(signal); ++it4; } this->SetNthOutput(0, outImage); } itk::Point TractsToDWIImageFilter::GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } itk::Vector TractsToDWIImageFilter::GetItkVector(double point[3]) { itk::Vector itkVector; itkVector[0] = point[0]; itkVector[1] = point[1]; itkVector[2] = point[2]; return itkVector; } vnl_vector_fixed TractsToDWIImageFilter::GetVnlVector(double point[3]) { vnl_vector_fixed vnlVector; vnlVector[0] = point[0]; vnlVector[1] = point[1]; vnlVector[2] = point[2]; return vnlVector; } vnl_vector_fixed TractsToDWIImageFilter::GetVnlVector(Vector& vector) { vnl_vector_fixed vnlVector; vnlVector[0] = vector[0]; vnlVector[1] = vector[1]; vnlVector[2] = vector[2]; return vnlVector; } } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h index 71e507a994..02ab223a9f 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h @@ -1,122 +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. ===================================================================*/ #ifndef __itkTractsToDWIImageFilter_h__ #define __itkTractsToDWIImageFilter_h__ // MITK #include #include #include #include #include #include // ITK #include #include #include #include #include typedef itk::VectorImage< short, 3 > DWIImageType; namespace itk { /** * \brief Generates artificial diffusion weighted image volume from the input fiberbundle using a generic multicompartment model. */ class TractsToDWIImageFilter : public ImageSource< DWIImageType > { public: typedef TractsToDWIImageFilter Self; typedef ImageSource< DWIImageType > Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; typedef itk::Image ItkDoubleImgType; typedef itk::Image ItkFloatImgType; typedef itk::Image ItkUcharImgType; typedef mitk::FiberBundleX::Pointer FiberBundleType; typedef itk::VectorImage< double, 3 > DoubleDwiType; typedef std::vector< mitk::KspaceArtifact* > KspaceArtifactList; typedef std::vector< mitk::DiffusionSignalModel* > DiffusionModelList; typedef itk::Matrix MatrixType; typedef mitk::DiffusionNoiseModel NoiseModelType; typedef itk::Image< double, 2 > SliceType; typedef itk::FFTRealToComplexConjugateImageFilter< double, 2 >::OutputImageType ComplexSliceType; itkNewMacro(Self) itkTypeMacro( TractsToDWIImageFilter, ImageToImageFilter ) // input + itkSetMacro( InterpolationShrink, double ) ///< large values shrink (towards nearest neighbour interpolation), small values strech interpolation function (towards linear interpolation) itkSetMacro( VolumeAccuracy, unsigned int ) ///< determines fiber sampling density and thereby the accuracy of the fiber volume fraction itkSetMacro( FiberBundle, FiberBundleType ) ///< input fiber bundle itkSetMacro( Spacing, mitk::Vector3D ) ///< output image spacing itkSetMacro( Origin, mitk::Point3D ) ///< output image origin itkSetMacro( DirectionMatrix, MatrixType ) ///< output image rotation itkSetMacro( EnforcePureFiberVoxels, bool ) ///< treat all voxels containing at least one fiber as fiber-only (actually disable non-fiber compartments for this voxel). itkSetMacro( ImageRegion, ImageRegion<3> ) ///< output image size itkSetMacro( NumberOfRepetitions, unsigned int ) ///< number of acquisition repetitions to reduce noise (default is no additional repetition) itkSetMacro( TissueMask, ItkUcharImgType::Pointer ) ///< voxels outside of this binary mask contain only noise (are treated as air) itkGetMacro( KspaceImage, ItkDoubleImgType::Pointer ) void SetNoiseModel(NoiseModelType* noiseModel){ m_NoiseModel = noiseModel; } ///< generates the noise added to the image values void SetFiberModels(DiffusionModelList modelList){ m_FiberModels = modelList; } ///< generate signal of fiber compartments void SetNonFiberModels(DiffusionModelList modelList){ m_NonFiberModels = modelList; } ///< generate signal of non-fiber compartments void SetKspaceArtifacts(KspaceArtifactList artifactList){ m_KspaceArtifacts = artifactList; } void GenerateData(); protected: TractsToDWIImageFilter(); virtual ~TractsToDWIImageFilter(); itk::Point GetItkPoint(double point[3]); itk::Vector GetItkVector(double point[3]); vnl_vector_fixed GetVnlVector(double point[3]); vnl_vector_fixed GetVnlVector(Vector< float, 3 >& vector); /** Transform generated image compartment by compartment, channel by channel and slice by slice using FFT and add k-space artifacts. */ std::vector< DoubleDwiType::Pointer > AddKspaceArtifacts(std::vector< DoubleDwiType::Pointer >& images); /** Rearrange FFT output to shift low frequencies to the iamge center (correct itk). */ TractsToDWIImageFilter::ComplexSliceType::Pointer RearrangeSlice(ComplexSliceType::Pointer slice); mitk::Vector3D m_Spacing; ///< output image spacing mitk::Vector3D m_UpsampledSpacing; mitk::Point3D m_Origin; ///< output image origin MatrixType m_DirectionMatrix; ///< output image rotation ImageRegion<3> m_ImageRegion; ///< output image size ImageRegion<3> m_UpsampledImageRegion; ItkUcharImgType::Pointer m_TissueMask; ///< voxels outside of this binary mask contain only noise (are treated as air) FiberBundleType m_FiberBundle; ///< input fiber bundle DiffusionModelList m_FiberModels; ///< generate signal of fiber compartments DiffusionModelList m_NonFiberModels; ///< generate signal of non-fiber compartments KspaceArtifactList m_KspaceArtifacts; NoiseModelType* m_NoiseModel; ///< generates the noise added to the image values bool m_CircleDummy; unsigned int m_VolumeAccuracy; ItkDoubleImgType::Pointer m_KspaceImage; unsigned int m_Upsampling; unsigned int m_NumberOfRepetitions; bool m_EnforcePureFiberVoxels; + double m_InterpolationShrink; }; } #include "itkTractsToDWIImageFilter.cpp" #endif diff --git a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundleX/mitkFiberBundleX.cpp b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundleX/mitkFiberBundleX.cpp index ded085ffcc..5bdedecc6f 100644 --- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundleX/mitkFiberBundleX.cpp +++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundleX/mitkFiberBundleX.cpp @@ -1,1643 +1,1727 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #define _USE_MATH_DEFINES #include "mitkFiberBundleX.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const char* mitk::FiberBundleX::COLORCODING_ORIENTATION_BASED = "Color_Orient"; //const char* mitk::FiberBundleX::COLORCODING_FA_AS_OPACITY = "Color_Orient_FA_Opacity"; const char* mitk::FiberBundleX::COLORCODING_FA_BASED = "FA_Values"; const char* mitk::FiberBundleX::COLORCODING_CUSTOM = "custom"; const char* mitk::FiberBundleX::FIBER_ID_ARRAY = "Fiber_IDs"; using namespace std; mitk::FiberBundleX::FiberBundleX( vtkPolyData* fiberPolyData ) : m_CurrentColorCoding(NULL) , m_NumFibers(0) , m_FiberSampling(0) { m_FiberPolyData = vtkSmartPointer::New(); if (fiberPolyData != NULL) { m_FiberPolyData = fiberPolyData; //m_FiberPolyData->DeepCopy(fiberPolyData); this->DoColorCodingOrientationBased(); } m_NumFibers = m_FiberPolyData->GetNumberOfLines(); this->UpdateFiberGeometry(); this->SetColorCoding(COLORCODING_ORIENTATION_BASED); this->GenerateFiberIds(); } mitk::FiberBundleX::~FiberBundleX() { } mitk::FiberBundleX::Pointer mitk::FiberBundleX::GetDeepCopy() { mitk::FiberBundleX::Pointer newFib = mitk::FiberBundleX::New(m_FiberPolyData); newFib->SetColorCoding(m_CurrentColorCoding); return newFib; } vtkSmartPointer mitk::FiberBundleX::GeneratePolyDataByIds(std::vector fiberIds) { MITK_DEBUG << "\n=====FINAL RESULT: fib_id ======\n"; MITK_DEBUG << "Number of new Fibers: " << fiberIds.size(); // iterate through the vectorcontainer hosting all desired fiber Ids vtkSmartPointer newFiberPolyData = vtkSmartPointer::New(); vtkSmartPointer newLineSet = vtkSmartPointer::New(); vtkSmartPointer newPointSet = vtkSmartPointer::New(); // if FA array available, initialize fa double array // if color orient array is available init color array vtkSmartPointer faValueArray; vtkSmartPointer colorsT; //colors and alpha value for each single point, RGBA = 4 components unsigned char rgba[4] = {0,0,0,0}; int componentSize = sizeof(rgba); if (m_FiberIdDataSet->GetPointData()->HasArray(COLORCODING_FA_BASED)){ MITK_DEBUG << "FA VALUES AVAILABLE, init array for new fiberbundle"; faValueArray = vtkSmartPointer::New(); } if (m_FiberIdDataSet->GetPointData()->HasArray(COLORCODING_ORIENTATION_BASED)){ MITK_DEBUG << "colorValues available, init array for new fiberbundle"; colorsT = vtkUnsignedCharArray::New(); colorsT->SetNumberOfComponents(componentSize); colorsT->SetName(COLORCODING_ORIENTATION_BASED); } std::vector::iterator finIt = fiberIds.begin(); while ( finIt != fiberIds.end() ) { if (*finIt < 0 || *finIt>GetNumFibers()){ MITK_INFO << "FiberID can not be negative or >NumFibers!!! check id Extraction!" << *finIt; break; } vtkSmartPointer fiber = m_FiberIdDataSet->GetCell(*finIt);//->DeepCopy(fiber); vtkSmartPointer fibPoints = fiber->GetPoints(); vtkSmartPointer newFiber = vtkSmartPointer::New(); newFiber->GetPointIds()->SetNumberOfIds( fibPoints->GetNumberOfPoints() ); for(int i=0; iGetNumberOfPoints(); i++) { // MITK_DEBUG << "id: " << fiber->GetPointId(i); // MITK_DEBUG << fibPoints->GetPoint(i)[0] << " | " << fibPoints->GetPoint(i)[1] << " | " << fibPoints->GetPoint(i)[2]; newFiber->GetPointIds()->SetId(i, newPointSet->GetNumberOfPoints()); newPointSet->InsertNextPoint(fibPoints->GetPoint(i)[0], fibPoints->GetPoint(i)[1], fibPoints->GetPoint(i)[2]); if (m_FiberIdDataSet->GetPointData()->HasArray(COLORCODING_FA_BASED)){ // MITK_DEBUG << m_FiberIdDataSet->GetPointData()->GetArray(FA_VALUE_ARRAY)->GetTuple(fiber->GetPointId(i)); } if (m_FiberIdDataSet->GetPointData()->HasArray(COLORCODING_ORIENTATION_BASED)){ // MITK_DEBUG << "ColorValue: " << m_FiberIdDataSet->GetPointData()->GetArray(COLORCODING_ORIENTATION_BASED)->GetTuple(fiber->GetPointId(i))[0]; } } newLineSet->InsertNextCell(newFiber); ++finIt; } newFiberPolyData->SetPoints(newPointSet); newFiberPolyData->SetLines(newLineSet); MITK_DEBUG << "new fiberbundle polydata points: " << newFiberPolyData->GetNumberOfPoints(); MITK_DEBUG << "new fiberbundle polydata lines: " << newFiberPolyData->GetNumberOfLines(); MITK_DEBUG << "=====================\n"; // mitk::FiberBundleX::Pointer newFib = mitk::FiberBundleX::New(newFiberPolyData); return newFiberPolyData; } // merge two fiber bundles mitk::FiberBundleX::Pointer mitk::FiberBundleX::AddBundle(mitk::FiberBundleX* fib) { if (fib==NULL) { MITK_WARN << "trying to call AddBundle with NULL argument"; return NULL; } vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); vtkSmartPointer vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); // add current fiber bundle int numFibers = GetNumFibers(); for( int i=0; iGetNextCell ( numPoints, points ); vtkSmartPointer container = vtkSmartPointer::New(); for( int j=0; jInsertNextPoint(m_FiberPolyData->GetPoint(points[j])); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); } vLines = fib->m_FiberPolyData->GetLines(); vLines->InitTraversal(); // add new fiber bundle numFibers = fib->GetNumFibers(); for( int i=0; iGetNextCell ( numPoints, points ); vtkSmartPointer container = vtkSmartPointer::New(); for( int j=0; jInsertNextPoint(fib->m_FiberPolyData->GetPoint(points[j])); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); } // initialize polydata vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle mitk::FiberBundleX::Pointer newFib = mitk::FiberBundleX::New(vNewPolyData); return newFib; } // subtract two fiber bundles mitk::FiberBundleX::Pointer mitk::FiberBundleX::SubtractBundle(mitk::FiberBundleX* fib) { vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); vtkSmartPointer vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); // iterate over current fibers int numFibers = GetNumFibers(); for( int i=0; iGetNextCell ( numPoints, points ); if (points==NULL) continue; vtkSmartPointer vLines2 = fib->m_FiberPolyData->GetLines(); vLines2->InitTraversal(); int numFibers2 = fib->GetNumFibers(); bool contained = false; for( int i2=0; i2GetNextCell ( numPoints2, points2 ); if (points2==NULL) continue; // check endpoints itk::Point point_start = GetItkPoint(m_FiberPolyData->GetPoint(points[0])); itk::Point point_end = GetItkPoint(m_FiberPolyData->GetPoint(points[numPoints-1])); itk::Point point2_start = GetItkPoint(fib->m_FiberPolyData->GetPoint(points2[0])); itk::Point point2_end = GetItkPoint(fib->m_FiberPolyData->GetPoint(points2[numPoints2-1])); if (point_start.SquaredEuclideanDistanceTo(point2_start)<=mitk::eps && point_end.SquaredEuclideanDistanceTo(point2_end)<=mitk::eps || point_start.SquaredEuclideanDistanceTo(point2_end)<=mitk::eps && point_end.SquaredEuclideanDistanceTo(point2_start)<=mitk::eps) { // further checking ??? if (numPoints2==numPoints) contained = true; } } // add to result because fiber is not subtracted if (!contained) { vtkSmartPointer container = vtkSmartPointer::New(); for( int j=0; jInsertNextPoint(m_FiberPolyData->GetPoint(points[j])); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); } } if(vNewLines->GetNumberOfCells()==0) return NULL; // initialize polydata vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle mitk::FiberBundleX::Pointer newFib = mitk::FiberBundleX::New(vNewPolyData); return newFib; } itk::Point mitk::FiberBundleX::GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } /* * set polydata (additional flag to recompute fiber geometry, default = true) */ void mitk::FiberBundleX::SetFiberPolyData(vtkSmartPointer fiberPD, bool updateGeometry) { if (fiberPD == NULL) this->m_FiberPolyData = vtkSmartPointer::New(); else { m_FiberPolyData->DeepCopy(fiberPD); DoColorCodingOrientationBased(); } m_NumFibers = m_FiberPolyData->GetNumberOfLines(); if (updateGeometry) UpdateFiberGeometry(); SetColorCoding(COLORCODING_ORIENTATION_BASED); GenerateFiberIds(); } /* * return vtkPolyData */ vtkSmartPointer mitk::FiberBundleX::GetFiberPolyData() { return m_FiberPolyData; } void mitk::FiberBundleX::DoColorCodingOrientationBased() { //===== FOR WRITING A TEST ======================== // colorT size == tupelComponents * tupelElements // compare color results // to cover this code 100% also polydata needed, where colorarray already exists // + one fiber with exactly 1 point // + one fiber with 0 points //================================================= /* make sure that processing colorcoding is only called when necessary */ if ( m_FiberPolyData->GetPointData()->HasArray(COLORCODING_ORIENTATION_BASED) && m_FiberPolyData->GetNumberOfPoints() == m_FiberPolyData->GetPointData()->GetArray(COLORCODING_ORIENTATION_BASED)->GetNumberOfTuples() ) { // fiberstructure is already colorcoded MITK_DEBUG << " NO NEED TO REGENERATE COLORCODING! " ; this->ResetFiberOpacity(); this->SetColorCoding(COLORCODING_ORIENTATION_BASED); return; } /* Finally, execute color calculation */ vtkPoints* extrPoints = NULL; extrPoints = m_FiberPolyData->GetPoints(); int numOfPoints = 0; if (extrPoints!=NULL) numOfPoints = extrPoints->GetNumberOfPoints(); //colors and alpha value for each single point, RGBA = 4 components unsigned char rgba[4] = {0,0,0,0}; // int componentSize = sizeof(rgba); int componentSize = 4; vtkSmartPointer colorsT = vtkSmartPointer::New(); colorsT->Allocate(numOfPoints * componentSize); colorsT->SetNumberOfComponents(componentSize); colorsT->SetName(COLORCODING_ORIENTATION_BASED); /* checkpoint: does polydata contain any fibers */ int numOfFibers = m_FiberPolyData->GetNumberOfLines(); if (numOfFibers < 1) { MITK_DEBUG << "\n ========= Number of Fibers is 0 and below ========= \n"; return; } /* extract single fibers of fiberBundle */ vtkCellArray* fiberList = m_FiberPolyData->GetLines(); fiberList->InitTraversal(); for (int fi=0; fiGetNextCell(pointsPerFiber, idList); // MITK_DEBUG << "Fib#: " << fi << " of " << numOfFibers << " pnts in fiber: " << pointsPerFiber ; /* single fiber checkpoints: is number of points valid */ if (pointsPerFiber > 1) { /* operate on points of single fiber */ for (int i=0; i 0) { /* The color value of the current point is influenced by the previous point and next point. */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > nextPntvtk(extrPoints->GetPoint(idList[i+1])[0], extrPoints->GetPoint(idList[i+1])[1], extrPoints->GetPoint(idList[i+1])[2]); vnl_vector_fixed< double, 3 > prevPntvtk(extrPoints->GetPoint(idList[i-1])[0], extrPoints->GetPoint(idList[i-1])[1], extrPoints->GetPoint(idList[i-1])[2]); vnl_vector_fixed< double, 3 > diff1; diff1 = currentPntvtk - nextPntvtk; vnl_vector_fixed< double, 3 > diff2; diff2 = currentPntvtk - prevPntvtk; vnl_vector_fixed< double, 3 > diff; diff = (diff1 - diff2) / 2.0; diff.normalize(); rgba[0] = (unsigned char) (255.0 * std::fabs(diff[0])); rgba[1] = (unsigned char) (255.0 * std::fabs(diff[1])); rgba[2] = (unsigned char) (255.0 * std::fabs(diff[2])); rgba[3] = (unsigned char) (255.0); } else if (i==0) { /* First point has no previous point, therefore only diff1 is taken */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > nextPntvtk(extrPoints->GetPoint(idList[i+1])[0], extrPoints->GetPoint(idList[i+1])[1], extrPoints->GetPoint(idList[i+1])[2]); vnl_vector_fixed< double, 3 > diff1; diff1 = currentPntvtk - nextPntvtk; diff1.normalize(); rgba[0] = (unsigned char) (255.0 * std::fabs(diff1[0])); rgba[1] = (unsigned char) (255.0 * std::fabs(diff1[1])); rgba[2] = (unsigned char) (255.0 * std::fabs(diff1[2])); rgba[3] = (unsigned char) (255.0); } else if (i==pointsPerFiber-1) { /* Last point has no next point, therefore only diff2 is taken */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > prevPntvtk(extrPoints->GetPoint(idList[i-1])[0], extrPoints->GetPoint(idList[i-1])[1], extrPoints->GetPoint(idList[i-1])[2]); vnl_vector_fixed< double, 3 > diff2; diff2 = currentPntvtk - prevPntvtk; diff2.normalize(); rgba[0] = (unsigned char) (255.0 * std::fabs(diff2[0])); rgba[1] = (unsigned char) (255.0 * std::fabs(diff2[1])); rgba[2] = (unsigned char) (255.0 * std::fabs(diff2[2])); rgba[3] = (unsigned char) (255.0); } colorsT->InsertTupleValue(idList[i], rgba); } //end for loop } else if (pointsPerFiber == 1) { /* a single point does not define a fiber (use vertex mechanisms instead */ continue; // colorsT->InsertTupleValue(0, rgba); } else { MITK_DEBUG << "Fiber with 0 points detected... please check your tractography algorithm!" ; continue; } }//end for loop m_FiberPolyData->GetPointData()->AddArray(colorsT); /*========================= - this is more relevant for renderer than for fiberbundleX datastructure - think about sourcing this to a explicit method which coordinates colorcoding */ this->SetColorCoding(COLORCODING_ORIENTATION_BASED); // =========================== //mini test, shall be ported to MITK TESTINGS! if (colorsT->GetSize() != numOfPoints*componentSize) MITK_DEBUG << "ALLOCATION ERROR IN INITIATING COLOR ARRAY"; } void mitk::FiberBundleX::DoColorCodingFaBased() { if(m_FiberPolyData->GetPointData()->HasArray(COLORCODING_FA_BASED) != 1 ) return; this->SetColorCoding(COLORCODING_FA_BASED); MITK_DEBUG << "FBX: done CC FA based"; this->GenerateFiberIds(); } void mitk::FiberBundleX::DoUseFaFiberOpacity() { if(m_FiberPolyData->GetPointData()->HasArray(COLORCODING_FA_BASED) != 1 ) return; if(m_FiberPolyData->GetPointData()->HasArray(COLORCODING_ORIENTATION_BASED) != 1 ) return; vtkDoubleArray* FAValArray = (vtkDoubleArray*) m_FiberPolyData->GetPointData()->GetArray(COLORCODING_FA_BASED); vtkUnsignedCharArray* ColorArray = dynamic_cast (m_FiberPolyData->GetPointData()->GetArray(COLORCODING_ORIENTATION_BASED)); for(long i=0; iGetNumberOfTuples(); i++) { double faValue = FAValArray->GetValue(i); faValue = faValue * 255.0; ColorArray->SetComponent(i,3, (unsigned char) faValue ); } this->SetColorCoding(COLORCODING_ORIENTATION_BASED); MITK_DEBUG << "FBX: done CC OPACITY"; this->GenerateFiberIds(); } void mitk::FiberBundleX::ResetFiberOpacity() { vtkUnsignedCharArray* ColorArray = dynamic_cast (m_FiberPolyData->GetPointData()->GetArray(COLORCODING_ORIENTATION_BASED)); if (ColorArray==NULL) return; for(long i=0; iGetNumberOfTuples(); i++) ColorArray->SetComponent(i,3, 255.0 ); } void mitk::FiberBundleX::SetFAMap(mitk::Image::Pointer FAimage) { MITK_DEBUG << "SetFAMap"; vtkSmartPointer faValues = vtkSmartPointer::New(); faValues->SetName(COLORCODING_FA_BASED); faValues->Allocate(m_FiberPolyData->GetNumberOfPoints()); - // MITK_DEBUG << faValues->GetNumberOfTuples(); - // MITK_DEBUG << faValues->GetSize(); - faValues->SetNumberOfValues(m_FiberPolyData->GetNumberOfPoints()); - // MITK_DEBUG << faValues->GetNumberOfTuples(); - // MITK_DEBUG << faValues->GetSize(); vtkPoints* pointSet = m_FiberPolyData->GetPoints(); for(long i=0; iGetNumberOfPoints(); ++i) { Point3D px; px[0] = pointSet->GetPoint(i)[0]; px[1] = pointSet->GetPoint(i)[1]; px[2] = pointSet->GetPoint(i)[2]; double faPixelValue = 1-FAimage->GetPixelValueByWorldCoordinate(px); - // faValues->InsertNextTuple1(faPixelValue); faValues->InsertValue(i, faPixelValue); - // MITK_DEBUG << faPixelValue; - // MITK_DEBUG << faValues->GetValue(i); - } m_FiberPolyData->GetPointData()->AddArray(faValues); this->GenerateFiberIds(); if(m_FiberPolyData->GetPointData()->HasArray(COLORCODING_FA_BASED)) MITK_DEBUG << "FA VALUE ARRAY SET"; - - // vtkDoubleArray* valueArray = (vtkDoubleArray*) m_FiberPolyData->GetPointData()->GetArray(FA_VALUE_ARRAY); - // for(long i=0; iGetNumberOfPoints(); i++) - // { - // MITK_DEBUG << "value at pos "<< i << ": " << valueArray->GetValue(i); - // } } void mitk::FiberBundleX::GenerateFiberIds() { if (m_FiberPolyData == NULL) return; vtkSmartPointer idFiberFilter = vtkSmartPointer::New(); idFiberFilter->SetInput(m_FiberPolyData); idFiberFilter->CellIdsOn(); // idFiberFilter->PointIdsOn(); // point id's are not needed idFiberFilter->SetIdsArrayName(FIBER_ID_ARRAY); idFiberFilter->FieldDataOn(); idFiberFilter->Update(); m_FiberIdDataSet = idFiberFilter->GetOutput(); MITK_DEBUG << "Generating Fiber Ids...[done] | " << m_FiberIdDataSet->GetNumberOfCells(); } +mitk::FiberBundleX::Pointer mitk::FiberBundleX::ExtractFiberSubset(ItkUcharImgType* mask, bool anyPoint) +{ + vtkSmartPointer polyData = this->GetFiberPolyData(); + if (anyPoint) + { + float minSpacing = 1; + if(mask->GetSpacing()[0]GetSpacing()[1] && mask->GetSpacing()[0]GetSpacing()[2]) + minSpacing = mask->GetSpacing()[0]; + else if (mask->GetSpacing()[1] < mask->GetSpacing()[2]) + minSpacing = mask->GetSpacing()[1]; + else + minSpacing = mask->GetSpacing()[2]; + + mitk::FiberBundleX::Pointer fibCopy = this->GetDeepCopy(); + fibCopy->ResampleFibers(minSpacing/2); + polyData = fibCopy->GetFiberPolyData(); + } + vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); + vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); + vtkSmartPointer vLines = polyData->GetLines(); + vLines->InitTraversal(); + + MITK_INFO << "Extracting fibers"; + boost::progress_display disp(m_NumFibers); + for (int i=0; iGetNextCell ( numPoints, pointIds ); + + vtkSmartPointer container = vtkSmartPointer::New(); + + if (numPoints>1) + { + if (anyPoint) + { + for (int j=0; jGetPoint(pointIds[j]); + + itk::Point itkP; + itkP[0] = p[0]; itkP[1] = p[1]; p[2] = p[2]; + itk::Index<3> idx; + mask->TransformPhysicalPointToIndex(itkP, idx); + if ( mask->GetPixel(idx)>0 ) + { + for (int j=0; jGetPoint(pointIds[j]); + vtkIdType id = vtkNewPoints->InsertNextPoint(p); + container->GetPointIds()->InsertNextId(id); + } + break; + } + } + } + else + { + double* start = polyData->GetPoint(pointIds[0]); + itk::Point itkStart; + itkStart[0] = start[0]; itkStart[1] = start[1]; itkStart[2] = start[2]; + itk::Index<3> idxStart; + mask->TransformPhysicalPointToIndex(itkStart, idxStart); + + double* end = polyData->GetPoint(pointIds[numPoints-1]); + itk::Point itkEnd; + itkEnd[0] = end[0]; itkEnd[1] = end[1]; itkEnd[2] = end[2]; + itk::Index<3> idxEnd; + mask->TransformPhysicalPointToIndex(itkEnd, idxEnd); + + if ( mask->GetPixel(idxStart)>0 && mask->GetPixel(idxEnd)>0 ) + { + for (int j=0; jGetPoint(pointIds[j]); + vtkIdType id = vtkNewPoints->InsertNextPoint(p); + container->GetPointIds()->InsertNextId(id); + } + } + } + } + + vtkNewCells->InsertNextCell(container); + } + + if (vtkNewCells->GetNumberOfCells()<=0) + return NULL; + + vtkSmartPointer newPolyData = vtkSmartPointer::New(); + newPolyData->SetPoints(vtkNewPoints); + newPolyData->SetLines(vtkNewCells); + return mitk::FiberBundleX::New(newPolyData); +} mitk::FiberBundleX::Pointer mitk::FiberBundleX::ExtractFiberSubset(mitk::PlanarFigure* pf) { if (pf==NULL) return NULL; std::vector tmp = ExtractFiberIdSubset(pf); if (tmp.size()<=0) return mitk::FiberBundleX::New(); vtkSmartPointer pTmp = GeneratePolyDataByIds(tmp); return mitk::FiberBundleX::New(pTmp); } std::vector mitk::FiberBundleX::ExtractFiberIdSubset(mitk::PlanarFigure* pf) { MITK_DEBUG << "Extracting fibers!"; // vector which is returned, contains all extracted FiberIds std::vector FibersInROI; if (pf==NULL) return FibersInROI; /* Handle type of planarfigure */ // if incoming pf is a pfc mitk::PlanarFigureComposite::Pointer pfcomp= dynamic_cast(pf); if (!pfcomp.IsNull()) { // process requested boolean operation of PFC switch (pfcomp->getOperationType()) { case 0: { MITK_DEBUG << "AND PROCESSING"; //AND //temporarly store results of the child in this vector, we need that to accumulate the std::vector childResults = this->ExtractFiberIdSubset(pfcomp->getChildAt(0)); MITK_DEBUG << "first roi got fibers in ROI: " << childResults.size(); MITK_DEBUG << "sorting..."; std::sort(childResults.begin(), childResults.end()); MITK_DEBUG << "sorting done"; std::vector AND_Assamblage(childResults.size()); //std::vector AND_Assamblage; fill(AND_Assamblage.begin(), AND_Assamblage.end(), -1); //AND_Assamblage.reserve(childResults.size()); //max size AND can reach anyway std::vector::iterator it; for (int i=1; igetNumberOfChildren(); ++i) { std::vector tmpChild = this->ExtractFiberIdSubset(pfcomp->getChildAt(i)); MITK_DEBUG << "ROI " << i << " has fibers in ROI: " << tmpChild.size(); sort(tmpChild.begin(), tmpChild.end()); it = std::set_intersection(childResults.begin(), childResults.end(), tmpChild.begin(), tmpChild.end(), AND_Assamblage.begin() ); } MITK_DEBUG << "resize Vector"; long i=0; while (i < AND_Assamblage.size() && AND_Assamblage[i] != -1){ //-1 represents a placeholder in the array ++i; } AND_Assamblage.resize(i); MITK_DEBUG << "returning AND vector, size: " << AND_Assamblage.size(); return AND_Assamblage; // break; } case 1: { //OR std::vector OR_Assamblage = this->ExtractFiberIdSubset(pfcomp->getChildAt(0)); std::vector::iterator it; MITK_DEBUG << OR_Assamblage.size(); for (int i=1; igetNumberOfChildren(); ++i) { it = OR_Assamblage.end(); std::vector tmpChild = this->ExtractFiberIdSubset(pfcomp->getChildAt(i)); OR_Assamblage.insert(it, tmpChild.begin(), tmpChild.end()); MITK_DEBUG << "ROI " << i << " has fibers in ROI: " << tmpChild.size() << " OR Assamblage: " << OR_Assamblage.size(); } sort(OR_Assamblage.begin(), OR_Assamblage.end()); it = unique(OR_Assamblage.begin(), OR_Assamblage.end()); OR_Assamblage.resize( it - OR_Assamblage.begin() ); MITK_DEBUG << "returning OR vector, size: " << OR_Assamblage.size(); return OR_Assamblage; } case 2: { //NOT //get IDs of all fibers std::vector childResults; childResults.reserve(this->GetNumFibers()); vtkSmartPointer idSet = m_FiberIdDataSet->GetCellData()->GetArray(FIBER_ID_ARRAY); MITK_DEBUG << "m_NumOfFib: " << this->GetNumFibers() << " cellIdNum: " << idSet->GetNumberOfTuples(); for(long i=0; iGetNumFibers(); i++) { MITK_DEBUG << "i: " << i << " idset: " << idSet->GetTuple(i)[0]; childResults.push_back(idSet->GetTuple(i)[0]); } std::sort(childResults.begin(), childResults.end()); std::vector NOT_Assamblage(childResults.size()); //fill it with -1, otherwise 0 will be stored and 0 can also be an ID of fiber! fill(NOT_Assamblage.begin(), NOT_Assamblage.end(), -1); std::vector::iterator it; for (long i=0; igetNumberOfChildren(); ++i) { std::vector tmpChild = ExtractFiberIdSubset(pfcomp->getChildAt(i)); sort(tmpChild.begin(), tmpChild.end()); it = std::set_difference(childResults.begin(), childResults.end(), tmpChild.begin(), tmpChild.end(), NOT_Assamblage.begin() ); } MITK_DEBUG << "resize Vector"; long i=0; while (NOT_Assamblage[i] != -1){ //-1 represents a placeholder in the array ++i; } NOT_Assamblage.resize(i); return NOT_Assamblage; } default: MITK_DEBUG << "we have an UNDEFINED composition... ERROR" ; break; } } else { mitk::Geometry2D::ConstPointer pfgeometry = pf->GetGeometry2D(); const mitk::PlaneGeometry* planeGeometry = dynamic_cast (pfgeometry.GetPointer()); Vector3D planeNormal = planeGeometry->GetNormal(); planeNormal.Normalize(); Point3D planeOrigin = planeGeometry->GetOrigin(); MITK_DEBUG << "planeOrigin: " << planeOrigin[0] << " | " << planeOrigin[1] << " | " << planeOrigin[2] << endl; MITK_DEBUG << "planeNormal: " << planeNormal[0] << " | " << planeNormal[1] << " | " << planeNormal[2] << endl; std::vector PointsOnPlane; // contains all pointIds which are crossing the cutting plane std::vector PointsInROI; // based on PointsOnPlane, all ROI relevant point IDs are stored here /* Define cutting plane by ROI (PlanarFigure) */ vtkSmartPointer plane = vtkSmartPointer::New(); plane->SetOrigin(planeOrigin[0],planeOrigin[1],planeOrigin[2]); plane->SetNormal(planeNormal[0],planeNormal[1],planeNormal[2]); /* get all points/fibers cutting the plane */ MITK_DEBUG << "start clipping"; vtkSmartPointer clipper = vtkSmartPointer::New(); clipper->SetInput(m_FiberIdDataSet); clipper->SetClipFunction(plane); clipper->GenerateClipScalarsOn(); clipper->GenerateClippedOutputOn(); vtkSmartPointer clipperout = clipper->GetClippedOutput(); MITK_DEBUG << "end clipping"; MITK_DEBUG << "init and update clipperoutput"; clipperout->GetPointData()->Initialize(); clipperout->Update(); MITK_DEBUG << "init and update clipperoutput completed"; MITK_DEBUG << "STEP 1: find all points which have distance 0 to the given plane"; /*======STEP 1====== * extract all points, which are crossing the plane */ // Scalar values describe the distance between each remaining point to the given plane. Values sorted by point index vtkSmartPointer distanceList = clipperout->GetPointData()->GetScalars(); vtkIdType sizeOfList = distanceList->GetNumberOfTuples(); PointsOnPlane.reserve(sizeOfList); /* use reserve for high-performant push_back, no hidden copy procedures are processed then! * size of list can be optimized by reducing allocation, but be aware of iterator and vector size*/ for (int i=0; iGetTuple(i); // check if point is on plane. // 0.01 due to some approximation errors when calculating distance if (distance[0] >= -0.01 && distance[0] <= 0.01) PointsOnPlane.push_back(i); } MITK_DEBUG << "Num Of points on plane: " << PointsOnPlane.size(); MITK_DEBUG << "Step 2: extract Interesting points with respect to given extraction planarFigure"; PointsInROI.reserve(PointsOnPlane.size()); /*=======STEP 2===== * extract ROI relevant pointIds */ mitk::PlanarCircle::Pointer circleName = mitk::PlanarCircle::New(); mitk::PlanarPolygon::Pointer polyName = mitk::PlanarPolygon::New(); if ( pf->GetNameOfClass() == circleName->GetNameOfClass() ) { //calculate circle radius mitk::Point3D V1w = pf->GetWorldControlPoint(0); //centerPoint mitk::Point3D V2w = pf->GetWorldControlPoint(1); //radiusPoint double distPF = V1w.EuclideanDistanceTo(V2w); for (int i=0; iGetPoint(PointsOnPlane[i])[0] - V1w[0]) * (clipperout->GetPoint(PointsOnPlane[i])[0] - V1w[0]) + (clipperout->GetPoint(PointsOnPlane[i])[1] - V1w[1]) * (clipperout->GetPoint(PointsOnPlane[i])[1] - V1w[1]) + (clipperout->GetPoint(PointsOnPlane[i])[2] - V1w[2]) * (clipperout->GetPoint(PointsOnPlane[i])[2] - V1w[2])) ; if( XdistPnt <= distPF) PointsInROI.push_back(PointsOnPlane[i]); } } else if ( pf->GetNameOfClass() == polyName->GetNameOfClass() ) { //create vtkPolygon using controlpoints from planarFigure polygon vtkSmartPointer polygonVtk = vtkSmartPointer::New(); //get the control points from pf and insert them to vtkPolygon unsigned int nrCtrlPnts = pf->GetNumberOfControlPoints(); for (int i=0; iGetPoints()->InsertNextPoint((double)pf->GetWorldControlPoint(i)[0], (double)pf->GetWorldControlPoint(i)[1], (double)pf->GetWorldControlPoint(i)[2] ); } //prepare everything for using pointInPolygon function double n[3]; polygonVtk->ComputeNormal(polygonVtk->GetPoints()->GetNumberOfPoints(), static_cast(polygonVtk->GetPoints()->GetData()->GetVoidPointer(0)), n); double bounds[6]; polygonVtk->GetPoints()->GetBounds(bounds); for (int i=0; iGetPoint(PointsOnPlane[i])[0], clipperout->GetPoint(PointsOnPlane[i])[1], clipperout->GetPoint(PointsOnPlane[i])[2]}; int isInPolygon = polygonVtk->PointInPolygon(checkIn, polygonVtk->GetPoints()->GetNumberOfPoints() , static_cast(polygonVtk->GetPoints()->GetData()->GetVoidPointer(0)), bounds, n); if( isInPolygon ) PointsInROI.push_back(PointsOnPlane[i]); } } MITK_DEBUG << "Step3: Identify fibers"; // we need to access the fiberId Array, so make sure that this array is available if (!clipperout->GetCellData()->HasArray(FIBER_ID_ARRAY)) { MITK_DEBUG << "ERROR: FiberID array does not exist, no correlation between points and fiberIds possible! Make sure calling GenerateFiberIds()"; return FibersInROI; // FibersInRoi is empty then } if (PointsInROI.size()<=0) return FibersInROI; // prepare a structure where each point id is represented as an indexId. // vector looks like: | pntId | fiberIdx | std::vector< long > pointindexFiberMap; // walk through the whole subline section and create an vector sorted by point index vtkCellArray *clipperlines = clipperout->GetLines(); clipperlines->InitTraversal(); long numOfLineCells = clipperlines->GetNumberOfCells(); long numofClippedPoints = clipperout->GetNumberOfPoints(); pointindexFiberMap.resize(numofClippedPoints); //prepare resulting vector FibersInROI.reserve(PointsInROI.size()); MITK_DEBUG << "\n===== Pointindex based structure initialized ======\n"; // go through resulting "sub"lines which are stored as cells, "i" corresponds to current line id. for (int i=0, ic=0 ; iGetCell(ic, npts, pts); // go through point ids in hosting subline, "j" corresponds to current pointindex in current line i. eg. idx[0]=45; idx[1]=46 for (long j=0; jGetCellData()->GetArray(FIBER_ID_ARRAY)->GetTuple(i)[0] << " to pointId: " << pts[j]; pointindexFiberMap[ pts[j] ] = clipperout->GetCellData()->GetArray(FIBER_ID_ARRAY)->GetTuple(i)[0]; // MITK_DEBUG << "in array: " << pointindexFiberMap[ pts[j] ]; } } MITK_DEBUG << "\n===== Pointindex based structure finalized ======\n"; // get all Points in ROI with according fiberID for (long k = 0; k < PointsInROI.size(); k++) { //MITK_DEBUG << "point " << PointsInROI[k] << " belongs to fiber " << pointindexFiberMap[ PointsInROI[k] ]; if (pointindexFiberMap[ PointsInROI[k] ]<=GetNumFibers() && pointindexFiberMap[ PointsInROI[k] ]>=0) FibersInROI.push_back(pointindexFiberMap[ PointsInROI[k] ]); else MITK_INFO << "ERROR in ExtractFiberIdSubset; impossible fiber id detected"; } m_PointsRoi = PointsInROI; } // detecting fiberId duplicates MITK_DEBUG << "check for duplicates"; sort(FibersInROI.begin(), FibersInROI.end()); bool hasDuplicats = false; for(long i=0; i::iterator it; it = unique (FibersInROI.begin(), FibersInROI.end()); FibersInROI.resize( it - FibersInROI.begin() ); } return FibersInROI; } void mitk::FiberBundleX::UpdateFiberGeometry() { vtkSmartPointer cleaner = vtkSmartPointer::New(); cleaner->SetInput(m_FiberPolyData); cleaner->PointMergingOff(); cleaner->Update(); m_FiberPolyData = cleaner->GetOutput(); m_FiberLengths.clear(); m_MeanFiberLength = 0; m_MedianFiberLength = 0; m_LengthStDev = 0; m_NumFibers = m_FiberPolyData->GetNumberOfLines(); if (m_NumFibers<=0) // no fibers present; apply default geometry { m_MinFiberLength = 0; m_MaxFiberLength = 0; mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); geometry->SetImageGeometry(true); float b[] = {0, 1, 0, 1, 0, 1}; geometry->SetFloatBounds(b); SetGeometry(geometry); return; } float min = itk::NumericTraits::NonpositiveMin(); float max = itk::NumericTraits::max(); float b[] = {max, min, max, min, max, min}; vtkCellArray* cells = m_FiberPolyData->GetLines(); cells->InitTraversal(); for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); int p = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); float length = 0; for (int j=0; jGetPoint(j, p1); if (p1[0]b[1]) b[1]=p1[0]; if (p1[1]b[3]) b[3]=p1[1]; if (p1[2]b[5]) b[5]=p1[2]; // calculate statistics if (jGetPoint(j+1, p2); float dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2])); length += dist; } } m_FiberLengths.push_back(length); m_MeanFiberLength += length; if (i==0) { m_MinFiberLength = length; m_MaxFiberLength = length; } else { if (lengthm_MaxFiberLength) m_MaxFiberLength = length; } } m_MeanFiberLength /= m_NumFibers; std::vector< float > sortedLengths = m_FiberLengths; std::sort(sortedLengths.begin(), sortedLengths.end()); for (int i=0; i1) m_LengthStDev /= (m_NumFibers-1); else m_LengthStDev = 0; m_LengthStDev = std::sqrt(m_LengthStDev); m_MedianFiberLength = sortedLengths.at(m_NumFibers/2); // provide some border margin for(int i=0; i<=4; i+=2) b[i] -=10; for(int i=1; i<=5; i+=2) b[i] +=10; mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); geometry->SetFloatBounds(b); this->SetGeometry(geometry); } QStringList mitk::FiberBundleX::GetAvailableColorCodings() { QStringList availableColorCodings; int numColors = m_FiberPolyData->GetPointData()->GetNumberOfArrays(); for(int i=0; iGetPointData()->GetArrayName(i)); } //this controlstructure shall be implemented by the calling method if (availableColorCodings.isEmpty()) MITK_DEBUG << "no colorcodings available in fiberbundleX"; return availableColorCodings; } char* mitk::FiberBundleX::GetCurrentColorCoding() { return m_CurrentColorCoding; } void mitk::FiberBundleX::SetColorCoding(const char* requestedColorCoding) { if (requestedColorCoding==NULL) return; MITK_DEBUG << "SetColorCoding:" << requestedColorCoding; if( strcmp (COLORCODING_ORIENTATION_BASED,requestedColorCoding) == 0 ) { this->m_CurrentColorCoding = (char*) COLORCODING_ORIENTATION_BASED; } else if( strcmp (COLORCODING_FA_BASED,requestedColorCoding) == 0 ) { this->m_CurrentColorCoding = (char*) COLORCODING_FA_BASED; } else if( strcmp (COLORCODING_CUSTOM,requestedColorCoding) == 0 ) { this->m_CurrentColorCoding = (char*) COLORCODING_CUSTOM; } else { MITK_DEBUG << "FIBERBUNDLE X: UNKNOWN COLORCODING in FIBERBUNDLEX Datastructure"; this->m_CurrentColorCoding = (char*) COLORCODING_CUSTOM; //will cause blank colorcoding of fibers } } void mitk::FiberBundleX::RotateAroundAxis(double x, double y, double z) { MITK_INFO << "Rotating fibers"; x = x*M_PI/180; y = y*M_PI/180; z = z*M_PI/180; vnl_matrix_fixed< double, 3, 3 > rotX; rotX.set_identity(); rotX[1][1] = cos(x); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(x); rotX[2][1] = -rotX[1][2]; vnl_matrix_fixed< double, 3, 3 > rotY; rotY.set_identity(); rotY[0][0] = cos(y); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(y); rotY[2][0] = -rotY[0][2]; vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity(); rotZ[0][0] = cos(z); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(z); rotZ[1][0] = -rotZ[0][1]; mitk::Geometry3D::Pointer geom = this->GetGeometry(); mitk::Point3D center = geom->GetCenter(); boost::progress_display disp(m_NumFibers); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); vtkSmartPointer vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); for (int i=0; iGetNextCell ( numPoints, pointIds ); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(pointIds[j]); vnl_vector_fixed< double, 3 > dir; dir[0] = p[0]-center[0]; dir[1] = p[1]-center[1]; dir[2] = p[2]-center[2]; dir = rotZ*rotY*rotX*dir; dir[0] += center[0]; dir[1] += center[1]; dir[2] += center[2]; vtkIdType id = vtkNewPoints->InsertNextPoint(dir.data_block()); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); UpdateColorCoding(); UpdateFiberGeometry(); } void mitk::FiberBundleX::ScaleFibers(double x, double y, double z) { MITK_INFO << "Scaling fibers"; boost::progress_display disp(m_NumFibers); + mitk::Geometry3D* geom = this->GetGeometry(); + mitk::Point3D c = geom->GetCenter(); + vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); vtkSmartPointer vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); for (int i=0; iGetNextCell ( numPoints, pointIds ); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(pointIds[j]); + p[0] -= c[0]; p[1] -= c[1]; p[2] -= c[2]; p[0] *= x; p[1] *= y; p[2] *= z; + p[0] += c[0]; p[1] += c[1]; p[2] += c[2]; vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); UpdateColorCoding(); UpdateFiberGeometry(); } void mitk::FiberBundleX::TranslateFibers(double x, double y, double z) { MITK_INFO << "Translating fibers"; boost::progress_display disp(m_NumFibers); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); vtkSmartPointer vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); for (int i=0; iGetNextCell ( numPoints, pointIds ); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(pointIds[j]); p[0] += x; p[1] += y; p[2] += z; vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); UpdateColorCoding(); UpdateFiberGeometry(); } void mitk::FiberBundleX::MirrorFibers(unsigned int axis) { if (axis>2) return; MITK_INFO << "Mirroring fibers"; boost::progress_display disp(m_NumFibers); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); vtkSmartPointer vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); for (int i=0; iGetNextCell ( numPoints, pointIds ); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(pointIds[j]); p[axis] = -p[axis]; vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); UpdateColorCoding(); UpdateFiberGeometry(); } bool mitk::FiberBundleX::ApplyCurvatureThreshold(float minRadius, bool deleteFibers) { if (minRadius<0) return true; vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); vtkSmartPointer vtkOldCells = m_FiberPolyData->GetLines(); vtkOldCells->InitTraversal(); MITK_INFO << "Applying curvature threshold"; boost::progress_display disp(m_FiberPolyData->GetNumberOfCells()); for (int i=0; iGetNumberOfCells(); i++) { ++disp ; vtkIdType numPoints(0); vtkIdType* points(NULL); vtkOldCells->GetNextCell ( numPoints, points ); // calculate curvatures vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(points[j], p1); double p2[3]; m_FiberPolyData->GetPoint(points[j+1], p2); double p3[3]; m_FiberPolyData->GetPoint(points[j+2], p3); vnl_vector_fixed< float, 3 > v1, v2, v3; v1[0] = p2[0]-p1[0]; v1[1] = p2[1]-p1[1]; v1[2] = p2[2]-p1[2]; v2[0] = p3[0]-p2[0]; v2[1] = p3[1]-p2[1]; v2[2] = p3[2]-p2[2]; v3[0] = p1[0]-p3[0]; v3[1] = p1[1]-p3[1]; v3[2] = p1[2]-p3[2]; float a = v1.magnitude(); float b = v2.magnitude(); float c = v3.magnitude(); float r = a*b*c/std::sqrt((a+b+c)*(a+b-c)*(b+c-a)*(a-b+c)); // radius of triangle via Heron's formula (area of triangle) vtkIdType id = vtkNewPoints->InsertNextPoint(p1); container->GetPointIds()->InsertNextId(id); if (deleteFibers && rInsertNextPoint(p2); // container->GetPointIds()->InsertNextId(id); vtkNewCells->InsertNextCell(container); container = vtkSmartPointer::New(); } else if (j==numPoints-3) { id = vtkNewPoints->InsertNextPoint(p2); container->GetPointIds()->InsertNextId(id); id = vtkNewPoints->InsertNextPoint(p3); container->GetPointIds()->InsertNextId(id); vtkNewCells->InsertNextCell(container); } } } if (vtkNewCells->GetNumberOfCells()<=0) return false; m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); UpdateColorCoding(); UpdateFiberGeometry(); return true; } bool mitk::FiberBundleX::RemoveShortFibers(float lengthInMM) { if (lengthInMM<=0 || lengthInMMm_MaxFiberLength) // can't remove all fibers return false; vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); vtkSmartPointer vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); float min = m_MaxFiberLength; MITK_INFO << "Removing short fibers"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetNextCell ( numPoints, pointIds ); if (m_FiberLengths.at(i)>=lengthInMM) { vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(pointIds[j]); vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); if (m_FiberLengths.at(i)GetNumberOfCells()<=0) return false; m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); UpdateColorCoding(); UpdateFiberGeometry(); return true; } bool mitk::FiberBundleX::RemoveLongFibers(float lengthInMM) { if (lengthInMM<=0 || lengthInMM>m_MaxFiberLength) return true; if (lengthInMM vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); vtkSmartPointer vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); MITK_INFO << "Removing long fibers"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetNextCell ( numPoints, pointIds ); if (m_FiberLengths.at(i)<=lengthInMM) { vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(pointIds[j]); vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } } if (vtkNewCells->GetNumberOfCells()<=0) return false; m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); UpdateColorCoding(); UpdateFiberGeometry(); return true; } void mitk::FiberBundleX::DoFiberSmoothing(int pointsPerCm, double tension, double continuity, double bias ) { vtkSmartPointer vtkSmoothPoints = vtkSmartPointer::New(); //in smoothpoints the interpolated points representing a fiber are stored. //in vtkcells all polylines are stored, actually all id's of them are stored vtkSmartPointer vtkSmoothCells = vtkSmartPointer::New(); //cellcontainer for smoothed lines vtkSmartPointer vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); vtkIdType pointHelperCnt = 0; MITK_INFO << "Resampling fibers"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetNextCell ( numPoints, pointIds ); vtkSmartPointer points = vtkSmartPointer::New(); for (int j=0; jInsertNextPoint(m_FiberPolyData->GetPoint(pointIds[j])); float length = m_FiberLengths.at(i); length /=10; int sampling = pointsPerCm*length; vtkSmartPointer xSpline = vtkSmartPointer::New(); vtkSmartPointer ySpline = vtkSmartPointer::New(); vtkSmartPointer zSpline = vtkSmartPointer::New(); xSpline->SetDefaultBias(bias); xSpline->SetDefaultTension(tension); xSpline->SetDefaultContinuity(continuity); ySpline->SetDefaultBias(bias); ySpline->SetDefaultTension(tension); ySpline->SetDefaultContinuity(continuity); zSpline->SetDefaultBias(bias); zSpline->SetDefaultTension(tension); zSpline->SetDefaultContinuity(continuity); vtkSmartPointer spline = vtkSmartPointer::New(); spline->SetXSpline(xSpline); spline->SetYSpline(ySpline); spline->SetZSpline(zSpline); spline->SetPoints(points); vtkSmartPointer functionSource = vtkSmartPointer::New(); functionSource->SetParametricFunction(spline); functionSource->SetUResolution(sampling); functionSource->SetVResolution(sampling); functionSource->SetWResolution(sampling); functionSource->Update(); vtkPolyData* outputFunction = functionSource->GetOutput(); vtkPoints* tmpSmoothPnts = outputFunction->GetPoints(); //smoothPoints of current fiber vtkSmartPointer smoothLine = vtkSmartPointer::New(); smoothLine->GetPointIds()->SetNumberOfIds(tmpSmoothPnts->GetNumberOfPoints()); for (int j=0; jGetNumberOfPoints(); j++) { smoothLine->GetPointIds()->SetId(j, j+pointHelperCnt); vtkSmoothPoints->InsertNextPoint(tmpSmoothPnts->GetPoint(j)); } vtkSmoothCells->InsertNextCell(smoothLine); pointHelperCnt += tmpSmoothPnts->GetNumberOfPoints(); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkSmoothPoints); m_FiberPolyData->SetLines(vtkSmoothCells); UpdateColorCoding(); UpdateFiberGeometry(); m_FiberSampling = pointsPerCm; } void mitk::FiberBundleX::DoFiberSmoothing(int pointsPerCm) { DoFiberSmoothing(pointsPerCm, 0, 0, 0 ); } // Resample fiber to get equidistant points void mitk::FiberBundleX::ResampleFibers(float pointDistance) { if (pointDistance<=0.00001) return; vtkSmartPointer newPoly = vtkSmartPointer::New(); vtkSmartPointer newCellArray = vtkSmartPointer::New(); vtkSmartPointer newPoints = vtkSmartPointer::New(); vtkSmartPointer vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); int numberOfLines = m_NumFibers; MITK_INFO << "Resampling fibers"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetNextCell ( numPoints, points ); vtkSmartPointer container = vtkSmartPointer::New(); double* point = m_FiberPolyData->GetPoint(points[0]); vtkIdType pointId = newPoints->InsertNextPoint(point); container->GetPointIds()->InsertNextId(pointId); float dtau = 0; int cur_p = 1; itk::Vector dR; float normdR = 0; for (;;) { while (dtau <= pointDistance && cur_p < numPoints) { itk::Vector v1; point = m_FiberPolyData->GetPoint(points[cur_p-1]); v1[0] = point[0]; v1[1] = point[1]; v1[2] = point[2]; itk::Vector v2; point = m_FiberPolyData->GetPoint(points[cur_p]); v2[0] = point[0]; v2[1] = point[1]; v2[2] = point[2]; dR = v2 - v1; normdR = std::sqrt(dR.GetSquaredNorm()); dtau += normdR; cur_p++; } if (dtau >= pointDistance) { itk::Vector v1; point = m_FiberPolyData->GetPoint(points[cur_p-1]); v1[0] = point[0]; v1[1] = point[1]; v1[2] = point[2]; itk::Vector v2 = v1 - dR*( (dtau-pointDistance)/normdR ); pointId = newPoints->InsertNextPoint(v2.GetDataPointer()); container->GetPointIds()->InsertNextId(pointId); } else { point = m_FiberPolyData->GetPoint(points[numPoints-1]); pointId = newPoints->InsertNextPoint(point); container->GetPointIds()->InsertNextId(pointId); break; } dtau = dtau-pointDistance; } newCellArray->InsertNextCell(container); } newPoly->SetPoints(newPoints); newPoly->SetLines(newCellArray); m_FiberPolyData = newPoly; UpdateFiberGeometry(); UpdateColorCoding(); m_FiberSampling = 10/pointDistance; } // reapply selected colorcoding in case polydata structure has changed void mitk::FiberBundleX::UpdateColorCoding() { char* cc = GetCurrentColorCoding(); if( strcmp (COLORCODING_ORIENTATION_BASED,cc) == 0 ) DoColorCodingOrientationBased(); else if( strcmp (COLORCODING_FA_BASED,cc) == 0 ) DoColorCodingFaBased(); } // reapply selected colorcoding in case polydata structure has changed bool mitk::FiberBundleX::Equals(mitk::FiberBundleX* fib) { if (fib==NULL) return false; mitk::FiberBundleX::Pointer tempFib = this->SubtractBundle(fib); mitk::FiberBundleX::Pointer tempFib2 = fib->SubtractBundle(this); if (tempFib.IsNull() && tempFib2.IsNull()) return true; return false; } /* ESSENTIAL IMPLEMENTATION OF SUPERCLASS METHODS */ void mitk::FiberBundleX::UpdateOutputInformation() { } void mitk::FiberBundleX::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::FiberBundleX::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::FiberBundleX::VerifyRequestedRegion() { return true; } void mitk::FiberBundleX::SetRequestedRegion( itk::DataObject *data ) { } diff --git a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundleX/mitkFiberBundleX.h b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundleX/mitkFiberBundleX.h index c369576fa4..3588003fdd 100644 --- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundleX/mitkFiberBundleX.h +++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundleX/mitkFiberBundleX.h @@ -1,155 +1,157 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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_FiberBundleX_H #define _MITK_FiberBundleX_H //includes for MITK datastructure #include #include "FiberTrackingExports.h" #include //includes storing fiberdata #include //may be replaced by class precompile argument #include // may be replaced by class #include // my be replaced by class #include #include #include namespace mitk { /** * \brief Base Class for Fiber Bundles; */ class FiberTracking_EXPORT FiberBundleX : public BaseData { public: + typedef itk::Image ItkUcharImgType; + // fiber colorcodings static const char* COLORCODING_ORIENTATION_BASED; static const char* COLORCODING_FA_BASED; static const char* COLORCODING_CUSTOM; static const char* FIBER_ID_ARRAY; virtual void UpdateOutputInformation(); virtual void SetRequestedRegionToLargestPossibleRegion(); virtual bool RequestedRegionIsOutsideOfTheBufferedRegion(); virtual bool VerifyRequestedRegion(); virtual void SetRequestedRegion( itk::DataObject *data ); mitkClassMacro( FiberBundleX, BaseData ) itkNewMacro( Self ) mitkNewMacro1Param(Self, vtkSmartPointer) // custom constructor // colorcoding related methods void SetColorCoding(const char*); void SetFAMap(mitk::Image::Pointer); void DoColorCodingOrientationBased(); void DoColorCodingFaBased(); void DoUseFaFiberOpacity(); void ResetFiberOpacity(); // fiber smoothing/resampling void ResampleFibers(float pointDistance = 1); void DoFiberSmoothing(int pointsPerCm); void DoFiberSmoothing(int pointsPerCm, double tension, double continuity, double bias ); bool RemoveShortFibers(float lengthInMM); bool RemoveLongFibers(float lengthInMM); bool ApplyCurvatureThreshold(float minRadius, bool deleteFibers); void MirrorFibers(unsigned int axis); void RotateAroundAxis(double x, double y, double z); void TranslateFibers(double x, double y, double z); void ScaleFibers(double x, double y, double z); // add/subtract fibers FiberBundleX::Pointer AddBundle(FiberBundleX* fib); FiberBundleX::Pointer SubtractBundle(FiberBundleX* fib); // fiber subset extraction FiberBundleX::Pointer ExtractFiberSubset(PlanarFigure *pf); std::vector ExtractFiberIdSubset(PlanarFigure* pf); + FiberBundleX::Pointer ExtractFiberSubset(ItkUcharImgType* mask, bool anyPoint); + vtkSmartPointer GeneratePolyDataByIds( std::vector ); // TODO: make protected void GenerateFiberIds(); // TODO: make protected - - // get/set data void SetFiberPolyData(vtkSmartPointer, bool updateGeometry = true); vtkSmartPointer GetFiberPolyData(); QStringList GetAvailableColorCodings(); char* GetCurrentColorCoding(); itkGetMacro( NumFibers, int) itkGetMacro( FiberSampling, int) itkGetMacro( MinFiberLength, float ) itkGetMacro( MaxFiberLength, float ) itkGetMacro( MeanFiberLength, float ) itkGetMacro( MedianFiberLength, float ) itkGetMacro( LengthStDev, float ) std::vector GetPointsRoi() { return m_PointsRoi; } // copy fiber bundle mitk::FiberBundleX::Pointer GetDeepCopy(); // compare fiber bundles bool Equals(FiberBundleX* fib); protected: FiberBundleX( vtkPolyData* fiberPolyData = NULL ); virtual ~FiberBundleX(); itk::Point GetItkPoint(double point[3]); // calculate geometry from fiber extent void UpdateFiberGeometry(); // calculate colorcoding values according to m_CurrentColorCoding void UpdateColorCoding(); private: // actual fiber container vtkSmartPointer m_FiberPolyData; // contains fiber ids vtkSmartPointer m_FiberIdDataSet; char* m_CurrentColorCoding; int m_NumFibers; std::vector< float > m_FiberLengths; float m_MinFiberLength; float m_MaxFiberLength; float m_MeanFiberLength; float m_MedianFiberLength; float m_LengthStDev; int m_FiberSampling; std::vector m_PointsRoi; // this global variable needs to be refactored }; } // namespace mitk #endif /* _MITK_FiberBundleX_H */ diff --git a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkStickModel.cpp b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkStickModel.cpp index 9189411df6..10222ae7c1 100644 --- a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkStickModel.cpp +++ b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkStickModel.cpp @@ -1,54 +1,55 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include template< class ScalarType > StickModel< ScalarType >::StickModel() : m_Diffusivity(0.001) , m_BValue(1000) { } template< class ScalarType > StickModel< ScalarType >::~StickModel() { } template< class ScalarType > typename StickModel< ScalarType >::PixelType StickModel< ScalarType >::SimulateMeasurement() { + this->m_FiberDirection.Normalize(); PixelType signal; signal.SetSize(this->m_GradientList.size()); for( unsigned int i=0; im_GradientList.size(); i++) { GradientType g = this->m_GradientList[i]; double bVal = g.GetNorm(); bVal *= bVal; if (bVal>0.0001) { double dot = this->m_FiberDirection*g; signal[i] = exp( -m_BValue * bVal * m_Diffusivity*dot*dot ); } else signal[i] = 1; } return signal; } diff --git a/Modules/MitkExt/Algorithms/mitkImageToSurfaceFilter.cpp b/Modules/MitkExt/Algorithms/mitkImageToSurfaceFilter.cpp index 70e9c10ae3..6b2633a228 100644 --- a/Modules/MitkExt/Algorithms/mitkImageToSurfaceFilter.cpp +++ b/Modules/MitkExt/Algorithms/mitkImageToSurfaceFilter.cpp @@ -1,215 +1,234 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; 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 "mitkException.h" #include #include #include #include #include #include #include +#include +#include +#include + #include "mitkProgressBar.h" mitk::ImageToSurfaceFilter::ImageToSurfaceFilter(): m_Smooth(false), m_Decimate( NoDecimation), m_Threshold(1.0), m_TargetReduction(0.95f), m_SmoothIteration(50), m_SmoothRelaxation(0.1) { } mitk::ImageToSurfaceFilter::~ImageToSurfaceFilter() { } void mitk::ImageToSurfaceFilter::CreateSurface(int time, vtkImageData *vtkimage, mitk::Surface * surface, const ScalarType threshold) { vtkImageChangeInformation *indexCoordinatesImageFilter = vtkImageChangeInformation::New(); indexCoordinatesImageFilter->SetInput(vtkimage); indexCoordinatesImageFilter->SetOutputOrigin(0.0,0.0,0.0); //MarchingCube -->create Surface vtkMarchingCubes *skinExtractor = vtkMarchingCubes::New(); skinExtractor->ComputeScalarsOff(); skinExtractor->SetInput(indexCoordinatesImageFilter->GetOutput());//RC++ indexCoordinatesImageFilter->Delete(); skinExtractor->SetValue(0, threshold); vtkPolyData *polydata; polydata = skinExtractor->GetOutput(); polydata->Register(NULL);//RC++ skinExtractor->Delete(); if (m_Smooth) { vtkSmoothPolyDataFilter *smoother = vtkSmoothPolyDataFilter::New(); //read poly1 (poly1 can be the original polygon, or the decimated polygon) smoother->SetInput(polydata);//RC++ smoother->SetNumberOfIterations( m_SmoothIteration ); smoother->SetRelaxationFactor( m_SmoothRelaxation ); smoother->SetFeatureAngle( 60 ); smoother->FeatureEdgeSmoothingOff(); smoother->BoundarySmoothingOff(); smoother->SetConvergence( 0 ); polydata->Delete();//RC-- polydata = smoother->GetOutput(); polydata->Register(NULL);//RC++ smoother->Delete(); } ProgressBar::GetInstance()->Progress(); //decimate = to reduce number of polygons if(m_Decimate==DecimatePro) { vtkDecimatePro *decimate = vtkDecimatePro::New(); decimate->SplittingOff(); decimate->SetErrorIsAbsolute(5); decimate->SetFeatureAngle(30); decimate->PreserveTopologyOn(); decimate->BoundaryVertexDeletionOff(); decimate->SetDegree(10); //std-value is 25! decimate->SetInput(polydata);//RC++ decimate->SetTargetReduction(m_TargetReduction); decimate->SetMaximumError(0.002); polydata->Delete();//RC-- polydata = decimate->GetOutput(); polydata->Register(NULL);//RC++ decimate->Delete(); } else if (m_Decimate==QuadricDecimation) { vtkQuadricDecimation* decimate = vtkQuadricDecimation::New(); decimate->SetTargetReduction(m_TargetReduction); decimate->SetInput(polydata); polydata->Delete(); polydata = decimate->GetOutput(); polydata->Register(NULL); decimate->Delete(); } polydata->Update(); ProgressBar::GetInstance()->Progress(); polydata->SetSource(NULL); if(polydata->GetNumberOfPoints() > 0) { mitk::Vector3D spacing = GetInput()->GetGeometry(time)->GetSpacing(); vtkPoints * points = polydata->GetPoints(); vtkMatrix4x4 *vtkmatrix = vtkMatrix4x4::New(); GetInput()->GetGeometry(time)->GetVtkTransform()->GetMatrix(vtkmatrix); double (*matrix)[4] = vtkmatrix->Element; unsigned int i,j; for(i=0;i<3;++i) for(j=0;j<3;++j) matrix[i][j]/=spacing[j]; unsigned int n = points->GetNumberOfPoints(); vtkFloatingPointType point[3]; for (i = 0; i < n; i++) { points->GetPoint(i, point); mitkVtkLinearTransformPoint(matrix,point,point); points->SetPoint(i, point); } vtkmatrix->Delete(); } ProgressBar::GetInstance()->Progress(); - surface->SetVtkPolyData(polydata, time); + // determine point_data normals for the poly data points. + vtkSmartPointer normalsGenerator = vtkSmartPointer::New(); + normalsGenerator->SetInput( polydata ); + + vtkSmartPointer cleanPolyDataFilter = vtkSmartPointer::New(); + cleanPolyDataFilter->SetInput(normalsGenerator->GetOutput()); + cleanPolyDataFilter->PieceInvariantOff(); + cleanPolyDataFilter->ConvertLinesToPointsOff(); + cleanPolyDataFilter->ConvertPolysToLinesOff(); + cleanPolyDataFilter->ConvertStripsToPolysOff(); + cleanPolyDataFilter->PointMergingOn(); + cleanPolyDataFilter->Update(); + + surface->SetVtkPolyData(cleanPolyDataFilter->GetOutput(), time); polydata->UnRegister(NULL); } void mitk::ImageToSurfaceFilter::GenerateData() { mitk::Surface *surface = this->GetOutput(); mitk::Image * image = (mitk::Image*)GetInput(); + if(image == NULL || !image->IsInitialized()) + mitkThrow() << "No input image set, please set an valid input image!"; + mitk::Image::RegionType outputRegion = image->GetRequestedRegion(); int tstart=outputRegion.GetIndex(3); int tmax=tstart+outputRegion.GetSize(3); //GetSize()==1 - will aber 0 haben, wenn nicht zeitaufgeloest if ((tmax-tstart) > 0) { ProgressBar::GetInstance()->AddStepsToDo( 4 * (tmax - tstart) ); } int t; for( t=tstart; t < tmax; ++t) { vtkImageData *vtkimagedata = image->GetVtkImageData(t); CreateSurface(t,vtkimagedata,surface,m_Threshold); ProgressBar::GetInstance()->Progress(); } } void mitk::ImageToSurfaceFilter::SetSmoothIteration(int smoothIteration) { m_SmoothIteration = smoothIteration; } void mitk::ImageToSurfaceFilter::SetSmoothRelaxation(float smoothRelaxation) { m_SmoothRelaxation = smoothRelaxation; } void mitk::ImageToSurfaceFilter::SetInput(const mitk::Image *image) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput(0, const_cast< mitk::Image * >( image ) ); } const mitk::Image *mitk::ImageToSurfaceFilter::GetInput(void) { if (this->GetNumberOfInputs() < 1) { return 0; } return static_cast ( this->ProcessObject::GetInput(0) ); } void mitk::ImageToSurfaceFilter::GenerateOutputInformation() { mitk::Image::ConstPointer inputImage =(mitk::Image*) this->GetInput(); //mitk::Image *inputImage = (mitk::Image*)this->GetImage(); mitk::Surface::Pointer output = this->GetOutput(); itkDebugMacro(<<"GenerateOutputInformation()"); if(inputImage.IsNull()) return; //Set Data } diff --git a/Modules/MitkExt/DataManagement/mitkBoundingObject.h b/Modules/MitkExt/DataManagement/mitkBoundingObject.h index 7a83e229cd..cf1642f39f 100644 --- a/Modules/MitkExt/DataManagement/mitkBoundingObject.h +++ b/Modules/MitkExt/DataManagement/mitkBoundingObject.h @@ -1,65 +1,69 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef BOUNDINGOBJECT_H_HEADER_INCLUDED #define BOUNDINGOBJECT_H_HEADER_INCLUDED #include #include "MitkExtExports.h" namespace mitk { //##Documentation //## @brief superclass of all bounding objects (cylinder, cuboid,...) //## //## Manages generic functions and provides an interface for IsInside() //## calculates a generic bounding box //## @ingroup Data class MitkExt_EXPORT BoundingObject : public mitk::Surface //BaseData { public: mitkClassMacro(BoundingObject, mitk::Surface); virtual bool IsInside(const mitk::Point3D& p) const=0; virtual mitk::ScalarType GetVolume(); itkGetMacro(Positive, bool); itkSetMacro(Positive, bool); itkBooleanMacro(Positive); //##Documentation //## @brief Sets the Geometry3D of the bounding object to fit the given //## geometry. //## //## The fit is done once, so if the given geometry changes it will //## \em not effect the bounding object. virtual void FitGeometry(Geometry3D* aGeometry3D); protected: BoundingObject(); virtual ~BoundingObject(); bool WriteXMLData( XMLWriter& xmlWriter ); //##Documentation //## \brief If \a true, the Boundingobject describes a positive volume, //## if \a false a negative volume. //## bool m_Positive; + +private: + BoundingObject(const BoundingObject&); + BoundingObject& operator=(const BoundingObject&); }; } #endif /* BOUNDINGOBJECT_H_HEADER_INCLUDED */ diff --git a/Modules/MitkExt/Testing/CMakeLists.txt b/Modules/MitkExt/Testing/CMakeLists.txt index 6a10de0dc0..9874b913ef 100644 --- a/Modules/MitkExt/Testing/CMakeLists.txt +++ b/Modules/MitkExt/Testing/CMakeLists.txt @@ -1,7 +1,8 @@ MITK_CREATE_MODULE_TESTS(EXTRA_DRIVER_INIT "RegisterCoreExtObjectFactory();;" EXTRA_DRIVER_INCLUDE "mitkCoreExtObjectFactory.h") if(BUILD_TESTING AND MODULE_IS_ENABLED) mitkAddCustomModuleTest(mitkLabeledImageToSurfaceFilterTest_BinaryBall mitkLabeledImageToSurfaceFilterTest ${MITK_DATA_DIR}/BallBinary30x30x30.pic.gz) +mitkAddCustomModuleTest(mitkImageToSurfaceFilterTest_BinaryBall mitkImageToSurfaceFilterTest ${MITK_DATA_DIR}/BallBinary30x30x30.nrrd) endif() diff --git a/Modules/MitkExt/Testing/files.cmake b/Modules/MitkExt/Testing/files.cmake index 604b7b6f67..fb643c22ea 100644 --- a/Modules/MitkExt/Testing/files.cmake +++ b/Modules/MitkExt/Testing/files.cmake @@ -1,37 +1,38 @@ set(MODULE_TESTS mitkAutoCropImageFilterTest.cpp mitkBoundingObjectCutterTest.cpp mitkCoreExtObjectFactoryTest mitkDataNodeExtTest.cpp mitkExternalToolsTest.cpp mitkMeshTest.cpp mitkMultiStepperTest.cpp mitkOrganTypePropertyTest.cpp mitkPipelineSmartPointerCorrectnessTest.cpp mitkPlaneFitTest.cpp mitkPointLocatorTest.cpp # mitkSegmentationInterpolationTest.cpp # mitkTestTemplate.cpp mitkUnstructuredGridTest.cpp mitkSimpleHistogramTest.cpp mitkToolManagerTest.cpp ) set(MODULE_IMAGE_TESTS mitkUnstructuredGridVtkWriterTest.cpp mitkCompressedImageContainerTest.cpp mitkCylindricToCartesianFilterTest.cpp #mitkExtractImageFilterTest.cpp mitkSurfaceToImageFilterTest.cpp ) set(MODULE_CUSTOM_TESTS mitkLabeledImageToSurfaceFilterTest.cpp + mitkImageToSurfaceFilterTest.cpp ) set(MODULE_TESTIMAGES US4DCyl.nrrd Pic3D.nrrd Pic2DplusT.nrrd BallBinary30x30x30.nrrd Png2D-bw.png binary.stl ball.stl ) diff --git a/Modules/MitkExt/Testing/mitkImageToSurfaceFilterTest.cpp b/Modules/MitkExt/Testing/mitkImageToSurfaceFilterTest.cpp new file mode 100644 index 0000000000..1a12bb5487 --- /dev/null +++ b/Modules/MitkExt/Testing/mitkImageToSurfaceFilterTest.cpp @@ -0,0 +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. + +===================================================================*/ +#include "mitkTestingMacros.h" +#include "mitkImageToSurfaceFilter.h" +#include "mitkItkImageFileReader.h" +#include "mitkException.h" + +bool CompareSurfacePointPositions(mitk::Surface::Pointer s1, mitk::Surface::Pointer s2) +{ + vtkPoints* p1 = s1->GetVtkPolyData()->GetPoints(); + vtkPoints* p2 = s2->GetVtkPolyData()->GetPoints(); + + if(p1->GetNumberOfPoints() != p2->GetNumberOfPoints()) + return false; + + for(int i = 0; i < p1->GetNumberOfPoints(); ++i) + { + if(p1->GetPoint(i)[0] != p2->GetPoint(i)[0] || + p1->GetPoint(i)[1] != p2->GetPoint(i)[1] || + p1->GetPoint(i)[2] != p2->GetPoint(i)[2] ) + { + return true; + } + } + return false; +} + +int mitkImageToSurfaceFilterTest(int argc, char* argv[]) +{ + MITK_TEST_BEGIN("ImageToSurfaceFilterTest"); + mitk::ImageToSurfaceFilter::Pointer testObject = mitk::ImageToSurfaceFilter::New(); + MITK_TEST_CONDITION_REQUIRED(testObject.IsNotNull(), "Testing instantiation of test object"); + + mitk::ItkImageFileReader::Pointer reader = mitk::ItkImageFileReader::New(); + reader->SetFileName(argv[1]); + reader->Update(); + mitk::Image::Pointer tImage = reader->GetOutput(); + + // testing initialization of member variables! + MITK_TEST_CONDITION_REQUIRED(testObject->GetThreshold() == 1.0f, "Testing initialization of threshold member variable"); + MITK_TEST_CONDITION_REQUIRED(testObject->GetSmooth() == false, "Testing initialization of smooth member variable"); + MITK_TEST_CONDITION_REQUIRED(testObject->GetDecimate() == mitk::ImageToSurfaceFilter::NoDecimation, "Testing initialization of decimate member variable"); + MITK_TEST_CONDITION_REQUIRED(testObject->GetTargetReduction() == 0.95f, "Testing initialization of target reduction member variable"); + + // test cases excluded until bug 14530 is fixed, since wrong exception is caught!! + //MITK_TEST_FOR_EXCEPTION_BEGIN(mitk::Exception) + //testObject->Update(); + //MITK_TEST_FOR_EXCEPTION_END(mitk::Exception) + + //mitk::Image::Pointer emptyImage = mitk::Image::New(); + //testObject->SetInput(emptyImage); + //MITK_TEST_FOR_EXCEPTION_BEGIN(mitk::Exception) + //testObject->Update(); + //MITK_TEST_FOR_EXCEPTION_END(mitk::Exception) + + testObject->SetInput(tImage); + MITK_TEST_CONDITION_REQUIRED(testObject->GetInput() == tImage, "Testing set / get input!"); + + testObject->Update(); + mitk::Surface::Pointer resultSurface = NULL; + resultSurface = testObject->GetOutput(); + MITK_TEST_CONDITION_REQUIRED(testObject->GetOutput() != NULL, "Testing surface generation!"); + + mitk::Surface::Pointer testSurface1 = testObject->GetOutput()->Clone(); + + testObject->SetDecimate(mitk::ImageToSurfaceFilter::DecimatePro); + testObject->SetTargetReduction(0.5f); + testObject->Update(); + mitk::Surface::Pointer testSurface2 = testObject->GetOutput()->Clone(); + + MITK_TEST_CONDITION_REQUIRED(testSurface1->GetVtkPolyData()->GetPoints()->GetNumberOfPoints() > testSurface2->GetVtkPolyData()->GetPoints()->GetNumberOfPoints() , "Testing DecimatePro mesh decimation!"); + + testObject->SetDecimate(mitk::ImageToSurfaceFilter::QuadricDecimation); + testObject->SetTargetReduction(0.5f); + testObject->Update(); + mitk::Surface::Pointer testSurface3 = testObject->GetOutput()->Clone(); + + MITK_TEST_CONDITION_REQUIRED(testSurface1->GetVtkPolyData()->GetPoints()->GetNumberOfPoints() > testSurface3->GetVtkPolyData()->GetPoints()->GetNumberOfPoints() , "Testing QuadricDecimation mesh decimation!"); + + testObject->SetSmooth(true); + testObject->SetDecimate(mitk::ImageToSurfaceFilter::NoDecimation); + testObject->Update(); + mitk::Surface::Pointer testSurface4 = testObject->GetOutput()->Clone(); + MITK_TEST_CONDITION_REQUIRED( CompareSurfacePointPositions(testSurface1, testSurface4), "Testing smoothing of surface changes point data!"); + + // thats it folks + MITK_TEST_END(); +} diff --git a/Modules/Qmitk/QmitkEventAdapter.h b/Modules/Qmitk/QmitkEventAdapter.h index 01cd98d741..f83ca791c5 100644 --- a/Modules/Qmitk/QmitkEventAdapter.h +++ b/Modules/Qmitk/QmitkEventAdapter.h @@ -1,37 +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 QMITKEVENTADAPTER_H_ #define QMITKEVENTADAPTER_H_ #include #include #include #include #include #include - +/** +* \deprecatedSince{2013_03} mitk::QmitkEventAdapter is deprecated. It will become obsolete. Adaption of events is now handeled (for Qt events) in +* QmitkRenderWindow. + * Refer to \see DataInteractionPage for general information about the concept of the new implementation + */ class QMITK_EXPORT QmitkEventAdapter { public: static mitk::MouseEvent AdaptMouseEvent(mitk::BaseRenderer* sender, QMouseEvent* mouseEvent); static mitk::WheelEvent AdaptWheelEvent(mitk::BaseRenderer* sender, QWheelEvent* wheelEvent); static mitk::KeyEvent AdaptKeyEvent(mitk::BaseRenderer* sender, QKeyEvent* keyEvent, const QPoint& point); }; #endif /*QMITKEVENTADAPTER_H_*/ diff --git a/Modules/Qmitk/QmitkSliderLevelWindowWidget.cpp b/Modules/Qmitk/QmitkSliderLevelWindowWidget.cpp index e4c9143bf1..348fb788d6 100644 --- a/Modules/Qmitk/QmitkSliderLevelWindowWidget.cpp +++ b/Modules/Qmitk/QmitkSliderLevelWindowWidget.cpp @@ -1,525 +1,526 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; 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 /** * Constructor */ QmitkSliderLevelWindowWidget::QmitkSliderLevelWindowWidget( QWidget * parent, Qt::WindowFlags f ) : QWidget( parent, f ) { m_Manager = mitk::LevelWindowManager::New(); itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSliderLevelWindowWidget::OnPropertyModified); m_ObserverTag = m_Manager->AddObserver(itk::ModifiedEvent(), command); m_IsObserverTagSet = true; setMouseTracking(true); m_Resize = false; m_Bottom = false; m_CtrlPressed = false; m_MouseDown = false; m_Font.setPointSize( 6 ); m_MoveHeight = height() - 25; m_ScaleVisible = true; m_Contextmenu = new QmitkLevelWindowWidgetContextMenu(this); //, true); //setBackgroundMode( Qt::NoBackground ); this->hide(); update(); } QmitkSliderLevelWindowWidget::~QmitkSliderLevelWindowWidget() { if ( m_IsObserverTagSet) { m_Manager->RemoveObserver(m_ObserverTag); m_IsObserverTagSet = false; } } void QmitkSliderLevelWindowWidget::setLevelWindowManager(mitk::LevelWindowManager* levelWindowManager) { if ( m_IsObserverTagSet) { m_Manager->RemoveObserver(m_ObserverTag); m_IsObserverTagSet = false; } m_Manager = levelWindowManager; if ( m_Manager.IsNotNull() ) { itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSliderLevelWindowWidget::OnPropertyModified); m_ObserverTag = m_Manager->AddObserver(itk::ModifiedEvent(), command); m_IsObserverTagSet = true; } } void QmitkSliderLevelWindowWidget::OnPropertyModified(const itk::EventObject& ) { try { m_LevelWindow = m_Manager->GetLevelWindow(); this->show(); update(); } catch(...) { try { this->hide(); } catch(...) { } } } void QmitkSliderLevelWindowWidget::paintEvent( QPaintEvent* itkNotUsed(e) ) { QPixmap pm(width(), height()); //pm.fill( static_cast(parent())->paletteBackgroundColor() ); pm.fill(this, 0, 0); QPainter painter(&pm); painter.setFont( m_Font ); //painter.setPen(static_cast(parent())->paletteForegroundColor()); painter.setPen(this->palette().color(this->foregroundRole())); QColor c(93,144,169); QColor cl = c.light(); QColor cd = c.dark(); painter.setBrush(c); painter.drawRect(m_Rect); float mr = m_LevelWindow.GetRange(); if ( mr < 1 ) mr = 1; float fact = (float) m_MoveHeight / mr; //begin draw scale if (m_ScaleVisible) { int minRange = (int)m_LevelWindow.GetRangeMin(); int maxRange = (int)m_LevelWindow.GetRangeMax(); int yValue = m_MoveHeight + (int)(minRange*fact); QString s = " 0"; if (minRange <= 0 && maxRange >= 0) { painter.drawLine( 5, yValue , 15, yValue); painter.drawText( 21, yValue + 3, s ); } int count = 1; int k = 5; bool enoughSpace = false; bool enoughSpace2 = false; double dStepSize = pow(10,floor(log10(mr/100))+1); for(int i = m_MoveHeight + (int)(minRange*fact); i < m_MoveHeight;)//negative { if (-count*dStepSize < minRange) break; yValue = m_MoveHeight + (int)((minRange + count*dStepSize)*fact); s = QString::number(-count*dStepSize); if (count % k && ((dStepSize*fact) > 2.5)) { painter.drawLine( 8, yValue, 12, yValue); enoughSpace = true; } else if (!(count % k)) { if ((k*dStepSize*fact) > 7) { painter.drawLine( 5, yValue, 15, yValue); painter.drawText( 21, yValue + 3, s ); enoughSpace2 = true; } else { k += 5; } } if (enoughSpace) { i=yValue; count++; } else if (enoughSpace2) { i=yValue; count += k; } else { i=yValue; count = k; } } count = 1; k = 5; enoughSpace = false; enoughSpace2 = false; for(int i = m_MoveHeight + (int)(minRange*fact); i >= 0;) { if (count*dStepSize > maxRange) break; yValue = m_MoveHeight + (int)((minRange - count*dStepSize)*fact); s = QString::number(count*dStepSize); if(count % k && ((dStepSize*fact) > 2.5)) { if (!(minRange > 0 && (count*dStepSize) < minRange)) painter.drawLine( 8, yValue, 12, yValue); enoughSpace = true; } else if (!(count % k)) { if ((k*dStepSize*fact) > 7) { if (!(minRange > 0 && (count*dStepSize) < minRange)) { painter.drawLine( 5, yValue, 15, yValue); painter.drawText( 21, yValue + 3, s ); } enoughSpace2 = true; } else { k += 5; } } if (enoughSpace) { i=yValue; count++; } else if (enoughSpace2) { i=yValue; count += k; } else { i=yValue; count = k; } } } //end draw scale painter.setPen (cl); painter.drawLine(m_Rect.topLeft(),m_Rect.topRight()); painter.drawLine(m_Rect.topLeft(),m_Rect.bottomLeft()); painter.setPen (cd); painter.drawLine(m_Rect.topRight(),m_Rect.bottomRight()); painter.drawLine(m_Rect.bottomRight(),m_Rect.bottomLeft()); painter.end(); QPainter p (this); p.drawPixmap(0, 0, pm); } /** * */ void QmitkSliderLevelWindowWidget::mouseMoveEvent( QMouseEvent* mouseEvent ) { if(!mouseEvent) return; if ( m_LevelWindow.IsFixed() ) return; if (!m_MouseDown) { if ( mouseEvent->pos().y() >= 0 && mouseEvent->pos().y() <= (m_Rect.topLeft().y() + 3) ) { setCursor(Qt::SizeVerCursor); m_UpperBound.setRect(m_Rect.topLeft().x(), m_Rect.topLeft().y() - 3, 17, 7); this->setToolTip("Ctrl + left click to change only upper bound"); m_Resize = true; } else if ( mouseEvent->pos().y() >= (m_Rect.bottomLeft().y() - 3) ) { setCursor(Qt::SizeVerCursor); m_LowerBound.setRect(m_Rect.bottomLeft().x(), m_Rect.bottomLeft().y() - 3, 17, 7); this->setToolTip("Ctrl + left click to change only lower bound"); m_Resize = true; m_Bottom = true; } else { setCursor(Qt::ArrowCursor); + this->setToolTip("Left click and mouse move to adjust the slider"); m_Resize = false; m_Bottom = false; } } else { float fact = (float) m_MoveHeight / m_LevelWindow.GetRange(); if ( m_Leftbutton ) { if (m_Resize && !m_CtrlPressed) { double diff = (mouseEvent->pos().y()) / fact; diff -= (m_StartPos.y()) / fact; m_StartPos = mouseEvent->pos(); if (diff == 0) return; float value; if (m_Bottom) value = m_LevelWindow.GetWindow() + ( ( 2 * diff ) ); else value = m_LevelWindow.GetWindow() - ( ( 2 * diff ) ); if ( value < 0 ) value = 0; m_LevelWindow.SetLevelWindow( m_LevelWindow.GetLevel(), value ); } else if(m_Resize && m_CtrlPressed) { if (!m_Bottom) { double diff = (mouseEvent->pos().y()) / fact; diff -= (m_StartPos.y()) / fact; m_StartPos = mouseEvent->pos(); if (diff == 0) return; float value; value = m_LevelWindow.GetWindow() - ( ( diff ) ); if ( value < 0 ) value = 0; float oldWindow; float oldLevel; float newLevel; oldWindow = m_LevelWindow.GetWindow(); oldLevel = m_LevelWindow.GetLevel(); newLevel = oldLevel + (value - oldWindow)/2; if (!((newLevel + value/2) > m_LevelWindow.GetRangeMax())) m_LevelWindow.SetLevelWindow( newLevel, value ); } else { double diff = (mouseEvent->pos().y()) / fact; diff -= (m_StartPos.y()) / fact; m_StartPos = mouseEvent->pos(); if (diff == 0) return; float value; value = m_LevelWindow.GetWindow() + ( ( diff ) ); if ( value < 0 ) value = 0; float oldWindow; float oldLevel; float newLevel; oldWindow = m_LevelWindow.GetWindow(); oldLevel = m_LevelWindow.GetLevel(); newLevel = oldLevel - (value - oldWindow)/2; if (!((newLevel - value/2) < m_LevelWindow.GetRangeMin())) m_LevelWindow.SetLevelWindow( newLevel, value ); } } else { const float minv = m_LevelWindow.GetRangeMin(); const float level = (m_MoveHeight - mouseEvent->pos().y()) / fact + minv; double diff = (mouseEvent->pos().x()) / fact; diff -= (m_StartPos.x()) / fact; m_StartPos = mouseEvent->pos(); float window; if (m_Bottom) window = m_LevelWindow.GetWindow() + ( ( 2 * diff ) ); else window = m_LevelWindow.GetWindow() - ( ( 2 * diff ) ); if ( window < 0 ) window = 0; m_LevelWindow.SetLevelWindow( level, window ); } m_Manager->SetLevelWindow(m_LevelWindow); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } } void QmitkSliderLevelWindowWidget::enterEvent ( QEvent * /*event*/ ) { /* if(event->type() != QEvent::MouseMove) return;*/ //mouseMoveEvent( static_cast< QMouseEvent* > ( event ) ); QPoint p = QCursor::pos(); p = this->mapFromGlobal(p); QMouseEvent ev(QEvent::MouseMove, p, Qt::NoButton, Qt::NoButton , Qt::NoModifier ); this->mouseMoveEvent( &ev ); } /** * */ void QmitkSliderLevelWindowWidget::mousePressEvent( QMouseEvent* mouseEvent ) { if ( m_LevelWindow.IsFixed() ) return; m_MouseDown = true; m_StartPos = mouseEvent->pos(); if ( mouseEvent->button() == Qt::LeftButton ) { if (mouseEvent->modifiers() == Qt::ControlModifier || mouseEvent->modifiers() == Qt::ShiftModifier) { m_CtrlPressed = true; } else { m_CtrlPressed = false; } m_Leftbutton = true; } else m_Leftbutton = false; mouseMoveEvent( mouseEvent ); } /** * */ void QmitkSliderLevelWindowWidget::resizeEvent ( QResizeEvent * event ) { m_MoveHeight = event->size().height() - 25; update(); } /** * */ void QmitkSliderLevelWindowWidget::mouseReleaseEvent( QMouseEvent* ) { if ( m_LevelWindow.IsFixed() ) return; m_MouseDown = false; } /** * */ void QmitkSliderLevelWindowWidget::update() { int rectWidth; if(m_ScaleVisible) { rectWidth = 17; setMinimumSize ( QSize( 50, 50 ) ); setMaximumSize ( QSize( 50, 2000 ) ); setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Expanding ) ); } else { rectWidth = 26; setMinimumSize ( QSize( 40, 50 ) ); setMaximumSize ( QSize( 50, 2000 ) ); setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Expanding ) ); } float mr = m_LevelWindow.GetRange(); if ( mr < 1 ) mr = 1; float fact = (float) m_MoveHeight / mr; float rectHeight = m_LevelWindow.GetWindow() * fact; if ( rectHeight < 15 ) rectHeight = 15; if ( m_LevelWindow.GetLowerWindowBound() < 0 ) m_Rect.setRect( 2, (int) (m_MoveHeight - (m_LevelWindow.GetUpperWindowBound() - m_LevelWindow.GetRangeMin()) * fact) , rectWidth, (int) rectHeight ); else m_Rect.setRect( 2, (int) (m_MoveHeight - (m_LevelWindow.GetUpperWindowBound() - m_LevelWindow.GetRangeMin()) * fact), rectWidth, (int) rectHeight ); QWidget::repaint(); } void QmitkSliderLevelWindowWidget::contextMenuEvent( QContextMenuEvent * ) { m_Contextmenu->setLevelWindowManager(m_Manager.GetPointer()); QMenu *contextMenu = new QMenu( this ); Q_CHECK_PTR( contextMenu ); if (m_ScaleVisible) contextMenu->addAction(tr("Hide Scale"), this, SLOT(hideScale())); else contextMenu->addAction(tr("Show Scale"), this, SLOT(showScale())); contextMenu->addSeparator(); m_Contextmenu->getContextMenu(contextMenu); // Fix: Bug #13327 we need to reset the m_MouseDown value // otherwise the cursor is not correctly restored afterwards m_MouseDown = false; } void QmitkSliderLevelWindowWidget::hideScale() { m_ScaleVisible = false; update(); } void QmitkSliderLevelWindowWidget::showScale() { m_ScaleVisible = true; update(); } void QmitkSliderLevelWindowWidget::setDataStorage(mitk::DataStorage* ds) { m_Manager->SetDataStorage(ds); } mitk::LevelWindowManager* QmitkSliderLevelWindowWidget::GetManager() { return m_Manager.GetPointer(); } diff --git a/Modules/QmitkExt/QmitkTransferFunctionGeneratorWidget.ui b/Modules/QmitkExt/QmitkTransferFunctionGeneratorWidget.ui index ac793cfc1b..a71c38d19d 100644 --- a/Modules/QmitkExt/QmitkTransferFunctionGeneratorWidget.ui +++ b/Modules/QmitkExt/QmitkTransferFunctionGeneratorWidget.ui @@ -1,422 +1,416 @@ QmitkTransferFunctionGeneratorWidget 0 0 349 316 1 1 16777215 16777215 Form 0 0 0 0 0 16777215 120 0 0 0 Presets Apply internal MITK transferfunction presets. Or save and load your own created transferfunctions in a folder in XML format. Qt::Vertical 20 0 true 0 0 0 0 Choose one of generic MITK internal presets to apply on standard CT data or MR data. Load a MITK internal preset -1 16 16 false true 0 1 0 0 16777215 25 Qt::AutoText Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop true 0 0 0 64 16777215 Load a transferfunction in xml-format from the filesystem. The load includes all transferfunctions: grayvalue, color and gradient. Load 0 0 64 16777215 Save a transferfunction in xml-format in the filesystem. The save includes all transferfunctions: grayvalue, color and gradient. Save 0 0 Threshold - Generate a threshold transfer function interactively. -Click on the cross and move the mouse. -With a vertical move the function will be steeper or flatter. -With a horizontal move the center of the function left or right. + Generate a threshold transfer function interactively. 0 0 0 0 48 48 Click and hold left mouse button on the cross. Move the mouse to the top and the function will be flatter. Move the mouse to the bottom and the function will be steeper. Move the mouse to the left and the function moves to the left. Move the mouse to the right and the function moves to the right. Qt::LeftToRight :/qmitk/cross.png true Qt::AlignCenter -1 Qt::NoTextInteraction 0 0 0 0 7 Click and hold left mouse button on the cross to interactively generate a threshold transferfunction Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop true 0 0 Bell - Generate a bell transfer function interactively. -Click on the cross and move the mouse. -With a vertical move the bell will be narrower or wider. -With a horizontal move the center of the bell moves to the left or right. + Generate a bell transfer function interactively. 0 0 0 0 48 48 Click and hold left mouse button on the cross. Move the mouse to the top and the bell will be wider. Move the mouse to the bottom and the bell will be flattened. Move the mouse to the left and the center of the bell moves to the left. Move the mouse to the right and the center of the bell moves to the right. :/qmitk/cross.png true Qt::AlignCenter Qt::NoTextInteraction 0 0 0 0 7 Click and hold left mouse button on the cross to interactively generate a bell transferfunction Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop true QmitkCrossWidget QLabel
QmitkCrossWidget.h
diff --git a/Modules/QmitkExt/QmitkTransferFunctionWidget.ui b/Modules/QmitkExt/QmitkTransferFunctionWidget.ui index dc252e2c8a..91690816dc 100755 --- a/Modules/QmitkExt/QmitkTransferFunctionWidget.ui +++ b/Modules/QmitkExt/QmitkTransferFunctionWidget.ui @@ -1,482 +1,521 @@ QmitkTransferFunctionWidget 0 0 300 542 1 1 Form 0 - modify actual seen window by dragging left and right slider. + Change transfer function window range. Qt::Horizontal 0 0 48 16777215 Resets range to histogram minimum and maximum. Reset 0 3 0 0 1 0 64 Left-click to select a point or add a new point. - Hold left mouse button to move selected point. +Hold left mouse button to move selected point. Click right mouse button to delete a point. true 0 0 48 0 48 16777215 Edit x-coordinate (grayvalue) of currently selected point. Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 Edit x-coordinate (grayvalue) of currently selected point. Grayvalue false + + + + Qt::Horizontal + + + + 40 + 20 + + + + 0 0 Edit y-coordinate (opacity) of currently selected point. Opacity Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 0 0 48 0 48 16777215 Edit y-coordinate (opacity) of currently selected point. Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 0 0 1 0 48 Left-click to select a point or add a new point. - Hold left mouse button to move selected point. +Hold left mouse button to move selected point. Click right mouse button to delete a point. Double-click left mouse button to change color of a point. 0 0 48 0 48 16777215 Edit x-coordinate (grayvalue) of currently selected point. Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Edit x-coordinate (grayvalue) of currently selected point. Grayvalue false + + + + Qt::Horizontal + + + + 40 + 20 + + + + 0 2 0 0 1 0 64 Left-click to select a point or add a new point. - Hold left mouse button to move selected point. +Hold left mouse button to move selected point. Click right mouse button to delete a point. 0 0 48 0 48 16777215 Edit x-coordinate (grayvalue) of currently selected point. Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Edit x-coordinate (grayvalue) of currently selected point. Grayvalue false + + + + Qt::Horizontal + + + + 40 + 20 + + + + Edit y-coordinate (opacity) of currently selected point. Opacity Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 0 0 48 0 48 16777215 Edit y-coordinate (opacity) of currently selected point. Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Qt::Vertical 20 0 QmitkPiecewiseFunctionCanvas QWidget
QmitkPiecewiseFunctionCanvas.h
QmitkColorTransferFunctionCanvas QWidget
QmitkColorTransferFunctionCanvas.h
QmitkFloatingPointSpanSlider QSlider
QmitkFloatingPointSpanSlider.h
diff --git a/Modules/Simulation/mitkSimulation.cpp b/Modules/Simulation/mitkSimulation.cpp index 181bd9f969..c499c7b059 100644 --- a/Modules/Simulation/mitkSimulation.cpp +++ b/Modules/Simulation/mitkSimulation.cpp @@ -1,158 +1,238 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkSimulation.h" +#include "mitkSimulationPropAssemblyVisitor.h" +#include +#include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include const float mitk::Simulation::ScaleFactor = 1000.0f; static sofa::simulation::Simulation::SPtr CreateSimulation(mitk::Simulation::SimulationType type = mitk::Simulation::Tree) { if (type == mitk::Simulation::DAG) return sofa::core::objectmodel::New(); else if (type == mitk::Simulation::Bgl) return sofa::core::objectmodel::New(); else return sofa::core::objectmodel::New(); } void mitk::Simulation::SetActiveSimulation(mitk::Simulation* simulation) { if (simulation == NULL) { sofa::simulation::setSimulation(NULL); sofa::core::visual::VisualParams::defaultInstance()->drawTool() = NULL; } else { sofa::simulation::Simulation* sofaSimulation = simulation->m_Simulation.get(); if (sofa::simulation::getSimulation() != sofaSimulation) { sofa::simulation::setSimulation(sofaSimulation); sofa::core::visual::VisualParams::defaultInstance()->drawTool() = &simulation->m_DrawTool; } } } mitk::Simulation::Simulation() : m_Simulation(CreateSimulation()), m_DefaultDT(0.0) { } mitk::Simulation::~Simulation() { if (m_Simulation != NULL) { if (m_RootNode != NULL) m_Simulation->unload(m_RootNode); if (sofa::simulation::getSimulation() == m_Simulation.get()) SetActiveSimulation(NULL); } } +void mitk::Simulation::AppendSnapshot(mitk::Surface::Pointer surface) const +{ + if (surface.IsNull()) + return; + + vtkSmartPointer snapshot = this->CreateSnapshot(); + + if (snapshot != NULL) + { + unsigned int timeStep = surface->GetSizeOfPolyDataSeries(); + + if (timeStep != 0 && surface->GetVtkPolyData(timeStep - 1) == NULL) + --timeStep; + + surface->SetVtkPolyData(snapshot, timeStep); + } +} + +vtkSmartPointer mitk::Simulation::CreateSnapshot() const +{ + if (m_RootNode == NULL) + return NULL; + + vtkSmartPointer propAssembly = vtkSmartPointer::New(); + SimulationPropAssemblyVisitor propAssemblyVisitor(propAssembly); + + m_RootNode->executeVisitor(&propAssemblyVisitor); + + vtkSmartPointer appendFilter = vtkSmartPointer::New(); + + vtkPropCollection* propCollection = propAssembly->GetParts(); + vtkProp* prop = NULL; + + for (propCollection->InitTraversal(); (prop = propCollection->GetNextProp()) != NULL; ) + { + vtkActor* actor = vtkActor::SafeDownCast(prop); + vtkPolyData* polyData = vtkPolyData::SafeDownCast(actor->GetMapper()->GetInput()); + + appendFilter->AddInput(polyData); + } + + vtkSmartPointer scaleTransform = vtkSmartPointer::New(); + scaleTransform->Scale(ScaleFactor, ScaleFactor, ScaleFactor); + + vtkSmartPointer transformFilter = vtkSmartPointer::New(); + transformFilter->SetInputConnection(appendFilter->GetOutputPort()); + transformFilter->SetTransform(scaleTransform); + + transformFilter->Update(); + + vtkSmartPointer snapshot = vtkSmartPointer::New(); + snapshot->ShallowCopy(transformFilter->GetOutputDataObject(0)); + + return snapshot; +} + double mitk::Simulation::GetDefaultDT() const { return m_DefaultDT; } mitk::SimulationDrawTool* mitk::Simulation::GetDrawTool() { return &m_DrawTool; } sofa::simulation::Node::SPtr mitk::Simulation::GetRootNode() const { return m_RootNode; } sofa::simulation::Simulation::SPtr mitk::Simulation::GetSimulation() const { return m_Simulation; } bool mitk::Simulation::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } void mitk::Simulation::SetAsActiveSimulation() { SetActiveSimulation(this); } void mitk::Simulation::SetDefaultDT(double dt) { m_DefaultDT = std::max(0.0, dt); } void mitk::Simulation::SetRequestedRegion(itk::DataObject*) { } void mitk::Simulation::SetRequestedRegionToLargestPossibleRegion() { } void mitk::Simulation::SetRootNode(sofa::simulation::Node* rootNode) { m_RootNode.reset(rootNode); } +mitk::Surface::Pointer mitk::Simulation::TakeSnapshot() const +{ + vtkSmartPointer snapshot = this->CreateSnapshot(); + + if (snapshot == NULL) + return NULL; + + Surface::Pointer surface = Surface::New(); + surface->SetVtkPolyData(snapshot); + + return surface; +} + void mitk::Simulation::UpdateOutputInformation() { if (this->GetSource().IsNotNull()) this->GetSource()->UpdateOutputInformation(); if (m_RootNode != NULL) { const sofa::defaulttype::BoundingBox& boundingBox = m_RootNode->f_bbox.getValue(); const sofa::defaulttype::Vector3& min = boundingBox.minBBox(); const sofa::defaulttype::Vector3& max = boundingBox.maxBBox(); mitk::Geometry3D::BoundsArrayType bounds; bounds[0] = static_cast(min.x() * ScaleFactor); bounds[1] = static_cast(max.x() * ScaleFactor); bounds[2] = static_cast(min.y() * ScaleFactor); bounds[3] = static_cast(max.y() * ScaleFactor); bounds[4] = static_cast(min.z() * ScaleFactor); bounds[5] = static_cast(max.z() * ScaleFactor); if(this->GetGeometry() != NULL) { this->GetGeometry()->SetBounds(bounds); } else { Geometry3D::Pointer geometry = Geometry3D::New(); geometry->SetBounds(bounds); this->SetGeometry(geometry); } } this->GetTimeSlicedGeometry()->UpdateInformation(); } bool mitk::Simulation::VerifyRequestedRegion() { return true; } diff --git a/Modules/Simulation/mitkSimulation.h b/Modules/Simulation/mitkSimulation.h index e0324cf73c..d58c61a614 100644 --- a/Modules/Simulation/mitkSimulation.h +++ b/Modules/Simulation/mitkSimulation.h @@ -1,71 +1,77 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 mitkSimulation_h #define mitkSimulation_h #include "mitkSimulationDrawTool.h" -#include +#include #include #include +#include +#include namespace mitk { class Simulation_EXPORT Simulation : public BaseData { public: enum SimulationType { Tree, DAG, Bgl }; mitkClassMacro(Simulation, BaseData); itkNewMacro(Self); static void SetActiveSimulation(Self* simulation); static const float ScaleFactor; + void AppendSnapshot(Surface::Pointer surface) const; double GetDefaultDT() const; SimulationDrawTool* GetDrawTool(); sofa::simulation::Node::SPtr GetRootNode() const; sofa::simulation::Simulation::SPtr GetSimulation() const; bool RequestedRegionIsOutsideOfTheBufferedRegion(); void SetAsActiveSimulation(); void SetDefaultDT(double dt); void SetRequestedRegion(itk::DataObject* data); void SetRequestedRegionToLargestPossibleRegion(); void SetRootNode(sofa::simulation::Node* rootNode); + Surface::Pointer TakeSnapshot() const; void UpdateOutputInformation(); bool VerifyRequestedRegion(); private: Simulation(); ~Simulation(); Simulation(Self&); Self& operator=(const Self&); + vtkSmartPointer CreateSnapshot() const; + sofa::simulation::Simulation::SPtr m_Simulation; sofa::simulation::Node::SPtr m_RootNode; SimulationDrawTool m_DrawTool; double m_DefaultDT; }; } #endif diff --git a/Modules/Simulation/mitkSimulationDrawTool.cpp b/Modules/Simulation/mitkSimulationDrawTool.cpp index 941dbdf00e..456a907ce4 100644 --- a/Modules/Simulation/mitkSimulationDrawTool.cpp +++ b/Modules/Simulation/mitkSimulationDrawTool.cpp @@ -1,627 +1,577 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkSimulation.h" #include "mitkSimulationDrawTool.h" -#include #include #include #include #include #include #include #include #include #include #include #include mitk::SimulationDrawTool::SimulationDrawTool() : m_PolygonMode(0), m_Wireframe(false), m_Update(true) { } mitk::SimulationDrawTool::~SimulationDrawTool() { - this->DeleteVtkObjects(); -} - -void mitk::SimulationDrawTool::DeleteVtkObjects() -{ - for (std::vector::const_iterator object = m_VtkObjects.begin(); object != m_VtkObjects.end(); ++object) - (*object)->Delete(); - - m_VtkObjects.clear(); - - for (std::vector::const_iterator actor = m_Actors.begin(); actor != m_Actors.end(); ++actor) - (*actor)->Delete(); - m_Actors.clear(); } void mitk::SimulationDrawTool::DisableUpdate() { m_Update = false; } - -std::vector mitk::SimulationDrawTool::GetActors() const +std::vector > mitk::SimulationDrawTool::GetActors() const { return m_Actors; } void mitk::SimulationDrawTool::InitProperty(vtkProperty* property) const { if (m_Wireframe) property->SetRepresentationToWireframe(); else property->SetRepresentationToSurface(); } void mitk::SimulationDrawTool::Reset() { - this->DeleteVtkObjects(); + m_Actors.clear(); m_Update = true; } void mitk::SimulationDrawTool::drawPoints(const std::vector& points, float pointSize, const Vec4f color) { if (!m_Update || points.empty()) return; unsigned int numPoints = points.size(); - vtkPoints* vtkPoints = vtkPoints::New(); + vtkSmartPointer vtkPoints = vtkSmartPointer< ::vtkPoints>::New(); vtkPoints->SetNumberOfPoints(numPoints); - vtkCellArray* cellArray = vtkCellArray::New(); + vtkSmartPointer cellArray = vtkSmartPointer::New(); for (unsigned int i = 0; i < numPoints; ++i) { vtkPoints->SetPoint(i, points[i].elems); cellArray->InsertNextCell(1); cellArray->InsertCellPoint(i); } - vtkPolyData* polyData = vtkPolyData::New(); + vtkSmartPointer polyData = vtkSmartPointer::New(); polyData->SetPoints(vtkPoints); polyData->SetVerts(cellArray); - vtkPoints->Delete(); - cellArray->Delete(); - - vtkPolyDataMapper* polyDataMapper = vtkPolyDataMapper::New(); + vtkSmartPointer polyDataMapper = vtkSmartPointer::New(); polyDataMapper->SetInput(polyData); - vtkActor* actor = vtkActor::New(); + vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(polyDataMapper); actor->SetScale(Simulation::ScaleFactor); vtkProperty* property = actor->GetProperty(); property->SetColor(color.x(), color.y(), color.z()); property->SetPointSize(pointSize); - m_VtkObjects.push_back(polyData); - m_VtkObjects.push_back(polyDataMapper); m_Actors.push_back(actor); } void mitk::SimulationDrawTool::drawLines(const std::vector& points, float lineWidth, const Vec4f color) { if (!m_Update || points.empty()) return; unsigned int numPoints = points.size(); std::vector indices; for (unsigned int i = 0; i < numPoints; i += 2) indices.push_back(Vec2i(i, i + 1)); this->drawLines(points, indices, lineWidth, color); } void mitk::SimulationDrawTool::drawLines(const std::vector& points, const std::vector& indices, float lineWidth, const Vec4f color) { if (!m_Update || points.empty()) return; unsigned int numPoints = points.size(); - vtkPoints* vtkPoints = vtkPoints::New(); + vtkSmartPointer vtkPoints = vtkSmartPointer< ::vtkPoints>::New(); vtkPoints->SetNumberOfPoints(numPoints); for (unsigned int i = 0; i < numPoints; ++i) vtkPoints->SetPoint(i, points[i].elems); - vtkPolyData* polyData = vtkPolyData::New(); + vtkSmartPointer polyData = vtkSmartPointer::New(); polyData->SetPoints(vtkPoints); - vtkPoints->Delete(); - - vtkCellArray* lines = vtkCellArray::New(); + vtkSmartPointer lines = vtkSmartPointer::New(); unsigned int numIndices = indices.size(); for (unsigned int i = 0; i < numIndices; ++i) { lines->InsertNextCell(2); lines->InsertCellPoint(indices[i].elems[0]); lines->InsertCellPoint(indices[i].elems[1]); } polyData->SetLines(lines); - lines->Delete(); - - vtkPolyDataMapper* polyDataMapper = vtkPolyDataMapper::New(); + vtkSmartPointer polyDataMapper = vtkSmartPointer::New(); polyDataMapper->SetInput(polyData); - vtkActor* actor = vtkActor::New(); + vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(polyDataMapper); actor->SetScale(Simulation::ScaleFactor); vtkProperty* property = actor->GetProperty(); property->SetLineWidth(lineWidth); property->SetColor(color.x(), color.y(), color.z()); - m_VtkObjects.push_back(polyData); - m_VtkObjects.push_back(polyDataMapper); m_Actors.push_back(actor); } void mitk::SimulationDrawTool::drawTriangles(const std::vector& points, const Vec4f color) { if (!m_Update || points.empty()) return; unsigned int numPoints = points.size(); - vtkPoints* vtkPoints = vtkPoints::New(); + vtkSmartPointer vtkPoints = vtkSmartPointer< ::vtkPoints>::New(); vtkPoints->SetNumberOfPoints(numPoints); for (unsigned int i = 0; i < numPoints; ++i) vtkPoints->SetPoint(i, points[i].elems); - vtkPolyData* polyData = vtkPolyData::New(); + vtkSmartPointer polyData = vtkSmartPointer::New(); polyData->SetPoints(vtkPoints); - vtkPoints->Delete(); - - vtkCellArray* triangles = vtkCellArray::New(); + vtkSmartPointer triangles = vtkSmartPointer::New(); for (unsigned int i = 0; i < points.size(); i += 3) { triangles->InsertNextCell(3); triangles->InsertCellPoint(i); triangles->InsertCellPoint(i + 1); triangles->InsertCellPoint(i + 2); } polyData->SetPolys(triangles); - triangles->Delete(); - - vtkPolyDataNormals* polyDataNormals = vtkPolyDataNormals::New(); + vtkSmartPointer polyDataNormals = vtkSmartPointer::New(); polyDataNormals->ComputeCellNormalsOff(); polyDataNormals->SetInput(polyData); polyDataNormals->SplittingOff(); - vtkPolyDataMapper* polyDataMapper = vtkPolyDataMapper::New(); + vtkSmartPointer polyDataMapper = vtkSmartPointer::New(); polyDataMapper->SetInput(polyDataNormals->GetOutput()); - vtkActor* actor = vtkActor::New(); + vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(polyDataMapper); actor->SetScale(Simulation::ScaleFactor); vtkProperty* property = actor->GetProperty(); - this->InitProperty(property); - property->SetColor(color.x(), color.y(), color.z()); - m_VtkObjects.push_back(polyData); - m_VtkObjects.push_back(polyDataMapper); - m_VtkObjects.push_back(polyDataNormals); m_Actors.push_back(actor); } void mitk::SimulationDrawTool::drawTriangles(const std::vector& points, const Vector3 normal, const Vec4f color) { if (!m_Update || points.empty()) return; unsigned int numPoints = points.size(); + unsigned int numNormals = numPoints / 3; - vtkPoints* vtkPoints = vtkPoints::New(); + vtkSmartPointer vtkPoints = vtkSmartPointer< ::vtkPoints>::New(); vtkPoints->SetNumberOfPoints(numPoints); for (unsigned int i = 0; i < numPoints; ++i) vtkPoints->SetPoint(i, points[i].elems); - vtkPolyData* polyData = vtkPolyData::New(); + vtkSmartPointer polyData = vtkSmartPointer::New(); polyData->SetPoints(vtkPoints); - vtkPoints->Delete(); - - vtkCellArray* triangles = vtkCellArray::New(); + vtkSmartPointer triangles = vtkSmartPointer::New(); for (unsigned int i = 0; i < points.size(); i += 3) { triangles->InsertNextCell(3); triangles->InsertCellPoint(i); triangles->InsertCellPoint(i + 1); triangles->InsertCellPoint(i + 2); } polyData->SetPolys(triangles); - triangles->Delete(); - - vtkFloatArray* normals = vtkFloatArray::New(); + vtkSmartPointer normals = vtkSmartPointer::New(); normals->SetNumberOfComponents(3); + normals->SetNumberOfTuples(numNormals); normals->SetName("Normals"); - for (int i = 0; i < numPoints; i += 3) - normals->InsertNextTuple(normal.elems); + for (unsigned int i = 0; i < numNormals; ++i) + normals->SetTuple(i, normal.elems); polyData->GetCellData()->SetNormals(normals); - normals->Delete(); - - vtkPolyDataMapper* polyDataMapper = vtkPolyDataMapper::New(); + vtkSmartPointer polyDataMapper = vtkSmartPointer::New(); polyDataMapper->SetInput(polyData); - vtkActor* actor = vtkActor::New(); + vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(polyDataMapper); actor->SetScale(Simulation::ScaleFactor); vtkProperty* property = actor->GetProperty(); - this->InitProperty(property); - property->SetColor(color.x(), color.y(), color.z()); - m_VtkObjects.push_back(polyData); - m_VtkObjects.push_back(polyDataMapper); m_Actors.push_back(actor); } void mitk::SimulationDrawTool::drawTriangles(const std::vector& points, const std::vector& indices, const std::vector& normals, const Vec4f color) { if (!m_Update || points.empty() || indices.empty() || normals.empty()) return; unsigned int numPoints = points.size(); - vtkPoints* vtkPoints = vtkPoints::New(); + vtkSmartPointer vtkPoints = vtkSmartPointer< ::vtkPoints>::New(); vtkPoints->SetNumberOfPoints(numPoints); for (unsigned int i = 0; i < numPoints; ++i) vtkPoints->SetPoint(i, points[i].elems); - vtkPolyData* polyData = vtkPolyData::New(); + vtkSmartPointer polyData = vtkSmartPointer::New(); polyData->SetPoints(vtkPoints); - vtkPoints->Delete(); - - vtkCellArray* triangles = vtkCellArray::New(); + vtkSmartPointer triangles = vtkSmartPointer::New(); unsigned int numIndices = indices.size(); for (unsigned int i = 0; i < numIndices; ++i) { triangles->InsertNextCell(3); triangles->InsertCellPoint(indices[i].elems[0]); triangles->InsertCellPoint(indices[i].elems[1]); triangles->InsertCellPoint(indices[i].elems[2]); } polyData->SetPolys(triangles); - triangles->Delete(); - unsigned int numNormals = normals.size(); - vtkFloatArray* vtkNormals = vtkFloatArray::New(); + vtkSmartPointer vtkNormals = vtkSmartPointer::New(); vtkNormals->SetNumberOfComponents(3); + vtkNormals->SetNumberOfTuples(numNormals); vtkNormals->SetName("Normals"); - for (int i = 0; i < numNormals; ++i) - vtkNormals->InsertNextTuple(normals[i].elems); + for (unsigned int i = 0; i < numNormals; ++i) + vtkNormals->SetTuple(i, normals[i].elems); polyData->GetCellData()->SetNormals(vtkNormals); - vtkNormals->Delete(); - - vtkPolyDataMapper* polyDataMapper = vtkPolyDataMapper::New(); + vtkSmartPointer polyDataMapper = vtkSmartPointer::New(); polyDataMapper->SetInput(polyData); - vtkActor* actor = vtkActor::New(); + vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(polyDataMapper); actor->SetScale(Simulation::ScaleFactor); vtkProperty* property = actor->GetProperty(); - this->InitProperty(property); - property->SetColor(color.x(), color.y(), color.z()); - m_VtkObjects.push_back(polyData); - m_VtkObjects.push_back(polyDataMapper); m_Actors.push_back(actor); } void mitk::SimulationDrawTool::drawTriangles(const std::vector&, const std::vector&, const std::vector&) { } void mitk::SimulationDrawTool::drawTriangleStrip(const std::vector&, const std::vector&, const Vec4f) { } void mitk::SimulationDrawTool::drawTriangleFan(const std::vector&, const std::vector&, const Vec4f) { } void mitk::SimulationDrawTool::drawFrame(const Vector3& position, const Quaternion& orientation, const Vec3f& size) { if (!m_Update) return; - const float radius = 0.05f; + float minSize = std::min(std::min(size.x(), size.y()), size.z()); + float maxSize = std::max(std::max(size.x(), size.y()), size.z()); + + if (maxSize > minSize * 2.0f) + { + if (minSize > 0.0f) + maxSize = minSize * 2.0f; + else + minSize = maxSize * 0.707f; + } + + const float radii[] = { minSize * 0.1f, maxSize * 0.2f }; bool wireframeBackup = m_Wireframe; m_Wireframe = false; - std::vector colors; - colors.push_back(Vec4f(0.0f, 0.0f, 1.0f, 1.0f)); - colors.push_back(Vec4f(0.0f, 1.0f, 0.0f, 1.0f)); - colors.push_back(Vec4f(1.0f, 0.0f, 0.0f, 1.0f)); - if (size.x() != 0.0f) { Vector3 point2 = position + orientation.rotate(Vec3f(size.x(), 0.0f, 0.0f)); - this->drawArrow(position, point2, radius, colors.back()); - colors.pop_back(); + Vector3 point3 = point2 + orientation.rotate(Vec3f(radii[1], 0.0f, 0.0f)); + Vec4f red(1.0f, 0.0f, 0.0f, 1.0f); + + this->drawCylinder(position, point2, radii[0], red); + this->drawCone(point2, point3, radii[1], 0.0f, red); } if (size.y() != 0.0f) { Vector3 point2 = position + orientation.rotate(Vec3f(0.0f, size.y(), 0.0f)); - this->drawArrow(position, point2, radius, colors.back()); - colors.pop_back(); + Vector3 point3 = point2 + orientation.rotate(Vec3f(0.0f, radii[1], 0.0f)); + Vec4f green(0.0f, 1.0f, 0.0f, 1.0f); + + this->drawCylinder(position, point2, radii[0], green); + this->drawCone(point2, point3, radii[1], 0.0f, green); } if (size.z() != 0.0f) { Vector3 point2 = position + orientation.rotate(Vec3f(0.0f, 0.0f, size.z())); - this->drawArrow(position, point2, radius, colors.back()); + Vector3 point3 = point2 + orientation.rotate(Vec3f(0.0f, 0.0f, radii[1])); + Vec4f blue(0.0f, 0.0f, 1.0f, 1.0f); + + this->drawCylinder(position, point2, radii[0], blue); + this->drawCone(point2, point3, radii[1], 0.0f, blue); } m_Wireframe = wireframeBackup; } void mitk::SimulationDrawTool::drawSpheres(const std::vector& points, const std::vector& radii, const Vec4f color) { if (!m_Update || points.empty()) return; unsigned int numSpheres = points.size(); for (unsigned int i = 0; i < numSpheres; ++i) { - vtkSphereSource *sphereSource = vtkSphereSource::New(); + vtkSmartPointer sphereSource = vtkSmartPointer::New(); sphereSource->SetCenter(const_cast(points[i].elems)); sphereSource->SetRadius(radii[i]); sphereSource->SetPhiResolution(16); sphereSource->SetThetaResolution(32); sphereSource->LatLongTessellationOn(); - vtkPolyDataMapper* polyDataMapper = vtkPolyDataMapper::New(); - polyDataMapper->SetInput(sphereSource->GetOutput()); + vtkSmartPointer polyDataMapper = vtkSmartPointer::New(); + polyDataMapper->SetInputConnection(sphereSource->GetOutputPort()); - vtkActor* actor = vtkActor::New(); + vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(polyDataMapper); actor->SetScale(Simulation::ScaleFactor); vtkProperty* property = actor->GetProperty(); - this->InitProperty(property); - property->SetColor(color.x(), color.y(), color.z()); - m_VtkObjects.push_back(sphereSource); - m_VtkObjects.push_back(polyDataMapper); m_Actors.push_back(actor); } } void mitk::SimulationDrawTool::drawSpheres(const std::vector& points, float radius, const Vec4f color) { if (!m_Update || points.empty()) return; unsigned int numPoints = points.size(); std::vector radii(numPoints, radius); this->drawSpheres(points, radii, color); } void mitk::SimulationDrawTool::drawCone(const Vector3& point1, const Vector3& point2, float radius1, float radius2, const Vec4f color, int subdivisions) { if (!m_Update) return; - vtkPoints* points = vtkPoints::New(); + vtkSmartPointer points = vtkSmartPointer::New(); points->SetNumberOfPoints(2); points->SetPoint(0, point1.elems); points->SetPoint(1, point2.elems); - vtkCellArray* line = vtkCellArray::New(); + vtkSmartPointer line = vtkSmartPointer::New(); line->InsertNextCell(2); line->InsertCellPoint(0); line->InsertCellPoint(1); - vtkPolyData* polyData = vtkPolyData::New(); + vtkSmartPointer polyData = vtkSmartPointer::New(); polyData->SetPoints(points); polyData->SetLines(line); - points->Delete(); - line->Delete(); - const char* radiiName = "Radii"; - vtkFloatArray* radii = vtkFloatArray::New(); + vtkSmartPointer radii = vtkSmartPointer::New(); radii->SetName(radiiName); radii->SetNumberOfTuples(2); radii->SetTuple1(0, radius1); radii->SetTuple1(1, radius2); vtkPointData* pointData = polyData->GetPointData(); pointData->AddArray(radii); pointData->SetActiveScalars(radiiName); - radii->Delete(); - - vtkTubeFilter* tubeFilter = vtkTubeFilter::New(); + vtkSmartPointer tubeFilter = vtkSmartPointer::New(); tubeFilter->SetInput(polyData); tubeFilter->CappingOn(); tubeFilter->SetNumberOfSides(subdivisions); tubeFilter->SetVaryRadiusToVaryRadiusByAbsoluteScalar(); - vtkPolyDataMapper* polyDataMapper = vtkPolyDataMapper::New(); - polyDataMapper->SetInput(tubeFilter->GetOutput()); + vtkSmartPointer polyDataMapper = vtkSmartPointer::New(); + polyDataMapper->SetInputConnection(tubeFilter->GetOutputPort()); polyDataMapper->ScalarVisibilityOff(); - vtkActor* actor = vtkActor::New(); + vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(polyDataMapper); actor->SetScale(Simulation::ScaleFactor); vtkProperty* property = actor->GetProperty(); - this->InitProperty(property); - property->SetColor(color.x(), color.y(), color.z()); - m_VtkObjects.push_back(polyData); - m_VtkObjects.push_back(tubeFilter); - m_VtkObjects.push_back(polyDataMapper); m_Actors.push_back(actor); } void mitk::SimulationDrawTool::drawCube(const float&, const Vec4f&, const int&) { } void mitk::SimulationDrawTool::drawCylinder(const Vector3& point1, const Vector3& point2, float radius, const Vec4f color, int subdivisions) { if (!m_Update) return; this->drawCone(point1, point2, radius, radius, color, subdivisions); } void mitk::SimulationDrawTool::drawCapsule(const Vector3&, const Vector3&, float, const Vec4f, int) { } void mitk::SimulationDrawTool::drawArrow(const Vector3& point1, const Vector3& point2, float radius, const Vec4f color, int subdivisions) { if (!m_Update) return; Vector3 point3 = point1 * 0.2f + point2 * 0.8f; this->drawCylinder(point1, point3, radius, color, subdivisions); this->drawCone(point3, point2, radius * 2.5f, 0.0f, color, subdivisions); } void mitk::SimulationDrawTool::drawPlus(const float& edgeRadius, const Vec4f& color, const int& subdivisions) { if (!m_Update) return; this->drawCylinder(Vector3(-1.0, 0.0, 0.0), Vector3(1.0, 0.0, 0.0), edgeRadius, color, subdivisions); this->drawCylinder(Vector3(0.0, -1.0, 0.0), Vector3(0.0, 1.0, 0.0), edgeRadius, color, subdivisions); this->drawCylinder(Vector3(0.0, 0.0, -1.0), Vector3(0.0, 0.0, 1.0), edgeRadius, color, subdivisions); } void mitk::SimulationDrawTool::drawPoint(const Vector3&, const Vec4f&) { } void mitk::SimulationDrawTool::drawPoint(const Vector3&, const Vector3&, const Vec4f&) { } void mitk::SimulationDrawTool::drawTriangle(const Vector3&, const Vector3&, const Vector3&, const Vector3&) { } void mitk::SimulationDrawTool::drawTriangle(const Vector3&, const Vector3&, const Vector3&, const Vector3&, const Vec4f&) { } void mitk::SimulationDrawTool::drawTriangle(const Vector3&, const Vector3&, const Vector3&, const Vector3&, const Vec4f&, const Vec4f&, const Vec4f&) { } void mitk::SimulationDrawTool::drawSphere(const Vector3&, float) { } void mitk::SimulationDrawTool::pushMatrix() { } void mitk::SimulationDrawTool::popMatrix() { } void mitk::SimulationDrawTool::multMatrix(float*) { } void mitk::SimulationDrawTool::scale(float) { } void mitk::SimulationDrawTool::setMaterial(const Vec4f&, std::string) { } void mitk::SimulationDrawTool::resetMaterial(const Vec4f&, std::string) { } void mitk::SimulationDrawTool::setPolygonMode(int mode, bool wireframe) { if (!m_Update) return; m_PolygonMode = mode; m_Wireframe = wireframe; } void mitk::SimulationDrawTool::setLightingEnabled(bool) { } void mitk::SimulationDrawTool::writeOverlayText(int, int, unsigned int, const Vec4f&, const char*) { } diff --git a/Modules/Simulation/mitkSimulationDrawTool.h b/Modules/Simulation/mitkSimulationDrawTool.h index 519b39c82b..948638a254 100644 --- a/Modules/Simulation/mitkSimulationDrawTool.h +++ b/Modules/Simulation/mitkSimulationDrawTool.h @@ -1,109 +1,107 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkSimulationDrawTool_h #define mitkSimulationDrawTool_h #include #include +#include +#include -class vtkActor; -class vtkObjectBase; class vtkProperty; namespace mitk { /** \brief Utility class used by SOFA classes to draw objects other than visual models. * * Implements the sofa::core::visual::DrawTool interface and replaces the default SOFA OpenGL implementation sofa::core::visual::DrawToolGL. * All draw methods create a VTK actor and append it to an internal list which can be queried by calling GetActors() to finally draw them. * In contrary to the original concept of DrawToolGL, which is set once during initialization of SOFA applications, every mitk::Simulation has its own exclusive copy of mitk::SimulationDrawTool. * Since SOFA can handle only a single DrawTool at once it must be ensured that the correct mitk::SimulationDrawTool is set when switching the active simulation. * * Each draw method checks if it is necessary to generate a new up-to-date VTK actor, i.e. after a simulation step, or if it is sufficient to use the already generated one. * This decision is controlled through the methods Reset() and DisableUpdate(). * The former method must be called right before a simulation step and mitk::SimulationMapper3D calls the latter method during rendering to disable unnecessary updates until the next simulation step. */ class Simulation_EXPORT SimulationDrawTool : public sofa::core::visual::DrawTool { public: SimulationDrawTool(); ~SimulationDrawTool(); /** \brief Disables creation of new VTK actors when calling draw methods. */ void DisableUpdate(); /** \brief Returns current list of VTK actors which were generated by draw methods since the last reset. * * \note Do not delete the VTK actors returned by this method. */ - std::vector GetActors() const; + std::vector > GetActors() const; /** \brief Clears internal lists of current VTK objects and enables creation of new VTK actors when calling draw methods. */ void Reset(); void drawPoints(const std::vector& points, float pointSize, const Vec4f color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f)); void drawLines(const std::vector& points, float lineWidth, const Vec4f color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f)); void drawLines(const std::vector& points, const std::vector& indices, float lineWidth, const Vec4f color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f)); void drawTriangles(const std::vector& points, const Vec4f color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f)); void drawTriangles(const std::vector& points, const Vector3 normal, const Vec4f color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f)); void drawTriangles(const std::vector& points, const std::vector& indices, const std::vector& normals, const Vec4f color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f)); void drawTriangles(const std::vector& points, const std::vector& normals, const std::vector& colors); void drawTriangleStrip(const std::vector& points, const std::vector& normals, const Vec4f color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f)); void drawTriangleFan(const std::vector& points, const std::vector& normals, const Vec4f color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f)); void drawFrame(const Vector3& position, const Quaternion& orientation, const Vec3f& size); void drawSpheres(const std::vector& points, const std::vector& radii, const Vec4f color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f)); void drawSpheres(const std::vector& points, float radius, const Vec4f color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f)); void drawCone(const Vector3& point1, const Vector3& point2, float radius1, float radius2, const Vec4f color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f), int subdivisions = 16); void drawCube(const float& edgeRadius, const Vec4f& color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f), const int& subdivisions = 16); void drawCylinder(const Vector3& point1, const Vector3& point2, float radius, const Vec4f color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f), int subdivisions = 16); void drawCapsule(const Vector3& point1, const Vector3& point2, float radius, const Vec4f color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f), int subdivisions = 16); void drawArrow(const Vector3& point1, const Vector3& point2, float radius, const Vec4f color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f), int subdivisions = 16); void drawPlus(const float& edgeRadius, const Vec4f& color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f), const int& subdivisions = 16); void drawPoint(const Vector3& position, const Vec4f& color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f)); void drawPoint(const Vector3& position, const Vector3& normal, const Vec4f& color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f)); void drawTriangle(const Vector3& point1, const Vector3& point2, const Vector3& point3, const Vector3& normal); void drawTriangle(const Vector3& point1, const Vector3& point2, const Vector3& point3, const Vector3& normal, const Vec4f& color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f)); void drawTriangle(const Vector3& point1, const Vector3& point2, const Vector3& point3, const Vector3& normal, const Vec4f& color1, const Vec4f& color2, const Vec4f& color3); void drawSphere(const Vector3& position, float radius); void pushMatrix(); void popMatrix(); void multMatrix(float* matrix); void scale(float factor); void setMaterial(const Vec4f& color, std::string name = ""); void resetMaterial(const Vec4f& color, std::string name = ""); void setPolygonMode(int mode, bool wireframe); void setLightingEnabled(bool isEnabled); void writeOverlayText(int x, int y, unsigned int fontSize, const Vec4f& color, const char* text); private: SimulationDrawTool(const SimulationDrawTool&); SimulationDrawTool& operator=(const SimulationDrawTool&); - void DeleteVtkObjects(); void InitProperty(vtkProperty* property) const; - std::vector m_VtkObjects; - std::vector m_Actors; + std::vector > m_Actors; int m_PolygonMode; bool m_Wireframe; bool m_Update; }; } #endif diff --git a/Modules/Simulation/mitkSimulationMapper3D.cpp b/Modules/Simulation/mitkSimulationMapper3D.cpp index fc65b28ae7..8b7a5c64f0 100644 --- a/Modules/Simulation/mitkSimulationMapper3D.cpp +++ b/Modules/Simulation/mitkSimulationMapper3D.cpp @@ -1,242 +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 "mitkSimulation.h" #include "mitkSimulationMapper3D.h" #include "mitkSimulationModel.h" #include "mitkSimulationPropAssemblyVisitor.h" #include #include mitk::SimulationMapper3D::LocalStorage::LocalStorage() : m_VtkProp(vtkSmartPointer::New()) { } mitk::SimulationMapper3D::LocalStorage::~LocalStorage() { } void mitk::SimulationMapper3D::SetDefaultProperties(DataNode* node, BaseRenderer* renderer, bool overwrite) { if (node != NULL) { mitk::Simulation* simulation = dynamic_cast(node->GetData()); if (simulation != NULL) { sofa::simulation::Node::SPtr rootNode = simulation->GetRootNode(); sofa::component::visualmodel::VisualStyle::SPtr visualStyle; rootNode->get(visualStyle); if (!visualStyle) { visualStyle = sofa::core::objectmodel::New(); sofa::core::visual::DisplayFlags* displayFlags = visualStyle->displayFlags.beginEdit(); displayFlags->setShowVisualModels(); visualStyle->displayFlags.endEdit(); rootNode->addObject(visualStyle); } const sofa::core::visual::DisplayFlags& displayFlags = visualStyle->displayFlags.getValue(); node->AddProperty("Simulation.Behavior.Behavior Models", BoolProperty::New(displayFlags.getShowBehaviorModels()), renderer, overwrite); node->AddProperty("Simulation.Behavior.Force Fields", BoolProperty::New(displayFlags.getShowForceFields()), renderer, overwrite); node->AddProperty("Simulation.Behavior.Interactions", BoolProperty::New(displayFlags.getShowInteractionForceFields()), renderer, overwrite); node->AddProperty("Simulation.Collision.Bounding Trees", BoolProperty::New(displayFlags.getShowBoundingCollisionModels()), renderer, overwrite); node->AddProperty("Simulation.Collision.Collision Models", BoolProperty::New(displayFlags.getShowCollisionModels()), renderer, overwrite); node->AddProperty("Simulation.Mapping.Mechanical Mappings", BoolProperty::New(displayFlags.getShowMechanicalMappings()), renderer, overwrite); node->AddProperty("Simulation.Mapping.Visual Mappings", BoolProperty::New(displayFlags.getShowMappings()), renderer, overwrite); node->AddProperty("Simulation.Options.Normals", BoolProperty::New(displayFlags.getShowNormals()), renderer, overwrite); node->AddProperty("Simulation.Options.Wire Frame", BoolProperty::New(displayFlags.getShowWireFrame()), renderer, overwrite); node->AddProperty("Simulation.Visual.Visual Models", BoolProperty::New(displayFlags.getShowVisualModels()), renderer, overwrite); } Superclass::SetDefaultProperties(node, renderer, overwrite); } } mitk::SimulationMapper3D::SimulationMapper3D() { } mitk::SimulationMapper3D::~SimulationMapper3D() { } void mitk::SimulationMapper3D::ApplyProperties(vtkActor* actor, mitk::BaseRenderer* renderer) { if (actor == NULL) { mitk::DataNode* node = this->GetDataNode(); bool showBehaviorModels; bool showForceFields; bool showInteractionForceFields; bool showBoundingCollisionModels; bool showCollisionModels; bool showMechanicalMappings; bool showMappings; bool showNormals; bool showWireFrame; bool showVisualModels; node->GetBoolProperty("Simulation.Behavior.Behavior Models", showBehaviorModels, renderer); node->GetBoolProperty("Simulation.Behavior.Force Fields", showForceFields, renderer); node->GetBoolProperty("Simulation.Behavior.Interactions", showInteractionForceFields, renderer); node->GetBoolProperty("Simulation.Collision.Bounding Trees", showBoundingCollisionModels, renderer); node->GetBoolProperty("Simulation.Collision.Collision Models", showCollisionModels, renderer); node->GetBoolProperty("Simulation.Mapping.Mechanical Mappings", showMechanicalMappings, renderer); node->GetBoolProperty("Simulation.Mapping.Visual Mappings", showMappings, renderer); node->GetBoolProperty("Simulation.Options.Normals", showNormals, renderer); node->GetBoolProperty("Simulation.Options.Wire Frame", showWireFrame, renderer); node->GetBoolProperty("Simulation.Visual.Visual Models", showVisualModels, renderer); mitk::Simulation* simulation = static_cast(this->GetData()); sofa::component::visualmodel::VisualStyle::SPtr visualStyle; simulation->GetRootNode()->get(visualStyle); bool update = false; sofa::core::visual::DisplayFlags* displayFlags = visualStyle->displayFlags.beginEdit(); if (showBehaviorModels != displayFlags->getShowBehaviorModels()) { displayFlags->setShowBehaviorModels(showBehaviorModels); update = true; } if (showForceFields != displayFlags->getShowForceFields()) { displayFlags->setShowForceFields(showForceFields); update = true; } if (showInteractionForceFields != displayFlags->getShowInteractionForceFields()) { displayFlags->setShowInteractionForceFields(showInteractionForceFields); update = true; } if (showBoundingCollisionModels != displayFlags->getShowBoundingCollisionModels()) { displayFlags->setShowBoundingCollisionModels(showBoundingCollisionModels); update = true; } if (showCollisionModels != displayFlags->getShowCollisionModels()) { displayFlags->setShowCollisionModels(showCollisionModels); update = true; } if (showMechanicalMappings != displayFlags->getShowMechanicalMappings()) { displayFlags->setShowMechanicalMappings(showMechanicalMappings); update = true; } if (showMappings != displayFlags->getShowMappings()) { displayFlags->setShowMappings(showMappings); update = true; } displayFlags->setShowNormals(showNormals); if (showWireFrame != displayFlags->getShowWireFrame()) { displayFlags->setShowWireFrame(showWireFrame); update = true; } displayFlags->setShowVisualModels(showVisualModels); visualStyle->displayFlags.endEdit(); if (update) simulation->GetDrawTool()->Reset(); } } void mitk::SimulationMapper3D::GenerateDataForRenderer(mitk::BaseRenderer* renderer) { mitk::Simulation* simulation = dynamic_cast(this->GetData()); if (sofa::simulation::getSimulation() == NULL) { if (simulation != NULL) { simulation->SetAsActiveSimulation(); simulation->GetDrawTool()->Reset(); } else { return; } } LocalStorage* localStorage = m_LocalStorageHandler.GetLocalStorage(renderer); localStorage->m_VtkProp = vtkSmartPointer::New(); if (simulation != NULL) { sofa::simulation::Simulation::SPtr sofaSimulation = simulation->GetSimulation(); sofa::simulation::Node::SPtr rootNode = simulation->GetRootNode(); sofa::core::visual::VisualParams* vParams = sofa::core::visual::VisualParams::defaultInstance(); SimulationDrawTool* drawTool = simulation->GetDrawTool(); sofa::simulation::Simulation* backupSimulation = NULL; sofa::core::visual::DrawTool* backupDrawTool = NULL; if (sofa::simulation::getSimulation() != sofaSimulation.get()) { backupSimulation = sofa::simulation::getSimulation(); backupDrawTool = vParams->drawTool(); sofa::simulation::setSimulation(sofaSimulation.get()); vParams->drawTool() = drawTool; } this->ApplyProperties(NULL, renderer); sofaSimulation->updateVisual(rootNode.get()); sofaSimulation->draw(vParams, rootNode.get()); drawTool->DisableUpdate(); SimulationPropAssemblyVisitor propAssemblyVisitor(localStorage->m_VtkProp); rootNode->executeVisitor(&propAssemblyVisitor); - std::vector actors = drawTool->GetActors(); + std::vector > actors = drawTool->GetActors(); - for (std::vector::const_iterator actor = actors.begin(); actor != actors.end(); ++actor) + for (std::vector >::const_iterator actor = actors.begin(); actor != actors.end(); ++actor) localStorage->m_VtkProp->AddPart(*actor); if (backupSimulation != NULL) { sofa::simulation::setSimulation(backupSimulation); vParams->drawTool() = backupDrawTool; } } } vtkProp* mitk::SimulationMapper3D::GetVtkProp(mitk::BaseRenderer* renderer) { return m_LocalStorageHandler.GetLocalStorage(renderer)->m_VtkProp; } diff --git a/Modules/Simulation/mitkSimulationModel.cpp b/Modules/Simulation/mitkSimulationModel.cpp index cebf7e866a..bd9c4a816d 100644 --- a/Modules/Simulation/mitkSimulationModel.cpp +++ b/Modules/Simulation/mitkSimulationModel.cpp @@ -1,337 +1,300 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkSimulation.h" #include "mitkSimulationModel.h" #include #include -#include #include #include #include #include #include #include #include #include -#include mitk::SimulationModel::SimulationModel() : m_LastTime(-1.0), m_LastShowNormals(false), m_LastShowVisualModels(true), m_LastShowWireFrame(false) { } mitk::SimulationModel::~SimulationModel() { - this->DeleteVtkTextures(); - this->DeleteVtkObjects(); -} - -void mitk::SimulationModel::DeleteVtkObjects() -{ - for (std::vector::const_iterator object = m_VtkObjects.begin(); object != m_VtkObjects.end(); ++object) - (*object)->Delete(); - - m_VtkObjects.clear(); - - for (std::vector::const_iterator actor = m_Actors.begin(); actor != m_Actors.end(); ++actor) - (*actor)->Delete(); - m_Actors.clear(); -} - -void mitk::SimulationModel::DeleteVtkTextures() -{ - for (std::map::const_iterator texture = m_Textures.begin(); texture != m_Textures.end(); ++texture) - texture->second->Delete(); - m_Textures.clear(); } void mitk::SimulationModel::DrawGroup(int ig, const sofa::core::visual::VisualParams* vparams, bool transparent) { const sofa::defaulttype::ResizableExtVector& triangles = this->getTriangles(); const sofa::defaulttype::ResizableExtVector& quads = this->getQuads(); FaceGroup g; if (ig < 0) { g.materialId = -1; g.tri0 = 0; g.nbt = triangles.size(); g.quad0 = 0; g.nbq = quads.size(); } else { g = groups.getValue()[ig]; } const sofa::defaulttype::ResizableExtVector& vertices = this->getVertices(); unsigned int numVertices = vertices.size(); - vtkPoints* points = vtkPoints::New(); + vtkSmartPointer points = vtkSmartPointer::New(); points->SetNumberOfPoints(numVertices); for (unsigned int i = 0; i < numVertices; ++i) points->SetPoint(i, vertices[i].elems); - vtkPolyData* polyData = vtkPolyData::New(); + vtkSmartPointer polyData = vtkSmartPointer::New(); polyData->SetPoints(points); - points->Delete(); - - vtkCellArray* polys = vtkCellArray::New(); + vtkSmartPointer polys = vtkSmartPointer::New(); int numTriangles = g.tri0 + g.nbt; int numQuads = g.quad0 + g.nbq; for (int i = g.tri0; i < numTriangles; ++i) { polys->InsertNextCell(3); polys->InsertCellPoint(triangles[i].elems[0]); polys->InsertCellPoint(triangles[i].elems[1]); polys->InsertCellPoint(triangles[i].elems[2]); } for (int i = g.quad0; i < numQuads; ++i) { polys->InsertNextCell(4); polys->InsertCellPoint(quads[i].elems[0]); polys->InsertCellPoint(quads[i].elems[1]); polys->InsertCellPoint(quads[i].elems[2]); polys->InsertCellPoint(quads[i].elems[3]); } polyData->SetPolys(polys); - polys->Delete(); - const sofa::defaulttype::ResizableExtVector& normals = this->getVnormals(); unsigned int numNormals = normals.size(); - vtkFloatArray* vtkNormals = vtkFloatArray::New(); + vtkSmartPointer vtkNormals = vtkSmartPointer::New(); vtkNormals->SetNumberOfComponents(3); + vtkNormals->SetNumberOfTuples(numNormals); for (unsigned int i = 0; i < numNormals; ++i) - vtkNormals->InsertNextTuple(normals[i].elems); + vtkNormals->SetTuple(i, normals[i].elems); polyData->GetPointData()->SetNormals(vtkNormals); - vtkNormals->Delete(); - sofa::core::loader::Material m = g.materialId >= 0 ? materials.getValue()[g.materialId] : material.getValue(); if (m.useTexture && m.activated) { const sofa::defaulttype::ResizableExtVector& texCoords = this->getVtexcoords(); unsigned int numTexCoords = texCoords.size(); - vtkFloatArray* vtkTexCoords = vtkFloatArray::New(); + vtkSmartPointer vtkTexCoords = vtkSmartPointer::New(); vtkTexCoords->SetNumberOfComponents(2); + vtkTexCoords->SetNumberOfTuples(numTexCoords); for (unsigned int i = 0; i < numTexCoords; ++i) - vtkTexCoords->InsertNextTuple(texCoords[i].elems); + vtkTexCoords->SetTuple(i, texCoords[i].elems); polyData->GetPointData()->SetTCoords(vtkTexCoords); - - vtkTexCoords->Delete(); } - vtkPolyDataMapper* polyDataMapper = vtkPolyDataMapper::New(); + vtkSmartPointer polyDataMapper = vtkSmartPointer::New(); polyDataMapper->SetInput(polyData); - vtkActor* actor = vtkActor::New(); + vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(polyDataMapper); actor->SetScale(Simulation::ScaleFactor); if (m.useTexture && m.activated) actor->SetTexture(m_Textures[g.materialId]); sofa::defaulttype::Vec4f ambient = !m.useAmbient ? sofa::defaulttype::Vec4f() : m.ambient; sofa::defaulttype::Vec4f diffuse = !m.useDiffuse ? sofa::defaulttype::Vec4f() : m.diffuse; sofa::defaulttype::Vec4f specular = !m.useSpecular ? sofa::defaulttype::Vec4f() : m.specular; float shininess = m.useShininess ? m.shininess : 45.0f; if (shininess == 0.0f) { specular.clear(); shininess = 1.0f; } vtkProperty* property = actor->GetProperty(); property->SetAmbientColor(ambient.x(), ambient.y(), ambient.z()); property->SetDiffuseColor(diffuse.x(), diffuse.y(), diffuse.z()); property->SetSpecular(1.0); property->SetSpecularColor(specular.x(), specular.y(), specular.z()); property->SetSpecularPower(shininess); if (vparams->displayFlags().getShowWireFrame()) property->SetRepresentationToWireframe(); - m_VtkObjects.push_back(polyData); - m_VtkObjects.push_back(polyDataMapper); m_Actors.push_back(actor); if (!m_LastShowNormals) return; - points = vtkPoints::New(); + points = vtkSmartPointer::New(); points->SetNumberOfPoints(numVertices * 2); - vtkCellArray* lines = vtkCellArray::New(); + vtkSmartPointer lines = vtkSmartPointer::New(); for (unsigned int i = 0; i < numVertices; ++i) { unsigned int j = 2 * i; unsigned int k = j + 1; points->SetPoint(j, vertices[i].elems); points->SetPoint(k, (vertices[i] + normals[i]).elems); lines->InsertNextCell(2); lines->InsertCellPoint(j); lines->InsertCellPoint(k); } - polyData = vtkPolyData::New(); + polyData = vtkSmartPointer::New(); polyData->SetPoints(points); polyData->SetLines(lines); - points->Delete(); - lines->Delete(); - - polyDataMapper = vtkPolyDataMapper::New(); + polyDataMapper = vtkSmartPointer::New(); polyDataMapper->SetInput(polyData); - actor = vtkActor::New(); + actor = vtkSmartPointer::New(); actor->SetMapper(polyDataMapper); actor->SetScale(Simulation::ScaleFactor); - m_VtkObjects.push_back(polyData); - m_VtkObjects.push_back(polyDataMapper); m_Actors.push_back(actor); } -std::vector mitk::SimulationModel::GetActors() const +std::vector > mitk::SimulationModel::GetActors() const { return m_Actors; } void mitk::SimulationModel::internalDraw(const sofa::core::visual::VisualParams* vparams, bool transparent) { double time = this->getContext()->getTime(); const sofa::core::visual::DisplayFlags& displayFlags = vparams->displayFlags(); bool showNormals = displayFlags.getShowNormals(); bool showVisualModels = displayFlags.getShowVisualModels(); bool showWireFrame = displayFlags.getShowWireFrame(); if (time == m_LastTime && showNormals == m_LastShowNormals && showVisualModels == m_LastShowVisualModels && showWireFrame == m_LastShowWireFrame) return; m_LastTime = time; m_LastShowNormals = showNormals; m_LastShowVisualModels = showVisualModels; m_LastShowWireFrame = showWireFrame; if (transparent) return; - this->DeleteVtkObjects(); + m_Actors.clear(); if (!vparams->displayFlags().getShowVisualModels()) return; sofa::helper::ReadAccessor > > groups = this->groups; if (groups.empty()) { this->DrawGroup(-1, vparams, transparent); } else { for (unsigned int i = 0; i < groups.size(); ++i) this->DrawGroup(i, vparams, transparent); } } bool mitk::SimulationModel::loadTexture(const std::string& filename) { return false; } bool mitk::SimulationModel::loadTextures() { - this->DeleteVtkTextures(); + m_Textures.clear(); std::vector activatedTextures; const sofa::helper::vector& materials = this->materials.getValue(); unsigned int numMaterials = materials.size(); for (unsigned int i = 0; i < numMaterials; ++i) { const sofa::core::loader::Material& material = materials[i]; if (material.useTexture && material.activated) activatedTextures.push_back(i); } unsigned int numActivatedTextures = activatedTextures.size(); for (unsigned int i = 0; i < numActivatedTextures; ++i) { std::string textureFilename = materials[activatedTextures[i]].textureFilename; if (!sofa::helper::system::DataRepository.findFile(textureFilename)) return false; - vtkImageReader2* imageReader = vtkImageReader2Factory::CreateImageReader2(textureFilename.c_str()); + vtkSmartPointer imageReader; + imageReader.TakeReference(vtkImageReader2Factory::CreateImageReader2(textureFilename.c_str())); if (imageReader == NULL) return false; imageReader->SetFileName(textureFilename.c_str()); - vtkTexture* texture = vtkTexture::New(); + vtkSmartPointer texture = vtkSmartPointer::New(); texture->SetInput(imageReader->GetOutputDataObject(0)); texture->InterpolateOn(); - imageReader->Delete(); - m_Textures.insert(std::make_pair(activatedTextures[i], texture)); } return true; } diff --git a/Modules/Simulation/mitkSimulationModel.h b/Modules/Simulation/mitkSimulationModel.h index b2a06fe9e1..e252966d3c 100644 --- a/Modules/Simulation/mitkSimulationModel.h +++ b/Modules/Simulation/mitkSimulationModel.h @@ -1,64 +1,60 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkSimulationModel_h #define mitkSimulationModel_h #include #include - -class vtkActor; -class vtkObjectBase; -class vtkTexture; +#include +#include +#include namespace mitk { class Simulation_EXPORT SimulationModel : public sofa::component::visualmodel::VisualModelImpl { public: SOFA_CLASS(SimulationModel, sofa::component::visualmodel::VisualModelImpl); - std::vector GetActors() const; + std::vector > GetActors() const; bool loadTexture(const std::string& filename); bool loadTextures(); protected: void internalDraw(const sofa::core::visual::VisualParams* vparams, bool transparent); private: SimulationModel(); ~SimulationModel(); SimulationModel(const MyType&); MyType& operator=(const MyType&); - void DeleteVtkObjects(); - void DeleteVtkTextures(); void DrawGroup(int ig, const sofa::core::visual::VisualParams* vparams, bool transparent); - std::vector m_VtkObjects; - std::vector m_Actors; - std::map m_Textures; + std::vector > m_Actors; + std::map > m_Textures; double m_LastTime; bool m_LastShowNormals; bool m_LastShowVisualModels; bool m_LastShowWireFrame; }; } #endif diff --git a/Modules/Simulation/mitkSimulationPropAssemblyVisitor.cpp b/Modules/Simulation/mitkSimulationPropAssemblyVisitor.cpp index ac546b6e11..60f9917385 100644 --- a/Modules/Simulation/mitkSimulationPropAssemblyVisitor.cpp +++ b/Modules/Simulation/mitkSimulationPropAssemblyVisitor.cpp @@ -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. ===================================================================*/ #include "mitkSimulationPropAssemblyVisitor.h" #include "mitkSimulationModel.h" #include #include mitk::SimulationPropAssemblyVisitor::SimulationPropAssemblyVisitor(vtkPropAssembly* propAssembly, const sofa::core::ExecParams* params) : Visitor(params), m_PropAssembly(propAssembly) { } mitk::SimulationPropAssemblyVisitor::~SimulationPropAssemblyVisitor() { } sofa::simulation::Visitor::Result mitk::SimulationPropAssemblyVisitor::processNodeTopDown(sofa::simulation::Node* node) { typedef sofa::simulation::Node::Sequence::const_iterator VisualModelIterator; VisualModelIterator end = node->visualModel.end(); for (VisualModelIterator visualModel = node->visualModel.begin(); visualModel != end; ++visualModel) { SimulationModel* simulationModel = dynamic_cast(*visualModel); if (simulationModel != NULL) { - std::vector actors = simulationModel->GetActors(); + std::vector > actors = simulationModel->GetActors(); - for (std::vector::const_iterator actor = actors.begin(); actor != actors.end(); ++actor) + for (std::vector >::const_iterator actor = actors.begin(); actor != actors.end(); ++actor) m_PropAssembly->AddPart(*actor); } } return RESULT_CONTINUE; } diff --git a/Modules/ToFHardware/CMakeLists.txt b/Modules/ToFHardware/CMakeLists.txt index c36179f834..466eeb91a3 100644 --- a/Modules/ToFHardware/CMakeLists.txt +++ b/Modules/ToFHardware/CMakeLists.txt @@ -1,34 +1,34 @@ #Define the platform string IF(WIN32) IF(CMAKE_CL_64) SET(_PLATFORM_STRING "W64") ELSE(CMAKE_CL_64) SET(_PLATFORM_STRING "W32") ENDIF(CMAKE_CL_64) ELSE(WIN32) IF(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") SET(_PLATFORM_STRING "L64") ELSE(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") SET(_PLATFORM_STRING "L32") ENDIF(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") ENDIF(WIN32) MITK_CREATE_MODULE(mitkToFHardware SUBPROJECTS MITK-ToF INCLUDE_DIRS ${MITK_BIN_DIR} INTERNAL_INCLUDE_DIRS ${INCLUDE_DIRS_INTERNAL} - DEPENDS Mitk MitkExt mitkOpenCVVideoSupport MitkIGT LegacyAdaptors + DEPENDS Mitk MitkExt mitkOpenCVVideoSupport MitkIGT LegacyAdaptors mitkCameraCalibration EXPORT_DEFINE MITK_TOFHARDWARE_EXPORT ADDITIONAL_LIBS ${ADDITIONAL_LIBS} ) add_subdirectory(Testing) add_subdirectory(Kinect) add_subdirectory(PMD) add_subdirectory(MesaSR4000) CONFIGURE_FILE(mitkToFConfig.h.in ${PROJECT_BINARY_DIR}/mitkToFConfig.h @ONLY) #foreach(tofhardwaresubfolder_dir ${tofhardwaresubfolder_dirs}) # add_subdirectory(${tofhardwaresubfolder_dirs}) #endforeach() diff --git a/Modules/ToFHardware/Documentation/doxygen/GeneratingDeviceModules.dox b/Modules/ToFHardware/Documentation/doxygen/GeneratingDeviceModules.dox new file mode 100644 index 0000000000..05d84dce5b --- /dev/null +++ b/Modules/ToFHardware/Documentation/doxygen/GeneratingDeviceModules.dox @@ -0,0 +1,89 @@ +/** +\page GeneratingDeviceModulesPage How to generate ToF DeviceModules + +The ToF-DeviceModule-Tutorial will help you implementing a new ToF-Device easily. +Using MicroServices for this purpose will be one of our main goals, too. + +If you do not know much about MicroServices, please take a look at: + +\ref MicroServices_Overview + +\section GeneratingDeviceModulsPageSec1 Generating a ToF-Device-Module in MITK + + + In order to implement your own device, you need to code the following objects: +
    +
  • device (the device itself) +
  • device factory (a singleton which produces instances of your device) +
  • controller (connection to the Hardware-SDK) +
  • Module Activator (Important for the MicroServices. This class ensures the automatic loading of the device.) +
+ + The following example shows how to implement a device, here we take the Kinect. + +
  • Creating a Sub-Folder + \n Following the Kinect-DeviceModule as a prototype, create a MODULENAME-Sub-Folder in your source directory. This MODULENAME-Folder is going to hold all the necessary files we will create in the next steps. + +
  • Create the CMake Files for our new camera-model in the MODULENAME-Folder < +
      +
    • CMakeList.txt + + In this file, the module is generated via CMake commands. The module name is set, the necessary libraries will be searched here in order to link them with your module. For the Kinect, we chose OpenNI and need the XnCppWrapper.h. Your device must inherit from the mitkToFCameraDevice and consequently your module must depend on mitkToFHardware -> what is the reason for the DEPENDS mitkToFHardware -line. For autoloading your Module with mitkToFHardware, insert the following CMake Macro: AUTOLOAD_WITH mitkToFHardware . We usually add an option for the user to activate the device module, but this is not essential (refer to OPTION(MITK_USE_TOF_KINECT "Enable support for Kinect camera" OFF)). + \n \arrow refer to CMakeList.text in the Kinect-Folder + + \Warning The dll/so files are not automatically deleted. + + \n
    • files.cmake + The files.cmake contains all the previously mentioned files (device, deviceFactory, controller, and ModuleActivator) + \n -> refer to mitkKinectActivator.cpp +
    + + +
  • Creating the Code Files in the MODULENAME-Folder +
      +
    • \a MODULENAMEController + \n -> While referring to mitkKinectcontroller.cpp and the mitkKinectcontroller.h, take a good look at the definition of the MITK_KINECTMODULE_EXPORT-class in the .h file + + \n
    • \a MODULENAMEDevice + Your device must inherit from ToFCameraDevice (e.g. class MITK_KINECTMODULE_EXPORT KinectDevice : public ToFCameraDevice) and consequently implement the methods of the ToFCameraDevice MicroService-Interface. (See ToFCameraDevice.h). Make sure to give your device a specific name in the method GetDeviceName(). All instances of your device will automatically be available in the view "ToFUtil", if you generate it via the factory. + \n -> refer to mitkKinectDevice.cpp and the mitkKinectDevice.h. + + \n
    • \a MODULENAMEDeviceFactory + Like the mitkToFCameraDevice, the mitkIToFDeviceFactory is a MicroService-Interface. The factory is meant for generation of devices of the same type. This concept allows for having multiple instances of the same camera connected. (Currently our GUI does not really support an actual connection of multiple devices, but the software framework, in principle, does.) Your factory must inherit from the mitkAbstractDeviceFactory, which provides some useful methods for device generation. Your factory instance should be registered as MicroService in order to be available in the view "ToF Device Generation". + \n -> refer to mitkKinectDeviceFactory.cpp and the mitkKinectDeviceFactory.h + + \n
    • \a MODULENAMEActivator + The load() method of this class will be called when the module is activated. If you would like to have an instance of your device registered as MicroService, you should call deviceFactory->ConnectToFDevice(); here. In addition, you can generate devices anywhere in your code via this method. The factory will automatically be available in the view "ToF Device Generation" if you register it like we do with the Kinect. TODO: Code example: + \n ->refer to mitkKinectActivator.cpp and the mitkKinectActivator.h or the mitkPMDModuleActivator.cpp and the mitkPMDModuleActivator.h. +
    + +\n + +If you did everything correct, your Module should be implemented an executable MODULENAME-Project will be generated and a working device should show up in the ServiceListWidget in the Connection-Part of ToFUtil. +Warning The dll/so files are not automatically deleted. After deactivating a device, please delete the concerning files in SUPERBUILDDIR/MITK-build/bin/mitkToFHardware/BUILDTYPE + + +\section GeneratingDeviceModulsPageSec2 [OPTIONAL] Adding a Testing Sub-Directory + +If you have any Tests you want to include, a Testing-Subdirectory in the newly created MODULENAME-Folder should be created. In this Folder we are going to put a CMakeLists.txt and a files.cmake the first one will just consist + + \code + MITK_CREATE_MODULE_TESTS() + \endcode + +while the later one, the files.cmake holds Information about TestFiles you created and put in the Folder. +E.g. for the Kinect: + + \code + set(MODULE_TESTS + mitkKinectControllerTest.cpp + mitkKinectDeviceTest.cpp + ) + \endcode + +As before, feel free to take a look at one of the existing Modules and their Testing-Subfolder as the Kinect´s. + +If you managed to implement your Module properly, an executable MODULENAMETestDriver will be generated. + + +*/ diff --git a/Modules/ToFHardware/Kinect/mitkKinectDevice.h b/Modules/ToFHardware/Kinect/mitkKinectDevice.h index 37cd126a85..4ddf45aeeb 100644 --- a/Modules/ToFHardware/Kinect/mitkKinectDevice.h +++ b/Modules/ToFHardware/Kinect/mitkKinectDevice.h @@ -1,161 +1,160 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkKinectModuleExports.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. * * \throws mitkException In case of no connection, an exception is thrown! * * @ingroup ToFHardware */ class MITK_KINECTMODULE_EXPORT KinectDevice : public ToFCameraDevice { public: - mitkClassMacro( KinectDevice , ToFCameraDevice ); itkNewMacro( Self ); /*! \brief opens a connection to the ToF camera \throws mitkException In case of no connection, an exception is thrown! */ virtual bool OnConnectCamera(); /*! \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 \throws mitkException In case of no connection, an exception is thrown! */ virtual void StartCamera(); /*! \brief stops the continuous updating of the camera */ virtual void StopCamera(); /*! \brief updates the camera for image acquisition \throws mitkException In case of no connection, an exception is thrown! */ 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 // /* // * TODO: Reenable doxygen comment when uncommenting, disabled to fix doxygen warning see bug 12882 // \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 int m_KinectDeviceNumber; private: }; } //END mitk namespace #endif diff --git a/Modules/ToFHardware/Kinect/mitkKinectDeviceFactory.h b/Modules/ToFHardware/Kinect/mitkKinectDeviceFactory.h index 56fe9c5de2..eeff536474 100644 --- a/Modules/ToFHardware/Kinect/mitkKinectDeviceFactory.h +++ b/Modules/ToFHardware/Kinect/mitkKinectDeviceFactory.h @@ -1,76 +1,87 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkKinectDeviceFactory_h #define __mitkKinectDeviceFactory_h #include "mitkKinectModuleExports.h" #include "mitkKinectDevice.h" #include "mitkAbstractToFDeviceFactory.h" +#include +#include namespace mitk { /** * \brief KinectDeviceFactory is an implementation of the factory pattern to generate Microsoft Kinect devices. * KinectDeviceFactory inherits from AbstractToFDeviceFactory which is a MicroService interface. * This offers users the oppertunity to generate new KinectDevices via a global instance of this factory. * @ingroup ToFHardware */ class MITK_KINECTMODULE_EXPORT KinectDeviceFactory : public itk::LightObject, public AbstractToFDeviceFactory { public: KinectDeviceFactory() { this->m_DeviceNumber = 1; } /*! \brief Defining the Factorie´s Name, here for the Kinect. */ std::string GetFactoryName() { return std::string("Kinect Factory"); } //Interating the Device name on calling the Factory std::string GetCurrentDeviceName() { std::stringstream name; if (m_DeviceNumber>1) { name << "Kinect " << m_DeviceNumber; } else { name << "Kinect "; } m_DeviceNumber++; return name.str(); } private: /*! \brief Create an instance of a KinectDevice. */ ToFCameraDevice::Pointer createToFCameraDevice() { KinectDevice::Pointer device = KinectDevice::New(); + + //Set default camera intrinsics for the kinect RGB camera. + //(OpenNI warps the distance data into the RGB space). + mitk::CameraIntrinsics::Pointer cameraIntrinsics = mitk::CameraIntrinsics::New(); + std::string pathToDefaulCalibrationFile(MITK_TOF_DATA_DIR); + pathToDefaulCalibrationFile.append("/CalibrationFiles/Kinect_RGB_camera.xml"); + cameraIntrinsics->FromXMLFile(pathToDefaulCalibrationFile); + device->SetProperty("CameraIntrinsics", mitk::CameraIntrinsicsProperty::New(cameraIntrinsics)); + return device.GetPointer(); } //Member variable as variable for our DeviceNumber int m_DeviceNumber; }; } #endif diff --git a/Modules/ToFHardware/MesaSR4000/mitkToFCameraMESASR4000DeviceFactory.h b/Modules/ToFHardware/MesaSR4000/mitkToFCameraMESASR4000DeviceFactory.h index 2ffb116ed1..da792364d4 100644 --- a/Modules/ToFHardware/MesaSR4000/mitkToFCameraMESASR4000DeviceFactory.h +++ b/Modules/ToFHardware/MesaSR4000/mitkToFCameraMESASR4000DeviceFactory.h @@ -1,74 +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 __mitkToFCameraMESASR4000DeviceFactory_h #define __mitkToFCameraMESASR4000DeviceFactory_h #include "mitkMESASR4000ModuleExports.h" #include "mitkToFCameraMESASR4000Device.h" #include "mitkAbstractToFDeviceFactory.h" +#include +#include +#include namespace mitk { /** * \brief ToFPMDRawPlayerDeviceFactory is an implementation of the factory pattern to generate MESASR4000Devices. * ToFCameraMESASR4000DeviceFactory inherits from AbstractToFDeviceFactory which is a MicroService interface. * This offers users the oppertunity to generate new Raw Player Devices via a global instance of this factory. * @ingroup ToFHardware */ class MITK_MESASR4000MODULE_EXPORT ToFCameraMESASR4000DeviceFactory : public itk::LightObject, public AbstractToFDeviceFactory { public: ToFCameraMESASR4000DeviceFactory() { this->m_DeviceNumber = 1; } /*! \brief Defining the Factorie´s Name, here for the MESASR4000DeviceFactory */ std::string GetFactoryName() { return std::string("MESA SR4000 Factory"); } std::string GetCurrentDeviceName() { std::stringstream name; if(m_DeviceNumber>1) { name << "MESA SR4000 "<< m_DeviceNumber; } else { name << "MESA SR4000"; } m_DeviceNumber++; return name.str(); } private: /*! \brief Create an instance of a ToFPMDRawDataDevice. */ ToFCameraDevice::Pointer createToFCameraDevice() { ToFCameraMESASR4000Device::Pointer device = ToFCameraMESASR4000Device::New(); + //Set default camera intrinsics for the Mesa-SR4000-camera. + mitk::CameraIntrinsics::Pointer cameraIntrinsics = mitk::CameraIntrinsics::New(); + std::string pathToDefaulCalibrationFile(MITK_TOF_DATA_DIR); + + pathToDefaulCalibrationFile.append("/CalibrationFiles/Mesa-SR4000_Camera.xml"); + cameraIntrinsics->FromXMLFile(pathToDefaulCalibrationFile); + device->SetProperty("CameraIntrinsics", mitk::CameraIntrinsicsProperty::New(cameraIntrinsics)); + return device.GetPointer(); } int m_DeviceNumber; }; } #endif diff --git a/Modules/ToFHardware/PMD/mitkToFCameraPMDCamBoardDeviceFactory.h b/Modules/ToFHardware/PMD/mitkToFCameraPMDCamBoardDeviceFactory.h index e31a04a17b..74f57d097f 100644 --- a/Modules/ToFHardware/PMD/mitkToFCameraPMDCamBoardDeviceFactory.h +++ b/Modules/ToFHardware/PMD/mitkToFCameraPMDCamBoardDeviceFactory.h @@ -1,76 +1,87 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkToFCameraPMDCamBoardDeviceFactory_h #define __mitkToFCameraPMDCamBoardDeviceFactory_h #include "mitkPMDModuleExports.h" #include "mitkToFCameraPMDCamBoardDevice.h" #include "mitkAbstractToFDeviceFactory.h" +#include +#include +#include namespace mitk { /** * \brief ToFPMDCamBoardDeviceFactory is an implementation of the factory pattern to generate CamBoard devices. * ToFPMDCamBoardDeviceFactory inherits from AbstractToFDeviceFactory which is a MicroService interface. * This offers users the oppertunity to generate new CamBoard Devices via a global instance of this factory. * @ingroup ToFHardware */ class MITK_PMDMODULE_EXPORT ToFCameraPMDCamBoardDeviceFactory : public itk::LightObject, public AbstractToFDeviceFactory { public: ToFCameraPMDCamBoardDeviceFactory() { this->m_DeviceNumber=1; } /*! \brief Defining the Factorie´s Name, here for the ToFPMDCamBoard. */ std::string GetFactoryName() { return std::string("PMD CamBoard Factory "); } std::string GetCurrentDeviceName() { std::stringstream name; if(m_DeviceNumber>1) { name << "PMD CamBoard "<< m_DeviceNumber; } else { name << "PMD CamBoard"; } m_DeviceNumber++; return name.str(); } private: /*! \brief Create an instance of a ToFPMDCamBoardDevice. */ ToFCameraDevice::Pointer createToFCameraDevice() { ToFCameraPMDCamBoardDevice::Pointer device = ToFCameraPMDCamBoardDevice::New(); + //Set default camera intrinsics for the CamBoard-camera. + mitk::CameraIntrinsics::Pointer cameraIntrinsics = mitk::CameraIntrinsics::New(); + std::string pathToDefaulCalibrationFile(MITK_TOF_DATA_DIR); + + pathToDefaulCalibrationFile.append("/CalibrationFiles/PMDCamBoard_camera.xml"); + cameraIntrinsics->FromXMLFile(pathToDefaulCalibrationFile); + device->SetProperty("CameraIntrinsics", mitk::CameraIntrinsicsProperty::New(cameraIntrinsics)); + return device.GetPointer(); } int m_DeviceNumber; }; } #endif diff --git a/Modules/ToFHardware/PMD/mitkToFCameraPMDCamCubeDeviceFactory.h b/Modules/ToFHardware/PMD/mitkToFCameraPMDCamCubeDeviceFactory.h index 89e494a407..9c9c9c35c6 100644 --- a/Modules/ToFHardware/PMD/mitkToFCameraPMDCamCubeDeviceFactory.h +++ b/Modules/ToFHardware/PMD/mitkToFCameraPMDCamCubeDeviceFactory.h @@ -1,75 +1,87 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkToFCameraPMDCamCubeDeviceFactory_h #define __mitkToFCameraPMDCamCubeDeviceFactory_h #include "mitkPMDModuleExports.h" #include "mitkToFCameraPMDCamCubeDevice.h" #include "mitkAbstractToFDeviceFactory.h" +#include +#include +#include namespace mitk { /** * \brief ToFPMDCamBoardDeviceFactory is an implementation of the factory pattern to generate Cam Cube Devices. * ToFPMDCamCubeDeviceFactory inherits from AbstractToFDeviceFactory which is a MicroService interface. * This offers users the oppertunity to generate new Cam Cube Devices via a global instance of this factory. * @ingroup ToFHardware */ class MITK_PMDMODULE_EXPORT ToFCameraPMDCamCubeDeviceFactory : public itk::LightObject, public AbstractToFDeviceFactory { public: ToFCameraPMDCamCubeDeviceFactory() { this->m_DeviceNumber=1; } /*! \brief Defining the Factorie´s Name, here for the ToFPMDCamCube. */ std::string GetFactoryName() { return std::string("PMD Camcube 2.0/3.0 Factory "); } std::string GetCurrentDeviceName() { std::stringstream name; if(m_DeviceNumber>1) { name << "PMD CamCube 2.0/3.0 "<< m_DeviceNumber; } else { name << "PMD CamCube 2.0/3.0 "; } m_DeviceNumber++; return name.str(); } private: /*! \brief Create an instance of a ToFPMDCamCubeDevice. */ ToFCameraDevice::Pointer createToFCameraDevice() { ToFCameraPMDCamCubeDevice::Pointer device = ToFCameraPMDCamCubeDevice::New(); + //Set default camera intrinsics for the CamCube Amplitude Camera. + mitk::CameraIntrinsics::Pointer cameraIntrinsics = mitk::CameraIntrinsics::New(); + std::string pathToDefaulCalibrationFile(MITK_TOF_DATA_DIR); + pathToDefaulCalibrationFile.append("/CalibrationFiles/PMDCamCube3_camera.xml"); + MITK_INFO <FromXMLFile(pathToDefaulCalibrationFile); + device->SetProperty("CameraIntrinsics", mitk::CameraIntrinsicsProperty::New(cameraIntrinsics)); + + return device.GetPointer(); } int m_DeviceNumber; }; } #endif diff --git a/Modules/ToFHardware/PMD/mitkToFCameraPMDO3DeviceFactory.h b/Modules/ToFHardware/PMD/mitkToFCameraPMDO3DeviceFactory.h index 6ddf17ac2d..37fa879413 100644 --- a/Modules/ToFHardware/PMD/mitkToFCameraPMDO3DeviceFactory.h +++ b/Modules/ToFHardware/PMD/mitkToFCameraPMDO3DeviceFactory.h @@ -1,75 +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 __mitkToFCameraPMDO3DeviceFactory_h #define __mitkToFCameraPMDO3DeviceFactory_h #include "mitkPMDModuleExports.h" #include "mitkToFCameraPMDO3Device.h" #include "mitkAbstractToFDeviceFactory.h" +#include +#include +#include + namespace mitk { /** * \brief ToFCameraPMDO3DeviceFactory is an implementation of the factory pattern to generate Do3 Devices. * ToFPMDCamCubeDeviceFactory inherits from AbstractToFDeviceFactory which is a MicroService interface. * This offers users the oppertunity to generate new Cam Cube Devices via a global instance of this factory. * @ingroup ToFHardware */ class MITK_PMDMODULE_EXPORT ToFCameraPMDO3DeviceFactory : public itk::LightObject, public AbstractToFDeviceFactory { public: ToFCameraPMDO3DeviceFactory() { this->m_DeviceNumber =1; } /*! \brief Defining the Factorie´s Name, here for the ToFPMDO3Device */ std::string GetFactoryName() { return std::string("PMD O3D Factory"); } std::string GetCurrentDeviceName() { std::stringstream name; if(m_DeviceNumber>1) { name << "PMD O3 "<< m_DeviceNumber; } else { name << "PMD O3"; } m_DeviceNumber++; return name.str(); } private: /*! \brief Create an instance of a ToFPMDO3DeviceFactory. */ ToFCameraDevice::Pointer createToFCameraDevice() { ToFCameraPMDO3Device::Pointer device = ToFCameraPMDO3Device::New(); +//-------------------------Intrinsics for 03 are missing----------------------------------- + //Set default camera intrinsics for the CamBoard-camera. + mitk::CameraIntrinsics::Pointer cameraIntrinsics = mitk::CameraIntrinsics::New(); + std::string pathToDefaulCalibrationFile(MITK_TOF_DATA_DIR); + + pathToDefaulCalibrationFile.append("/CalibrationFiles/Default_Parameters.xml"); + cameraIntrinsics->FromXMLFile(pathToDefaulCalibrationFile); + device->SetProperty("CameraIntrinsics", mitk::CameraIntrinsicsProperty::New(cameraIntrinsics)); + +//------------------------------------------------------------------------------------------ + return device.GetPointer(); } int m_DeviceNumber; }; } #endif diff --git a/Modules/ToFHardware/PMD/mitkToFCameraPMDPlayerDeviceFactory.h b/Modules/ToFHardware/PMD/mitkToFCameraPMDPlayerDeviceFactory.h index f3f7374b2d..1ec824224d 100644 --- a/Modules/ToFHardware/PMD/mitkToFCameraPMDPlayerDeviceFactory.h +++ b/Modules/ToFHardware/PMD/mitkToFCameraPMDPlayerDeviceFactory.h @@ -1,76 +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 __mitkToFCameraPMDPlayerDeviceFactory_h #define __mitkToFCameraPMDPlayerDeviceFactory_h #include "mitkPMDModuleExports.h" #include "mitkToFCameraPMDPlayerDevice.h" #include "mitkAbstractToFDeviceFactory.h" +#include +#include +#include namespace mitk { /** * \brief ToFPMDPlayerDeviceFactory is an implementation of the factory pattern to generate PMD Player Devices. * ToFPMDPlayerDeviceFactory inherits from AbstractToFDeviceFactory which is a MicroService interface. * This offers users the oppertunity to generate new PMD Player Devices via a global instance of this factory. * @ingroup ToFHardware */ class MITK_PMDMODULE_EXPORT ToFCameraPMDPlayerDeviceFactory : public itk::LightObject, public AbstractToFDeviceFactory { public: ToFCameraPMDPlayerDeviceFactory() { this->m_DeviceNumber=1; } /*! \brief Defining the Factorie´s Name, here for the ToFPMDPlayer. */ std::string GetFactoryName() { return std::string("PMD Player Factory"); } std::string GetCurrentDeviceName() { std::stringstream name; if(m_DeviceNumber>1) { name << "PMD Player "<< m_DeviceNumber; } else { name << "PMD Player"; } m_DeviceNumber++; return name.str(); } private: /*! \brief Create an instance of a ToFPMDPlayerDevice. */ ToFCameraDevice::Pointer createToFCameraDevice() { ToFCameraPMDPlayerDevice::Pointer device = ToFCameraPMDPlayerDevice::New(); +//-------------------------If no Intrinsics are specified------------------------------ + //Set default camera intrinsics for the PMD-Player. + mitk::CameraIntrinsics::Pointer cameraIntrinsics = mitk::CameraIntrinsics::New(); + std::string pathToDefaulCalibrationFile(MITK_TOF_DATA_DIR); + + pathToDefaulCalibrationFile.append("/CalibrationFiles/Default_Parameters.xml"); + cameraIntrinsics->FromXMLFile(pathToDefaulCalibrationFile); + device->SetProperty("CameraIntrinsics", mitk::CameraIntrinsicsProperty::New(cameraIntrinsics)); + +//------------------------------------------------------------------------------------------ + return device.GetPointer(); } int m_DeviceNumber; }; } #endif diff --git a/Modules/ToFHardware/PMD/mitkToFCameraPMDRawDataCamBoardDeviceFactory.h b/Modules/ToFHardware/PMD/mitkToFCameraPMDRawDataCamBoardDeviceFactory.h index bf11054fb2..9e5b9805d1 100644 --- a/Modules/ToFHardware/PMD/mitkToFCameraPMDRawDataCamBoardDeviceFactory.h +++ b/Modules/ToFHardware/PMD/mitkToFCameraPMDRawDataCamBoardDeviceFactory.h @@ -1,69 +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. ===================================================================*/ #ifndef __mitkToFCameraPMDRawDataCamBoardDeviceFactory_h #define __mitkToFCameraPMDRawDataCamBoardDeviceFactory_h #include "mitkPMDModuleExports.h" #include "mitkToFCameraPMDRawDataCamBoardDevice.h" #include "mitkAbstractToFDeviceFactory.h" +#include +#include +#include namespace mitk { /** * \brief ToFPMDRawPlayerDeviceFactory is an implementation of the factory pattern to generate Raw Player Devices. * ToFPMDRawPlayerDeviceFactory inherits from AbstractToFDeviceFactory which is a MicroService interface. * This offers users the oppertunity to generate new Raw Player Devices via a global instance of this factory. * @ingroup ToFHardware */ class MITK_PMDMODULE_EXPORT ToFCameraPMDRawDataCamBoardDeviceFactory : public itk::LightObject, public AbstractToFDeviceFactory { public: ToFCameraPMDRawDataCamBoardDeviceFactory() { this->m_DeviceNumber=0; } /*! \brief Defining the Factorie´s Name, here for the RawDataCamBoardDeviceFactory. */ std::string GetFactoryName() { return std::string("PMD Raw Data CamBoard Factory "); } std::string GetCurrentDeviceName() { std::stringstream name; name<<"PMD Raw Data CamBoard Device " << m_DeviceNumber++; return name.str (); } private: /*! \brief Create an instance of a RawDataCamBoardDeviceFactory. */ ToFCameraDevice::Pointer createToFCameraDevice() { ToFCameraPMDRawDataCamBoardDevice::Pointer device = ToFCameraPMDRawDataCamBoardDevice::New(); + //Set default camera intrinsics for the RawDataCamBoard-camera + mitk::CameraIntrinsics::Pointer cameraIntrinsics = mitk::CameraIntrinsics::New(); + std::string pathToDefaulCalibrationFile(MITK_TOF_DATA_DIR); + + pathToDefaulCalibrationFile.append("/CalibrationFiles/PMDCamBoard_camera.xml"); + cameraIntrinsics->FromXMLFile(pathToDefaulCalibrationFile); + device->SetProperty("CameraIntrinsics", mitk::CameraIntrinsicsProperty::New(cameraIntrinsics)); + return device.GetPointer(); } int m_DeviceNumber; }; } #endif diff --git a/Modules/ToFHardware/PMD/mitkToFCameraPMDRawDataCamCubeDeviceFactory.h b/Modules/ToFHardware/PMD/mitkToFCameraPMDRawDataCamCubeDeviceFactory.h index 91b9106a7e..f4ba0fe70b 100644 --- a/Modules/ToFHardware/PMD/mitkToFCameraPMDRawDataCamCubeDeviceFactory.h +++ b/Modules/ToFHardware/PMD/mitkToFCameraPMDRawDataCamCubeDeviceFactory.h @@ -1,75 +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. ===================================================================*/ #ifndef __mitkToFCameraPMDRawDataCamCubeDeviceFactory_h #define __mitkToFCameraPMDRawDataCamCubeDeviceFactory_h #include "mitkPMDModuleExports.h" #include "mitkToFCameraPMDRawDataCamCubeDevice.h" #include "mitkAbstractToFDeviceFactory.h" +#include +#include +#include namespace mitk { /** * \brief ToFPMDRawPlayerDeviceFactory is an implementation of the factory pattern to generate Raw Player Devices. * ToFPMDRawPlayerDeviceFactory inherits from AbstractToFDeviceFactory which is a MicroService interface. * This offers users the oppertunity to generate new Raw Player Devices via a global instance of this factory. * @ingroup ToFHardware */ class MITK_PMDMODULE_EXPORT ToFCameraPMDRawDataCamCubeDeviceFactory : public itk::LightObject, public AbstractToFDeviceFactory { public: ToFCameraPMDRawDataCamCubeDeviceFactory() { this->m_DeviceNumber = 1; } /*! \brief Defining the Factorie´s Name, here for the RawDataDeviceFactory. */ std::string GetFactoryName() { return std::string("PMD RAW Data Camcube Factory "); } std::string GetCurrentDeviceName() { std::stringstream name; if(m_DeviceNumber>1) { name << "PMD Raw Data CamCube 2.0/3.0 "<< m_DeviceNumber; } else { name << "PMD Raw Data CamCube 2.0/3.0"; } m_DeviceNumber++; return name.str(); } private: /*! \brief Create an instance of a ToFPMDRawDataDevice. */ ToFCameraDevice::Pointer createToFCameraDevice() { ToFCameraPMDRawDataCamCubeDevice::Pointer device = ToFCameraPMDRawDataCamCubeDevice::New(); + //Set default camera intrinsics for the RawDataCamCube-Camera. + mitk::CameraIntrinsics::Pointer cameraIntrinsics = mitk::CameraIntrinsics::New(); + std::string pathToDefaulCalibrationFile(MITK_TOF_DATA_DIR); + + pathToDefaulCalibrationFile.append("/CalibrationFiles/PMDCamCube3_camera.xml"); + cameraIntrinsics->FromXMLFile(pathToDefaulCalibrationFile); + device->SetProperty("CameraIntrinsics", mitk::CameraIntrinsicsProperty::New(cameraIntrinsics)); + return device.GetPointer(); } int m_DeviceNumber; }; } #endif diff --git a/Modules/ToFHardware/mitkToFCameraMITKPlayerDeviceFactory.h b/Modules/ToFHardware/mitkToFCameraMITKPlayerDeviceFactory.h index 24a4c2e83b..4296a2dd99 100644 --- a/Modules/ToFHardware/mitkToFCameraMITKPlayerDeviceFactory.h +++ b/Modules/ToFHardware/mitkToFCameraMITKPlayerDeviceFactory.h @@ -1,80 +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. ===================================================================*/ #ifndef __mitkToFCameraMITKPlayerDeviceFactory_h #define __mitkToFCameraMITKPlayerDeviceFactory_h #include "mitkToFHardwareExports.h" #include "mitkToFCameraMITKPlayerDevice.h" #include "mitkAbstractToFDeviceFactory.h" +#include +#include +#include namespace mitk { /** * \brief ToFPlayerDeviceFactory is an implementation of the factory pattern to generate ToFPlayer devices. * ToFPlayerDeviceFactory inherits from AbstractToFDeviceFactory which is a MicroService interface. * This offers users the oppertunity to generate new ToFPlayerDevices via a global instance of this factory. * @ingroup ToFHardware */ class MITK_TOFHARDWARE_EXPORT ToFCameraMITKPlayerDeviceFactory : public itk::LightObject, public AbstractToFDeviceFactory { public: ToFCameraMITKPlayerDeviceFactory() { m_DeviceNumber = 1; } /*! \brief Defining the Factorie´s Name, here for the ToFPlayer. */ std::string GetFactoryName() { return std::string("MITK Player Factory"); } std::string GetCurrentDeviceName() { std::stringstream name; if(m_DeviceNumber>1) { name << "MITK Player "<< m_DeviceNumber; } else { name << "MITK Player"; } m_DeviceNumber++; return name.str(); } private: /*! \brief Create an instance of a ToFPlayerDevice. */ ToFCameraDevice::Pointer createToFCameraDevice() { ToFCameraMITKPlayerDevice::Pointer device = ToFCameraMITKPlayerDevice::New(); +////-------------------------If no Intrinsics are specified------------------------------ +// //Set default camera intrinsics for the MITK-Player. +// mitk::CameraIntrinsics::Pointer cameraIntrinsics = mitk::CameraIntrinsics::New(); +// std::string pathToDefaulCalibrationFile(MITK_TOF_DATA_DIR); +// +// pathToDefaulCalibrationFile.append("/CalibrationFiles/Default_Parameters.xml"); +// cameraIntrinsics->FromXMLFile(pathToDefaulCalibrationFile); +// device->SetProperty("CameraIntrinsics", mitk::CameraIntrinsicsProperty::New(cameraIntrinsics)); +// +////------------------------------------------------------------------------------------------ + return device.GetPointer(); } int m_DeviceNumber; }; } #endif diff --git a/Modules/ToFHardware/mitkToFCameraPMDCamBoardControllerStub.cpp b/Modules/ToFHardware/mitkToFCameraPMDCamBoardControllerStub.cpp deleted file mode 100644 index f94fa13c00..0000000000 --- a/Modules/ToFHardware/mitkToFCameraPMDCamBoardControllerStub.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#include "mitkToFCameraPMDCamBoardController.h" - -namespace mitk -{ - ToFCameraPMDCamBoardController::ToFCameraPMDCamBoardController() - { - MITK_WARN("ToF") << "Error: PMD CamBoard currently not available"; - } - - ToFCameraPMDCamBoardController::~ToFCameraPMDCamBoardController() - { - MITK_WARN("ToF") << "Error: PMD CamBoard currently not available"; - } - - bool ToFCameraPMDCamBoardController::OpenCameraConnection() - { - MITK_WARN("ToF") << "Error: PMD CamBoard currently not available"; - return true; - } - - bool mitk::ToFCameraPMDCamBoardController::SetDistanceOffset( float offset ) - { - MITK_WARN("ToF") << "Error: PMD CamBoard currently not available"; - return true; - } - - float mitk::ToFCameraPMDCamBoardController::GetDistanceOffset() - { - MITK_WARN("ToF") << "Error: PMD CamBoard currently not available"; - return 0.0; - } - - bool mitk::ToFCameraPMDCamBoardController::SetRegionOfInterest( unsigned int leftUpperCornerX, unsigned int leftUpperCornerY, unsigned int width, unsigned int height ) - { - MITK_WARN("ToF") << "Error: PMD CamBoard currently not available"; - return true; - } - - bool mitk::ToFCameraPMDCamBoardController::SetRegionOfInterest( unsigned int roi[4] ) - { - MITK_WARN("ToF") << "Error: PMD CamBoard currently not available"; - return true; - } - - unsigned int* mitk::ToFCameraPMDCamBoardController::GetRegionOfInterest() - { - MITK_WARN("ToF") << "Error: PMD CamBoard currently not available"; - return NULL; - } - - bool mitk::ToFCameraPMDCamBoardController::SetExposureMode( int mode ) - { - MITK_WARN("ToF") << "Error: PMD CamBoard currently not available"; - return true; - } - - bool mitk::ToFCameraPMDCamBoardController::SetFieldOfView( float fov ) - { - MITK_WARN("ToF") << "Error: PMD CamBoard currently not available"; - return true; - } - - bool mitk::ToFCameraPMDCamBoardController::SetFPNCalibration( bool on ) - { - MITK_WARN("ToF") << "Error: PMD CamBoard currently not available"; - return true; - } - - bool mitk::ToFCameraPMDCamBoardController::SetFPPNCalibration( bool on ) - { - MITK_WARN("ToF") << "Error: PMD CamBoard currently not available"; - return true; - } - - bool mitk::ToFCameraPMDCamBoardController::SetLinearityCalibration( bool on ) - { - MITK_WARN("ToF") << "Error: PMD CamBoard currently not available"; - return true; - } - - bool mitk::ToFCameraPMDCamBoardController::SetLensCalibration( bool on ) - { - MITK_WARN("ToF") << "Error: PMD CamBoard currently not available"; - return true; - } - - bool ToFCameraPMDCamBoardController::GetAmplitudes(float* amplitudeArray) - { - MITK_WARN("ToF") << "Error: PMD CamBoard currently not available"; - return true; - } - - bool ToFCameraPMDCamBoardController::GetAmplitudes(char* sourceData, float* amplitudeArray) - { - MITK_WARN("ToF") << "Error: PMD CamBoard currently not available"; - return true; - } - - bool ToFCameraPMDCamBoardController::GetIntensities(float* intensityArray) - { - MITK_WARN("ToF") << "Error: PMD CamBoard currently not available"; - return true; - } - - bool ToFCameraPMDCamBoardController::GetIntensities(char* sourceData, float* intensityArray) - { - MITK_WARN("ToF") << "Error: PMD CamBoard currently not available"; - return true; - } - - bool ToFCameraPMDCamBoardController::GetDistances(float* distanceArray) - { - MITK_WARN("ToF") << "Error: PMD CamBoard currently not available"; - return true; - } - - bool ToFCameraPMDCamBoardController::GetDistances(char* sourceData, float* distanceArray) - { - MITK_WARN("ToF") << "Error: PMD CamBoard currently not available"; - return true; - } - - void ToFCameraPMDCamBoardController::TransformCameraOutput(float* in, float* out, bool isDist) - { - MITK_WARN("ToF") << "Error: PMD CamBoard currently not available"; - } - -} diff --git a/Modules/ToFHardware/mitkToFCameraPMDCamCubeControllerStub.cpp b/Modules/ToFHardware/mitkToFCameraPMDCamCubeControllerStub.cpp deleted file mode 100644 index fdc521d1a8..0000000000 --- a/Modules/ToFHardware/mitkToFCameraPMDCamCubeControllerStub.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ -#include "mitkToFCameraPMDCamCubeController.h" - -namespace mitk -{ - ToFCameraPMDCamCubeController::ToFCameraPMDCamCubeController() - { - MITK_WARN("ToF") << "Error: PMD Camcube currently not available"; - } - - ToFCameraPMDCamCubeController::~ToFCameraPMDCamCubeController() - { - } - - bool ToFCameraPMDCamCubeController::OpenCameraConnection() - { - MITK_WARN("ToF") << "Error: PMD Camcube currently not available"; - return true; - } - - bool mitk::ToFCameraPMDCamCubeController::SetDistanceOffset( float offset ) - { - MITK_WARN("ToF") << "Error: PMD Camcube currently not available"; - return true; - } - - float mitk::ToFCameraPMDCamCubeController::GetDistanceOffset() - { - MITK_WARN("ToF") << "Error: PMD Camcube currently not available"; - return 0.0f; - } - - bool mitk::ToFCameraPMDCamCubeController::SetRegionOfInterest( unsigned int leftUpperCornerX, unsigned int leftUpperCornerY, unsigned int width, unsigned int height ) - { - MITK_WARN("ToF") << "Error: PMD Camcube currently not available"; - return true; - } - - bool mitk::ToFCameraPMDCamCubeController::SetRegionOfInterest( unsigned int roi[4] ) - { - MITK_WARN("ToF") << "Error: PMD Camcube currently not available"; - return true; - } - - unsigned int* mitk::ToFCameraPMDCamCubeController::GetRegionOfInterest() - { - MITK_WARN("ToF") << "Error: PMD Camcube currently not available"; - return NULL; - } - - bool mitk::ToFCameraPMDCamCubeController::SetExposureMode( int mode ) - { - MITK_WARN("ToF") << "Error: PMD Camcube currently not available"; - return true; - } - - bool mitk::ToFCameraPMDCamCubeController::SetFieldOfView( float fov ) - { - MITK_WARN("ToF") << "Error: PMD Camcube currently not available"; - return true; - } - - bool mitk::ToFCameraPMDCamCubeController::SetFPNCalibration( bool on ) - { - MITK_WARN("ToF") << "Error: PMD Camcube currently not available"; - return true; - } - - bool mitk::ToFCameraPMDCamCubeController::SetFPPNCalibration( bool on ) - { - MITK_WARN("ToF") << "Error: PMD Camcube currently not available"; - return true; - } - - bool mitk::ToFCameraPMDCamCubeController::SetLinearityCalibration( bool on ) - { - MITK_WARN("ToF") << "Error: PMD Camcube currently not available"; - return true; - } - - bool mitk::ToFCameraPMDCamCubeController::SetLensCalibration( bool on ) - { - MITK_WARN("ToF") << "Error: PMD Camcube currently not available"; - return true; - } -} diff --git a/Modules/ToFProcessing/mitkToFDistanceImageToSurfaceFilter.cpp b/Modules/ToFProcessing/mitkToFDistanceImageToSurfaceFilter.cpp index 99a07bc4a7..2b24b19331 100644 --- a/Modules/ToFProcessing/mitkToFDistanceImageToSurfaceFilter.cpp +++ b/Modules/ToFProcessing/mitkToFDistanceImageToSurfaceFilter.cpp @@ -1,296 +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. ===================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include mitk::ToFDistanceImageToSurfaceFilter::ToFDistanceImageToSurfaceFilter() : m_IplScalarImage(NULL), m_CameraIntrinsics(), m_TextureImageWidth(0), m_TextureImageHeight(0), m_InterPixelDistance(), m_TextureIndex(0) { m_InterPixelDistance.Fill(0.045); m_CameraIntrinsics = mitk::CameraIntrinsics::New(); m_CameraIntrinsics->SetFocalLength(295.78960196187319,296.1255427948447); m_CameraIntrinsics->SetFocalLength(5.9421434211923247e+02,5.9104053696870778e+02); m_CameraIntrinsics->SetPrincipalPoint(3.3930780975300314e+02,2.4273913761751615e+02); m_CameraIntrinsics->SetDistorsionCoeffs(-0.36874385358645773f,-0.14339503290129013,0.0033210108720361795,-0.004277703352074105); m_ReconstructionMode = WithInterPixelDistance; } mitk::ToFDistanceImageToSurfaceFilter::~ToFDistanceImageToSurfaceFilter() { } void mitk::ToFDistanceImageToSurfaceFilter::SetInput( Image* distanceImage, mitk::CameraIntrinsics::Pointer cameraIntrinsics ) { this->SetCameraIntrinsics(cameraIntrinsics); this->SetInput(0,distanceImage); } void mitk::ToFDistanceImageToSurfaceFilter::SetInput( unsigned int idx, Image* distanceImage, mitk::CameraIntrinsics::Pointer cameraIntrinsics ) { this->SetCameraIntrinsics(cameraIntrinsics); this->SetInput(idx,distanceImage); } void mitk::ToFDistanceImageToSurfaceFilter::SetInput( mitk::Image* distanceImage ) { this->SetInput(0,distanceImage); } void mitk::ToFDistanceImageToSurfaceFilter::SetInput( unsigned int idx, 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, distanceImage); // Process object is not const-correct so the const_cast is required here this->CreateOutputsForAllInputs(); } mitk::Image* mitk::ToFDistanceImageToSurfaceFilter::GetInput() { return this->GetInput(0); } mitk::Image* mitk::ToFDistanceImageToSurfaceFilter::GetInput( unsigned int idx ) { if (this->GetNumberOfInputs() < 1) { mitkThrow() << "No input given for ToFDistanceImageToSurfaceFilter"; } return static_cast< mitk::Image*>(this->ProcessObject::GetInput(idx)); } void mitk::ToFDistanceImageToSurfaceFilter::GenerateData() { mitk::Surface::Pointer output = this->GetOutput(); assert(output); mitk::Image::Pointer input = this->GetInput(); assert(input); // mesh points int xDimension = input->GetDimension(0); int yDimension = input->GetDimension(1); unsigned int size = xDimension*yDimension; //size of the image-array std::vector isPointValid; isPointValid.resize(size); vtkSmartPointer points = vtkSmartPointer::New(); points->SetDataTypeToDouble(); vtkSmartPointer polys = vtkSmartPointer::New(); vtkSmartPointer scalarArray = vtkSmartPointer::New(); vtkSmartPointer textureCoords = vtkSmartPointer::New(); textureCoords->SetNumberOfComponents(2); textureCoords->Allocate(size); //Make a vtkIdList to save the ID's of the polyData corresponding to the image //pixel ID's. See below for more documentation. - vtkSmartPointer vertexIdList = vtkSmartPointer::New(); + m_VertexIdList = vtkSmartPointer::New(); //Allocate the object once else it would automatically allocate new memory //for every vertex and perform a copy which is expensive. - vertexIdList->Allocate(size); + m_VertexIdList->Allocate(size); + m_VertexIdList->SetNumberOfIds(size); + for(int i = 0; i < size; ++i) + { + m_VertexIdList->SetId(i, 0); + } float* scalarFloatData = NULL; if (this->m_IplScalarImage) // if scalar image is defined use it for texturing { scalarFloatData = (float*)this->m_IplScalarImage->imageData; } else if (this->GetInput(m_TextureIndex)) // otherwise use intensity image (input(2)) { scalarFloatData = (float*)this->GetInput(m_TextureIndex)->GetData(); } float* inputFloatData = (float*)(input->GetSliceData(0, 0, 0)->GetData()); //calculate world coordinates mitk::ToFProcessingCommon::ToFPoint2D focalLengthInPixelUnits; mitk::ToFProcessingCommon::ToFScalarType focalLengthInMm; if((m_ReconstructionMode == WithOutInterPixelDistance) || (m_ReconstructionMode == Kinect)) { focalLengthInPixelUnits[0] = m_CameraIntrinsics->GetFocalLengthX(); focalLengthInPixelUnits[1] = m_CameraIntrinsics->GetFocalLengthY(); } else if( m_ReconstructionMode == WithInterPixelDistance) { //convert focallength from pixel to mm 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::Point3D origin = input->GetGeometry()->GetOrigin(); for (int j=0; jInsertPoint(pixelID, cartesianCoordinates.GetDataPointer()). //If we use points->InsertNextPoint(...) instead, the ID's do not //correspond to the image pixel ID's. Thus, we have to save them //in the vertexIdList. - vertexIdList->InsertId(pixelID, points->InsertNextPoint(cartesianCoordinates.GetDataPointer())); + m_VertexIdList->SetId(pixelID, points->InsertNextPoint(cartesianCoordinates.GetDataPointer())); if((i >= 1) && (j >= 1)) { //This little piece of art explains the ID's: // // P(x_1y_1)---P(xy_1) // | | // | | // | | // P(x_1y)-----P(xy) // //We can only start triangulation if we are at vertex (1,1), //because we need the other 3 vertices near this one. //To go one pixel line back in the image array, we have to //subtract 1x xDimension. vtkIdType xy = pixelID; vtkIdType x_1y = pixelID-1; vtkIdType xy_1 = pixelID-xDimension; vtkIdType x_1y_1 = xy_1-1; //Find the corresponding vertex ID's in the saved vertexIdList: - vtkIdType xyV = vertexIdList->GetId(xy); - vtkIdType x_1yV = vertexIdList->GetId(x_1y); - vtkIdType xy_1V = vertexIdList->GetId(xy_1); - vtkIdType x_1y_1V = vertexIdList->GetId(x_1y_1); + vtkIdType xyV = m_VertexIdList->GetId(xy); + vtkIdType x_1yV = m_VertexIdList->GetId(x_1y); + vtkIdType xy_1V = m_VertexIdList->GetId(xy_1); + vtkIdType x_1y_1V = m_VertexIdList->GetId(x_1y_1); if (isPointValid[xy]&&isPointValid[x_1y]&&isPointValid[x_1y_1]&&isPointValid[xy_1]) // check if points of cell are valid { polys->InsertNextCell(3); polys->InsertCellPoint(x_1yV); polys->InsertCellPoint(xyV); polys->InsertCellPoint(x_1y_1V); polys->InsertNextCell(3); polys->InsertCellPoint(x_1y_1V); polys->InsertCellPoint(xyV); polys->InsertCellPoint(xy_1V); } } //Scalar values are necessary for mapping colors/texture onto the surface if (scalarFloatData) { - scalarArray->InsertTuple1(vertexIdList->GetId(pixelID), scalarFloatData[pixelID]); + scalarArray->InsertTuple1(m_VertexIdList->GetId(pixelID), scalarFloatData[pixelID]); } //These Texture Coordinates will map color pixel and vertices 1:1 (e.g. for Kinect). float xNorm = (((float)i)/xDimension);// correct video texture scale for kinect float yNorm = ((float)j)/yDimension; //don't flip. we don't need to flip. - textureCoords->InsertTuple2(vertexIdList->GetId(pixelID), xNorm, yNorm); + textureCoords->InsertTuple2(m_VertexIdList->GetId(pixelID), xNorm, yNorm); } } } vtkSmartPointer mesh = vtkSmartPointer::New(); mesh->SetPoints(points); mesh->SetPolys(polys); //Pass the scalars to the polydata (if they were set). if (scalarArray->GetNumberOfTuples()>0) { mesh->GetPointData()->SetScalars(scalarArray); } //Pass the TextureCoords to the polydata anyway (to save them). mesh->GetPointData()->SetTCoords(textureCoords); output->SetVtkPolyData(mesh); } void mitk::ToFDistanceImageToSurfaceFilter::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::ToFDistanceImageToSurfaceFilter::GenerateOutputInformation() { this->GetOutput(); itkDebugMacro(<<"GenerateOutputInformation()"); } void mitk::ToFDistanceImageToSurfaceFilter::SetScalarImage(IplImage* iplScalarImage) { this->m_IplScalarImage = iplScalarImage; this->Modified(); } IplImage* mitk::ToFDistanceImageToSurfaceFilter::GetScalarImage() { return this->m_IplScalarImage; } void mitk::ToFDistanceImageToSurfaceFilter::SetTextureImageWidth(int width) { this->m_TextureImageWidth = width; } void mitk::ToFDistanceImageToSurfaceFilter::SetTextureImageHeight(int height) { this->m_TextureImageHeight = height; } diff --git a/Modules/ToFProcessing/mitkToFDistanceImageToSurfaceFilter.h b/Modules/ToFProcessing/mitkToFDistanceImageToSurfaceFilter.h index 0dc4de56ed..9f12e4b86c 100644 --- a/Modules/ToFProcessing/mitkToFDistanceImageToSurfaceFilter.h +++ b/Modules/ToFProcessing/mitkToFDistanceImageToSurfaceFilter.h @@ -1,163 +1,172 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkToFDistanceImageToSurfaceFilter_h #define __mitkToFDistanceImageToSurfaceFilter_h #include #include #include #include #include #include "mitkCameraIntrinsics.h" #include #include +#include +#include + namespace mitk { /** * @brief Converts a Time-of-Flight (ToF) distance image to a 3D surface using the pinhole camera model for coordinate computation. * The intrinsic parameters of the camera (FocalLength, PrincipalPoint, InterPixelDistance) are set via SetCameraIntrinsics(). The * measured distance for each pixel corresponds to the distance between the object point and the corresponding image point on the * image plane. * * 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 ToFDistanceImageToSurfaceFilter : public SurfaceSource { public: mitkClassMacro( ToFDistanceImageToSurfaceFilter , SurfaceSource ); itkNewMacro( Self ); itkSetMacro(CameraIntrinsics, mitk::CameraIntrinsics::Pointer); itkGetMacro(CameraIntrinsics, mitk::CameraIntrinsics::Pointer); itkSetMacro(InterPixelDistance,ToFProcessingCommon::ToFPoint2D); itkGetMacro(InterPixelDistance,ToFProcessingCommon::ToFPoint2D); itkSetMacro(TextureIndex,int); + itkSetMacro(VertexIdList, vtkSmartPointer); + itkGetMacro(VertexIdList, vtkSmartPointer); + /** * @brief The ReconstructionModeType enum: Defines the reconstruction mode, if using no interpixeldistances and focal lenghts in pixel units or interpixeldistances and focal length in mm. The Kinect option defines a special reconstruction mode for the kinect. */ enum ReconstructionModeType{ WithOutInterPixelDistance = 1, WithInterPixelDistance = 2, Kinect = 3}; itkSetEnumMacro(ReconstructionMode,ReconstructionModeType); itkGetEnumMacro(ReconstructionMode,ReconstructionModeType); /*! \brief Set scalar image used as texture of the surface. \param iplScalarImage OpenCV image for texturing */ void SetScalarImage(IplImage* iplScalarImage); /*! \brief Set scalar image used as texture of the surface. \return OpenCV image for texturing */ IplImage* GetScalarImage(); /*! \brief Set width of the scalar image used for texturing the surface \param width width (x-dimension) of the texture image */ void SetTextureImageWidth(int width); /*! \brief Set height of the scalar image used for texturing the surface \param height height (y-dimension) of the texture image */ void SetTextureImageHeight(int height); /*! \brief Sets the input of this filter \param distanceImage input is the distance image of e.g. a ToF camera */ virtual void SetInput( Image* distanceImage); /*! \brief Sets the input of this filter and the intrinsic parameters \param distanceImage input is the distance image of e.g. a ToF camera */ virtual void SetInput( Image* distanceImage, mitk::CameraIntrinsics::Pointer cameraIntrinsics ); /*! \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, Image* distanceImage); /*! \brief Sets the input of this filter at idx and the intrinsic parameters \param idx number of the current input \param distanceImage input is the distance image of e.g. a ToF camera \param cameraIntrinsics This is the camera model which holds parameters like focal length, pixel size, etc. which are needed for the reconstruction of the surface. */ virtual void SetInput( unsigned int idx, Image* distanceImage, mitk::CameraIntrinsics::Pointer cameraIntrinsics ); /*! \brief Returns the input of this filter */ Image* GetInput(); /*! \brief Returns the input with id idx of this filter */ Image* GetInput(unsigned int idx); protected: /*! \brief Standard constructor */ ToFDistanceImageToSurfaceFilter(); /*! \brief Standard destructor */ ~ToFDistanceImageToSurfaceFilter(); 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(); IplImage* m_IplScalarImage; ///< Scalar image used for surface texturing mitk::CameraIntrinsics::Pointer m_CameraIntrinsics; ///< Specifies the intrinsic parameters int m_TextureImageWidth; ///< Width (x-dimension) of the texture image int m_TextureImageHeight; ///< Height (y-dimension) of the texture image ToFProcessingCommon::ToFPoint2D m_InterPixelDistance; ///< distance in mm between two adjacent pixels on the ToF camera chip int m_TextureIndex; ///< Index of the input used as texture image when no scalar image was set via SetIplScalarImage(). 0 = Distance, 1 = Amplitude, 2 = Intensity ReconstructionModeType m_ReconstructionMode; ///< The ReconstructionModeType enum: Defines the reconstruction mode, if using no interpixeldistances and focal lenghts in pixel units or interpixeldistances and focal length in mm. The Kinect option defines a special reconstruction mode for the kinect. + + vtkSmartPointer m_VertexIdList; ///< Make a vtkIdList to save the ID's of the polyData corresponding to the image pixel ID's. This can be accessed after generate data to obtain the mapping. + }; } //END mitk namespace #endif diff --git a/Modules/ToFUI/Qmitk/QmitkToFConnectionWidget.cpp b/Modules/ToFUI/Qmitk/QmitkToFConnectionWidget.cpp index fb1b7a218f..a11cd28691 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFConnectionWidget.cpp +++ b/Modules/ToFUI/Qmitk/QmitkToFConnectionWidget.cpp @@ -1,387 +1,382 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 "mitkCameraIntrinsics.h" #include "mitkCameraIntrinsicsProperty.h" //itk headers #include //Setting the View_ID const std::string QmitkToFConnectionWidget::VIEW_ID = "org.mitk.views.qmitktofconnectionwidget2"; //Constructor of 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(); //Setting m_Controls= NULL on Startup-> CreateQtPartControl will generate the Gui Widget if !m_Controls m_Controls = NULL; //Calling CreateQtPartControl CreateQtPartControl(this); } //Destructor of QmitkToFConnectionWidget QmitkToFConnectionWidget::~QmitkToFConnectionWidget() { //Keno´s MitkServiceListWidget must not be deinizialized here. Qmitk methods destroy their children automatically before self-destruction } void QmitkToFConnectionWidget::CreateQtPartControl(QWidget *parent) //Definition of CreateQtPartControll-Methode in QmitkToFConnectionWidget; Input= Pointer { if (!m_Controls) //Define if not alreaddy exists { // create GUI widgets m_Controls = new Ui::QmitkToFConnectionWidgetControls2; m_Controls->setupUi(parent); //and hide them on startup this->HideAllParameterWidgets(); // initzializing MitkServiceListWidget here std::string empty= ""; m_Controls->m_DeviceList->Initialize("ToFDeviceName", empty);// the empty could just be any kind of filter this->CreateConnections(); //OnSelectCamera(); //todo: warum geht das hier nicht? -> Sasch fragen } } //Creating the SIGNAL-SLOT-Connectuions void QmitkToFConnectionWidget::CreateConnections() { if ( m_Controls ) { //ConnectCameraButton as a trigger for OnConnectCamera() connect( (QObject*)(m_Controls->m_ConnectCameraButton), SIGNAL(clicked()),(QObject*) this, SLOT(OnConnectCamera()) ); //QmitkServiceListWidget::ServiceSelectionChanged as a Signal for the OnSlectCamera() slot connect( m_Controls->m_DeviceList, SIGNAL(ServiceSelectionChanged(mitk::ServiceReference)), this, SLOT(OnSelectCamera())); /*Creating an other Datanode structur for Kinect is done here: As soon as a Kinect is connected, the KinectParameterWidget is enabled, which can be used to trigger the KinectAcqusitionModeChanged-Method, to create a working Data-Node-structure*/ connect( m_Controls->m_KinectParameterWidget, SIGNAL(AcquisitionModeChanged()), this, SIGNAL(KinectAcquisitionModeChanged()) ); } } mitk::ToFImageGrabber::Pointer QmitkToFConnectionWidget::GetToFImageGrabber() { return m_ToFImageGrabber; } //The OnSelectCamer-Method is in charge of activating the appropiate ParameterWidgets void QmitkToFConnectionWidget::OnSelectCamera() { //Here we are getting our decvie through the QmitkServiceListWidget-Instance m_DeviceList through the GetSelectedService-Method mitk::ToFCameraDevice* device = m_Controls->m_DeviceList->GetSelectedService(); //getting the selectedCamera through a static Method used to transform the device->GetNameOfClass QString selectedCamera = QString::fromStdString(device->GetNameOfClass()); this->HideAllParameterWidgets(); //reactivating the Widgets on slecting a device if (selectedCamera.contains("PMD")) //Check if selectedCamera string contains ".." for each device { this->m_Controls->m_PMDParameterWidget->show(); //and activate the correct widget } else if (selectedCamera.contains("MESA")) { this->m_Controls->m_MESAParameterWidget->show(); } else if (selectedCamera.contains("Kinect")) { this->m_Controls->m_KinectParameterWidget->show(); } emit (selectedCamera); } //This Methods hides all Widgets (later each widget is activated on its own) void QmitkToFConnectionWidget::HideAllParameterWidgets() { this->m_Controls->m_PMDParameterWidget->hide(); this->m_Controls->m_MESAParameterWidget->hide(); this->m_Controls->m_KinectParameterWidget->hide(); } //OnConnectCamera-Method; represents one of the main parts of ToFConnectionWidget2. void QmitkToFConnectionWidget::OnConnectCamera() { //Introducing the boolean variable playerMode and set it to false by default bool playerMode = false; //After connecting a device if (m_Controls->m_ConnectCameraButton->text()=="Connect") { //Reset the status of some GUI-Elements m_Controls->m_ConnectCameraButton->setEnabled(false); //ConnectCameraButton gets disabled, what leads to other changes later m_Controls->m_DeviceList->setEnabled(false); //Deactivating the Instance of QmitkServiceListWidget //repaint the widget this->repaint(); QString tmpFileName(""); QString fileFilter(""); //Getting the device- and the slectedCamera-variables using the ServiceListWidget as we did it in the CameraSelect-Method mitk::ToFCameraDevice* device = m_Controls->m_DeviceList->GetSelectedService(); QString selectedCamera = QString::fromStdString(device->GetNameOfClass()); emit ToFCameraSelected(selectedCamera); //Creating a new instance of m_ToFImageGrabber this->m_ToFImageGrabber = NULL; this->m_ToFImageGrabber = mitk::ToFImageGrabber::New(); //Feeding it with the Info from ServiceListWidget this->m_ToFImageGrabber->SetCameraDevice(device); // Calling Alex FixForKinect, if the Kinect is selected if (selectedCamera.contains("Kinect") ) { MITK_INFO<< "Kinect is connected here"; //If the particular property is selected, the suitable data-node will be generated this->m_ToFImageGrabber->SetBoolProperty("RGB", m_Controls->m_KinectParameterWidget->IsAcquisitionModeRGB());//-------------------------------------------------------- this->m_ToFImageGrabber->SetBoolProperty("IR", m_Controls->m_KinectParameterWidget->IsAcquisitionModeIR()); } //Activation of "PlayerMode". If the selectedCamera String contains "Player", we start the Player Mode if (selectedCamera.contains("Player")) { playerMode = true; //IF PMD-Player selected if (selectedCamera.contains("PMD")) { fileFilter.append("PMD Files (*.pmd)"); //And seting the corresponding fileFilter } else { fileFilter.append("NRRD Images (*.nrrd);;PIC Images - deprecated (*.pic)"); } } // if a player was selected, the playerMode-variable is true, and we will enter the following code if (playerMode) { //open a QFileDialog to chose the corresponding file from the disc tmpFileName = QFileDialog::getOpenFileName(NULL, "Play Image From...", "", fileFilter); //If no fileName is returned by the Dialog,Button and Widget have to return to default(disconnected) + Opening a MessageBox if (tmpFileName.isEmpty()) { m_Controls->m_ConnectCameraButton->setChecked(false); m_Controls->m_ConnectCameraButton->setEnabled(true); //re-enabling the ConnectCameraButton m_Controls->m_DeviceList->setEnabled(true); //Reactivating ServiceListWidget this->OnSelectCamera(); //Calling the OnSelctCamera-Method -> Hides all Widget and just activates the needed ones QMessageBox::information( this, "Template functionality", "Please select a valid image before starting some action."); return; } if(selectedCamera.contains("PMDPlayer")) //If PMD-Player is selected, set ToFImageGrabberProperty correspondingly { this->m_ToFImageGrabber->SetStringProperty("PMDFileName", tmpFileName.toStdString().c_str() ); } else //Default action { 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() ); //"Incorrect format"-warning while using .nrrd or .pic files if (extension != ".pic" && extension != ".nrrd") { msg = msg + "Invalid file format, please select a \".nrrd\"-file"; throw std::logic_error(msg.c_str()); } //Checking for npos. If available, check for the Amplitude-, Intensity- and RGBImage int found = baseFilename.rfind("_DistanceImage"); //Defining "found" variable+checking if baseFilname contains "_DistanceImage". If not, found == npos(0) if (found == std::string::npos) //If found =0 { found = baseFilename.rfind("_AmplitudeImage"); //If "_AmplitudeImage" is found, the found variable is 1-> the next if statment is false } if (found == std::string::npos) { found = baseFilename.rfind("_IntensityImage"); //found = true if baseFilename cotains "_IntesityImage" } if (found == std::string::npos) { found = baseFilename.rfind("_RGBImage"); } if (found == std::string::npos) //If none of the Nodes is found, display an error { 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);//Set the baseFilenamePrefix as a substring from baseFilname //Set corresponding FileNames std::string distanceImageFileName = dir + "/" + baseFilenamePrefix + "_DistanceImage" + extension; //Set the name as: directory+FilenamePrefix+""+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)) { } 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_DeviceList->setEnabled(true); this->OnSelectCamera(); return; } } } //End "PlayerMode" m_Controls->m_ConnectCameraButton->setText("Disconnect"); //Reset the ConnectCameraButton to disconnected //if a connection could be established try { 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); //Activating the respective widgets if (selectedCamera.contains("PMD")) { this->m_Controls->m_PMDParameterWidget->ActivateAllParameters(); } else if (selectedCamera.contains("MESA")) { this->m_Controls->m_MESAParameterWidget->ActivateAllParameters(); } else if (selectedCamera.contains("Kinect")) { this->m_Controls->m_KinectParameterWidget->ActivateAllParameters(); } else { this->HideAllParameterWidgets(); } // send connect signal to the caller functionality emit ToFCameraConnected(); } else //##### TODO: Remove this else part once all controllers are throwing exceptions //if they cannot to any device! { //Throw an error if the Connection failed and reset the Widgets <- better catch an exception! 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_ConnectCameraButton->setText("Connect"); m_Controls->m_DeviceList->setEnabled(true); //Reactivating ServiceListWidget this->OnSelectCamera(); return; } }catch(std::exception &e) { //catch exceptions of camera which cannot connect give a better reason QMessageBox::critical( this, "Connection failed.", e.what() ); m_Controls->m_ConnectCameraButton->setChecked(false); m_Controls->m_ConnectCameraButton->setEnabled(true); m_Controls->m_ConnectCameraButton->setText("Connect"); m_Controls->m_DeviceList->setEnabled(true); //Reactivating ServiceListWidget this->OnSelectCamera(); return; } m_Controls->m_ConnectCameraButton->setEnabled(true); // ask wether camera parameters (intrinsics, ...) should be loaded if (QMessageBox::question(this,"Camera parameters","Do you want to specify your own camera intrinsics?",QMessageBox::Yes,QMessageBox::No)==QMessageBox::Yes) { - MITK_INFO<<"Yes"; QString fileName = QFileDialog::getOpenFileName(this,"Open camera intrinsics","/","*.xml"); mitk::CameraIntrinsics::Pointer cameraIntrinsics = mitk::CameraIntrinsics::New(); cameraIntrinsics->FromXMLFile(fileName.toStdString()); this->m_ToFImageGrabber->SetProperty("CameraIntrinsics",mitk::CameraIntrinsicsProperty::New(cameraIntrinsics)); } - else - { - MITK_INFO<<"No"; - } } 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_DeviceList->setEnabled(true); //Reactivating ServiceListWidget this->OnSelectCamera(); // send disconnect signal to the caller functionality emit ToFCameraDisconnected(); } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionQuantificationViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionQuantificationViewControls.ui index 7c36dac61a..07bfa4f2c7 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionQuantificationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionQuantificationViewControls.ui @@ -1,300 +1,303 @@ QmitkDiffusionQuantificationViewControls 0 0 343 612 0 0 QmitkTemplate Please Select Input Data Q-Ball/Tensor Image <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> + + true + General Parameters Scale Image Values: 1000.000000000000000 1.000000000000000 Q-Ball Imaging QFrame::NoFrame QFrame::Raised 0 Generalized GFA QFrame::NoFrame QFrame::Raised 0 true k true true p true false GFA QFrame::NoFrame QFrame::Raised 0 Min. angle Max. angle false Curvature Tensor Imaging false FA (Fractional Anisotropy) false RA (Relative Anisotropy) false AD (Axial Diffusivity) false RD (Radial Diffusivity) false MD (Mean Diffusivity) false 1-(λ2+λ3)/(2*λ1) Qt::Vertical QSizePolicy::Expanding 20 220 QmitkDataStorageComboBox.h diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.cpp index 0869c112ea..dfa9bd2b38 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.cpp @@ -1,1751 +1,1703 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkFiberProcessingView.h" #include // Qt #include // MITK #include #include #include #include #include #include #include #include #include #include #include #include // ITK #include #include #include #include #include #include #include #include const std::string QmitkFiberProcessingView::VIEW_ID = "org.mitk.views.fiberprocessing"; const std::string id_DataManager = "org.mitk.views.datamanager"; using namespace mitk; QmitkFiberProcessingView::QmitkFiberProcessingView() : QmitkFunctionality() , m_Controls( 0 ) , m_MultiWidget( NULL ) , m_CircleCounter(0) , m_PolygonCounter(0) , m_UpsamplingFactor(5) { } // Destructor QmitkFiberProcessingView::~QmitkFiberProcessingView() { } void QmitkFiberProcessingView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkFiberProcessingViewControls; m_Controls->setupUi( parent ); m_Controls->doExtractFibersButton->setDisabled(true); m_Controls->PFCompoANDButton->setDisabled(true); m_Controls->PFCompoORButton->setDisabled(true); m_Controls->PFCompoNOTButton->setDisabled(true); m_Controls->m_PlanarFigureButtonsFrame->setEnabled(false); m_Controls->m_RectangleButton->setVisible(false); connect( m_Controls->doExtractFibersButton, SIGNAL(clicked()), this, SLOT(DoFiberExtraction()) ); connect( m_Controls->m_CircleButton, SIGNAL( clicked() ), this, SLOT( OnDrawCircle() ) ); connect( m_Controls->m_PolygonButton, SIGNAL( clicked() ), this, SLOT( OnDrawPolygon() ) ); connect(m_Controls->PFCompoANDButton, SIGNAL(clicked()), this, SLOT(GenerateAndComposite()) ); connect(m_Controls->PFCompoORButton, SIGNAL(clicked()), this, SLOT(GenerateOrComposite()) ); connect(m_Controls->PFCompoNOTButton, SIGNAL(clicked()), this, SLOT(GenerateNotComposite()) ); connect(m_Controls->m_JoinBundles, SIGNAL(clicked()), this, SLOT(JoinBundles()) ); connect(m_Controls->m_SubstractBundles, SIGNAL(clicked()), this, SLOT(SubstractBundles()) ); connect(m_Controls->m_GenerateRoiImage, SIGNAL(clicked()), this, SLOT(GenerateRoiImage()) ); connect(m_Controls->m_Extract3dButton, SIGNAL(clicked()), this, SLOT(Extract3d())); connect( m_Controls->m_ProcessFiberBundleButton, SIGNAL(clicked()), this, SLOT(ProcessSelectedBundles()) ); connect( m_Controls->m_ResampleFibersButton, SIGNAL(clicked()), this, SLOT(ResampleSelectedBundles()) ); connect(m_Controls->m_FaColorFibersButton, SIGNAL(clicked()), this, SLOT(DoImageColorCoding())); connect( m_Controls->m_PruneFibersButton, SIGNAL(clicked()), this, SLOT(PruneBundle()) ); connect( m_Controls->m_CurvatureThresholdButton, SIGNAL(clicked()), this, SLOT(ApplyCurvatureThreshold()) ); connect( m_Controls->m_MirrorFibersButton, SIGNAL(clicked()), this, SLOT(MirrorFibers()) ); + connect( m_Controls->m_ExtractMask, SIGNAL(clicked()), this, SLOT(ExtractMask()) ); } } - -void QmitkFiberProcessingView::Extract3d() +void QmitkFiberProcessingView::ExtractMask() { - std::vector nodes = this->GetDataManagerSelection(); - if (nodes.empty()) + if (m_MaskImageNode.IsNull()) return; - mitk::FiberBundleX::Pointer fib = mitk::FiberBundleX::New(); - mitk::Surface::Pointer roi = mitk::Surface::New(); - bool fibB = false; - bool roiB = false; - for (int i=0; i(m_MaskImageNode->GetData()); + for (int i=0; i(nodes.at(i)->GetData())) - { - fib = dynamic_cast(nodes.at(i)->GetData()); - fibB = true; - } - else if (dynamic_cast(nodes.at(i)->GetData())) - { - roi = dynamic_cast(nodes.at(i)->GetData()); - roiB = true; - } - } - if (!fibB) - return; - if (!roiB) - return; - - vtkSmartPointer polyRoi = roi->GetVtkPolyData(); - vtkSmartPointer polyFib = fib->GetFiberPolyData(); - - vtkSmartPointer selectEnclosedPoints = vtkSmartPointer::New(); - selectEnclosedPoints->SetInput(polyFib); - selectEnclosedPoints->SetSurface(polyRoi); - selectEnclosedPoints->Update(); - - vtkSmartPointer newPoly = vtkSmartPointer::New(); - vtkSmartPointer newCellArray = vtkSmartPointer::New(); - vtkSmartPointer newPoints = vtkSmartPointer::New(); + mitk::FiberBundleX::Pointer fib = dynamic_cast(m_SelectedFB.at(i)->GetData()); + QString name(m_SelectedFB.at(i)->GetName().c_str()); - vtkSmartPointer newPolyComplement = vtkSmartPointer::New(); - vtkSmartPointer newCellArrayComplement = vtkSmartPointer::New(); - vtkSmartPointer newPointsComplement = vtkSmartPointer::New(); + itkUCharImageType::Pointer mask = itkUCharImageType::New(); + mitk::CastToItkImage(mitkMask, mask); + mitk::FiberBundleX::Pointer newFib = fib->ExtractFiberSubset(mask, false); + DataNode::Pointer newNode = DataNode::New(); + newNode->SetData(newFib); + name += "_ending-in-mask"; + newNode->SetName(name.toStdString()); + GetDefaultDataStorage()->Add(newNode); + } +} - vtkSmartPointer vLines = polyFib->GetLines(); +void QmitkFiberProcessingView::Extract3d() +{ + if (m_MaskImageNode.IsNull()) + return; - vLines->InitTraversal(); - int numberOfLines = vLines->GetNumberOfCells(); - // each line - for (int j=0; j(m_MaskImageNode->GetData()); + for (int i=0; iGetNextCell ( numPoints, points ); - bool isPassing = false; + mitk::FiberBundleX::Pointer fib = dynamic_cast(m_SelectedFB.at(i)->GetData()); + QString name(m_SelectedFB.at(i)->GetName().c_str()); - // each point of this line - for (int k=0; kIsInside(points[k])) - { - isPassing = true; - // fill new polydata - vtkSmartPointer container = vtkSmartPointer::New(); - for (int k=0; kGetPoint(points[k]); - vtkIdType pointId = newPoints->InsertNextPoint(point); - container->GetPointIds()->InsertNextId(pointId); - } - newCellArray->InsertNextCell(container); - break; - } - } - if (!isPassing) - { - vtkSmartPointer container = vtkSmartPointer::New(); - for (int k=0; kGetPoint(points[k]); - vtkIdType pointId = newPointsComplement->InsertNextPoint(point); - container->GetPointIds()->InsertNextId(pointId); - } - newCellArrayComplement->InsertNextCell(container); - } + itkUCharImageType::Pointer mask = itkUCharImageType::New(); + mitk::CastToItkImage(mitkMask, mask); + mitk::FiberBundleX::Pointer newFib = fib->ExtractFiberSubset(mask, true); + DataNode::Pointer newNode = DataNode::New(); + newNode->SetData(newFib); + name += "_passing-mask"; + newNode->SetName(name.toStdString()); + GetDefaultDataStorage()->Add(newNode); } - - newPoly->SetPoints(newPoints); - newPoly->SetLines(newCellArray); - mitk::FiberBundleX::Pointer fb = mitk::FiberBundleX::New(newPoly); - DataNode::Pointer newNode = DataNode::New(); - newNode->SetData(fb); - newNode->SetName("passing surface"); - GetDefaultDataStorage()->Add(newNode); - - newPolyComplement->SetPoints(newPointsComplement); - newPolyComplement->SetLines(newCellArrayComplement); - mitk::FiberBundleX::Pointer fbComplement = mitk::FiberBundleX::New(newPolyComplement); - DataNode::Pointer newNodeComplement = DataNode::New(); - newNodeComplement->SetData(fbComplement); - newNodeComplement->SetName("not passing surface"); - GetDefaultDataStorage()->Add(newNodeComplement); } void QmitkFiberProcessingView::GenerateRoiImage(){ if (m_SelectedPF.empty()) return; mitk::Geometry3D::Pointer geometry; if (!m_SelectedFB.empty()) { mitk::FiberBundleX::Pointer fib = dynamic_cast(m_SelectedFB.front()->GetData()); geometry = fib->GetGeometry(); } else return; mitk::Vector3D spacing = geometry->GetSpacing(); spacing /= m_UpsamplingFactor; mitk::Point3D newOrigin = geometry->GetOrigin(); mitk::Geometry3D::BoundsArrayType bounds = geometry->GetBounds(); newOrigin[0] += bounds.GetElement(0); newOrigin[1] += bounds.GetElement(2); newOrigin[2] += bounds.GetElement(4); itk::Matrix direction; itk::ImageRegion<3> imageRegion; for (int i=0; i<3; i++) for (int j=0; j<3; j++) direction[j][i] = geometry->GetMatrixColumn(i)[j]/spacing[j]; imageRegion.SetSize(0, geometry->GetExtent(0)*m_UpsamplingFactor); imageRegion.SetSize(1, geometry->GetExtent(1)*m_UpsamplingFactor); imageRegion.SetSize(2, geometry->GetExtent(2)*m_UpsamplingFactor); m_PlanarFigureImage = itkUCharImageType::New(); m_PlanarFigureImage->SetSpacing( spacing ); // Set the image spacing m_PlanarFigureImage->SetOrigin( newOrigin ); // Set the image origin m_PlanarFigureImage->SetDirection( direction ); // Set the image direction m_PlanarFigureImage->SetRegions( imageRegion ); m_PlanarFigureImage->Allocate(); m_PlanarFigureImage->FillBuffer( 0 ); Image::Pointer tmpImage = Image::New(); tmpImage->InitializeByItk(m_PlanarFigureImage.GetPointer()); tmpImage->SetVolume(m_PlanarFigureImage->GetBufferPointer()); for (int i=0; iInitializeByItk(m_PlanarFigureImage.GetPointer()); tmpImage->SetVolume(m_PlanarFigureImage->GetBufferPointer()); node->SetData(tmpImage); node->SetName("ROI Image"); this->GetDefaultDataStorage()->Add(node); } void QmitkFiberProcessingView::CompositeExtraction(mitk::DataNode::Pointer node, mitk::Image* image) { if (dynamic_cast(node.GetPointer()->GetData()) && !dynamic_cast(node.GetPointer()->GetData())) { m_PlanarFigure = dynamic_cast(node.GetPointer()->GetData()); AccessFixedDimensionByItk_2( image, InternalReorientImagePlane, 3, m_PlanarFigure->GetGeometry(), -1); // itk::Image< unsigned char, 3 >::Pointer outimage = itk::Image< unsigned char, 3 >::New(); // outimage->SetSpacing( m_PlanarFigure->GetGeometry()->GetSpacing()/m_UpsamplingFactor ); // Set the image spacing // mitk::Point3D origin = m_PlanarFigure->GetGeometry()->GetOrigin(); // mitk::Point3D indexOrigin; // m_PlanarFigure->GetGeometry()->WorldToIndex(origin, indexOrigin); // indexOrigin[0] = indexOrigin[0] - .5 * (1.0-1.0/m_UpsamplingFactor); // indexOrigin[1] = indexOrigin[1] - .5 * (1.0-1.0/m_UpsamplingFactor); // indexOrigin[2] = indexOrigin[2] - .5 * (1.0-1.0/m_UpsamplingFactor); // mitk::Point3D newOrigin; // m_PlanarFigure->GetGeometry()->IndexToWorld(indexOrigin, newOrigin); // outimage->SetOrigin( newOrigin ); // Set the image origin // itk::Matrix matrix; // for (int i=0; i<3; i++) // for (int j=0; j<3; j++) // matrix[j][i] = m_PlanarFigure->GetGeometry()->GetMatrixColumn(i)[j]/m_PlanarFigure->GetGeometry()->GetSpacing().GetElement(i); // outimage->SetDirection( matrix ); // Set the image direction // itk::ImageRegion<3> upsampledRegion; // upsampledRegion.SetSize(0, m_PlanarFigure->GetGeometry()->GetParametricExtentInMM(0)/m_PlanarFigure->GetGeometry()->GetSpacing()[0]); // upsampledRegion.SetSize(1, m_PlanarFigure->GetGeometry()->GetParametricExtentInMM(1)/m_PlanarFigure->GetGeometry()->GetSpacing()[1]); // upsampledRegion.SetSize(2, 1); // typename itk::Image< unsigned char, 3 >::RegionType::SizeType upsampledSize = upsampledRegion.GetSize(); // for (unsigned int n = 0; n < 2; n++) // { // upsampledSize[n] = upsampledSize[n] * m_UpsamplingFactor; // } // upsampledRegion.SetSize( upsampledSize ); // outimage->SetRegions( upsampledRegion ); // outimage->Allocate(); // this->m_InternalImage = mitk::Image::New(); // this->m_InternalImage->InitializeByItk( outimage.GetPointer() ); // this->m_InternalImage->SetVolume( outimage->GetBufferPointer() ); AccessFixedDimensionByItk_2( m_InternalImage, InternalCalculateMaskFromPlanarFigure, 3, 2, node->GetName() ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkFiberProcessingView::InternalReorientImagePlane( const itk::Image< TPixel, VImageDimension > *image, mitk::Geometry3D* planegeo3D, int additionalIndex ) { MITK_DEBUG << "InternalReorientImagePlane() start"; typedef itk::Image< TPixel, VImageDimension > ImageType; typedef itk::Image< float, VImageDimension > FloatImageType; typedef itk::ResampleImageFilter ResamplerType; typename ResamplerType::Pointer resampler = ResamplerType::New(); mitk::PlaneGeometry* planegeo = dynamic_cast(planegeo3D); float upsamp = m_UpsamplingFactor; float gausssigma = 0.5; // Spacing typename ResamplerType::SpacingType spacing = planegeo->GetSpacing(); spacing[0] = image->GetSpacing()[0] / upsamp; spacing[1] = image->GetSpacing()[1] / upsamp; spacing[2] = image->GetSpacing()[2]; resampler->SetOutputSpacing( spacing ); // Size typename ResamplerType::SizeType size; size[0] = planegeo->GetParametricExtentInMM(0) / spacing[0]; size[1] = planegeo->GetParametricExtentInMM(1) / spacing[1]; size[2] = 1; resampler->SetSize( size ); // Origin typename mitk::Point3D orig = planegeo->GetOrigin(); typename mitk::Point3D corrorig; planegeo3D->WorldToIndex(orig,corrorig); corrorig[0] += 0.5/upsamp; corrorig[1] += 0.5/upsamp; corrorig[2] += 0; planegeo3D->IndexToWorld(corrorig,corrorig); resampler->SetOutputOrigin(corrorig ); // Direction typename ResamplerType::DirectionType direction; typename mitk::AffineTransform3D::MatrixType matrix = planegeo->GetIndexToWorldTransform()->GetMatrix(); for(int c=0; cSetOutputDirection( direction ); // Gaussian interpolation if(gausssigma != 0) { double sigma[3]; for( unsigned int d = 0; d < 3; d++ ) { sigma[d] = gausssigma * image->GetSpacing()[d]; } double alpha = 2.0; typedef itk::GaussianInterpolateImageFunction GaussianInterpolatorType; typename GaussianInterpolatorType::Pointer interpolator = GaussianInterpolatorType::New(); interpolator->SetInputImage( image ); interpolator->SetParameters( sigma, alpha ); resampler->SetInterpolator( interpolator ); } else { // typedef typename itk::BSplineInterpolateImageFunction // InterpolatorType; typedef typename itk::LinearInterpolateImageFunction InterpolatorType; typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); interpolator->SetInputImage( image ); resampler->SetInterpolator( interpolator ); } // Other resampling options resampler->SetInput( image ); resampler->SetDefaultPixelValue(0); MITK_DEBUG << "Resampling requested image plane ... "; resampler->Update(); MITK_DEBUG << " ... done"; if(additionalIndex < 0) { this->m_InternalImage = mitk::Image::New(); this->m_InternalImage->InitializeByItk( resampler->GetOutput() ); this->m_InternalImage->SetVolume( resampler->GetOutput()->GetBufferPointer() ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkFiberProcessingView::InternalCalculateMaskFromPlanarFigure( itk::Image< TPixel, VImageDimension > *image, unsigned int axis, std::string nodeName ) { MITK_DEBUG << "InternalCalculateMaskFromPlanarFigure() start"; typedef itk::Image< TPixel, VImageDimension > ImageType; typedef itk::CastImageFilter< ImageType, itkUCharImageType > CastFilterType; // Generate mask image as new image with same header as input image and // initialize with "1". itkUCharImageType::Pointer newMaskImage = itkUCharImageType::New(); newMaskImage->SetSpacing( image->GetSpacing() ); // Set the image spacing newMaskImage->SetOrigin( image->GetOrigin() ); // Set the image origin newMaskImage->SetDirection( image->GetDirection() ); // Set the image direction newMaskImage->SetRegions( image->GetLargestPossibleRegion() ); newMaskImage->Allocate(); newMaskImage->FillBuffer( 1 ); // Generate VTK polygon from (closed) PlanarFigure polyline // (The polyline points are shifted by -0.5 in z-direction to make sure // that the extrusion filter, which afterwards elevates all points by +0.5 // in z-direction, creates a 3D object which is cut by the the plane z=0) const Geometry2D *planarFigureGeometry2D = m_PlanarFigure->GetGeometry2D(); const PlanarFigure::PolyLineType planarFigurePolyline = m_PlanarFigure->GetPolyLine( 0 ); const Geometry3D *imageGeometry3D = m_InternalImage->GetGeometry( 0 ); vtkPolyData *polyline = vtkPolyData::New(); polyline->Allocate( 1, 1 ); // Determine x- and y-dimensions depending on principal axis int i0, i1; switch ( axis ) { case 0: i0 = 1; i1 = 2; break; case 1: i0 = 0; i1 = 2; break; case 2: default: i0 = 0; i1 = 1; break; } // Create VTK polydata object of polyline contour vtkPoints *points = vtkPoints::New(); PlanarFigure::PolyLineType::const_iterator it; std::vector indices; unsigned int numberOfPoints = 0; for ( it = planarFigurePolyline.begin(); it != planarFigurePolyline.end(); ++it ) { Point3D point3D; // Convert 2D point back to the local index coordinates of the selected // image Point2D point2D = it->Point; planarFigureGeometry2D->WorldToIndex(point2D, point2D); point2D[0] -= 0.5/m_UpsamplingFactor; point2D[1] -= 0.5/m_UpsamplingFactor; planarFigureGeometry2D->IndexToWorld(point2D, point2D); planarFigureGeometry2D->Map( point2D, point3D ); // Polygons (partially) outside of the image bounds can not be processed // further due to a bug in vtkPolyDataToImageStencil if ( !imageGeometry3D->IsInside( point3D ) ) { float bounds[2] = {0,0}; bounds[0] = this->m_InternalImage->GetLargestPossibleRegion().GetSize().GetElement(i0); bounds[1] = this->m_InternalImage->GetLargestPossibleRegion().GetSize().GetElement(i1); imageGeometry3D->WorldToIndex( point3D, point3D ); // if (point3D[i0]<0) // point3D[i0] = 0.5; // else if (point3D[i0]>bounds[0]) // point3D[i0] = bounds[0]-0.5; // if (point3D[i1]<0) // point3D[i1] = 0.5; // else if (point3D[i1]>bounds[1]) // point3D[i1] = bounds[1]-0.5; if (point3D[i0]<0) point3D[i0] = 0.0; else if (point3D[i0]>bounds[0]) point3D[i0] = bounds[0]-0.001; if (point3D[i1]<0) point3D[i1] = 0.0; else if (point3D[i1]>bounds[1]) point3D[i1] = bounds[1]-0.001; points->InsertNextPoint( point3D[i0], point3D[i1], -0.5 ); numberOfPoints++; } else { imageGeometry3D->WorldToIndex( point3D, point3D ); // Add point to polyline array points->InsertNextPoint( point3D[i0], point3D[i1], -0.5 ); numberOfPoints++; } } polyline->SetPoints( points ); points->Delete(); vtkIdType *ptIds = new vtkIdType[numberOfPoints]; for ( vtkIdType i = 0; i < numberOfPoints; ++i ) { ptIds[i] = i; } polyline->InsertNextCell( VTK_POLY_LINE, numberOfPoints, ptIds ); // Extrude the generated contour polygon vtkLinearExtrusionFilter *extrudeFilter = vtkLinearExtrusionFilter::New(); extrudeFilter->SetInput( polyline ); extrudeFilter->SetScaleFactor( 1 ); extrudeFilter->SetExtrusionTypeToNormalExtrusion(); extrudeFilter->SetVector( 0.0, 0.0, 1.0 ); // Make a stencil from the extruded polygon vtkPolyDataToImageStencil *polyDataToImageStencil = vtkPolyDataToImageStencil::New(); polyDataToImageStencil->SetInput( extrudeFilter->GetOutput() ); // Export from ITK to VTK (to use a VTK filter) typedef itk::VTKImageImport< itkUCharImageType > ImageImportType; typedef itk::VTKImageExport< itkUCharImageType > ImageExportType; typename ImageExportType::Pointer itkExporter = ImageExportType::New(); itkExporter->SetInput( newMaskImage ); vtkImageImport *vtkImporter = vtkImageImport::New(); this->ConnectPipelines( itkExporter, vtkImporter ); vtkImporter->Update(); // Apply the generated image stencil to the input image vtkImageStencil *imageStencilFilter = vtkImageStencil::New(); imageStencilFilter->SetInputConnection( vtkImporter->GetOutputPort() ); imageStencilFilter->SetStencil( polyDataToImageStencil->GetOutput() ); imageStencilFilter->ReverseStencilOff(); imageStencilFilter->SetBackgroundValue( 0 ); imageStencilFilter->Update(); // Export from VTK back to ITK vtkImageExport *vtkExporter = vtkImageExport::New(); vtkExporter->SetInputConnection( imageStencilFilter->GetOutputPort() ); vtkExporter->Update(); typename ImageImportType::Pointer itkImporter = ImageImportType::New(); this->ConnectPipelines( vtkExporter, itkImporter ); itkImporter->Update(); // calculate cropping bounding box m_InternalImageMask3D = itkImporter->GetOutput(); m_InternalImageMask3D->SetDirection(image->GetDirection()); itk::ImageRegionConstIterator itmask(m_InternalImageMask3D, m_InternalImageMask3D->GetLargestPossibleRegion()); itk::ImageRegionIterator itimage(image, image->GetLargestPossibleRegion()); itmask = itmask.Begin(); itimage = itimage.Begin(); typename ImageType::SizeType lowersize = {{9999999999,9999999999,9999999999}}; typename ImageType::SizeType uppersize = {{0,0,0}}; while( !itmask.IsAtEnd() ) { if(itmask.Get() == 0) { itimage.Set(0); } else { typename ImageType::IndexType index = itimage.GetIndex(); typename ImageType::SizeType signedindex; signedindex[0] = index[0]; signedindex[1] = index[1]; signedindex[2] = index[2]; lowersize[0] = signedindex[0] < lowersize[0] ? signedindex[0] : lowersize[0]; lowersize[1] = signedindex[1] < lowersize[1] ? signedindex[1] : lowersize[1]; lowersize[2] = signedindex[2] < lowersize[2] ? signedindex[2] : lowersize[2]; uppersize[0] = signedindex[0] > uppersize[0] ? signedindex[0] : uppersize[0]; uppersize[1] = signedindex[1] > uppersize[1] ? signedindex[1] : uppersize[1]; uppersize[2] = signedindex[2] > uppersize[2] ? signedindex[2] : uppersize[2]; } ++itmask; ++itimage; } typename ImageType::IndexType index; index[0] = lowersize[0]; index[1] = lowersize[1]; index[2] = lowersize[2]; typename ImageType::SizeType size; size[0] = uppersize[0] - lowersize[0] + 1; size[1] = uppersize[1] - lowersize[1] + 1; size[2] = uppersize[2] - lowersize[2] + 1; itk::ImageRegion<3> cropRegion = itk::ImageRegion<3>(index, size); // crop internal mask typedef itk::RegionOfInterestImageFilter< itkUCharImageType, itkUCharImageType > ROIMaskFilterType; typename ROIMaskFilterType::Pointer roi2 = ROIMaskFilterType::New(); roi2->SetRegionOfInterest(cropRegion); roi2->SetInput(m_InternalImageMask3D); roi2->Update(); m_InternalImageMask3D = roi2->GetOutput(); Image::Pointer tmpImage = Image::New(); tmpImage->InitializeByItk(m_InternalImageMask3D.GetPointer()); tmpImage->SetVolume(m_InternalImageMask3D->GetBufferPointer()); Image::Pointer tmpImage2 = Image::New(); tmpImage2->InitializeByItk(m_PlanarFigureImage.GetPointer()); const Geometry3D *pfImageGeometry3D = tmpImage2->GetGeometry( 0 ); const Geometry3D *intImageGeometry3D = tmpImage->GetGeometry( 0 ); typedef itk::ImageRegionIteratorWithIndex IteratorType; IteratorType imageIterator (m_InternalImageMask3D, m_InternalImageMask3D->GetRequestedRegion()); imageIterator.GoToBegin(); while ( !imageIterator.IsAtEnd() ) { unsigned char val = imageIterator.Value(); if (val>0) { itk::Index<3> index = imageIterator.GetIndex(); Point3D point; point[0] = index[0]; point[1] = index[1]; point[2] = index[2]; intImageGeometry3D->IndexToWorld(point, point); pfImageGeometry3D->WorldToIndex(point, point); point[i0] += 0.5; point[i1] += 0.5; index[0] = point[0]; index[1] = point[1]; index[2] = point[2]; if (pfImageGeometry3D->IsIndexInside(index)) m_PlanarFigureImage->SetPixel(index, 1); } ++imageIterator; } // Clean up VTK objects polyline->Delete(); extrudeFilter->Delete(); polyDataToImageStencil->Delete(); vtkImporter->Delete(); imageStencilFilter->Delete(); //vtkExporter->Delete(); // TODO: crashes when outcommented; memory leak?? delete[] ptIds; } void QmitkFiberProcessingView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } void QmitkFiberProcessingView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } /* OnSelectionChanged is registered to SelectionService, therefore no need to implement SelectionService Listener explicitly */ void QmitkFiberProcessingView::UpdateGui() { + m_Controls->m_Extract3dButton->setEnabled(false); + m_Controls->m_ExtractMask->setEnabled(false); + // are fiber bundles selected? if ( m_SelectedFB.empty() ) { m_Controls->m_InputData->setTitle("Please Select Input Data"); m_Controls->m_JoinBundles->setEnabled(false); m_Controls->m_SubstractBundles->setEnabled(false); m_Controls->m_ProcessFiberBundleButton->setEnabled(false); m_Controls->doExtractFibersButton->setEnabled(false); - m_Controls->m_Extract3dButton->setEnabled(false); m_Controls->m_ResampleFibersButton->setEnabled(false); m_Controls->m_PlanarFigureButtonsFrame->setEnabled(false); m_Controls->m_FaColorFibersButton->setEnabled(false); m_Controls->m_PruneFibersButton->setEnabled(false); m_Controls->m_CurvatureThresholdButton->setEnabled(false); if (m_SelectedSurfaces.size()>0) m_Controls->m_MirrorFibersButton->setEnabled(true); else m_Controls->m_MirrorFibersButton->setEnabled(false); } else { m_Controls->m_InputData->setTitle("Input Data"); m_Controls->m_PlanarFigureButtonsFrame->setEnabled(true); m_Controls->m_ProcessFiberBundleButton->setEnabled(true); m_Controls->m_ResampleFibersButton->setEnabled(true); m_Controls->m_PruneFibersButton->setEnabled(true); m_Controls->m_CurvatureThresholdButton->setEnabled(true); m_Controls->m_MirrorFibersButton->setEnabled(true); - if (m_SelectedSurfaces.size()>0) - m_Controls->m_Extract3dButton->setEnabled(true); - // one bundle and one planar figure needed to extract fibers if (!m_SelectedPF.empty()) { m_Controls->doExtractFibersButton->setEnabled(true); } // more than two bundles needed to join/subtract if (m_SelectedFB.size() > 1) { m_Controls->m_JoinBundles->setEnabled(true); m_Controls->m_SubstractBundles->setEnabled(true); } else { m_Controls->m_JoinBundles->setEnabled(false); m_Controls->m_SubstractBundles->setEnabled(false); } if (m_SelectedImage.IsNotNull()) m_Controls->m_FaColorFibersButton->setEnabled(true); + + if (m_MaskImageNode.IsNotNull()) + { + m_Controls->m_Extract3dButton->setEnabled(true); + m_Controls->m_ExtractMask->setEnabled(true); + } } // are planar figures selected? if ( m_SelectedPF.empty() ) { m_Controls->doExtractFibersButton->setEnabled(false); m_Controls->PFCompoANDButton->setEnabled(false); m_Controls->PFCompoORButton->setEnabled(false); m_Controls->PFCompoNOTButton->setEnabled(false); m_Controls->m_GenerateRoiImage->setEnabled(false); } else { if ( !m_SelectedFB.empty() ) m_Controls->m_GenerateRoiImage->setEnabled(true); else m_Controls->m_GenerateRoiImage->setEnabled(false); if (m_SelectedPF.size() > 1) { m_Controls->PFCompoANDButton->setEnabled(true); m_Controls->PFCompoORButton->setEnabled(true); m_Controls->PFCompoNOTButton->setEnabled(false); } else { m_Controls->PFCompoANDButton->setEnabled(false); m_Controls->PFCompoORButton->setEnabled(false); m_Controls->PFCompoNOTButton->setEnabled(true); } } } void QmitkFiberProcessingView::OnSelectionChanged( std::vector nodes ) { //reset existing Vectors containing FiberBundles and PlanarFigures from a previous selection m_SelectedFB.clear(); m_SelectedPF.clear(); m_SelectedSurfaces.clear(); m_SelectedImage = NULL; + m_MaskImageNode = NULL; m_Controls->m_FibLabel->setText("mandatory"); m_Controls->m_PfLabel->setText("needed for extraction"); for( std::vector::iterator it = nodes.begin(); it != nodes.end(); ++it ) { mitk::DataNode::Pointer node = *it; if ( dynamic_cast(node->GetData()) ) { m_Controls->m_FibLabel->setText(node->GetName().c_str()); m_SelectedFB.push_back(node); } else if (dynamic_cast(node->GetData())) { m_Controls->m_PfLabel->setText(node->GetName().c_str()); m_SelectedPF.push_back(node); } else if (dynamic_cast(node->GetData())) + { m_SelectedImage = dynamic_cast(node->GetData()); + + bool isBinary = false; + node->GetPropertyValue("binary", isBinary); + if (isBinary) + m_MaskImageNode = node; + } else if (dynamic_cast(node->GetData())) { m_Controls->m_PfLabel->setText(node->GetName().c_str()); m_SelectedSurfaces.push_back(dynamic_cast(node->GetData())); } } UpdateGui(); GenerateStats(); } void QmitkFiberProcessingView::OnDrawPolygon() { // bool checked = m_Controls->m_PolygonButton->isChecked(); // if(!this->AssertDrawingIsPossible(checked)) // return; mitk::PlanarPolygon::Pointer figure = mitk::PlanarPolygon::New(); figure->ClosedOn(); this->AddFigureToDataStorage(figure, QString("Polygon%1").arg(++m_PolygonCounter)); MITK_DEBUG << "PlanarPolygon created ..."; mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDefaultDataStorage()->GetAll(); mitk::DataNode* node = 0; mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; mitk::PlanarFigure* figureP = 0; for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() ; it++) { node = const_cast(it->Value().GetPointer()); figureP = dynamic_cast(node->GetData()); if(figureP) { figureInteractor = dynamic_cast(node->GetInteractor()); if(figureInteractor.IsNull()) figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", node); mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); } } } void QmitkFiberProcessingView::OnDrawCircle() { mitk::PlanarCircle::Pointer figure = mitk::PlanarCircle::New(); this->AddFigureToDataStorage(figure, QString("Circle%1").arg(++m_CircleCounter)); this->GetDataStorage()->Modified(); mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDefaultDataStorage()->GetAll(); mitk::DataNode* node = 0; mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; mitk::PlanarFigure* figureP = 0; for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End(); it++) { node = const_cast(it->Value().GetPointer()); figureP = dynamic_cast(node->GetData()); if(figureP) { figureInteractor = dynamic_cast(node->GetInteractor()); if(figureInteractor.IsNull()) figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", node); mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); } } } void QmitkFiberProcessingView::Activated() { } void QmitkFiberProcessingView::AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *propertyKey, mitk::BaseProperty *property ) { // initialize figure's geometry with empty geometry mitk::PlaneGeometry::Pointer emptygeometry = mitk::PlaneGeometry::New(); figure->SetGeometry2D( emptygeometry ); //set desired data to DataNode where Planarfigure is stored mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetName(name.toStdString()); newNode->SetData(figure); newNode->AddProperty( "planarfigure.default.line.color", mitk::ColorProperty::New(1.0,0.0,0.0)); newNode->AddProperty( "planarfigure.line.width", mitk::FloatProperty::New(2.0)); newNode->AddProperty( "planarfigure.drawshadow", mitk::BoolProperty::New(true)); newNode->AddProperty( "selected", mitk::BoolProperty::New(true) ); newNode->AddProperty( "planarfigure.ishovering", mitk::BoolProperty::New(true) ); newNode->AddProperty( "planarfigure.drawoutline", mitk::BoolProperty::New(true) ); newNode->AddProperty( "planarfigure.drawquantities", mitk::BoolProperty::New(false) ); newNode->AddProperty( "planarfigure.drawshadow", mitk::BoolProperty::New(true) ); newNode->AddProperty( "planarfigure.line.width", mitk::FloatProperty::New(3.0) ); newNode->AddProperty( "planarfigure.shadow.widthmodifier", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.outline.width", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.helperline.width", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.line.color", mitk::ColorProperty::New(1.0,1.0,1.0) ); newNode->AddProperty( "planarfigure.default.line.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.outline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.default.outline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.helperline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.default.helperline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.markerline.color", mitk::ColorProperty::New(0.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.default.markerline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.marker.color", mitk::ColorProperty::New(1.0,1.0,1.0) ); newNode->AddProperty( "planarfigure.default.marker.opacity",mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.line.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.line.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.outline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.outline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.helperline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.helperline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.markerline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.markerline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.marker.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.marker.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.selected.line.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.line.opacity",mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.selected.outline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.outline.opacity", mitk::FloatProperty::New(2.0)); newNode->AddProperty( "planarfigure.selected.helperline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.helperline.opacity",mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.selected.markerline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.markerline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.selected.marker.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.marker.opacity",mitk::FloatProperty::New(2.0)); // figure drawn on the topmost layer / image newNode->SetColor(1.0,1.0,1.0); newNode->SetOpacity(0.8); GetDataStorage()->Add(newNode ); std::vector selectedNodes = GetDataManagerSelection(); for(unsigned int i = 0; i < selectedNodes.size(); i++) { selectedNodes[i]->SetSelected(false); } newNode->SetSelected(true); } void QmitkFiberProcessingView::DoFiberExtraction() { if ( m_SelectedFB.empty() ){ QMessageBox::information( NULL, "Warning", "No fibe bundle selected!"); MITK_WARN("QmitkFiberProcessingView") << "no fibe bundle selected"; return; } for (int i=0; i(m_SelectedFB.at(i)->GetData()); mitk::PlanarFigure::Pointer roi = dynamic_cast (m_SelectedPF.at(0)->GetData()); mitk::FiberBundleX::Pointer extFB = fib->ExtractFiberSubset(roi); if (extFB->GetNumFibers()<=0) continue; mitk::DataNode::Pointer node; node = mitk::DataNode::New(); node->SetData(extFB); QString name(m_SelectedFB.at(i)->GetName().c_str()); name += "_"; name += m_SelectedPF.at(0)->GetName().c_str(); node->SetName(name.toStdString()); GetDataStorage()->Add(node); m_SelectedFB.at(i)->SetVisibility(false); } } void QmitkFiberProcessingView::GenerateAndComposite() { mitk::PlanarFigureComposite::Pointer PFCAnd = mitk::PlanarFigureComposite::New(); mitk::PlaneGeometry* currentGeometry2D = dynamic_cast( const_cast(GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetCurrentWorldGeometry2D())); PFCAnd->SetGeometry2D(currentGeometry2D); PFCAnd->setOperationType(mitk::PFCOMPOSITION_AND_OPERATION); for( std::vector::iterator it = m_SelectedPF.begin(); it != m_SelectedPF.end(); ++it ) { mitk::DataNode::Pointer nodePF = *it; mitk::PlanarFigure::Pointer tmpPF = dynamic_cast( nodePF->GetData() ); PFCAnd->addPlanarFigure( tmpPF ); PFCAnd->addDataNode( nodePF ); PFCAnd->setDisplayName("AND_COMPO"); } AddCompositeToDatastorage(PFCAnd, NULL); } void QmitkFiberProcessingView::GenerateOrComposite() { mitk::PlanarFigureComposite::Pointer PFCOr = mitk::PlanarFigureComposite::New(); mitk::PlaneGeometry* currentGeometry2D = dynamic_cast( const_cast(GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetCurrentWorldGeometry2D())); PFCOr->SetGeometry2D(currentGeometry2D); PFCOr->setOperationType(mitk::PFCOMPOSITION_OR_OPERATION); for( std::vector::iterator it = m_SelectedPF.begin(); it != m_SelectedPF.end(); ++it ) { mitk::DataNode::Pointer nodePF = *it; mitk::PlanarFigure::Pointer tmpPF = dynamic_cast( nodePF->GetData() ); PFCOr->addPlanarFigure( tmpPF ); PFCOr->addDataNode( nodePF ); PFCOr->setDisplayName("OR_COMPO"); } AddCompositeToDatastorage(PFCOr, NULL); } void QmitkFiberProcessingView::GenerateNotComposite() { mitk::PlanarFigureComposite::Pointer PFCNot = mitk::PlanarFigureComposite::New(); mitk::PlaneGeometry* currentGeometry2D = dynamic_cast( const_cast(GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetCurrentWorldGeometry2D())); PFCNot->SetGeometry2D(currentGeometry2D); PFCNot->setOperationType(mitk::PFCOMPOSITION_NOT_OPERATION); for( std::vector::iterator it = m_SelectedPF.begin(); it != m_SelectedPF.end(); ++it ) { mitk::DataNode::Pointer nodePF = *it; mitk::PlanarFigure::Pointer tmpPF = dynamic_cast( nodePF->GetData() ); PFCNot->addPlanarFigure( tmpPF ); PFCNot->addDataNode( nodePF ); PFCNot->setDisplayName("NOT_COMPO"); } AddCompositeToDatastorage(PFCNot, NULL); } /* CLEANUP NEEDED */ void QmitkFiberProcessingView::AddCompositeToDatastorage(mitk::PlanarFigureComposite::Pointer pfcomp, mitk::DataNode::Pointer parentDataNode ) { mitk::DataNode::Pointer newPFCNode; newPFCNode = mitk::DataNode::New(); newPFCNode->SetName( pfcomp->getDisplayName() ); newPFCNode->SetData(pfcomp); newPFCNode->SetVisibility(true); switch (pfcomp->getOperationType()) { case 0: { if (!parentDataNode.IsNull()) { GetDataStorage()->Add(newPFCNode, parentDataNode); } else { GetDataStorage()->Add(newPFCNode); } //iterate through its childs for(int i=0; igetNumberOfChildren(); ++i) { mitk::PlanarFigure::Pointer tmpPFchild = pfcomp->getChildAt(i); mitk::DataNode::Pointer savedPFchildNode = pfcomp->getDataNodeAt(i); mitk::PlanarFigureComposite::Pointer pfcompcast= dynamic_cast(tmpPFchild.GetPointer()); if ( !pfcompcast.IsNull() ) { // child is of type planar Figure composite // make new node of the child, cuz later the child has to be removed of its old position in datamanager // feed new dataNode with information of the savedDataNode, which is gonna be removed soon mitk::DataNode::Pointer newChildPFCNode; newChildPFCNode = mitk::DataNode::New(); newChildPFCNode->SetData(tmpPFchild); newChildPFCNode->SetName( savedPFchildNode->GetName() ); pfcompcast->setDisplayName( savedPFchildNode->GetName() ); //name might be changed in DataManager by user //update inside vector the dataNodePointer pfcomp->replaceDataNodeAt(i, newChildPFCNode); AddCompositeToDatastorage(pfcompcast, newPFCNode); //the current PFCNode becomes the childs parent // remove savedNode here, cuz otherwise its children will change their position in the dataNodeManager // without having its parent anymore //GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_DEBUG << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " still exists"; } } else { // child is not of type PlanarFigureComposite, so its one of the planarFigures // create new dataNode containing the data of the old dataNode, but position in dataManager will be // modified cuz we re setting a (new) parent. mitk::DataNode::Pointer newPFchildNode = mitk::DataNode::New(); newPFchildNode->SetName(savedPFchildNode->GetName() ); newPFchildNode->SetData(tmpPFchild); newPFchildNode->SetVisibility(true); // replace the dataNode in PFComp DataNodeVector pfcomp->replaceDataNodeAt(i, newPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; } else { MITK_DEBUG << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " still exists"; } MITK_DEBUG << "adding " << newPFchildNode->GetName() << " to " << newPFCNode->GetName(); //add new child to datamanager with its new position as child of newPFCNode parent GetDataStorage()->Add(newPFchildNode, newPFCNode); } } GetDataStorage()->Modified(); break; } case 1: { if (!parentDataNode.IsNull()) { MITK_DEBUG << "adding " << newPFCNode->GetName() << " to " << parentDataNode->GetName() ; GetDataStorage()->Add(newPFCNode, parentDataNode); } else { MITK_DEBUG << "adding " << newPFCNode->GetName(); GetDataStorage()->Add(newPFCNode); } for(int i=0; igetNumberOfChildren(); ++i) { mitk::PlanarFigure::Pointer tmpPFchild = pfcomp->getChildAt(i); mitk::DataNode::Pointer savedPFchildNode = pfcomp->getDataNodeAt(i); mitk::PlanarFigureComposite::Pointer pfcompcast= dynamic_cast(tmpPFchild.GetPointer()); if ( !pfcompcast.IsNull() ) { // child is of type planar Figure composite // make new node of the child, cuz later the child has to be removed of its old position in datamanager // feed new dataNode with information of the savedDataNode, which is gonna be removed soon mitk::DataNode::Pointer newChildPFCNode; newChildPFCNode = mitk::DataNode::New(); newChildPFCNode->SetData(tmpPFchild); newChildPFCNode->SetName( savedPFchildNode->GetName() ); pfcompcast->setDisplayName( savedPFchildNode->GetName() ); //name might be changed in DataManager by user //update inside vector the dataNodePointer pfcomp->replaceDataNodeAt(i, newChildPFCNode); AddCompositeToDatastorage(pfcompcast, newPFCNode); //the current PFCNode becomes the childs parent // remove savedNode here, cuz otherwise its children will change their position in the dataNodeManager // without having its parent anymore //GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_DEBUG << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " still exists"; } } else { // child is not of type PlanarFigureComposite, so its one of the planarFigures // create new dataNode containing the data of the old dataNode, but position in dataManager will be // modified cuz we re setting a (new) parent. mitk::DataNode::Pointer newPFchildNode = mitk::DataNode::New(); newPFchildNode->SetName(savedPFchildNode->GetName() ); newPFchildNode->SetData(tmpPFchild); newPFchildNode->SetVisibility(true); // replace the dataNode in PFComp DataNodeVector pfcomp->replaceDataNodeAt(i, newPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_DEBUG << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " still exists"; } MITK_DEBUG << "adding " << newPFchildNode->GetName() << " to " << newPFCNode->GetName(); //add new child to datamanager with its new position as child of newPFCNode parent GetDataStorage()->Add(newPFchildNode, newPFCNode); } } GetDataStorage()->Modified(); break; } case 2: { if (!parentDataNode.IsNull()) { MITK_DEBUG << "adding " << newPFCNode->GetName() << " to " << parentDataNode->GetName() ; GetDataStorage()->Add(newPFCNode, parentDataNode); } else { MITK_DEBUG << "adding " << newPFCNode->GetName(); GetDataStorage()->Add(newPFCNode); } //iterate through its childs for(int i=0; igetNumberOfChildren(); ++i) { mitk::PlanarFigure::Pointer tmpPFchild = pfcomp->getChildAt(i); mitk::DataNode::Pointer savedPFchildNode = pfcomp->getDataNodeAt(i); mitk::PlanarFigureComposite::Pointer pfcompcast= dynamic_cast(tmpPFchild.GetPointer()); if ( !pfcompcast.IsNull() ) { // child is of type planar Figure composite // makeRemoveBundle new node of the child, cuz later the child has to be removed of its old position in datamanager // feed new dataNode with information of the savedDataNode, which is gonna be removed soon mitk::DataNode::Pointer newChildPFCNode; newChildPFCNode = mitk::DataNode::New(); newChildPFCNode->SetData(tmpPFchild); newChildPFCNode->SetName( savedPFchildNode->GetName() ); pfcompcast->setDisplayName( savedPFchildNode->GetName() ); //name might be changed in DataManager by user //update inside vector the dataNodePointer pfcomp->replaceDataNodeAt(i, newChildPFCNode); AddCompositeToDatastorage(pfcompcast, newPFCNode); //the current PFCNode becomes the childs parent // remove savedNode here, cuz otherwise its children will change their position in the dataNodeManager // without having its parent anymore //GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_DEBUG << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " still exists"; } } else { // child is not of type PlanarFigureComposite, so its one of the planarFigures // create new dataNode containing the data of the old dataNode, but position in dataManager will be // modified cuz we re setting a (new) parent. mitk::DataNode::Pointer newPFchildNode = mitk::DataNode::New(); newPFchildNode->SetName(savedPFchildNode->GetName() ); newPFchildNode->SetData(tmpPFchild); newPFchildNode->SetVisibility(true); // replace the dataNode in PFComp DataNodeVector pfcomp->replaceDataNodeAt(i, newPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_DEBUG << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_DEBUG << savedPFchildNode->GetName() << " still exists"; } MITK_DEBUG << "adding " << newPFchildNode->GetName() << " to " << newPFCNode->GetName(); //add new child to datamanager with its new position as child of newPFCNode parent GetDataStorage()->Add(newPFchildNode, newPFCNode); } } GetDataStorage()->Modified(); break; } default: MITK_DEBUG << "we have an UNDEFINED composition... ERROR" ; break; } } void QmitkFiberProcessingView::JoinBundles() { if ( m_SelectedFB.size()<2 ){ QMessageBox::information( NULL, "Warning", "Select at least two fiber bundles!"); MITK_WARN("QmitkFiberProcessingView") << "Select at least two fiber bundles!"; return; } std::vector::const_iterator it = m_SelectedFB.begin(); mitk::FiberBundleX::Pointer newBundle = dynamic_cast((*it)->GetData()); QString name(""); name += QString((*it)->GetName().c_str()); ++it; for (it; it!=m_SelectedFB.end(); ++it) { newBundle = newBundle->AddBundle(dynamic_cast((*it)->GetData())); name += "+"+QString((*it)->GetName().c_str()); } mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); GetDataStorage()->Add(fbNode); } void QmitkFiberProcessingView::SubstractBundles() { if ( m_SelectedFB.size()<2 ){ QMessageBox::information( NULL, "Warning", "Select at least two fiber bundles!"); MITK_WARN("QmitkFiberProcessingView") << "Select at least two fiber bundles!"; return; } std::vector::const_iterator it = m_SelectedFB.begin(); mitk::FiberBundleX::Pointer newBundle = dynamic_cast((*it)->GetData()); QString name(""); name += QString((*it)->GetName().c_str()); ++it; for (it; it!=m_SelectedFB.end(); ++it) { newBundle = newBundle->SubtractBundle(dynamic_cast((*it)->GetData())); if (newBundle.IsNull()) break; name += "-"+QString((*it)->GetName().c_str()); } if (newBundle.IsNull()) { QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers. Did you select the fiber bundles in the correct order? X-Y is not equal to Y-X!"); return; } mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); GetDataStorage()->Add(fbNode); } void QmitkFiberProcessingView::PruneBundle() { int minLength = this->m_Controls->m_PruneFibersSpinBox->value(); int maxLength = this->m_Controls->m_MaxPruneFibersSpinBox->value(); for (int i=0; i(m_SelectedFB.at(i)->GetData()); if (!fib->RemoveShortFibers(minLength)) QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers."); else if (!fib->RemoveLongFibers(maxLength)) QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers."); } GenerateStats(); RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberProcessingView::ApplyCurvatureThreshold() { int mm = this->m_Controls->m_MinCurvatureRadiusBox->value(); for (int i=0; i(m_SelectedFB.at(i)->GetData()); if (!fib->ApplyCurvatureThreshold(mm, this->m_Controls->m_RemoveFiberDueToCurvatureCheckbox->isChecked())) QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers."); } GenerateStats(); RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberProcessingView::GenerateStats() { if ( m_SelectedFB.empty() ) return; QString stats(""); for( int i=0; i(node->GetData())) { if (i>0) stats += "\n-----------------------------\n"; stats += QString(node->GetName().c_str()) + "\n"; mitk::FiberBundleX::Pointer fib = dynamic_cast(node->GetData()); stats += "Number of fibers: "+ QString::number(fib->GetNumFibers()) + "\n"; stats += "Min. length: "+ QString::number(fib->GetMinFiberLength(),'f',1) + " mm\n"; stats += "Max. length: "+ QString::number(fib->GetMaxFiberLength(),'f',1) + " mm\n"; stats += "Mean length: "+ QString::number(fib->GetMeanFiberLength(),'f',1) + " mm\n"; stats += "Median length: "+ QString::number(fib->GetMedianFiberLength(),'f',1) + " mm\n"; stats += "Standard deviation: "+ QString::number(fib->GetLengthStDev(),'f',1) + " mm\n"; } } this->m_Controls->m_StatsTextEdit->setText(stats); } void QmitkFiberProcessingView::ProcessSelectedBundles() { if ( m_SelectedFB.empty() ){ QMessageBox::information( NULL, "Warning", "No fibe bundle selected!"); MITK_WARN("QmitkFiberProcessingView") << "no fibe bundle selected"; return; } int generationMethod = m_Controls->m_GenerationBox->currentIndex(); for( int i=0; i(node->GetData())) { mitk::FiberBundleX::Pointer fib = dynamic_cast(node->GetData()); QString name(node->GetName().c_str()); DataNode::Pointer newNode = NULL; switch(generationMethod){ case 0: newNode = GenerateTractDensityImage(fib, false, true); name += "_TDI"; break; case 1: newNode = GenerateTractDensityImage(fib, false, false); name += "_TDI"; break; case 2: newNode = GenerateTractDensityImage(fib, true, false); name += "_envelope"; break; case 3: newNode = GenerateColorHeatmap(fib); break; case 4: newNode = GenerateFiberEndingsImage(fib); name += "_fiber_endings"; break; case 5: newNode = GenerateFiberEndingsPointSet(fib); name += "_fiber_endings"; break; } if (newNode.IsNotNull()) { newNode->SetName(name.toStdString()); GetDataStorage()->Add(newNode); } } } } // generate pointset displaying the fiber endings mitk::DataNode::Pointer QmitkFiberProcessingView::GenerateFiberEndingsPointSet(mitk::FiberBundleX::Pointer fib) { mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); vtkSmartPointer fiberPolyData = fib->GetFiberPolyData(); vtkSmartPointer vLines = fiberPolyData->GetLines(); vLines->InitTraversal(); int count = 0; int numFibers = fib->GetNumFibers(); for( int i=0; iGetNextCell ( numPoints, points ); if (numPoints>0) { double* point = fiberPolyData->GetPoint(points[0]); itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; pointSet->InsertPoint(count, itkPoint); count++; } if (numPoints>2) { double* point = fiberPolyData->GetPoint(points[numPoints-1]); itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; pointSet->InsertPoint(count, itkPoint); count++; } } mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( pointSet ); return node; } // generate image displaying the fiber endings mitk::DataNode::Pointer QmitkFiberProcessingView::GenerateFiberEndingsImage(mitk::FiberBundleX::Pointer fib) { typedef unsigned char OutPixType; typedef itk::Image OutImageType; typedef itk::TractsToFiberEndingsImageFilter< OutImageType > ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(fib); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image OutImageType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); return node; } // generate rgba heatmap from fiber bundle mitk::DataNode::Pointer QmitkFiberProcessingView::GenerateColorHeatmap(mitk::FiberBundleX::Pointer fib) { typedef itk::RGBAPixel OutPixType; typedef itk::Image OutImageType; typedef itk::TractsToRgbaImageFilter< OutImageType > ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(fib); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { itk::Image::Pointer itkImage = itk::Image::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); return node; } // generate tract density image from fiber bundle mitk::DataNode::Pointer QmitkFiberProcessingView::GenerateTractDensityImage(mitk::FiberBundleX::Pointer fib, bool binary, bool absolute) { const mitk::Geometry2D* bla = GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetCurrentWorldGeometry2D(); typedef float OutPixType; typedef itk::Image OutImageType; itk::TractDensityImageFilter< OutImageType >::Pointer generator = itk::TractDensityImageFilter< OutImageType >::New(); generator->SetFiberBundle(fib); generator->SetBinaryOutput(binary); generator->SetOutputAbsoluteValues(absolute); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); return node; } void QmitkFiberProcessingView::ResampleSelectedBundles() { int factor = this->m_Controls->m_ResampleFibersSpinBox->value(); for (int i=0; i(m_SelectedFB.at(i)->GetData()); fib->DoFiberSmoothing(factor); } GenerateStats(); RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberProcessingView::MirrorFibers() { unsigned int axis = this->m_Controls->m_AxisSelectionBox->currentIndex(); for (int i=0; i(m_SelectedFB.at(i)->GetData()); fib->MirrorFibers(axis); } if (m_SelectedFB.size()>0) GenerateStats(); if (m_SelectedSurfaces.size()>0) { for (int i=0; i poly = surf->GetVtkPolyData(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); for (int i=0; iGetNumberOfPoints(); i++) { double* point = poly->GetPoint(i); point[axis] *= -1; vtkNewPoints->InsertNextPoint(point); } poly->SetPoints(vtkNewPoints); surf->CalculateBoundingBox(); } } RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberProcessingView::DoImageColorCoding() { if (m_SelectedImage.IsNull()) return; for( int i=0; i(m_SelectedFB.at(i)->GetData()); fib->SetFAMap(m_SelectedImage); fib->SetColorCoding(mitk::FiberBundleX::COLORCODING_FA_BASED); fib->DoColorCodingFaBased(); } if(m_MultiWidget) m_MultiWidget->RequestUpdate(); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h index c3e6a43d98..806782e4d0 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h @@ -1,176 +1,178 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkFiberProcessingView_h #define QmitkFiberProcessingView_h #include #include "ui_QmitkFiberProcessingViewControls.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*! \brief View to process fiber bundles. Supplies methods to extract fibers from the bundle, join and subtract bundles, generate images from the selected bundle and much more. \sa QmitkFunctionality \ingroup Functionalities */ class QmitkFiberProcessingView : public QmitkFunctionality { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: typedef itk::Image< unsigned char, 3 > itkUCharImageType; static const std::string VIEW_ID; QmitkFiberProcessingView(); virtual ~QmitkFiberProcessingView(); virtual void CreateQtPartControl(QWidget *parent); virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget); virtual void StdMultiWidgetNotAvailable(); virtual void Activated(); protected slots: void OnDrawCircle(); ///< add circle interactors etc. void OnDrawPolygon(); ///< add circle interactors etc. void DoFiberExtraction(); ///< Extract fibers from selected bundle void GenerateAndComposite(); void GenerateOrComposite(); void GenerateNotComposite(); void PruneBundle(); ///< remove too short/too long fibers void MirrorFibers(); ///< mirror bundle on the specified plane void JoinBundles(); ///< merge selected fiber bundles void SubstractBundles(); ///< subtract bundle A from bundle B. Not commutative! Defined by order of selection. void GenerateRoiImage(); ///< generate binary image of selected planar figures. void ProcessSelectedBundles(); ///< start selected operation on fiber bundle (e.g. tract density image generation) void ResampleSelectedBundles(); ///< smooth fiber bundle using the specified number of sampling points per cm. void DoImageColorCoding(); ///< color fibers by selected scalar image void Extract3d(); ///< extract all fibers passing the selected surface mesh void ApplyCurvatureThreshold(); ///< remove/split fibers with a too high curvature threshold + void ExtractMask(); ///< extract all fibers passing the selected surface mesh virtual void AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *propertyKey = NULL, mitk::BaseProperty *property = NULL ); protected: /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged( std::vector nodes ); Ui::QmitkFiberProcessingViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; /** Connection from VTK to ITK */ template void ConnectPipelines(VTK_Exporter* exporter, ITK_Importer importer) { importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); importer->SetSpacingCallback(exporter->GetSpacingCallback()); importer->SetOriginCallback(exporter->GetOriginCallback()); importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); importer->SetCallbackUserData(exporter->GetCallbackUserData()); } template void ConnectPipelines(ITK_Exporter exporter, VTK_Importer* importer) { importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); importer->SetSpacingCallback(exporter->GetSpacingCallback()); importer->SetOriginCallback(exporter->GetOriginCallback()); importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); importer->SetCallbackUserData(exporter->GetCallbackUserData()); } template < typename TPixel, unsigned int VImageDimension > void InternalCalculateMaskFromPlanarFigure( itk::Image< TPixel, VImageDimension > *image, unsigned int axis, std::string nodeName ); template < typename TPixel, unsigned int VImageDimension > void InternalReorientImagePlane( const itk::Image< TPixel, VImageDimension > *image, mitk::Geometry3D* planegeo3D, int additionalIndex ); void GenerateStats(); ///< generate statistics of selected fiber bundles void UpdateGui(); ///< update button activity etc. dpending on current datamanager selection int m_CircleCounter; ///< used for data node naming int m_PolygonCounter; ///< used for data node naming std::vector m_SelectedFB; ///< selected fiber bundle nodes std::vector m_SelectedPF; ///< selected planar figure nodes std::vector m_SelectedSurfaces; mitk::Image::Pointer m_SelectedImage; mitk::Image::Pointer m_InternalImage; mitk::PlanarFigure::Pointer m_PlanarFigure; itkUCharImageType::Pointer m_InternalImageMask3D; itkUCharImageType::Pointer m_PlanarFigureImage; float m_UpsamplingFactor; ///< upsampling factor for all image generations + mitk::DataNode::Pointer m_MaskImageNode; void AddCompositeToDatastorage(mitk::PlanarFigureComposite::Pointer, mitk::DataNode::Pointer); void debugPFComposition(mitk::PlanarFigureComposite::Pointer , int ); void CompositeExtraction(mitk::DataNode::Pointer node, mitk::Image* image); mitk::DataNode::Pointer GenerateTractDensityImage(mitk::FiberBundleX::Pointer fib, bool binary, bool absolute); mitk::DataNode::Pointer GenerateColorHeatmap(mitk::FiberBundleX::Pointer fib); mitk::DataNode::Pointer GenerateFiberEndingsImage(mitk::FiberBundleX::Pointer fib); mitk::DataNode::Pointer GenerateFiberEndingsPointSet(mitk::FiberBundleX::Pointer fib); }; #endif // _QMITKFIBERTRACKINGVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui index 179ceb0366..f6417c6711 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui @@ -1,954 +1,984 @@ QmitkFiberProcessingViewControls 0 0 492 - 809 + 866 Form Please Select Input Data <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> <html><head/><body><p><span style=" color:#969696;">needed for extraction</span></p></body></html> Input DTI Fiber Bundle: Binary seed ROI. If not specified, the whole image area is seeded. ROI: Fiber Extraction 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. + Returns all fibers contained in bundle X that are not contained in bundle Y (not commutative!). Select at least two fiber bundles to execute. - Extract + Substract - + 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. + Extract fibers starting/ending inside of the selected binary mask. - Substract + Ending in Mask - + + + + Qt::Horizontal + + + + 40 + 20 + + + + + false 0 0 200 16777215 11 Merge selected fiber bundles. Select at least two fiber bundles to execute. Join - - - - 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 fibers passing through selected ROI or composite ROI. Select ROI and fiber bundle to execute. - Extract 3D + Extract - + false 0 0 16777215 16777215 11 Generate a binary image containing all selected ROIs. Select at least one ROI (planar figure) and a reference fiber bundle or image. ROI Image + + + + false + + + + 0 + 0 + + + + + 200 + 16777215 + + + + + 11 + + + + Extract fibers passing through the selected binary mask. + + + Passing Mask + + + 0 0 200 0 16777215 60 QFrame::NoFrame QFrame::Raised 0 Qt::Horizontal 40 20 false 60 16777215 Create AND composition with selected ROIs. AND false 60 16777215 Create OR composition with selected ROIs. OR false 60 16777215 Create NOT composition from selected ROI. NOT Fiber Processing QFormLayout::AllNonFixedFieldsGrow false 0 0 200 16777215 11 Perform selected operation on all selected fiber bundles. Generate Image QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Tract Density Image (TDI) Normalized TDI Binary Envelope Fiber Bundle Image Fiber Endings Image Fiber Endings Pointset Upsampling factor 1 0.100000000000000 10.000000000000000 0.100000000000000 1.000000000000000 false 0 0 200 16777215 11 Resample fibers using a Kochanek spline interpolation. Smooth Fibers Points per cm 1 50 5 false 0 0 200 16777215 11 Remove fibers shorter/longer than the specified length (in mm). Length Threshold QFrame::NoFrame QFrame::Raised 0 0 Minimum fiber length in mm 0 1000 20 Maximum fiber length in mm 0 10000 500 false 0 0 200 16777215 11 Remove fibers with a too high curvature Curvature Threshold QFrame::NoFrame QFrame::Raised 6 0 0 Minimum radius of circle created by three consecutive points of a fiber 100.000000000000000 0.100000000000000 2.000000000000000 Remove whole fiber if it is exceeding the curvature threshold, otherwise remove only high curvature part. Remove Fiber true false 0 0 200 16777215 11 Mirror fibers around specified axis. Mirror Fibers 0 3 3 Sagittal Coronal Axial false 0 0 200 16777215 11 Apply float image values (0-1) as color coding to the selected fiber bundle. Color By Scalar Map Fiber Statistics Courier 10 Pitch false true Qt::Vertical 20 40 diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.cpp index 41ce65dcc8..ac69ba56e4 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.cpp @@ -1,1321 +1,1328 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //misc #define _USE_MATH_DEFINES #include // Blueberry #include #include // Qmitk #include "QmitkFiberfoxView.h" // MITK #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define _USE_MATH_DEFINES #include const std::string QmitkFiberfoxView::VIEW_ID = "org.mitk.views.fiberfoxview"; QmitkFiberfoxView::QmitkFiberfoxView() : QmitkAbstractView() , m_Controls( 0 ) , m_SelectedImage( NULL ) , m_SelectedBundle( NULL ) { } // Destructor QmitkFiberfoxView::~QmitkFiberfoxView() { } void QmitkFiberfoxView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkFiberfoxViewControls; m_Controls->setupUi( parent ); m_Controls->m_VarianceBox->setVisible(false); m_Controls->m_GeometryMessage->setVisible(false); m_Controls->m_DiffusionPropsMessage->setVisible(false); m_Controls->m_T2bluringParamFrame->setVisible(false); m_Controls->m_KspaceParamFrame->setVisible(false); m_Controls->m_StickModelFrame->setVisible(false); m_Controls->m_AdvancedFiberOptionsFrame->setVisible(false); connect((QObject*) m_Controls->m_GenerateImageButton, SIGNAL(clicked()), (QObject*) this, SLOT(GenerateImage())); connect((QObject*) m_Controls->m_GenerateFibersButton, SIGNAL(clicked()), (QObject*) this, SLOT(GenerateFibers())); connect((QObject*) m_Controls->m_CircleButton, SIGNAL(clicked()), (QObject*) this, SLOT(OnDrawROI())); connect((QObject*) m_Controls->m_FlipButton, SIGNAL(clicked()), (QObject*) this, SLOT(OnFlipButton())); connect((QObject*) m_Controls->m_JoinBundlesButton, SIGNAL(clicked()), (QObject*) this, SLOT(JoinBundles())); connect((QObject*) m_Controls->m_VarianceBox, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(OnVarianceChanged(double))); connect((QObject*) m_Controls->m_DistributionBox, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(OnDistributionChanged(int))); connect((QObject*) m_Controls->m_FiberDensityBox, SIGNAL(valueChanged(int)), (QObject*) this, SLOT(OnFiberDensityChanged(int))); connect((QObject*) m_Controls->m_FiberSamplingBox, SIGNAL(valueChanged(int)), (QObject*) this, SLOT(OnFiberSamplingChanged(int))); connect((QObject*) m_Controls->m_TensionBox, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(OnTensionChanged(double))); connect((QObject*) m_Controls->m_ContinuityBox, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(OnContinuityChanged(double))); connect((QObject*) m_Controls->m_BiasBox, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(OnBiasChanged(double))); connect((QObject*) m_Controls->m_AddT2Smearing, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddT2Smearing(int))); connect((QObject*) m_Controls->m_AddGibbsRinging, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddGibbsRinging(int))); connect((QObject*) m_Controls->m_ConstantRadiusBox, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnConstantRadius(int))); connect((QObject*) m_Controls->m_CopyBundlesButton, SIGNAL(clicked()), (QObject*) this, SLOT(CopyBundles())); connect((QObject*) m_Controls->m_TransformBundlesButton, SIGNAL(clicked()), (QObject*) this, SLOT(ApplyTransform())); connect((QObject*) m_Controls->m_AlignOnGrid, SIGNAL(clicked()), (QObject*) this, SLOT(AlignOnGrid())); connect((QObject*) m_Controls->m_FiberCompartmentModelBox, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(FiberModelFrameVisibility(int))); connect((QObject*) m_Controls->m_NonFiberCompartmentModelBox, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(FiberModelFrameVisibility(int))); connect((QObject*) m_Controls->m_AdvancedFiberOptionsBox, SIGNAL( stateChanged(int)), (QObject*) this, SLOT(ShowAdvancedFiberOptions(int))); } } void QmitkFiberfoxView::ShowAdvancedFiberOptions(int state) { if (state) m_Controls->m_AdvancedFiberOptionsFrame->setVisible(true); else m_Controls->m_AdvancedFiberOptionsFrame->setVisible(false); } void QmitkFiberfoxView::FiberModelFrameVisibility(int index) { m_Controls->m_TensorModelFrame->setVisible(false); m_Controls->m_StickModelFrame->setVisible(false); switch (index) { case 0: m_Controls->m_TensorModelFrame->setVisible(true); break; case 1: m_Controls->m_StickModelFrame->setVisible(true); break; default: m_Controls->m_TensorModelFrame->setVisible(true); } } void QmitkFiberfoxView::NonFiberModelFrameVisibility(int index) { } void QmitkFiberfoxView::OnConstantRadius(int value) { if (value>0 && m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnAddT2Smearing(int value) { if (value>0) m_Controls->m_T2bluringParamFrame->setVisible(true); else m_Controls->m_T2bluringParamFrame->setVisible(false); } void QmitkFiberfoxView::OnAddGibbsRinging(int value) { if (value>0) m_Controls->m_KspaceParamFrame->setVisible(true); else m_Controls->m_KspaceParamFrame->setVisible(false); } void QmitkFiberfoxView::OnDistributionChanged(int value) { if (value==1) m_Controls->m_VarianceBox->setVisible(true); else m_Controls->m_VarianceBox->setVisible(false); if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnVarianceChanged(double value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnFiberDensityChanged(int value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnFiberSamplingChanged(int value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnTensionChanged(double value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnContinuityChanged(double value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnBiasChanged(double value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::AlignOnGrid() { for (int i=0; i(m_SelectedFiducials.at(i)->GetData()); mitk::Point3D wc0 = pe->GetWorldControlPoint(0); mitk::DataStorage::SetOfObjects::ConstPointer parentFibs = GetDataStorage()->GetSources(m_SelectedFiducials.at(i)); for( mitk::DataStorage::SetOfObjects::const_iterator it = parentFibs->begin(); it != parentFibs->end(); ++it ) { mitk::DataNode::Pointer pFibNode = *it; if ( pFibNode.IsNotNull() && dynamic_cast(pFibNode->GetData()) ) { mitk::DataStorage::SetOfObjects::ConstPointer parentImgs = GetDataStorage()->GetSources(pFibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = parentImgs->begin(); it2 != parentImgs->end(); ++it2 ) { mitk::DataNode::Pointer pImgNode = *it2; if ( pImgNode.IsNotNull() && dynamic_cast(pImgNode->GetData()) ) { mitk::Image::Pointer img = dynamic_cast(pImgNode->GetData()); mitk::Geometry3D::Pointer geom = img->GetGeometry(); itk::Index<3> idx; geom->WorldToIndex(wc0, idx); mitk::Point3D cIdx; cIdx[0]=idx[0]; cIdx[1]=idx[1]; cIdx[2]=idx[2]; mitk::Point3D world; geom->IndexToWorld(cIdx,world); mitk::Vector3D trans = world - wc0; pe->GetGeometry()->Translate(trans); break; } } break; } } } for( int i=0; iGetSources(fibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it = sources->begin(); it != sources->end(); ++it ) { mitk::DataNode::Pointer imgNode = *it; if ( imgNode.IsNotNull() && dynamic_cast(imgNode->GetData()) ) { mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(fibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations->begin(); it2 != derivations->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse::Pointer pe = dynamic_cast(fiducialNode->GetData()); mitk::Point3D wc0 = pe->GetWorldControlPoint(0); mitk::Image::Pointer img = dynamic_cast(imgNode->GetData()); mitk::Geometry3D::Pointer geom = img->GetGeometry(); itk::Index<3> idx; geom->WorldToIndex(wc0, idx); mitk::Point3D cIdx; cIdx[0]=idx[0]; cIdx[1]=idx[1]; cIdx[2]=idx[2]; mitk::Point3D world; geom->IndexToWorld(cIdx,world); mitk::Vector3D trans = world - wc0; pe->GetGeometry()->Translate(trans); } } break; } } } for( int i=0; i(m_SelectedImages.at(i)->GetData()); mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(m_SelectedImages.at(i)); for( mitk::DataStorage::SetOfObjects::const_iterator it = derivations->begin(); it != derivations->end(); ++it ) { mitk::DataNode::Pointer fibNode = *it; if ( fibNode.IsNotNull() && dynamic_cast(fibNode->GetData()) ) { mitk::DataStorage::SetOfObjects::ConstPointer derivations2 = GetDataStorage()->GetDerivations(fibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations2->begin(); it2 != derivations2->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse::Pointer pe = dynamic_cast(fiducialNode->GetData()); mitk::Point3D wc0 = pe->GetWorldControlPoint(0); mitk::Geometry3D::Pointer geom = img->GetGeometry(); itk::Index<3> idx; geom->WorldToIndex(wc0, idx); mitk::Point3D cIdx; cIdx[0]=idx[0]; cIdx[1]=idx[1]; cIdx[2]=idx[2]; mitk::Point3D world; geom->IndexToWorld(cIdx,world); mitk::Vector3D trans = world - wc0; pe->GetGeometry()->Translate(trans); } } } } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnFlipButton() { if (m_SelectedFiducial.IsNull()) return; std::map::iterator it = m_DataNodeToPlanarFigureData.find(m_SelectedFiducial.GetPointer()); if( it != m_DataNodeToPlanarFigureData.end() ) { QmitkPlanarFigureData& data = it->second; data.m_Flipped += 1; data.m_Flipped %= 2; } if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } QmitkFiberfoxView::GradientListType QmitkFiberfoxView::GenerateHalfShell(int NPoints) { NPoints *= 2; GradientListType pointshell; int numB0 = NPoints/10; if (numB0==0) numB0=1; GradientType g; g.Fill(0.0); for (int i=0; i theta; theta.set_size(NPoints); vnl_vector phi; phi.set_size(NPoints); double C = sqrt(4*M_PI); phi(0) = 0.0; phi(NPoints-1) = 0.0; for(int i=0; i0 && i std::vector > QmitkFiberfoxView::MakeGradientList() { std::vector > retval; vnl_matrix_fixed* U = itk::PointShell >::DistributePointShell(); // Add 0 vector for B0 int numB0 = ndirs/10; if (numB0==0) numB0=1; itk::Vector v; v.Fill(0.0); for (int i=0; i v; v[0] = U->get(0,i); v[1] = U->get(1,i); v[2] = U->get(2,i); retval.push_back(v); } return retval; } void QmitkFiberfoxView::OnAddBundle() { if (m_SelectedImage.IsNull()) return; mitk::DataStorage::SetOfObjects::ConstPointer children = GetDataStorage()->GetDerivations(m_SelectedImage); mitk::FiberBundleX::Pointer bundle = mitk::FiberBundleX::New(); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( bundle ); QString name = QString("Bundle_%1").arg(children->size()); node->SetName(name.toStdString()); m_SelectedBundle = node; m_SelectedBundles.push_back(node); UpdateGui(); GetDataStorage()->Add(node, m_SelectedImage); } void QmitkFiberfoxView::OnDrawROI() { if (m_SelectedBundle.IsNull()) OnAddBundle(); if (m_SelectedBundle.IsNull()) return; mitk::DataStorage::SetOfObjects::ConstPointer children = GetDataStorage()->GetDerivations(m_SelectedBundle); mitk::PlanarEllipse::Pointer figure = mitk::PlanarEllipse::New(); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( figure ); QList nodes = this->GetDataManagerSelection(); for( int i=0; iSetSelected(false); m_SelectedFiducial = node; QString name = QString("Fiducial_%1").arg(children->size()); node->SetName(name.toStdString()); node->SetSelected(true); GetDataStorage()->Add(node, m_SelectedBundle); this->DisableCrosshairNavigation(); mitk::PlanarFigureInteractor::Pointer figureInteractor = dynamic_cast(node->GetInteractor()); if(figureInteractor.IsNull()) figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", node); mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); UpdateGui(); } bool CompareLayer(mitk::DataNode::Pointer i,mitk::DataNode::Pointer j) { int li = -1; i->GetPropertyValue("layer", li); int lj = -1; j->GetPropertyValue("layer", lj); return liGetSources(m_SelectedFiducial); for( mitk::DataStorage::SetOfObjects::const_iterator it = parents->begin(); it != parents->end(); ++it ) if(dynamic_cast((*it)->GetData())) m_SelectedBundles.push_back(*it); if (m_SelectedBundles.empty()) return; } vector< vector< mitk::PlanarEllipse::Pointer > > fiducials; vector< vector< unsigned int > > fliplist; for (int i=0; iGetDerivations(m_SelectedBundles.at(i)); std::vector< mitk::DataNode::Pointer > childVector; for( mitk::DataStorage::SetOfObjects::const_iterator it = children->begin(); it != children->end(); ++it ) childVector.push_back(*it); sort(childVector.begin(), childVector.end(), CompareLayer); vector< mitk::PlanarEllipse::Pointer > fib; vector< unsigned int > flip; float radius = 1; int count = 0; for( std::vector< mitk::DataNode::Pointer >::const_iterator it = childVector.begin(); it != childVector.end(); ++it ) { mitk::DataNode::Pointer node = *it; if ( node.IsNotNull() && dynamic_cast(node->GetData()) ) { mitk::PlanarEllipse* ellipse = dynamic_cast(node->GetData()); if (m_Controls->m_ConstantRadiusBox->isChecked()) { ellipse->SetTreatAsCircle(true); mitk::Point2D c = ellipse->GetControlPoint(0); mitk::Point2D p = ellipse->GetControlPoint(1); mitk::Vector2D v = p-c; if (count==0) { radius = v.GetVnlVector().magnitude(); ellipse->SetControlPoint(1, p); } else { v.Normalize(); v *= radius; ellipse->SetControlPoint(1, c+v); } } fib.push_back(ellipse); std::map::iterator it = m_DataNodeToPlanarFigureData.find(node.GetPointer()); if( it != m_DataNodeToPlanarFigureData.end() ) { QmitkPlanarFigureData& data = it->second; flip.push_back(data.m_Flipped); } else flip.push_back(0); } count++; } if (fib.size()>1) { fiducials.push_back(fib); fliplist.push_back(flip); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); if (fib.size()<3) return; } itk::FibersFromPlanarFiguresFilter::Pointer filter = itk::FibersFromPlanarFiguresFilter::New(); filter->SetFiducials(fiducials); filter->SetFlipList(fliplist); switch(m_Controls->m_DistributionBox->currentIndex()){ case 0: filter->SetFiberDistribution(itk::FibersFromPlanarFiguresFilter::DISTRIBUTE_UNIFORM); break; case 1: filter->SetFiberDistribution(itk::FibersFromPlanarFiguresFilter::DISTRIBUTE_GAUSSIAN); filter->SetVariance(m_Controls->m_VarianceBox->value()); break; } filter->SetDensity(m_Controls->m_FiberDensityBox->value()); filter->SetTension(m_Controls->m_TensionBox->value()); filter->SetContinuity(m_Controls->m_ContinuityBox->value()); filter->SetBias(m_Controls->m_BiasBox->value()); filter->SetFiberSampling(m_Controls->m_FiberSamplingBox->value()); filter->Update(); vector< mitk::FiberBundleX::Pointer > fiberBundles = filter->GetFiberBundles(); for (int i=0; iSetData( fiberBundles.at(i) ); if (fiberBundles.at(i)->GetNumFibers()>50000) m_SelectedBundles.at(i)->SetVisibility(false); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberfoxView::GenerateImage() { itk::ImageRegion<3> imageRegion; imageRegion.SetSize(0, m_Controls->m_SizeX->value()); imageRegion.SetSize(1, m_Controls->m_SizeY->value()); imageRegion.SetSize(2, m_Controls->m_SizeZ->value()); mitk::Vector3D spacing; spacing[0] = m_Controls->m_SpacingX->value(); spacing[1] = m_Controls->m_SpacingY->value(); spacing[2] = m_Controls->m_SpacingZ->value(); mitk::Point3D origin; origin[0] = spacing[0]/2; origin[1] = spacing[1]/2; origin[2] = spacing[2]/2; itk::Matrix directionMatrix; directionMatrix.SetIdentity(); if (m_SelectedBundle.IsNull()) { mitk::Image::Pointer image = mitk::ImageGenerator::GenerateGradientImage( m_Controls->m_SizeX->value(), m_Controls->m_SizeY->value(), m_Controls->m_SizeZ->value(), m_Controls->m_SpacingX->value(), m_Controls->m_SpacingY->value(), m_Controls->m_SpacingZ->value()); + mitk::Geometry3D* geom = image->GetGeometry(); + geom->SetOrigin(origin); + mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( image ); node->SetName("Dummy"); GetDataStorage()->Add(node); m_SelectedImage = node; mitk::BaseData::Pointer basedata = node->GetData(); if (basedata.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( basedata->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } UpdateGui(); return; } DiffusionSignalModel::GradientListType gradientList; double bVal = 1000; if (m_SelectedDWI.IsNull()) { gradientList = GenerateHalfShell(m_Controls->m_NumGradientsBox->value());; bVal = m_Controls->m_BvalueBox->value(); } else { mitk::DiffusionImage::Pointer dwi = dynamic_cast*>(m_SelectedDWI->GetData()); imageRegion = dwi->GetVectorImage()->GetLargestPossibleRegion(); spacing = dwi->GetVectorImage()->GetSpacing(); origin = dwi->GetVectorImage()->GetOrigin(); directionMatrix = dwi->GetVectorImage()->GetDirection(); bVal = dwi->GetB_Value(); mitk::DiffusionImage::GradientDirectionContainerType::Pointer dirs = dwi->GetDirections(); for (int i=0; iSize(); i++) { DiffusionSignalModel::GradientType g; g[0] = dirs->at(i)[0]; g[1] = dirs->at(i)[1]; g[2] = dirs->at(i)[2]; gradientList.push_back(g); } } // storage for generated phantom image mitk::DataNode::Pointer resultNode = mitk::DataNode::New(); // signal models QString signalModelString("Ball"); itk::TractsToDWIImageFilter::DiffusionModelList fiberModelList, nonFiberModelList; mitk::TensorModel tensorModel; mitk::StickModel stickModel; // free diffusion mitk::BallModel ballModel; ballModel.SetGradientList(gradientList); ballModel.SetBvalue(bVal); ballModel.SetDiffusivity(m_Controls->m_BallD->value()); ballModel.SetSignalScale(m_Controls->m_NonFiberS0Box->value()); ballModel.SetRelaxationT2(m_Controls->m_NonFiberRelaxationT2Box->value()); nonFiberModelList.push_back(&ballModel); resultNode->AddProperty("Fiberfox.Ball.Diffusivity", DoubleProperty::New(m_Controls->m_BallD->value())); resultNode->AddProperty("Fiberfox.Ball.Scaling", DoubleProperty::New(m_Controls->m_NonFiberS0Box->value())); if (m_Controls->m_AddT2Smearing->isChecked()) resultNode->AddProperty("Fiberfox.Ball.T2", DoubleProperty::New(m_Controls->m_NonFiberRelaxationT2Box->value())); // intra-axonal diffusion switch (m_Controls->m_FiberCompartmentModelBox->currentIndex()) { case 0: MITK_INFO << "Using zeppelin model"; tensorModel.SetGradientList(gradientList); tensorModel.SetBvalue(bVal); tensorModel.SetKernelFA(m_Controls->m_TensorFaBox->value()); tensorModel.SetSignalScale(m_Controls->m_FiberS0Box->value()); tensorModel.SetRelaxationT2(m_Controls->m_FiberRelaxationT2Box->value()); fiberModelList.push_back(&tensorModel); signalModelString += "-Zeppelin"; resultNode->AddProperty("Fiberfox.Zeppelin.FA", DoubleProperty::New(m_Controls->m_TensorFaBox->value())); resultNode->AddProperty("Fiberfox.Zeppelin.Scaling", DoubleProperty::New(m_Controls->m_FiberS0Box->value())); if (m_Controls->m_AddT2Smearing->isChecked()) resultNode->AddProperty("Fiberfox.Zeppelin.T2", DoubleProperty::New(m_Controls->m_FiberRelaxationT2Box->value())); break; case 1: MITK_INFO << "Using stick model"; stickModel.SetGradientList(gradientList); stickModel.SetDiffusivity(m_Controls->m_StickDiffusivityBox->value()); stickModel.SetSignalScale(m_Controls->m_FiberS0Box->value()); stickModel.SetRelaxationT2(m_Controls->m_FiberRelaxationT2Box->value()); fiberModelList.push_back(&stickModel); signalModelString += "-Stick"; resultNode->AddProperty("Fiberfox.Stick.Diffusivity", DoubleProperty::New(m_Controls->m_StickDiffusivityBox->value())); resultNode->AddProperty("Fiberfox.Stick.Scaling", DoubleProperty::New(m_Controls->m_FiberS0Box->value())); if (m_Controls->m_AddT2Smearing->isChecked()) resultNode->AddProperty("Fiberfox.Stick.T2", DoubleProperty::New(m_Controls->m_FiberRelaxationT2Box->value())); break; } itk::TractsToDWIImageFilter::KspaceArtifactList artifactList; // noise model double snr = m_Controls->m_NoiseLevel->value(); double noiseVariance = 0; if (snr <= 0) snr = 0.0001; if (snr<=99) { noiseVariance = (double)m_Controls->m_FiberS0Box->value()/snr; noiseVariance *= noiseVariance; } mitk::RicianNoiseModel noiseModel; noiseModel.SetNoiseVariance(noiseVariance); // artifact models + QString artifactModelString(""); mitk::GibbsRingingArtifact gibbsModel; if (m_Controls->m_AddGibbsRinging->isChecked()) { + artifactModelString += "_Gibbs-ringing"; resultNode->AddProperty("Fiberfox.k-Space-Undersampling", IntProperty::New(m_Controls->m_KspaceUndersamplingBox->currentText().toInt())); gibbsModel.SetKspaceCropping((double)m_Controls->m_KspaceUndersamplingBox->currentText().toInt()); artifactList.push_back(&gibbsModel); } mitk::T2SmearingArtifact t2Model; if (m_Controls->m_AddT2Smearing->isChecked()) { + artifactModelString += "_T2-blurring"; t2Model.SetReadoutPulseLength(1); artifactList.push_back(&t2Model); } for (int i=0; i(m_SelectedBundles.at(i)->GetData()); if (fiberBundle->GetNumFibers()<=0) continue; itk::TractsToDWIImageFilter::Pointer filter = itk::TractsToDWIImageFilter::New(); filter->SetImageRegion(imageRegion); filter->SetSpacing(spacing); filter->SetOrigin(origin); filter->SetDirectionMatrix(directionMatrix); filter->SetFiberBundle(fiberBundle); filter->SetFiberModels(fiberModelList); filter->SetNonFiberModels(nonFiberModelList); filter->SetNoiseModel(&noiseModel); filter->SetKspaceArtifacts(artifactList); filter->SetNumberOfRepetitions(m_Controls->m_RepetitionsBox->value()); filter->SetEnforcePureFiberVoxels(m_Controls->m_EnforcePureFiberVoxelsBox->isChecked()); + filter->SetInterpolationShrink(m_Controls->m_InterpolationShrink->value()); if (m_TissueMask.IsNotNull()) { ItkUcharImgType::Pointer mask = ItkUcharImgType::New(); mitk::CastToItkImage(m_TissueMask, mask); filter->SetTissueMask(mask); } filter->Update(); mitk::DiffusionImage::Pointer image = mitk::DiffusionImage::New(); image->SetVectorImage( filter->GetOutput() ); image->SetB_Value(bVal); image->SetDirections(gradientList); image->InitializeFromVectorImage(); -// image->GetGeometry()->SetImageGeometry(false); resultNode->SetData( image ); resultNode->SetName(m_SelectedBundle->GetName() - +"_D"+QString::number(m_Controls->m_SizeX->value()).toStdString() - +"-"+QString::number(m_Controls->m_SizeY->value()).toStdString() - +"-"+QString::number(m_Controls->m_SizeZ->value()).toStdString() + +"_D"+QString::number(imageRegion.GetSize(0)).toStdString() + +"-"+QString::number(imageRegion.GetSize(1)).toStdString() + +"-"+QString::number(imageRegion.GetSize(2)).toStdString() +"_S"+QString::number(spacing[0]).toStdString() +"-"+QString::number(spacing[1]).toStdString() +"-"+QString::number(spacing[2]).toStdString() +"_b"+QString::number(bVal).toStdString() +"_SNR"+QString::number(snr).toStdString() - +"_"+signalModelString.toStdString()); + +"_"+signalModelString.toStdString() + +artifactModelString.toStdString()); GetDataStorage()->Add(resultNode, m_SelectedBundle); resultNode->AddProperty("Fiberfox.SNR", DoubleProperty::New(snr)); resultNode->AddProperty("Fiberfox.Repetitions", IntProperty::New(m_Controls->m_RepetitionsBox->value())); resultNode->AddProperty("Fiberfox.b-value", DoubleProperty::New(bVal)); resultNode->AddProperty("Fiberfox.Model", StringProperty::New(signalModelString.toStdString())); if (m_Controls->m_KspaceImageBox->isChecked()) { itk::Image::Pointer kspace = filter->GetKspaceImage(); mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk(kspace.GetPointer()); image->SetVolume(kspace->GetBufferPointer()); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( image ); node->SetName(m_SelectedBundle->GetName()+"_k-space"); GetDataStorage()->Add(node, m_SelectedBundle); } mitk::BaseData::Pointer basedata = resultNode->GetData(); if (basedata.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( basedata->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } } void QmitkFiberfoxView::ApplyTransform() { vector< mitk::DataNode::Pointer > selectedBundles; for( int i=0; iGetDerivations(m_SelectedImages.at(i)); for( mitk::DataStorage::SetOfObjects::const_iterator it = derivations->begin(); it != derivations->end(); ++it ) { mitk::DataNode::Pointer fibNode = *it; if ( fibNode.IsNotNull() && dynamic_cast(fibNode->GetData()) ) selectedBundles.push_back(fibNode); } } if (selectedBundles.empty()) selectedBundles = m_SelectedBundles2; if (!selectedBundles.empty()) { std::vector::const_iterator it = selectedBundles.begin(); for (it; it!=selectedBundles.end(); ++it) { mitk::FiberBundleX::Pointer fib = dynamic_cast((*it)->GetData()); fib->RotateAroundAxis(m_Controls->m_XrotBox->value(), m_Controls->m_YrotBox->value(), m_Controls->m_ZrotBox->value()); fib->TranslateFibers(m_Controls->m_XtransBox->value(), m_Controls->m_YtransBox->value(), m_Controls->m_ZtransBox->value()); fib->ScaleFibers(m_Controls->m_XscaleBox->value(), m_Controls->m_YscaleBox->value(), m_Controls->m_ZscaleBox->value()); // handle child fiducials if (m_Controls->m_IncludeFiducials->isChecked()) { mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(*it); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations->begin(); it2 != derivations->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse* pe = dynamic_cast(fiducialNode->GetData()); mitk::Geometry3D* geom = pe->GetGeometry(); // translate mitk::Vector3D world; world[0] = m_Controls->m_XtransBox->value(); world[1] = m_Controls->m_YtransBox->value(); world[2] = m_Controls->m_ZtransBox->value(); geom->Translate(world); // calculate rotation matrix double x = m_Controls->m_XrotBox->value()*M_PI/180; double y = m_Controls->m_YrotBox->value()*M_PI/180; double z = m_Controls->m_ZrotBox->value()*M_PI/180; itk::Matrix< float, 3, 3 > rotX; rotX.SetIdentity(); rotX[1][1] = cos(x); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(x); rotX[2][1] = -rotX[1][2]; itk::Matrix< float, 3, 3 > rotY; rotY.SetIdentity(); rotY[0][0] = cos(y); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(y); rotY[2][0] = -rotY[0][2]; itk::Matrix< float, 3, 3 > rotZ; rotZ.SetIdentity(); rotZ[0][0] = cos(z); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(z); rotZ[1][0] = -rotZ[0][1]; itk::Matrix< float, 3, 3 > rot = rotZ*rotY*rotX; // transform control point coordinate into geometry translation geom->SetOrigin(pe->GetWorldControlPoint(0)); mitk::Point2D cp; cp.Fill(0.0); pe->SetControlPoint(0, cp); // rotate fiducial geom->GetIndexToWorldTransform()->SetMatrix(rot*geom->GetIndexToWorldTransform()->GetMatrix()); // implicit translation mitk::Vector3D trans; trans[0] = geom->GetOrigin()[0]-fib->GetGeometry()->GetCenter()[0]; trans[1] = geom->GetOrigin()[1]-fib->GetGeometry()->GetCenter()[1]; trans[2] = geom->GetOrigin()[2]-fib->GetGeometry()->GetCenter()[2]; mitk::Vector3D newWc = rot*trans; newWc = newWc-trans; geom->Translate(newWc); } } } } } else { for (int i=0; i(m_SelectedFiducials.at(i)->GetData()); mitk::Geometry3D* geom = pe->GetGeometry(); // translate mitk::Vector3D world; world[0] = m_Controls->m_XtransBox->value(); world[1] = m_Controls->m_YtransBox->value(); world[2] = m_Controls->m_ZtransBox->value(); geom->Translate(world); // calculate rotation matrix double x = m_Controls->m_XrotBox->value()*M_PI/180; double y = m_Controls->m_YrotBox->value()*M_PI/180; double z = m_Controls->m_ZrotBox->value()*M_PI/180; itk::Matrix< float, 3, 3 > rotX; rotX.SetIdentity(); rotX[1][1] = cos(x); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(x); rotX[2][1] = -rotX[1][2]; itk::Matrix< float, 3, 3 > rotY; rotY.SetIdentity(); rotY[0][0] = cos(y); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(y); rotY[2][0] = -rotY[0][2]; itk::Matrix< float, 3, 3 > rotZ; rotZ.SetIdentity(); rotZ[0][0] = cos(z); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(z); rotZ[1][0] = -rotZ[0][1]; itk::Matrix< float, 3, 3 > rot = rotZ*rotY*rotX; // transform control point coordinate into geometry translation geom->SetOrigin(pe->GetWorldControlPoint(0)); mitk::Point2D cp; cp.Fill(0.0); pe->SetControlPoint(0, cp); // rotate fiducial geom->GetIndexToWorldTransform()->SetMatrix(rot*geom->GetIndexToWorldTransform()->GetMatrix()); } if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberfoxView::CopyBundles() { if ( m_SelectedBundles.size()<1 ){ QMessageBox::information( NULL, "Warning", "Select at least one fiber bundle!"); MITK_WARN("QmitkFiberProcessingView") << "Select at least one fiber bundle!"; return; } std::vector::const_iterator it = m_SelectedBundles.begin(); for (it; it!=m_SelectedBundles.end(); ++it) { // find parent image mitk::DataNode::Pointer parentNode; mitk::DataStorage::SetOfObjects::ConstPointer parentImgs = GetDataStorage()->GetSources(*it); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = parentImgs->begin(); it2 != parentImgs->end(); ++it2 ) { mitk::DataNode::Pointer pImgNode = *it2; if ( pImgNode.IsNotNull() && dynamic_cast(pImgNode->GetData()) ) { parentNode = pImgNode; break; } } mitk::FiberBundleX::Pointer fib = dynamic_cast((*it)->GetData()); mitk::FiberBundleX::Pointer newBundle = fib->GetDeepCopy(); QString name((*it)->GetName().c_str()); name += "_copy"; mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); if (parentNode.IsNotNull()) GetDataStorage()->Add(fbNode, parentNode); else GetDataStorage()->Add(fbNode); // copy child fiducials if (m_Controls->m_IncludeFiducials->isChecked()) { mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(*it); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations->begin(); it2 != derivations->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse::Pointer pe = mitk::PlanarEllipse::New(); pe->DeepCopy(dynamic_cast(fiducialNode->GetData())); mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetData(pe); newNode->SetName(fiducialNode->GetName()); GetDataStorage()->Add(newNode, fbNode); } } } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberfoxView::JoinBundles() { if ( m_SelectedBundles.size()<2 ){ QMessageBox::information( NULL, "Warning", "Select at least two fiber bundles!"); MITK_WARN("QmitkFiberProcessingView") << "Select at least two fiber bundles!"; return; } std::vector::const_iterator it = m_SelectedBundles.begin(); mitk::FiberBundleX::Pointer newBundle = dynamic_cast((*it)->GetData()); QString name(""); name += QString((*it)->GetName().c_str()); ++it; for (it; it!=m_SelectedBundles.end(); ++it) { newBundle = newBundle->AddBundle(dynamic_cast((*it)->GetData())); name += "+"+QString((*it)->GetName().c_str()); } mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); GetDataStorage()->Add(fbNode); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberfoxView::UpdateGui() { m_Controls->m_FiberBundleLabel->setText("mandatory"); m_Controls->m_GeometryFrame->setEnabled(true); m_Controls->m_GeometryMessage->setVisible(false); m_Controls->m_DiffusionPropsMessage->setVisible(false); m_Controls->m_FiberGenMessage->setVisible(true); m_Controls->m_TransformBundlesButton->setEnabled(false); m_Controls->m_CopyBundlesButton->setEnabled(false); m_Controls->m_GenerateFibersButton->setEnabled(false); m_Controls->m_FlipButton->setEnabled(false); m_Controls->m_CircleButton->setEnabled(false); m_Controls->m_BvalueBox->setEnabled(true); m_Controls->m_NumGradientsBox->setEnabled(true); m_Controls->m_JoinBundlesButton->setEnabled(false); m_Controls->m_AlignOnGrid->setEnabled(false); if (m_SelectedFiducial.IsNotNull()) { m_Controls->m_TransformBundlesButton->setEnabled(true); m_Controls->m_FlipButton->setEnabled(true); m_Controls->m_AlignOnGrid->setEnabled(true); } if (m_SelectedImage.IsNotNull() || m_SelectedBundle.IsNotNull()) { m_Controls->m_TransformBundlesButton->setEnabled(true); m_Controls->m_CircleButton->setEnabled(true); m_Controls->m_FiberGenMessage->setVisible(false); m_Controls->m_AlignOnGrid->setEnabled(true); } if (m_TissueMask.IsNotNull()) { m_Controls->m_GeometryMessage->setVisible(true); m_Controls->m_GeometryFrame->setEnabled(false); } if (m_SelectedDWI.IsNotNull()) { m_Controls->m_DiffusionPropsMessage->setVisible(true); m_Controls->m_BvalueBox->setEnabled(false); m_Controls->m_NumGradientsBox->setEnabled(false); m_Controls->m_GeometryMessage->setVisible(true); m_Controls->m_GeometryFrame->setEnabled(false); } if (m_SelectedBundle.IsNotNull()) { m_Controls->m_CopyBundlesButton->setEnabled(true); m_Controls->m_GenerateFibersButton->setEnabled(true); m_Controls->m_FiberBundleLabel->setText(m_SelectedBundle->GetName().c_str()); if (m_SelectedBundles.size()>1) m_Controls->m_JoinBundlesButton->setEnabled(true); } } void QmitkFiberfoxView::OnSelectionChanged( berry::IWorkbenchPart::Pointer, const QList& nodes ) { m_SelectedBundles2.clear(); m_SelectedImages.clear(); m_SelectedFiducials.clear(); m_SelectedFiducial = NULL; m_TissueMask = NULL; m_SelectedBundles.clear(); m_SelectedBundle = NULL; m_SelectedImage = NULL; m_SelectedDWI = NULL; m_Controls->m_TissueMaskLabel->setText("optional"); // iterate all selected objects, adjust warning visibility for( int i=0; i*>(node->GetData()) ) { m_SelectedDWI = node; m_SelectedImage = node; m_SelectedImages.push_back(node); } else if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_SelectedImages.push_back(node); m_SelectedImage = node; bool isBinary = false; node->GetPropertyValue("binary", isBinary); if (isBinary) { m_TissueMask = dynamic_cast(node->GetData()); m_Controls->m_TissueMaskLabel->setText(node->GetName().c_str()); } } else if ( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_SelectedBundles2.push_back(node); if (m_Controls->m_RealTimeFibers->isChecked() && node!=m_SelectedBundle) { m_SelectedBundle = node; m_SelectedBundles.push_back(node); mitk::FiberBundleX::Pointer newFib = dynamic_cast(node->GetData()); if (newFib->GetNumFibers()!=m_Controls->m_FiberDensityBox->value()) GenerateFibers(); } else { m_SelectedBundle = node; m_SelectedBundles.push_back(node); } } else if ( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_SelectedFiducials.push_back(node); m_SelectedFiducial = node; m_SelectedBundles.clear(); mitk::DataStorage::SetOfObjects::ConstPointer parents = GetDataStorage()->GetSources(node); for( mitk::DataStorage::SetOfObjects::const_iterator it = parents->begin(); it != parents->end(); ++it ) { mitk::DataNode::Pointer pNode = *it; if ( pNode.IsNotNull() && dynamic_cast(pNode->GetData()) ) { m_SelectedBundle = pNode; m_SelectedBundles.push_back(pNode); } } } } UpdateGui(); } void QmitkFiberfoxView::EnableCrosshairNavigation() { MITK_DEBUG << "EnableCrosshairNavigation"; // enable the crosshair navigation if (mitk::ILinkedRenderWindowPart* linkedRenderWindow = dynamic_cast(this->GetRenderWindowPart())) { MITK_DEBUG << "enabling linked navigation"; linkedRenderWindow->EnableLinkedNavigation(true); // linkedRenderWindow->EnableSlicingPlanes(true); } if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::DisableCrosshairNavigation() { MITK_DEBUG << "DisableCrosshairNavigation"; // disable the crosshair navigation during the drawing if (mitk::ILinkedRenderWindowPart* linkedRenderWindow = dynamic_cast(this->GetRenderWindowPart())) { MITK_DEBUG << "disabling linked navigation"; linkedRenderWindow->EnableLinkedNavigation(false); // linkedRenderWindow->EnableSlicingPlanes(false); } } void QmitkFiberfoxView::NodeRemoved(const mitk::DataNode* node) { if (node == m_SelectedImage) m_SelectedImage = NULL; if (node == m_SelectedBundle) m_SelectedBundle = NULL; mitk::DataNode* nonConstNode = const_cast(node); std::map::iterator it = m_DataNodeToPlanarFigureData.find(nonConstNode); if( it != m_DataNodeToPlanarFigureData.end() ) { QmitkPlanarFigureData& data = it->second; // remove observers data.m_Figure->RemoveObserver( data.m_EndPlacementObserverTag ); data.m_Figure->RemoveObserver( data.m_SelectObserverTag ); data.m_Figure->RemoveObserver( data.m_StartInteractionObserverTag ); data.m_Figure->RemoveObserver( data.m_EndInteractionObserverTag ); m_DataNodeToPlanarFigureData.erase( it ); } } void QmitkFiberfoxView::NodeAdded( const mitk::DataNode* node ) { // add observer for selection in renderwindow mitk::PlanarFigure* figure = dynamic_cast(node->GetData()); bool isPositionMarker (false); node->GetBoolProperty("isContourMarker", isPositionMarker); if( figure && !isPositionMarker ) { MITK_DEBUG << "figure added. will add interactor if needed."; mitk::PlanarFigureInteractor::Pointer figureInteractor = dynamic_cast(node->GetInteractor()); mitk::DataNode* nonConstNode = const_cast( node ); if(figureInteractor.IsNull()) { figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", nonConstNode); } else { // just to be sure that the interactor is not added twice mitk::GlobalInteraction::GetInstance()->RemoveInteractor(figureInteractor); } MITK_DEBUG << "adding interactor to globalinteraction"; mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); MITK_DEBUG << "will now add observers for planarfigure"; QmitkPlanarFigureData data; data.m_Figure = figure; // // add observer for event when figure has been placed typedef itk::SimpleMemberCommand< QmitkFiberfoxView > SimpleCommandType; // SimpleCommandType::Pointer initializationCommand = SimpleCommandType::New(); // initializationCommand->SetCallbackFunction( this, &QmitkFiberfoxView::PlanarFigureInitialized ); // data.m_EndPlacementObserverTag = figure->AddObserver( mitk::EndPlacementPlanarFigureEvent(), initializationCommand ); // add observer for event when figure is picked (selected) typedef itk::MemberCommand< QmitkFiberfoxView > MemberCommandType; MemberCommandType::Pointer selectCommand = MemberCommandType::New(); selectCommand->SetCallbackFunction( this, &QmitkFiberfoxView::PlanarFigureSelected ); data.m_SelectObserverTag = figure->AddObserver( mitk::SelectPlanarFigureEvent(), selectCommand ); // add observer for event when interaction with figure starts SimpleCommandType::Pointer startInteractionCommand = SimpleCommandType::New(); startInteractionCommand->SetCallbackFunction( this, &QmitkFiberfoxView::DisableCrosshairNavigation); data.m_StartInteractionObserverTag = figure->AddObserver( mitk::StartInteractionPlanarFigureEvent(), startInteractionCommand ); // add observer for event when interaction with figure starts SimpleCommandType::Pointer endInteractionCommand = SimpleCommandType::New(); endInteractionCommand->SetCallbackFunction( this, &QmitkFiberfoxView::EnableCrosshairNavigation); data.m_EndInteractionObserverTag = figure->AddObserver( mitk::EndInteractionPlanarFigureEvent(), endInteractionCommand ); m_DataNodeToPlanarFigureData[nonConstNode] = data; } } void QmitkFiberfoxView::PlanarFigureSelected( itk::Object* object, const itk::EventObject& ) { mitk::TNodePredicateDataType::Pointer isPf = mitk::TNodePredicateDataType::New(); mitk::DataStorage::SetOfObjects::ConstPointer allPfs = this->GetDataStorage()->GetSubset( isPf ); for ( mitk::DataStorage::SetOfObjects::const_iterator it = allPfs->begin(); it!=allPfs->end(); ++it) { mitk::DataNode* node = *it; if( node->GetData() == object ) { node->SetSelected(true); m_SelectedFiducial = node; } else node->SetSelected(false); } UpdateGui(); this->RequestRenderWindowUpdate(); } void QmitkFiberfoxView::SetFocus() { m_Controls->m_CircleButton->setFocus(); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxViewControls.ui index c04a7f4127..b8a746e398 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxViewControls.ui @@ -1,1926 +1,1950 @@ QmitkFiberfoxViewControls 0 0 493 1140 Form 0 Fiber Definition Qt::Vertical 20 40 color: rgb(255, 0, 0); Please select an image or an existing fiber bundle to draw the fiber fiducials. If you can't provide a suitable image, generate one using the "Signal Generation" tab. Qt::AutoText Qt::AlignJustify|Qt::AlignVCenter true Fiducial Options All fiducials are treated as circles with the same radius as the first fiducial. Use Constant Fiducial Radius false false Align selected fiducials with voxel grid. Shifts selected fiducials to nearest voxel center. Align With Grid Operations false Copy Bundles false Transform Selection QFrame::NoFrame QFrame::Raised 0 Y false Rotation angle (in degree) around x-axis. -360.000000000000000 360.000000000000000 0.100000000000000 Axis: false Rotation angle (in degree) around y-axis. -360.000000000000000 360.000000000000000 0.100000000000000 Translation: false Translation (in mm) in direction of the z-axis. -100.000000000000000 100.000000000000000 0.100000000000000 Translation (in mm) in direction of the y-axis. -100.000000000000000 100.000000000000000 0.100000000000000 X false Rotation: false Z false Rotation angle (in degree) around z-axis. -360.000000000000000 360.000000000000000 0.100000000000000 Translation (in mm) in direction of the x-axis. -100.000000000000000 100.000000000000000 0.100000000000000 Scaling: false Scaling factor for selected fiber bundle along the x-axis. 0.010000000000000 1.000000000000000 0.010000000000000 1.000000000000000 Scaling factor for selected fiber bundle along the y-axis. 0.010000000000000 1.000000000000000 0.010000000000000 1.000000000000000 Scaling factor for selected fiber bundle along the z-axis. 0.010000000000000 1.000000000000000 0.010000000000000 1.000000000000000 false Join Bundles If checked, the fiducials belonging to the modified bundle are also modified. Include Fiducials true Fiber Options QFrame::NoFrame QFrame::Raised 0 QFrame::NoFrame QFrame::Raised 0 Tension: false Fiber Sampling: false 3 -1.000000000000000 1.000000000000000 0.100000000000000 0.000000000000000 Fiber sampling points (per cm) 1 100 1 10 3 -1.000000000000000 1.000000000000000 0.100000000000000 0.000000000000000 Bias: false Continuity: false 3 -1.000000000000000 1.000000000000000 0.100000000000000 0.000000000000000 QFrame::NoFrame QFrame::Raised QFormLayout::AllNonFixedFieldsGrow 6 0 #Fibers: false Specify number of fibers to generate for the selected bundle. 1 1000000 100 100 false Generate Fibers QFrame::NoFrame QFrame::Raised 0 Select fiber distribution inside of the fiducials. Uniform Gaussian Fiber Distribution: false Variance of the gaussian 3 0.001000000000000 10.000000000000000 0.010000000000000 0.100000000000000 QFrame::NoFrame QFrame::Raised 0 Disable to only generate fibers if "Generate Fibers" button is pressed. Real Time Fibers true Disable to only generate fibers if "Generate Fibers" button is pressed. Advanced Options false QFrame::NoFrame QFrame::Raised 0 false 30 30 Draw elliptical fiducial. :/QmitkDiffusionImaging/circle.png:/QmitkDiffusionImaging/circle.png 32 32 false true false 30 30 Flip fiber waypoints of selcted fiducial around one axis. :/QmitkDiffusionImaging/refresh.xpm:/QmitkDiffusionImaging/refresh.xpm 32 32 false true Qt::Horizontal 40 20 Signal Generation Data Fiber Bundle: false <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> true Tissue Mask: false <html><head/><body><p><span style=" color:#969696;">optional</span></p></body></html> true Noise and Artifacts true QFrame::NoFrame QFrame::Raised 6 0 k-Space Undersampling: false Image is upsampled using this factor, afterwards fourier transformed, cropped to the original size and then inverse fourier transformed. 1 2 4 8 16 32 64 128 256 Add T2 Blurring false QFrame::NoFrame QFrame::Raised 0 SNR: Signal to noise ratio (for values > 99, no noise at all is added to the image). Value relative to the fiber signal scaling factor. 4 0.000000000000000 100.000000000000000 0.001000000000000 25.000000000000000 true QFrame::NoFrame QFrame::Raised 0 Fiber T2: false T2 of fiber tissue (in milliseconds). 1 10000 1 90 Non Fiber T2: false T2 of non-fiber tissue (in milliseconds). 1 10000 1 2200 Add Gibbs Ringing false true Start DWI generation from selected fiebr bundle. If no fiber bundle is selected, a grayscale image containing a simple gradient is generated. Generate Image Intra-axonal Compartment false false QFrame::NoFrame QFrame::Raised 0 Determins anisotropy of kernel tensor (zeppelin-model). 0.010000000000000 1.000000000000000 0.100000000000000 0.700000000000000 Fractional Anisotropy: Select signal model for intra-axonal compartment. Zeppelin Model Stick Model QFrame::NoFrame QFrame::Raised 0 Signal Scale: false Scaling factor for intra-axonal signal. 0 10000 1 200 QFrame::NoFrame QFrame::Raised 0 Diffusivity parameter of the stick-model. 4 0.000100000000000 1.000000000000000 0.000500000000000 0.005000000000000 Diffusivity: Image Settings QFrame::NoFrame QFrame::Raised 0 3 0.100000000000000 50.000000000000000 0.100000000000000 2.500000000000000 Image Spacing: 3 0.100000000000000 50.000000000000000 0.100000000000000 2.500000000000000 3 0.100000000000000 50.000000000000000 0.100000000000000 2.500000000000000 Image Dimensions: Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions. 1 1000 1 32 Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions. 1 100 1 32 Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions. 1 100 1 5 QFrame::NoFrame QFrame::Raised QFormLayout::AllNonFixedFieldsGrow 6 6 0 #Gradient Directions: Number of gradient directions distributed over the half sphere. 0 10000 1 60 b-Value: false b-value in mm/s² 0 10000 100 1000 Repetitions: Number of signal averages. Increase to reduce noise. 1 100 1 1 + + + + Interpolation Shrink: + + + + + + + Large values shrink (towards nearest neighbour interpolation), small values strech interpolation function (towards linear interpolation). + + + 1 + + + 10000 + + + 10 + + + color: rgb(255, 0, 0); Using mask image geometry! Treat voxel content as fiber-only if at least one fiber is present. Enforce Pure Fiber Voxels false color: rgb(255, 0, 0); Using gradients of selected DWI! Output k-Space Image false Qt::Vertical 20 40 Extra-axonal Compartment Select signal model for extra-axonal compartment. Ball Model QFrame::NoFrame QFrame::Raised 0 Diffusivity: Diffusivity parameter of the ball-model. 4 0.000100000000000 1.000000000000000 0.000500000000000 0.001000000000000 Signal Scale: false Scaling factor extra-axonal signal. 0 10000 1 100 + tabWidget m_CircleButton m_FlipButton m_RealTimeFibers m_AdvancedFiberOptionsBox m_DistributionBox m_VarianceBox m_FiberDensityBox m_FiberSamplingBox m_TensionBox m_ContinuityBox m_BiasBox m_GenerateFibersButton m_ConstantRadiusBox m_AlignOnGrid m_XrotBox m_YrotBox m_ZrotBox m_XtransBox m_YtransBox m_ZtransBox m_XscaleBox m_YscaleBox m_ZscaleBox m_TransformBundlesButton m_CopyBundlesButton m_JoinBundlesButton m_IncludeFiducials m_GenerateImageButton m_SizeX m_SizeY m_SizeZ m_SpacingX m_SpacingY m_SpacingZ m_NumGradientsBox m_BvalueBox m_RepetitionsBox + m_InterpolationShrink m_EnforcePureFiberVoxelsBox m_KspaceImageBox m_FiberCompartmentModelBox m_TensorFaBox m_StickDiffusivityBox m_FiberS0Box m_NonFiberCompartmentModelBox m_BallD m_NonFiberS0Box m_NoiseLevel m_AddT2Smearing m_FiberRelaxationT2Box m_NonFiberRelaxationT2Box m_AddGibbsRinging m_KspaceUndersamplingBox - tabWidget diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkGibbsTrackingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkGibbsTrackingViewControls.ui index 8e0c1595a5..539502c5c4 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkGibbsTrackingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkGibbsTrackingViewControls.ui @@ -1,1082 +1,1088 @@ QmitkGibbsTrackingViewControls 0 0 463 1011 0 0 0 0 QmitkTemplate QFormLayout::AllNonFixedFieldsGrow Please Select Input Data Q-Ball/Tensor Image: Mandatory input <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> + + true + Mask Image: Optional input to limit the algorithms search space. <html><head/><body><p><span style=" color:#969696;">optional</span></p></body></html> + + true + QFrame::NoFrame QFrame::Plain 0 0 0 false No Q-Ball image selected. Qt::LeftToRight Start Tractography :/qmitk/play.xpm:/qmitk/play.xpm false Qt::LeftToRight Stop Tractography :/qmitk/stop.xpm:/qmitk/stop.xpm Parameters 0 Iterations: 10^7 Specify number of iterations for the tracking algorithm. 9 6 Qt::Horizontal QSlider::TicksBelow true Activate continuous visualization of intermediate results. Visualize Tractography true Visualize intermediate result. :/QmitkDiffusionImaging/Refresh_48.png:/QmitkDiffusionImaging/Refresh_48.png true Advanced Settings Output File: QFrame::NoFrame QFrame::Plain 0 0 0 Select output file name and folder. ... N/A true true QFrame::StyledPanel QFrame::Raised 9 0 9 0 4 Particle Width: 0 Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 0.1 Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Particle Weight: 1 99 1 10 Qt::Horizontal QSlider::NoTicks Start Temperature: automatic estimation from gfa map and q-ball data. 0 1000 1 0 Qt::Horizontal true QSlider::NoTicks IE Bias < 0 < EE Bias -50 50 1 Qt::Horizontal QSlider::NoTicks 0.001 Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Curvature Threshold: Balance In/Ex Energy: 45° Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter auto = 0.5 * min. spacing; sigma 100 1 Qt::Horizontal QSlider::NoTicks Particle Length: auto Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Min. Fiber Length: Only fibers longer than specified are accepted. 500 1 40 Qt::Horizontal QSlider::NoTicks Allow only fiber curvature values smaller than the selected threshold. 180 1 45 Qt::Horizontal QSlider::NoTicks End Temperature: 40mm Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter auto Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 1 100 1 10 Qt::Horizontal false false QSlider::NoTicks auto Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter auto = 1.5 * min. spacing; l 100 1 Qt::Horizontal QSlider::NoTicks Random Seed auto Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter auto = 1.5 * min. spacing; l -1 100 1 -1 Qt::Horizontal QSlider::NoTicks QFrame::NoFrame QFrame::Plain 0 0 0 true Save current parameters as xml (.gtp) Qt::LeftToRight Save Parameters :/qmitk/btnMoveDown.png:/qmitk/btnMoveDown.png true Load parameters from xml file (.gtp) Qt::LeftToRight Load Parameters :/qmitk/btnMoveUp.png:/qmitk/btnMoveUp.png Monitor Progress: - Will only be updated if tracking is visualized Will only be updated if tracking is visualized Accepted Fibers: Connections: Particles: Proposal Acceptance Rate: Tracking Time: Will only be updated if tracking is visualized - - - - - Qt::Vertical QSizePolicy::Expanding 0 0 diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkODFDetailsViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkODFDetailsViewControls.ui index 5d21d510aa..0d3b3707e6 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkODFDetailsViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkODFDetailsViewControls.ui @@ -1,205 +1,208 @@ QmitkODFDetailsViewControls 0 0 351 734 0 0 QmitkTemplate 6 9 Please Select Input Data DTI/QBI: <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> + + true + Overview 0 9 0 0 0 0 0 0 true 0 0 200 200 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 ODF Values true 0 0 0 200 Qt::Vertical QSizePolicy::Expanding 20 220 QmitkODFDetailsWidget QWidget
    QmitkODFDetailsWidget.h
    1
    QmitkODFRenderWidget QWidget
    QmitkODFRenderWidget.h
    1
    diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkOdfMaximaExtractionViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkOdfMaximaExtractionViewControls.ui index d89adae693..22858ce939 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkOdfMaximaExtractionViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkOdfMaximaExtractionViewControls.ui @@ -1,473 +1,479 @@ QmitkOdfMaximaExtractionViewControls 0 0 392 761 Form false Extract ODF peaks using a semicontinuous method (Aganj et al. 2010). EXPERIMENTAL! Start Analytical Extraction (only SH order 4) Please Select Input Data Select a tensor image or a SH coefficient image (generate using Q-Ball reconstruction view). ShCoeff/DTI: Mask Image: <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> + + true + <html><head/><body><p><span style=" color:#969696;">optional</span></p></body></html> + + true + Parameters QFrame::NoFrame QFrame::Raised 0 6 Vector normalization: <html><head/><body><p>The vector fields are always coorected for image spacing and using the lagest eigenvalue in case of the tensor peak extraction. This is done for visualizytion purposes. The output direction images are not affected.</p></body></html> 1 No Normalization MAX Normalize Single Vec Normalization false QFrame::NoFrame QFrame::Raised 0 6 SH Order: Absolute threshold: false Absolute peak threshold (only used for the finite differences method). The value is additionally scaled by 1/GFA. 3 0.000000000000000 1.000000000000000 0.001000000000000 0.010000000000000 Max. Peaks: false Peak threshold relative to the largest peak per voxel. 0.000000000000000 1.000000000000000 0.050000000000000 0.400000000000000 false Maximum number of peaks to extract. 1 1000 3 Relative threshold: false 1 2 4 6 8 10 12 Clustering angle: Cluster close directions. Define "close" here. 90 25 Angular threshold: Discard smaller peaks in the defined angle around the maximum peaks. 0 90 0 Qt::Vertical 20 259 Import From Other Tools false Generate Q-Ball image and MITK compatible SH coefficient from other toolkits. Import SH - Coefficients Define SH coefficient convention (depends on toolkit) FSL MRtrix false Generate vector field and direction images from the FSL qboot peak extraction output. Import Peak Image false Extract ODF peaks using finite differences on the densely sampled ODF surface. Start Finite Differences Extraction false Extract principal eigenvectors of input tensors. Start Tensor Principal Direction Extraction Output QFormLayout::AllNonFixedFieldsGrow Only for visualization purposes! The vectors are automatically corrected for image spacing and for the largest eigenvalue in case of the tensor peak extraction. Vector Field true Output unsigned char image containing the number of directions per voxel. #Directions per Voxel false Output one image per extracted direction containing the direction vecors as pixel values. Direction Images false diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkPreprocessingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkPreprocessingViewControls.ui index 89790ae3f1..c818538c87 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkPreprocessingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkPreprocessingViewControls.ui @@ -1,546 +1,549 @@ QmitkPreprocessingViewControls 0 0 892 1079 0 0 false QmitkPreprocessingViewControls true Please Select Input Data Raw DWI: <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> + + true + 0 0 Info 0 0 Qt::ScrollBarAsNeeded Qt::ScrollBarAlwaysOff true 100 true false true b-Value Number of gradients Qt::Horizontal 40 20 false Generate pointset displaying the gradient vectors (applied measurement frame). Show gradients Non diffusion weighted image 0 30 Average and extract all images that were acquired without diffusion weighting. true false If multiple baseline acquisitions are present, the default behaviour is to output an averaged image. Extract B0 Create a 3D+t data set containing all b0 images as timesteps Extract all B0 images without averaging Modify DWI QFrame::NoFrame QFrame::Raised 0 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 "Merge radius" > 0 is configured. 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 "Merge radius" > 0 is configured. 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 "Merge radius" > 0 is configured. 6 2.000000000000000 0.000100000000000 0.001000000000000 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 "Merge radius" > 0 is configured. 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 "Merge radius" > 0 is configured. 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 "Merge radius" > 0 is configured. Merge radius false Multiple acquistions of one gradient direction can be averaged. Due to rounding errors, similar gradients often differ in the last decimal positions. The Merge radius allows to average them by taking all directions within a certain radius into account. Average redundant gradients Qt::Horizontal QFrame::NoFrame QFrame::Raised 0 9 Specify desired number of gradients per shell: false Retain only the specified number of gradient directions and according image volumes. The retained directions are spread equally over the half sphere using an iterative energy repulsion strategy. Reduce number of gradients Qt::Horizontal false Sometimes the gradient directions are not located on one half sphere. Mirror gradients to half sphere Merge selected images false Merges selected DWIs of same dimension. If several b-values are present, the resulting image will contain multiple b-shells. Merge selected DWIs 0 0 Measurment frame Qt::Horizontal 40 20 false 0 0 0 0 IBeamCursor true Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff true false false true true 0 false true true New Row New Row New Row New Column New Column New Column false Apply new mesurement frame Qt::Vertical 20 40 diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkQBallReconstructionViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkQBallReconstructionViewControls.ui index 2fd8a33444..16f500cf6e 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkQBallReconstructionViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkQBallReconstructionViewControls.ui @@ -1,329 +1,332 @@ QmitkQBallReconstructionViewControls 0 0 372 844 0 0 true QmitkQBallReconstructionViewControls Please Select Input Data Input for Q-Ball reconstruction. Raw DWI: Input for Q-Ball reconstruction. <font color='red'>mandatory</font> + + true + Parameters Advanced Settings QFrame::StyledPanel QFrame::Raised QFrame::NoFrame QFrame::Raised 0 true B0 Threshold false QFrame::NoFrame QFrame::Raised 0 QFrame::NoFrame QFrame::Raised 0 true Regularization Parameter Lambda: false true Maximum l-Level: false true -1 true Spherical Harmonics: 3 1.000000000000000 0.001000000000000 0.006000000000000 Output SH-Coefficient Image <html><head/><body><p>Only for a dataset with 3 Shells and an arethmetic progression (e.g. b1=1000, b2=2000, b3=3000 ).</p><p>Weightings will be applied on the interpolated directions.</p></body></html> Use Shell Weights 2 Numerical Standard Solid Angle Constraint Solid Angle ADC-Profile only Raw Signal only Multi-Shell TextLabel false Start Reconstruction true Qt::LeftToRight false Multi-Shell Reconstruction Qt::Vertical 20 0 diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStochasticFiberTrackingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStochasticFiberTrackingViewControls.ui index 4feba4a624..5e9e080193 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStochasticFiberTrackingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStochasticFiberTrackingViewControls.ui @@ -1,209 +1,215 @@ QmitkStochasticFiberTrackingViewControls 0 0 340 258 0 0 QmitkTemplate 3 3 0 false Start Tractography Qt::Vertical QSizePolicy::Expanding 20 220 Parameters Maximum tract length in #voxel. 1 500 100 Qt::Horizontal Maximum tract length in #voxel. Max. Tract Length: 100 Number of tracts started in each voxel of the seed ROI. Seeds per Voxel: 1 Likelihood cache in Megabytes. Max. Chache Size: 1GB Number of tracts started in each voxel of the seed ROI. 1 10000 Qt::Horizontal Likelihood cache in Megabytes. 1 10 1 Qt::Horizontal Qt::Horizontal QSizePolicy::Fixed 200 0 Please Select Input Data Raw DWI: <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> + + true + Seed ROI: <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> + + true + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingViewControls.ui index 3eddac0906..70c7894995 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingViewControls.ui @@ -1,361 +1,370 @@ QmitkStreamlineTrackingViewControls 0 0 368 449 0 0 QmitkTemplate 3 3 0 Qt::Vertical QSizePolicy::Expanding 20 220 false Start Tractography Parameters f: 1 g: 0 Qt::Horizontal QSizePolicy::Fixed 200 0 Step Size: auto Weighting factor between first eigenvector (f=1 equals FACT tracking) and input vector dependent direction (f=0). 0 100 100 Qt::Horizontal Stepsize in mm (auto = 0.1*minimal spacing) 0 100 0 Qt::Horizontal FA Threshold: 0.2 Weighting factor between input vector (g=0) and tensor deflection (g=1 equals TEND tracking) 0 100 0 Qt::Horizontal Seeds per Voxel: 1 Number of tracts started in each voxel of the seed ROI. 1 100 Qt::Horizontal Default is nearest neighbor interpolation. Enable trilinear interpolation false Minimally allowed curcature radius (in mm, interpolated auto = 0.5 minimal spacing, noninterpolated auto = 0.1 minimal spacing) -1 50 -1 Qt::Horizontal Min. Tract Length: 40mm Fractional Anisotropy Threshold 0 100 20 Qt::Horizontal Minimum tract length in mm. 0 500 40 Qt::Horizontal Min. Curvature Radius: auto Please Select Input Data <html><head/><body><p><span style=" color:#969696;">optional</span></p></body></html> + + true + Binary seed ROI. If not specified, the whole image area is seeded. Seed ROI: Input DTI Tensor Image: <html><head/><body><p><span style=" color:#969696;">optional</span></p></body></html> + + true + Only track insida mask area. Mask Image: <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> + + true + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkTensorReconstructionViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkTensorReconstructionViewControls.ui index 692fa967fa..9a3caa0579 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkTensorReconstructionViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkTensorReconstructionViewControls.ui @@ -1,514 +1,517 @@ QmitkTensorReconstructionViewControls 0 0 380 1002 0 0 true QmitkTensorReconstructionViewControls Please Select Input Data: <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> + + true + Raw DWI/DTI: Tensor Reconstruction Advanced Settings false QFrame::StyledPanel QFrame::Raised 9 QFrame::NoFrame QFrame::Raised 0 B0 Threshold false 10000 Only influences WLS reconstruction Ignore voxels with negative eigenvalues 0 Weighted Linear Least Squares With correction for negative eigenvalues false Select raw DWI! Start Reconstruction Estimate Diffusion Image from Tensors QFrame::NoFrame QFrame::Raised QFormLayout::AllNonFixedFieldsGrow 6 6 0 how fuzzy the confidence boundary should be. By default, confidence boundary is perfectly sharp (float); default: "0" how fuzzy the confidence boundary should be. By default, confidence boundary is perfectly sharp (float); default: "0" how fuzzy the confidence boundary should be. By default, confidence boundary is perfectly sharp (float); default: "0" B-Value false #Gradient Directions 3 12 42 92 162 252 362 492 642 812 1002 10000 100 1000 false Start DWI Estimation Estimate Q-Ball Image from Tensors false Calculate ODF value as tensor value in the according direction Start QBI Estimation Estimate Residuals false false false percentages of error 1 Per volume 200 300 Per slice outliers per slice QFrame::NoFrame QFrame::Raised 0 300 400 QFrame::NoFrame QFrame::Raised 0 20 255 Volume: .., Slice:.. false Calculate the residual from a dti and a dwi image Residual Image Calculation QmitkResidualAnalysisWidget QWidget
    QmitkResidualAnalysisWidget.h
    1
    QmitkResidualViewWidget QGraphicsView
    QmitkResidualViewWidget.h
    diff --git a/Plugins/org.mitk.gui.qt.simulation/files.cmake b/Plugins/org.mitk.gui.qt.simulation/files.cmake index 74291cf11e..342a0f859e 100644 --- a/Plugins/org.mitk.gui.qt.simulation/files.cmake +++ b/Plugins/org.mitk.gui.qt.simulation/files.cmake @@ -1,36 +1,39 @@ set(SRC_CPP_FILES ) set(INTERNAL_CPP_FILES org_mitk_gui_qt_simulation_Activator.cpp + QmitkSimulationPreferencePage.cpp QmitkSimulationView.cpp ) set(UI_FILES + src/internal/QmitkSimulationPreferencePageControls.ui src/internal/QmitkSimulationViewControls.ui ) set(MOC_H_FILES src/internal/org_mitk_gui_qt_simulation_Activator.h + src/internal/QmitkSimulationPreferencePage.h src/internal/QmitkSimulationView.h ) set(CACHED_RESOURCE_FILES resources/icon.png plugin.xml ) set(QRC_FILES resources/Simulation.qrc ) set(CPP_FILES ) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach() foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach() diff --git a/Plugins/org.mitk.gui.qt.simulation/plugin.xml b/Plugins/org.mitk.gui.qt.simulation/plugin.xml index 36271f5cd6..b16639779a 100644 --- a/Plugins/org.mitk.gui.qt.simulation/plugin.xml +++ b/Plugins/org.mitk.gui.qt.simulation/plugin.xml @@ -1,9 +1,14 @@ + + + diff --git a/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationPreferencePage.cpp b/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationPreferencePage.cpp new file mode 100644 index 0000000000..d22ca55d04 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationPreferencePage.cpp @@ -0,0 +1,244 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "QmitkSimulationPreferencePage.h" +#include +#include +#include +#include +#include + +typedef sofa::helper::system::Plugin Plugin; +typedef sofa::helper::system::PluginManager PluginManager; +typedef sofa::helper::system::PluginManager::PluginIterator PluginIterator; +typedef sofa::helper::system::PluginManager::PluginMap PluginMap; + +berry::IPreferences::Pointer getSimulationPreferences() +{ + berry::ServiceRegistry& serviceRegistry = berry::Platform::GetServiceRegistry(); + berry::IPreferencesService::Pointer preferencesService = serviceRegistry.GetServiceById(berry::IPreferencesService::ID); + berry::IPreferences::Pointer preferences = preferencesService->GetSystemPreferences(); + return preferences->Node("/org.mitk.views.simulation"); +} + +void initSOFAPlugins(berry::IPreferences::Pointer preferences) +{ + if (preferences.IsNull()) + return; + + QString pluginPaths = preferences->GetByteArray(QmitkSimulationPreferencePage::PLUGIN_PATHS, "").c_str(); + + if (pluginPaths.isEmpty()) + return; + + QStringList pluginPathList = pluginPaths.split(';', QString::SkipEmptyParts); + QStringListIterator it(pluginPathList); + + typedef sofa::helper::system::PluginManager PluginManager; + PluginManager& pluginManager = PluginManager::getInstance(); + + while (it.hasNext()) + { + std::string path = it.next().toStdString(); + std::ostringstream errlog; + + pluginManager.loadPlugin(path, &errlog); + + if (errlog.str().empty()) + pluginManager.getPluginMap()[path].initExternalModule(); + } +} + +const std::string QmitkSimulationPreferencePage::PLUGIN_PATHS = "plugin paths"; + +QmitkSimulationPreferencePage::QmitkSimulationPreferencePage() + : m_Preferences(getSimulationPreferences()), + m_Control(NULL) +{ + initSOFAPlugins(m_Preferences); +} + +QmitkSimulationPreferencePage::~QmitkSimulationPreferencePage() +{ +} + +void QmitkSimulationPreferencePage::CreateQtControl(QWidget* parent) +{ + m_Control = new QWidget(parent); + m_Controls.setupUi(m_Control); + + QStringList headerLabels; + headerLabels << "Name" << "License" << "Version" << "Path"; + m_Controls.pluginsTreeWidget->setHeaderLabels(headerLabels); + + connect(m_Controls.pluginsTreeWidget, SIGNAL(itemSelectionChanged()), this, SLOT(OnPluginTreeWidgetItemSelectionChanged())); + connect(m_Controls.addButton, SIGNAL(clicked()), this, SLOT(OnAddButtonClicked())); + connect(m_Controls.removeButton, SIGNAL(clicked()), this, SLOT(OnRemoveButtonClicked())); + + this->Update(); +} + +QWidget* QmitkSimulationPreferencePage::GetQtControl() const +{ + return m_Control; +} + +void QmitkSimulationPreferencePage::Init(berry::IWorkbench::Pointer) +{ +} + +void QmitkSimulationPreferencePage::OnAddButtonClicked() +{ + QString filter = "SOFA Plugins "; + +#if defined(__APPLE__) + filter += "(*.dylib*)"; +#elif defined(WIN32) + filter += "(*.dll)"; +#else + filter += "(*.so)"; +#endif + + std::string path = QFileDialog::getOpenFileName(m_Control, "Add SOFA Library", "", filter).toStdString(); + + PluginManager &pluginManager = PluginManager::getInstance(); + std::ostringstream errlog; + + if (pluginManager.loadPlugin(path, &errlog)) + { + if (!errlog.str().empty()) + { + QMessageBox* messageBox = new QMessageBox(m_Control); + messageBox->setIcon(QMessageBox::Warning); + messageBox->setStandardButtons(QMessageBox::Ok); + messageBox->setText(errlog.str().c_str()); + messageBox->setWindowTitle("Warning"); + messageBox->show(); + } + + Plugin& plugin = pluginManager.getPluginMap()[path]; + plugin.initExternalModule(); + + QStringList pluginItem; + + pluginItem + << plugin.getModuleName() + << plugin.getModuleLicense() + << plugin.getModuleVersion() + << path.c_str(); + + m_Controls.pluginsTreeWidget->addTopLevelItem(new QTreeWidgetItem(pluginItem)); + } + else + { + QMessageBox* messageBox = new QMessageBox(m_Control); + messageBox->setIcon(QMessageBox::Critical); + messageBox->setStandardButtons(QMessageBox::Ok); + messageBox->setText(errlog.str().c_str()); + messageBox->setWindowTitle("Error"); + messageBox->show(); + } +} + +void QmitkSimulationPreferencePage::OnPluginTreeWidgetItemSelectionChanged() +{ + QList selectedItems = m_Controls.pluginsTreeWidget->selectedItems(); + + if (!selectedItems.isEmpty()) + { + PluginMap& pluginMap = sofa::helper::system::PluginManager::getInstance().getPluginMap(); + std::string path = selectedItems[0]->text(3).toStdString(); + + m_Controls.descriptionPlainTextEdit->setPlainText(pluginMap[path].getModuleDescription()); + m_Controls.removeButton->setEnabled(true); + } + else + { + m_Controls.descriptionPlainTextEdit->clear(); + m_Controls.componentsListWidget->clear(); + m_Controls.removeButton->setEnabled(false); + } +} + +void QmitkSimulationPreferencePage::OnRemoveButtonClicked() +{ + QList selectedItems = m_Controls.pluginsTreeWidget->selectedItems(); + + if (selectedItems.isEmpty()) + return; + + std::string path = selectedItems[0]->text(3).toStdString(); + + PluginManager& pluginManager = PluginManager::getInstance(); + std::ostringstream errlog; + + if (pluginManager.unloadPlugin(path, &errlog)) + { + delete selectedItems[0]; + } + else + { + QMessageBox* messageBox = new QMessageBox(m_Control); + messageBox->setIcon(QMessageBox::Critical); + messageBox->setStandardButtons(QMessageBox::Ok); + messageBox->setText(errlog.str().c_str()); + messageBox->setWindowTitle("Error"); + messageBox->show(); + } +} + +void QmitkSimulationPreferencePage::PerformCancel() +{ +} + +bool QmitkSimulationPreferencePage::PerformOk() +{ + PluginManager& pluginManager = PluginManager::getInstance(); + PluginMap& pluginMap = pluginManager.getPluginMap(); + std::string pluginPaths; + + for (PluginIterator it = pluginMap.begin(); it != pluginMap.end(); ++it) + { + if (!pluginPaths.empty()) + pluginPaths += ";"; + + pluginPaths += it->first; + } + + m_Preferences->PutByteArray(PLUGIN_PATHS, pluginPaths); + return true; +} + +void QmitkSimulationPreferencePage::Update() +{ + PluginManager& pluginManager = PluginManager::getInstance(); + PluginMap& pluginMap = pluginManager.getPluginMap(); + + for (PluginIterator it = pluginMap.begin(); it != pluginMap.end(); ++it) + { + Plugin& plugin = it->second; + + QStringList pluginItem; + + pluginItem + << plugin.getModuleName() + << plugin.getModuleLicense() + << plugin.getModuleVersion() + << it->first.c_str(); + + m_Controls.pluginsTreeWidget->addTopLevelItem(new QTreeWidgetItem(pluginItem)); + } +} diff --git a/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationPreferencePage.h b/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationPreferencePage.h new file mode 100644 index 0000000000..484c855305 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationPreferencePage.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 QmitkSimulationPreferencePage_h +#define QmitkSimulationPreferencePage_h + +#include +#include +#include +#include + +berry::IPreferences::Pointer getSimulationPreferences(); +void initSOFAPlugins(berry::IPreferences::Pointer preferences = getSimulationPreferences()); + +class SIMULATION_EXPORT QmitkSimulationPreferencePage : public QObject, public berry::IQtPreferencePage +{ + Q_OBJECT + Q_INTERFACES(berry::IPreferencePage) + +public: + static const std::string PLUGIN_PATHS; + + QmitkSimulationPreferencePage(); + ~QmitkSimulationPreferencePage(); + + void CreateQtControl(QWidget* parent); + QWidget* GetQtControl() const; + void Init(berry::IWorkbench::Pointer workbench); + void PerformCancel(); + bool PerformOk(); + void Update(); + +private slots: + void OnAddButtonClicked(); + void OnPluginTreeWidgetItemSelectionChanged(); + void OnRemoveButtonClicked(); + +private: + berry::IPreferences::Pointer m_Preferences; + QWidget* m_Control; + Ui::QmitkSimulationPreferencePageControls m_Controls; +}; + +#endif diff --git a/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationPreferencePageControls.ui b/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationPreferencePageControls.ui new file mode 100644 index 0000000000..a7320be2ce --- /dev/null +++ b/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationPreferencePageControls.ui @@ -0,0 +1,157 @@ + + + QmitkSimulationPreferencePageControls + + + + 0 + 0 + 640 + 480 + + + + + + + Plugins + + + + + + + QAbstractItemView::NoEditTriggers + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + 0 + + + false + + + false + + + true + + + false + + + 4 + + + false + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + + + + + + Components + + + + + + + Description + + + + + + + true + + + + + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::NoSelection + + + QAbstractItemView::SelectRows + + + true + + + + + + + + + + + Add... + + + + + + + false + + + Remove + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationView.cpp b/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationView.cpp index 3d99571142..d54415ee0d 100644 --- a/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationView.cpp +++ b/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationView.cpp @@ -1,158 +1,263 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ +#include "QmitkSimulationPreferencePage.h" #include "QmitkSimulationView.h" +#include #include #include #include +#include #include +static void InitializeViews(mitk::IRenderWindowPart* renderWindowPart, mitk::Geometry3D* geometry) +{ + if (renderWindowPart == NULL || geometry == NULL) + return; + + mitk::IRenderingManager* renderingManager = renderWindowPart->GetRenderingManager(); + + if (renderingManager != NULL) + renderingManager->InitializeViews(geometry, mitk::RenderingManager::REQUEST_UPDATE_ALL, true); +} + QmitkSimulationView::QmitkSimulationView() - : m_Timer(this) + : m_SelectionWasRemovedFromDataStorage(false), + m_Timer(this) { + this->GetDataStorage()->RemoveNodeEvent.AddListener( + mitk::MessageDelegate1(this, &QmitkSimulationView::OnNodeRemovedFromDataStorage)); + connect(&m_Timer, SIGNAL(timeout()), this, SLOT(OnTimerTimeout())); + initSOFAPlugins(); } QmitkSimulationView::~QmitkSimulationView() { + this->GetDataStorage()->RemoveNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkSimulationView::OnNodeRemovedFromDataStorage)); } void QmitkSimulationView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); - m_Controls.cmbSimulation->SetDataStorage(this->GetDataStorage()); - m_Controls.cmbSimulation->SetPredicate(mitk::NodePredicateDataType::New("Simulation")); + m_Controls.simulationComboBox->SetDataStorage(this->GetDataStorage()); + m_Controls.simulationComboBox->SetPredicate(mitk::NodePredicateDataType::New("Simulation")); + + m_Controls.stepsRecordedLabel->hide(); - connect(m_Controls.btnAnimate, SIGNAL(toggled(bool)), this, SLOT(OnAnimateButtonToggled(bool))); - connect(m_Controls.btnResetScene, SIGNAL(clicked()), this, SLOT(OnResetSceneButtonClicked())); - connect(m_Controls.btnStep, SIGNAL(clicked()), this, SLOT(OnStepButtonClicked())); - connect(m_Controls.cmbSimulation, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnSimulationComboBoxSelectionChanged(const mitk::DataNode*))); - connect(m_Controls.spnDT, SIGNAL(valueChanged(double)), this, SLOT(OnDTSpinBoxValueChanged(double))); + connect(m_Controls.animateButton, SIGNAL(toggled(bool)), this, SLOT(OnAnimateButtonToggled(bool))); + connect(m_Controls.recordButton, SIGNAL(toggled(bool)), this, SLOT(OnRecordButtonToggled(bool))); + connect(m_Controls.resetButton, SIGNAL(clicked()), this, SLOT(OnResetButtonClicked())); + connect(m_Controls.stepButton, SIGNAL(clicked()), this, SLOT(OnStepButtonClicked())); + connect(m_Controls.simulationComboBox, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnSimulationComboBoxSelectionChanged(const mitk::DataNode*))); + connect(m_Controls.dtSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnDTSpinBoxValueChanged(double))); + connect(m_Controls.snapshotButton, SIGNAL(clicked()), this, SLOT(OnSnapshotButtonClicked())); + + if (m_Controls.simulationComboBox->GetSelectedNode().IsNotNull()) + this->OnSimulationComboBoxSelectionChanged(m_Controls.simulationComboBox->GetSelectedNode()); } void QmitkSimulationView::OnAnimateButtonToggled(bool toggled) { - if (SetSelectionAsCurrentSimulation()) + if (this->SetSelectionAsCurrentSimulation()) { - mitk::Simulation::Pointer simulation = dynamic_cast(m_Controls.cmbSimulation->GetSelectedNode()->GetData()); + mitk::Simulation::Pointer simulation = dynamic_cast(m_Selection->GetData()); sofa::simulation::Simulation::SPtr sofaSimulation = simulation->GetSimulation(); sofa::simulation::Node::SPtr rootNode = simulation->GetRootNode(); rootNode->getContext()->setAnimate(toggled); if (toggled) { - m_Controls.btnStep->setEnabled(false); + m_Controls.stepButton->setEnabled(false); m_Timer.start(0); } } if (!toggled) { m_Timer.stop(); - m_Controls.btnStep->setEnabled(true); + m_Controls.stepButton->setEnabled(true); } } void QmitkSimulationView::OnDTSpinBoxValueChanged(double value) { - if (SetSelectionAsCurrentSimulation()) + if (!this->SetSelectionAsCurrentSimulation()) + return; + + mitk::Simulation::Pointer simulation = dynamic_cast(m_Selection->GetData()); + sofa::simulation::Node::SPtr rootNode = simulation->GetRootNode(); + + rootNode->setDt(value == 0.0 + ? simulation->GetDefaultDT() + : value); +} + +void QmitkSimulationView::OnNodeRemovedFromDataStorage(const mitk::DataNode* node) +{ + if (m_Selection.IsNotNull() && m_Selection.GetPointer() == node) + m_SelectionWasRemovedFromDataStorage = true; +} + +void QmitkSimulationView::OnRecordButtonToggled(bool toggled) +{ + if (!toggled) { - mitk::Simulation::Pointer simulation = dynamic_cast(m_Controls.cmbSimulation->GetSelectedNode()->GetData()); - sofa::simulation::Node::SPtr rootNode = simulation->GetRootNode(); + if (m_Record.IsNotNull()) + { + mitk::DataNode::Pointer dataNode = mitk::DataNode::New(); + dataNode->SetData(m_Record); + dataNode->SetName(m_Record->GetTimeSteps() == 1 ? "Snapshot" : "Record"); - rootNode->setDt(value == 0.0 - ? simulation->GetDefaultDT() - : value); + this->GetDataStorage()->Add(dataNode, m_Selection); + InitializeViews(this->GetRenderWindowPart(), m_Record->GetTimeSlicedGeometry()); + + m_Record = NULL; + } + + m_Controls.stepsRecordedLabel->hide(); + m_Controls.stepsRecordedLabel->setText("0 steps recorded"); + } + else if (toggled) + { + m_Controls.stepsRecordedLabel->show(); } } -void QmitkSimulationView::OnResetSceneButtonClicked() +void QmitkSimulationView::OnResetButtonClicked() { - if (SetSelectionAsCurrentSimulation()) - { - mitk::Simulation::Pointer simulation = dynamic_cast(m_Controls.cmbSimulation->GetSelectedNode()->GetData()); - sofa::simulation::Simulation::SPtr sofaSimulation = simulation->GetSimulation(); - sofa::simulation::Node::SPtr rootNode = simulation->GetRootNode(); + if (!this->SetSelectionAsCurrentSimulation()) + return; - m_Controls.spnDT->setValue(0.0); - sofaSimulation->reset(rootNode.get()); + if (m_Controls.recordButton->isChecked()) + m_Controls.recordButton->setChecked(false); - rootNode->setTime(0.0); - rootNode->execute(sofa::core::ExecParams::defaultInstance()); + mitk::Simulation::Pointer simulation = dynamic_cast(m_Selection->GetData()); + sofa::simulation::Simulation::SPtr sofaSimulation = simulation->GetSimulation(); + sofa::simulation::Node::SPtr rootNode = simulation->GetRootNode(); - simulation->GetDrawTool()->Reset(); + m_Controls.dtSpinBox->setValue(0.0); + sofaSimulation->reset(rootNode.get()); - this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS); - } + rootNode->setTime(0.0); + rootNode->execute(sofa::core::ExecParams::defaultInstance()); + + simulation->GetDrawTool()->Reset(); + + this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS); } void QmitkSimulationView::OnSimulationComboBoxSelectionChanged(const mitk::DataNode* node) { - if (m_Controls.btnAnimate->isChecked()) - m_Controls.btnAnimate->setChecked(false); + if (m_Controls.animateButton->isChecked()) + m_Controls.animateButton->setChecked(false); + + if (m_SelectionWasRemovedFromDataStorage) + { + m_SelectionWasRemovedFromDataStorage = false; + m_Selection = NULL; + } + + if (m_Controls.recordButton->isChecked()) + m_Controls.recordButton->setChecked(false); if (node != NULL) { - m_Controls.grpSimulation->setEnabled(true); + m_Selection = m_Controls.simulationComboBox->GetSelectedNode(); + m_Controls.sceneGroupBox->setEnabled(true); + m_Controls.snapshotButton->setEnabled(true); static_cast(node->GetData())->SetAsActiveSimulation(); } else { - m_Controls.grpSimulation->setEnabled(false); + m_Selection = NULL; + m_Controls.sceneGroupBox->setEnabled(false); + m_Controls.snapshotButton->setEnabled(false); mitk::Simulation::SetActiveSimulation(NULL); } } +void QmitkSimulationView::OnSnapshotButtonClicked() +{ + if (!this->SetSelectionAsCurrentSimulation()) + return; + + mitk::Simulation::Pointer simulation = dynamic_cast(m_Selection->GetData()); + + mitk::Surface::Pointer snapshot = simulation->TakeSnapshot(); + + if (snapshot.IsNull()) + return; + + mitk::DataNode::Pointer snapshotDataNode = mitk::DataNode::New(); + snapshotDataNode->SetData(snapshot); + snapshotDataNode->SetName("Snapshot"); + + this->GetDataStorage()->Add(snapshotDataNode, m_Selection); +} + void QmitkSimulationView::OnStepButtonClicked() { - if (SetSelectionAsCurrentSimulation()) + if (!this->SetSelectionAsCurrentSimulation()) + return; + + mitk::Simulation::Pointer simulation = dynamic_cast(m_Controls.simulationComboBox->GetSelectedNode()->GetData()); + sofa::simulation::Simulation::SPtr sofaSimulation = simulation->GetSimulation(); + sofa::simulation::Node::SPtr rootNode = simulation->GetRootNode(); + + simulation->GetDrawTool()->Reset(); + + sofaSimulation->animate(rootNode.get(), rootNode->getDt()); + + this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS); + + if (m_Controls.recordButton->isChecked()) { - mitk::Simulation::Pointer simulation = dynamic_cast(m_Controls.cmbSimulation->GetSelectedNode()->GetData()); - sofa::simulation::Simulation::SPtr sofaSimulation = simulation->GetSimulation(); - sofa::simulation::Node::SPtr rootNode = simulation->GetRootNode(); + if (m_Record.IsNull()) + m_Record = mitk::Surface::New(); - simulation->GetDrawTool()->Reset(); + simulation->AppendSnapshot(m_Record); - sofaSimulation->animate(rootNode.get(), rootNode->getDt()); + unsigned int numSteps = m_Record->GetTimeSteps(); + QString plural = numSteps != 1 ? "s" : ""; - this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS); + m_Controls.stepsRecordedLabel->setText(QString("%1 step%2 recorded").arg(numSteps).arg(plural)); } } void QmitkSimulationView::SetFocus() { - m_Controls.btnAnimate->setFocus(); + m_Controls.animateButton->setFocus(); } bool QmitkSimulationView::SetSelectionAsCurrentSimulation() const { - mitk::DataNode::Pointer selectedNode = m_Controls.cmbSimulation->GetSelectedNode(); - - if (selectedNode.IsNotNull()) + if (m_Selection.IsNotNull()) { - static_cast(m_Controls.cmbSimulation->GetSelectedNode()->GetData())->SetAsActiveSimulation(); + static_cast(m_Selection->GetData())->SetAsActiveSimulation(); return true; } return false; } void QmitkSimulationView::OnTimerTimeout() { this->OnStepButtonClicked(); } diff --git a/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationView.h b/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationView.h index ffce7519ae..95284276ba 100644 --- a/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationView.h +++ b/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationView.h @@ -1,53 +1,60 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkSimulationView_h #define QmitkSimulationView_h +#include #include #include #include class QmitkSimulationView : public QmitkAbstractView { Q_OBJECT public: QmitkSimulationView(); ~QmitkSimulationView(); void CreateQtPartControl(QWidget* parent); void SetFocus(); +private slots: + void OnAnimateButtonToggled(bool toggled); + void OnDTSpinBoxValueChanged(double value); + void OnRecordButtonToggled(bool toggled); + void OnResetButtonClicked(); + void OnSimulationComboBoxSelectionChanged(const mitk::DataNode* node); + void OnSnapshotButtonClicked(); + void OnStepButtonClicked(); + void OnTimerTimeout(); + private: QmitkSimulationView(const QmitkSimulationView&); QmitkSimulationView& operator=(const QmitkSimulationView&); + void OnNodeRemovedFromDataStorage(const mitk::DataNode* node); bool SetSelectionAsCurrentSimulation() const; Ui::QmitkSimulationViewControls m_Controls; + bool m_SelectionWasRemovedFromDataStorage; + mitk::DataNode::Pointer m_Selection; + mitk::Surface::Pointer m_Record; QTimer m_Timer; - -private slots: - void OnAnimateButtonToggled(bool toggled); - void OnDTSpinBoxValueChanged(double value); - void OnResetSceneButtonClicked(); - void OnSimulationComboBoxSelectionChanged(const mitk::DataNode* node); - void OnStepButtonClicked(); - void OnTimerTimeout(); }; #endif diff --git a/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationViewControls.ui b/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationViewControls.ui index 5ee48dfb0d..12a7bd372f 100644 --- a/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationViewControls.ui @@ -1,167 +1,179 @@ QmitkSimulationViewControls true 0 0 301 548 Simulation - + - - - QLayout::SetMinimumSize - - - - - - 0 - 0 - - - - Simulation - - - - - - - - 0 - 0 - - - - - - - - + false - + Scene - - + + + + + 0 + 0 + + + + + + 0 0 Animate true false - - + + 0 0 Step - - + + 0 0 - Reset Scene + Reset - - - - - - - 0 - 0 - - - - dt - - - - - - - - 0 - 0 - - - - s - - - 3 - - - 0.010000000000000 - - - - + + + + + 0 + 0 + + + + dt + + + + + + + + 0 + 0 + + + + s + + + 3 + + + 0.010000000000000 + + + + + + + + + + Surface Recording + + + + + + Record + + + true + + + + + + + false + + + Take Snapshot + + + + + + + 0 step(s) recorded + + Qt::Vertical 20 421 QmitkDataStorageComboBox - QWidget + QComboBox
    QmitkDataStorageComboBox.h
    diff --git a/Plugins/org.mitk.gui.qt.simulation/src/internal/org_mitk_gui_qt_simulation_Activator.cpp b/Plugins/org.mitk.gui.qt.simulation/src/internal/org_mitk_gui_qt_simulation_Activator.cpp index 3a15490521..d29e31d03b 100644 --- a/Plugins/org.mitk.gui.qt.simulation/src/internal/org_mitk_gui_qt_simulation_Activator.cpp +++ b/Plugins/org.mitk.gui.qt.simulation/src/internal/org_mitk_gui_qt_simulation_Activator.cpp @@ -1,40 +1,42 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "org_mitk_gui_qt_simulation_Activator.h" +#include "QmitkSimulationPreferencePage.h" #include "QmitkSimulationView.h" #include #include #include void mitk::org_mitk_gui_qt_simulation_Activator::start(ctkPluginContext* context) { + BERRY_REGISTER_EXTENSION_CLASS(QmitkSimulationPreferencePage, context); BERRY_REGISTER_EXTENSION_CLASS(QmitkSimulationView, context); QmitkNodeDescriptorManager* nodeDescriptorManager = QmitkNodeDescriptorManager::GetInstance(); if (nodeDescriptorManager != NULL) { mitk::NodePredicateDataType::Pointer isSimulation = mitk::NodePredicateDataType::New("Simulation"); nodeDescriptorManager->AddDescriptor(new QmitkNodeDescriptor("Simulation", ":/Simulation/icon.png", isSimulation, nodeDescriptorManager)); } } void mitk::org_mitk_gui_qt_simulation_Activator::stop(ctkPluginContext*) { } Q_EXPORT_PLUGIN2(org_mitk_gui_qt_simulation, mitk::org_mitk_gui_qt_simulation_Activator) 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 a5e308f9f9..3fde750bdb 100644 --- a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp +++ b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp @@ -1,616 +1,618 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 //QT headers #include #include #include // MITK #include #include #include #include #include #include #include #include #include //itk headers #include // VTK #include // ITK #include const std::string QmitkToFUtilView::VIEW_ID = "org.mitk.views.tofutil"; //Constructor 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_2DDisplayCount(0) , m_RealTimeClock(NULL) , m_StepsForFramerate(100) , m_2DTimeBefore(0.0) , m_2DTimeAfter(0.0) , m_CameraIntrinsics(NULL) { 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(); } //Destructor, specifically calling OnToFCameraStopped() and OnToFCammeraDiconnected() QmitkToFUtilView::~QmitkToFUtilView() { OnToFCameraStopped(); OnToFCameraDisconnected(); } //Createing the PartControl Signal-Slot principal 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 ); //Looking for Input and Defining reaction connect(m_Frametimer, SIGNAL(timeout()), this, SLOT(OnUpdateCamera())); connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(KinectAcquisitionModeChanged()), this, SLOT(OnKinectAcquisitionModeChanged()) ); // Todo in Widget2 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_SurfaceCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnSurfaceCheckboxChecked(bool)) ); connect( (QObject*)(m_Controls->m_TextureCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnTextureCheckBoxChecked(bool)) ); connect( (QObject*)(m_Controls->m_KinectTextureCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnKinectRGBTextureCheckBoxChecked(bool)) ); } } //SetFocus-Method -> actually seting Focus to the Recorder void QmitkToFUtilView::SetFocus() { m_Controls->m_ToFRecorderWidget->setFocus(); } //Activated-Method->Generating RenderWindow 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()->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SliceLockedOn(); GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SliceLockedOn(); GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SliceLockedOn(); this->GetRenderWindowPart()->GetRenderingManager()->InitializeViews(); this->UseToFVisibilitySettings(true); if (this->m_ToFCompositeFilter) { m_Controls->m_ToFCompositeFilterWidget->SetToFCompositeFilter(this->m_ToFCompositeFilter); } if (this->GetDataStorage()) { 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); } } } //ZomnnieView-Method -> Resetting GUI to default. Why not just QmitkToFUtilView()?! void QmitkToFUtilView::ActivatedZombieView(berry::IWorkbenchPartReference::Pointer /*zombieView*/) { ResetGUIToDefault(); } void QmitkToFUtilView::Deactivated() { } void QmitkToFUtilView::Visible() { } //Reset of the ToFUtilView void QmitkToFUtilView::Hidden() { ResetGUIToDefault(); } void QmitkToFUtilView::OnToFCameraConnected() { MITK_DEBUG <<"OnToFCameraConnected"; this->m_2DDisplayCount = 0; this->m_ToFImageGrabber = m_Controls->m_ToFConnectionWidget->GetToFImageGrabber(); // initialize surface generation this->m_ToFDistanceImageToSurfaceFilter = mitk::ToFDistanceImageToSurfaceFilter::New(); this->m_ToFSurfaceVtkMapper3D = mitk::ToFSurfaceVtkMapper3D::New(); // initialize ToFImageRecorder and ToFRecorderWidget this->m_ToFImageRecorder = mitk::ToFImageRecorder::New(); 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(); m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); // initialize ToFCompositeFilterWidget this->m_ToFCompositeFilter = mitk::ToFCompositeFilter::New(); if (this->m_ToFCompositeFilter) { m_Controls->m_ToFCompositeFilterWidget->SetToFCompositeFilter(this->m_ToFCompositeFilter); } if (this->GetDataStorage()) { m_Controls->m_ToFCompositeFilterWidget->SetDataStorage(this->GetDataStorage()); } // initialize measurement widget m_Controls->tofMeasurementWidget->InitializeWidget(this->GetRenderWindowPart()->GetQmitkRenderWindows(),this->GetDataStorage(), this->m_ToFDistanceImageToSurfaceFilter->GetCameraIntrinsics()); this->m_RealTimeClock = mitk::RealTimeClock::New(); this->m_2DTimeBefore = this->m_RealTimeClock->GetCurrentStamp(); 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()->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SliceLockedOff(); GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SliceLockedOff(); GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Frontal); GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SliceLockedOff(); this->UseToFVisibilitySettings(false); //global reinit this->GetRenderWindowPart()->GetRenderingManager()->InitializeViews(); 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(); } void QmitkToFUtilView::OnKinectAcquisitionModeChanged() { if (m_ToFCompositeFilter.IsNotNull()&&m_ToFImageGrabber.IsNotNull()) { if (m_SelectedCamera.contains("Kinect")) { if (m_ToFImageGrabber->GetBoolProperty("RGB")) { this->m_RGBImageNode = ReplaceNodeData("RGB image",this->m_ToFImageGrabber->GetOutput(3)); this->m_ToFDistanceImageToSurfaceFilter->SetInput(3,this->m_ToFImageGrabber->GetOutput(3)); } else if (m_ToFImageGrabber->GetBoolProperty("IR")) { this->m_MitkAmplitudeImage = m_ToFCompositeFilter->GetOutput(1); this->m_AmplitudeImageNode = ReplaceNodeData("Amplitude image",m_MitkAmplitudeImage); } } this->UseToFVisibilitySettings(true); } } void QmitkToFUtilView::OnToFCameraStarted() { if (m_ToFImageGrabber.IsNotNull()) { // initialize camera intrinsics if (this->m_ToFImageGrabber->GetProperty("CameraIntrinsics")) { m_CameraIntrinsics = dynamic_cast(this->m_ToFImageGrabber->GetProperty("CameraIntrinsics"))->GetValue(); + MITK_INFO << m_CameraIntrinsics->ToString(); } else { m_CameraIntrinsics = NULL; + MITK_ERROR << "No camera intrinsics were found!"; } // 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); std::string rgbFileName; m_ToFImageGrabber->GetCameraDevice()->GetStringProperty("RGBImageFileName",rgbFileName); if ((m_SelectedCamera.contains("Kinect"))||(rgbFileName!="")) { //set the reconstruction mode for kinect this->m_ToFDistanceImageToSurfaceFilter->SetReconstructionMode(mitk::ToFDistanceImageToSurfaceFilter::Kinect); if (rgbFileName!="" || m_ToFImageGrabber->GetBoolProperty("RGB") ) { this->m_RGBImageNode = ReplaceNodeData("RGB image",this->m_ToFImageGrabber->GetOutput(3)); } else if (m_ToFImageGrabber->GetBoolProperty("IR")) { this->m_MitkAmplitudeImage = m_ToFCompositeFilter->GetOutput(1); } } else { this->m_RGBImageNode = NULL; 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); } this->m_AmplitudeImageNode = ReplaceNodeData("Amplitude image",m_MitkAmplitudeImage); this->m_IntensityImageNode = ReplaceNodeData("Intensity image",m_MitkIntensityImage); 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_KinectTextureCheckBox->isChecked()) { OnKinectRGBTextureCheckBoxChecked(true); } } m_Controls->m_TextureCheckBox->setEnabled(true); } void QmitkToFUtilView::OnToFCameraStopped() { m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); m_Controls->m_ToFCompositeFilterWidget->setEnabled(false); m_Controls->SurfacePropertiesBox->setEnabled(false); this->m_Frametimer->stop(); } void QmitkToFUtilView::OnToFCameraSelected(const QString selected) { m_SelectedCamera = selected; if ((selected.contains("CamBoard"))||(selected.contains("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_KinectTextureCheckBox->setEnabled(false); this->m_Controls->m_SurfaceCheckBox->setChecked(false); this->m_Controls->m_TextureCheckBox->setChecked(false); this->m_Controls->m_KinectTextureCheckBox->setChecked(false); } else { this->m_Controls->m_SurfaceCheckBox->setEnabled(true); this->m_Controls->m_TextureCheckBox->setEnabled(true); this->m_Controls->m_KinectTextureCheckBox->setEnabled(true); } } void QmitkToFUtilView::OnSurfaceCheckboxChecked(bool checked) { if(checked) { //initialize the surface once MITK_DEBUG << "OnSurfaceCheckboxChecked true"; this->m_SurfaceNode->SetData(this->m_Surface); this->m_SurfaceNode->SetMapper(mitk::BaseRenderer::Standard3D, m_ToFSurfaceVtkMapper3D); //we need to initialize (reinit) the surface, to make it fit into the renderwindow this->GetRenderWindowPart()->GetRenderingManager()->InitializeViews( this->m_Surface->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS, true); //the default camera position is rather unfortunate, //that's why we set our own position according to the surface center mitk::Point3D surfaceCenter= this->m_Surface->GetGeometry()->GetCenter(); vtkCamera* camera3d = GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderer()->GetVtkRenderer()->GetActiveCamera(); //1m distance to camera should be a nice default value for most cameras camera3d->SetPosition(0,0,-1000); camera3d->SetViewUp(0,-1,0); camera3d->SetFocalPoint(0,0,surfaceCenter[2]); camera3d->SetViewAngle(40); camera3d->SetClippingRange(1, 10000); } } void QmitkToFUtilView::OnUpdateCamera() { //##### Code for surface ##### if (m_Controls->m_SurfaceCheckBox->isChecked()) { // update surface m_ToFDistanceImageToSurfaceFilter->SetTextureIndex(m_Controls->m_ToFVisualisationSettingsWidget->GetSelectedImageIndex()); //if the user wants to see the texture, it has to be updated for every frame if(m_Controls->m_KinectTextureCheckBox->isChecked() && (m_SelectedCamera.contains("Kinect")) && (m_ToFImageGrabber->GetBoolProperty("RGB"))) { //remove the vtkScalarsToColors object, if there was one. this->m_ToFSurfaceVtkMapper3D->SetVtkScalarsToColors(NULL); //set RGB-iamge as texture this->m_ToFSurfaceVtkMapper3D->SetTexture((this->m_ToFImageGrabber->GetOutput(3)->GetVtkImageData())); } else { //we have to delete the texture, if there was one. this->m_ToFSurfaceVtkMapper3D->SetTexture(NULL); //get the colortransferfunction from the visualization widget this->m_ToFSurfaceVtkMapper3D->SetVtkScalarsToColors(m_Controls->m_ToFVisualisationSettingsWidget->GetSelectedColorTransferFunction()); } //update pipeline this->m_Surface->Update(); } //##### End code for surface ##### 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::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::OnKinectRGBTextureCheckBoxChecked(bool checked) { if((m_SelectedCamera.contains("Kinect")) && (m_ToFImageGrabber->GetBoolProperty("RGB"))) { if (checked) { //define the dimensions of the texture this->m_ToFDistanceImageToSurfaceFilter->SetTextureImageWidth(this->m_ToFImageGrabber->GetOutput(3)->GetDimension(0)); this->m_ToFDistanceImageToSurfaceFilter->SetTextureImageHeight(this->m_ToFImageGrabber->GetOutput(3)->GetDimension(1)); } } } 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) { if(this->m_IntensityImageNode.IsNotNull()) this->m_IntensityImageNode->SetVisibility(true); if(this->m_RGBImageNode.IsNotNull()) this->m_RGBImageNode->SetVisibility(false); } this->RequestRenderWindowUpdate(); 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()->GetQmitkRenderWindow("sagittal")->GetRenderWindow() ) ); this->m_DistanceImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetRenderWindow() ) ); this->m_DistanceImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderWindow() ) ); this->m_DistanceImageNode->SetBoolProperty("use color",!useToF); this->m_DistanceImageNode->GetPropertyList()->DeleteProperty("LookupTable"); } if (m_AmplitudeImageNode.IsNotNull()) { if ((m_SelectedCamera.contains("Kinect"))&&(m_ToFImageGrabber->GetBoolProperty("RGB"))) { this->m_AmplitudeImageNode->SetProperty( "visible" , mitk::BoolProperty::New( false )); } else { this->m_AmplitudeImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); } this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetRenderWindow() ) ); this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetRenderWindow() ) ); this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderWindow() ) ); this->m_AmplitudeImageNode->SetBoolProperty("use color",!useToF); this->m_AmplitudeImageNode->GetPropertyList()->DeleteProperty("LookupTable"); } if (m_IntensityImageNode.IsNotNull()) { if (m_SelectedCamera.contains("Kinect")) { this->m_IntensityImageNode->SetProperty( "visible" , mitk::BoolProperty::New( false )); } else { this->m_IntensityImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetRenderWindow() ) ); this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetRenderWindow() ) ); this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderWindow() ) ); this->m_IntensityImageNode->SetBoolProperty("use color",!useToF); this->m_IntensityImageNode->GetPropertyList()->DeleteProperty("LookupTable"); } } if ((m_RGBImageNode.IsNotNull())) { if ((m_SelectedCamera.contains("Kinect"))&&(m_ToFImageGrabber->GetBoolProperty("IR"))) { this->m_RGBImageNode->SetProperty( "visible" , mitk::BoolProperty::New( false )); } else { this->m_RGBImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); this->m_RGBImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetRenderWindow() ) ); this->m_RGBImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetRenderWindow() ) ); this->m_RGBImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("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()->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()->GetQmitkRenderWindow("3d")->GetRenderWindow() ) ); } //disable/enable gradient background this->GetRenderWindowPart()->EnableDecorations(!useToF, QStringList(QString("background"))); }