diff --git a/Modules/QtWidgets/include/QmitkMxNMultiWidget.h b/Modules/QtWidgets/include/QmitkMxNMultiWidget.h index dbc9613c5d..bbb622e0ff 100644 --- a/Modules/QtWidgets/include/QmitkMxNMultiWidget.h +++ b/Modules/QtWidgets/include/QmitkMxNMultiWidget.h @@ -1,119 +1,125 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QmitkMxNMultiWidget_h #define QmitkMxNMultiWidget_h -// qt widgets module #include "MitkQtWidgetsExports.h" + +// qt widgets module #include "QmitkAbstractMultiWidget.h" +#include +#include /** * @brief The 'QmitkMxNMultiWidget' is a 'QmitkAbstractMultiWidget' that is used to display multiple render windows at once. * Render windows can dynamically be added and removed to change the layout of the multi widget. This * is done by using the 'SetLayout'-function to define a layout. This will automatically add or remove * the appropriate number of render window widgets. */ class MITKQTWIDGETS_EXPORT QmitkMxNMultiWidget : public QmitkAbstractMultiWidget { Q_OBJECT public: QmitkMxNMultiWidget(QWidget* parent = nullptr, Qt::WindowFlags f = 0, const QString& multiWidgetName = "mxnmulti"); ~QmitkMxNMultiWidget(); void InitializeMultiWidget() override; void Synchronize(bool synchronized) override; QmitkRenderWindow* GetRenderWindow(const QString& widgetName) const override; QmitkRenderWindow* GetRenderWindow(const mitk::AnatomicalPlane& orientation) const override; void SetActiveRenderWindowWidget(RenderWindowWidgetPointer activeRenderWindowWidget) override; /** * @brief Initialize the active render windows of the MxNMultiWidget to the given geometry. * * @param geometry The geometry to be used to initialize / update the * active render window's time and slice navigation controller. * @param resetCamera If true, the camera and crosshair will be reset to the default view (centered, no zoom). * If false, the current crosshair position and the camera zoom will be stored and reset * after the reference geometry has been updated. */ void InitializeViews(const mitk::TimeGeometry* geometry, bool resetCamera) override; /** * @brief Forward the given time geometry to all base renderers, so that they can store it as their * interaction reference geometry. * This will update the alignment status of the reference geometry for each base renderer. * For more details, see 'BaseRenderer::SetInteractionReferenceGeometry'. * Overridem from 'QmitkAbstractMultiWidget'. */ void SetInteractionReferenceGeometry(const mitk::TimeGeometry* referenceGeometry) override; /** * @brief Returns true if the render windows are coupled; false if not. * * For the MxNMultiWidget the render windows are typically decoupled. */ bool HasCoupledRenderWindows() const override; void SetSelectedPosition(const mitk::Point3D& newPosition, const QString& widgetName) override; const mitk::Point3D GetSelectedPosition(const QString& widgetName) const override; void SetCrosshairVisibility(bool visible) override; bool GetCrosshairVisibility() const override; void SetCrosshairGap(unsigned int gapSize) override; void ResetCrosshair() override; void SetWidgetPlaneMode(int userMode) override; mitk::SliceNavigationController* GetTimeNavigationController(); void AddPlanesToDataStorage(); void RemovePlanesFromDataStorage(); public Q_SLOTS: // mouse events void wheelEvent(QWheelEvent* e) override; void mousePressEvent(QMouseEvent* e) override; void moveEvent(QMoveEvent* e) override; Q_SIGNALS: void WheelMoved(QWheelEvent *); void Moved(); protected: void RemoveRenderWindowWidget() override; private: void SetLayoutImpl() override; void SetInteractionSchemeImpl() override { } void CreateRenderWindowWidget(); + void SetInitialSelection(); + void ToggleSynchronization(QmitkSynchronizedNodeSelectionWidget* synchronizedWidget); mitk::SliceNavigationController* m_TimeNavigationController; + std::unique_ptr m_SynchronizedWidgetConnector; bool m_CrosshairVisibility; }; #endif diff --git a/Modules/QtWidgets/include/QmitkRenderWindowUtilityWidget.h b/Modules/QtWidgets/include/QmitkRenderWindowUtilityWidget.h index 05cde2fb5e..9a2d0089cf 100644 --- a/Modules/QtWidgets/include/QmitkRenderWindowUtilityWidget.h +++ b/Modules/QtWidgets/include/QmitkRenderWindowUtilityWidget.h @@ -1,70 +1,74 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QmitkRenderWindowUtilityWidget_h #define QmitkRenderWindowUtilityWidget_h -// qt widgets module #include "MitkQtWidgetsExports.h" -#include "QmitkSliceNavigationWidget.h" -#include "QmitkStepperAdapter.h" -#include "QmitkRenderWindow.h" -#include "QmitkRenderWindowContextDataStorageInspector.h" -#include "mitkRenderWindowViewDirectionController.h" -// mitk core -#include "mitkDataStorage.h" +// qt widgets module +#include +#include +#include +#include +#include // qt #include #include #include #include +namespace mitk +{ + class DataStorage; +} + +class QmitkRenderWindow; + class MITKQTWIDGETS_EXPORT QmitkRenderWindowUtilityWidget : public QWidget { Q_OBJECT public: + QmitkRenderWindowUtilityWidget( QWidget* parent = nullptr, QmitkRenderWindow* renderWindow = nullptr, mitk::DataStorage* dataStorage = nullptr ); ~QmitkRenderWindowUtilityWidget() override; - void SetInvertedSliceNavigation(bool inverted); + void ToggleSynchronization(bool synchronized); + + void SetGeometry(const itk::EventObject& event); Q_SIGNALS: - void ReinitAction(QList selectedNodes); - void ResetAction(QList selectedNodes); + void SynchronizationToggled(QmitkSynchronizedNodeSelectionWidget* synchronizedWidget); private: - QHBoxLayout* m_Layout; - QMenuBar* m_MenuBar; - - QmitkRenderWindow* m_RenderWindow; - mitk::DataStorage* m_DataStorage; - - QmitkRenderWindowContextDataStorageInspector* m_RenderWindowInspector; + mitk::BaseRenderer* m_BaseRenderer; + QmitkSynchronizedNodeSelectionWidget* m_NodeSelectionWidget; QmitkSliceNavigationWidget* m_SliceNavigationWidget; QmitkStepperAdapter* m_StepperAdapter; + std::unique_ptr m_RenderWindowLayerController; std::unique_ptr m_RenderWindowViewDirectionController; QComboBox* m_ViewDirectionSelector; void ChangeViewDirection(const QString& viewDirection); + }; #endif diff --git a/Modules/QtWidgets/include/QmitkRenderWindowWidget.h b/Modules/QtWidgets/include/QmitkRenderWindowWidget.h index c3420b49ef..6716bdf177 100644 --- a/Modules/QtWidgets/include/QmitkRenderWindowWidget.h +++ b/Modules/QtWidgets/include/QmitkRenderWindowWidget.h @@ -1,130 +1,123 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QmitkRenderWindowWidget_h #define QmitkRenderWindowWidget_h -// qt widgets module #include "MitkQtWidgetsExports.h" -#include "QmitkRenderWindow.h" -#include "QmitkRenderWindowUtilityWidget.h" + +// qt widgets module +#include // mitk core #include #include #include // qt #include #include +#include class vtkCornerAnnotation; /** * @brief The 'QmitkRenderWindowWidget' is a QFrame that holds a render window * and some associates properties, e.g. decorations. * Decorations are corner annotation (text and color), frame color or background color * and can be set using this class. * The 'QmitkRenderWindowWidget' is used inside a 'QmitkAbstractMultiWidget', where a map contains * several render window widgets to create the multi widget display. * This class uses a CrosshairManager, which allows to use plane geometries as crosshair. */ class MITKQTWIDGETS_EXPORT QmitkRenderWindowWidget : public QFrame { Q_OBJECT public: QmitkRenderWindowWidget( QWidget* parent = nullptr, const QString& widgetName = "", - mitk::DataStorage* dataStorage = nullptr, - bool windowControls = false); + mitk::DataStorage* dataStorage = nullptr); ~QmitkRenderWindowWidget() override; void SetDataStorage(mitk::DataStorage* dataStorage); const QString& GetWidgetName() const { return m_WidgetName; }; QmitkRenderWindow* GetRenderWindow() const { return m_RenderWindow; }; mitk::SliceNavigationController* GetSliceNavigationController() const; void RequestUpdate(); void ForceImmediateUpdate(); + void AddUtilityWidget(QWidget* utilityWidget); + void SetGradientBackgroundColors(const mitk::Color& upper, const mitk::Color& lower); void ShowGradientBackground(bool enable); std::pair GetGradientBackgroundColors() const { return m_GradientBackgroundColors; }; bool IsGradientBackgroundOn() const; void SetDecorationColor(const mitk::Color& color); mitk::Color GetDecorationColor() const { return m_DecorationColor; }; void ShowColoredRectangle(bool show); bool IsColoredRectangleVisible() const; void ShowCornerAnnotation(bool show); bool IsCornerAnnotationVisible() const; void SetCornerAnnotationText(const std::string& cornerAnnotation); std::string GetCornerAnnotationText() const; bool IsRenderWindowMenuActivated() const; void SetCrosshairVisibility(bool visible); bool GetCrosshairVisibility(); void SetCrosshairGap(unsigned int gapSize); void AddPlanesToDataStorage(); void RemovePlanesFromDataStorage(); void SetCrosshairPosition(const mitk::Point3D& newPosition); mitk::Point3D GetCrosshairPosition() const; void SetGeometry(const itk::EventObject& event); void SetGeometrySlice(const itk::EventObject& event); -private Q_SLOTS: - - void OnReinitAction(QList selectedNodes); - - void OnResetAction(QList selectedNodes); +public Q_SLOTS: void OnResetGeometry(); private: void InitializeGUI(); void InitializeDecorations(); - void ComputeInvertedSliceNavigation(); void ResetGeometry(const mitk::TimeGeometry* referenceGeometry); QString m_WidgetName; QVBoxLayout* m_Layout; mitk::DataStorage* m_DataStorage; QmitkRenderWindow* m_RenderWindow; mitk::CrosshairManager::Pointer m_CrosshairManager; std::pair m_GradientBackgroundColors; mitk::Color m_DecorationColor; vtkSmartPointer m_CornerAnnotation; - QmitkRenderWindowUtilityWidget* m_UtilityWidget; - - bool m_WindowControls; - }; #endif diff --git a/Modules/QtWidgets/include/QmitkSynchronizedWidgetConnector.h b/Modules/QtWidgets/include/QmitkSynchronizedWidgetConnector.h index 6f5575799b..ad672d5223 100644 --- a/Modules/QtWidgets/include/QmitkSynchronizedWidgetConnector.h +++ b/Modules/QtWidgets/include/QmitkSynchronizedWidgetConnector.h @@ -1,148 +1,150 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QmitkSynchronizedWidgetConnector_h #define QmitkSynchronizedWidgetConnector_h #include // mitk core #include // mitk qt widgets #include // qt #include /* * @brief This class connects different 'QmitkSynchronizedNodeSelectionWidget', such that * they can synchronize their current node selection and their current selection mode. * * In order to synchronize a new node selection widget with other already connected * node selection widgets, 'ConnectWidget(const QmitkSynchronizedNodeSelectionWidget*)' has to be used. * In order to desynchronize a node selection widget, * 'DisconnectWidget(const QmitkSynchronizedNodeSelectionWidget*)' has to be used. * If a new node selection has been connected / synchronized, * 'SynchronizeWidget(QmitkSynchronizedNodeSelectionWidget*' can be used to initialy set * the current selection and the current selection mode. * For this, both values are stored in this class internally. */ class MITKQTWIDGETS_EXPORT QmitkSynchronizedWidgetConnector : public QObject { Q_OBJECT public: using NodeList = QList; QmitkSynchronizedWidgetConnector(); /* - * @brief This function connects the different signals and slots, such that changes to the - * current list of nodes and the selection mode can be forwarded or received. + * @brief This function connects the different signals and slots of this instance and the given + * given node selection widget, such that changes to the current list of nodes + * and the selection mode can be forwarded or received. * The connections are as follows: * - QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged * -> QmitkSynchronizedWidgetConnector::ChangeSelection * - QmitkSynchronizedWidgetConnector::NodeSelectionChanged * -> QmitkAbstractNodeSelectionWidget::SetCurrentSelection * - QmitkSynchronizedNodeSelectionWidget::SelectionModeChanged * -> QmitkSynchronizedWidgetConnector::ChangeSelectionMode * - QmitkSynchronizedWidgetConnector::SelectionModeChanged * -> QmitkSynchronizedNodeSelectionWidget::SetSelectAll * * @param nodeSelectionWidget The synchronized node selection widget to be connected / synchronized. */ void ConnectWidget(const QmitkSynchronizedNodeSelectionWidget* nodeSelectionWidget) const; /* - * @brief This function disconnects the different signals and slots, such that changes to the - * current list of nodes and the selection mode cannot be forwarded or received anymore. + * @brief This function disconnects the different signals and slot of this instance and the given + * given node selection widget, such that changes to the current list of nodes + * and the selection mode cannot be forwarded or received anymore. * * @param nodeSelectionWidget The synchronized node selection widget to be disconnected / desynchronized. */ void DisconnectWidget(const QmitkSynchronizedNodeSelectionWidget* nodeSelectionWidget) const; /* - * @brief This function set the current selection and the selection mode of the given node selection widget. - * It can be used to initialize a newly connected / synchronized. - * The required values are stored in this class internally. + * @brief This function sets the current selection and the selection mode of the given node selection widget + * to the values of this instance. The required values are stored in this class internally. + * It can be used to newly initialize the given node selection widget. * * @param nodeSelectionWidget The synchronized node selection widget for which the * current selection and the selection mode should be set. */ void SynchronizeWidget(QmitkSynchronizedNodeSelectionWidget* nodeSelectionWidget) const; /* * @brief Get the current internal node selection. * * @return NodeList The current internal node selection stored as a member variable. */ NodeList GetNodeSelection() const; /* * @brief Get the current internal selection mode. * * @return The current internal selection mode stored as a member variable. */ bool GetSelectionMode() const; Q_SIGNALS: /* * @brief A signal that will be emitted by the 'ChangeSelection'-slot. * This happens if a new selection / list of nodes is set from outside of this class, * e.g. from a QmitkSynchronizedNodeSelectionWidget. * This signal is connected to the 'SetCurrentSelection'-slot of each * QmitkSynchronizedNodeSelectionWidget to propagate the new selection. * * @param nodes A list of data nodes that are newly selected. */ void NodeSelectionChanged(NodeList nodes); /* * @brief A signal that will be emitted by the 'ChangeSelectionMode'-slot. * This happens if the selection mode is change from outside of this class, * e.g. from a QmitkSynchronizedNodeSelectionWidget. * This signal is connected to the 'SetSelectAll'-slot of each * QmitkSynchronizedNodeSelectionWidget to propagate the selection mode. * * @param selectAll True, if the selection mode is changed to "select all" nodes. * False otherwise. */ void SelectionModeChanged(bool selectAll); public Q_SLOTS: /* * @brief Set a new internal selection and send this new selection to connected * QmitkSynchronizedNodeSelectionWidgets using the 'NodeSelectionChanged'-signal. * * This slot itself is connected to the 'CurrentSelectionChanged'-signal of each * QmitkSynchronizedNodeSelectionWidget to receive a new selection. * * @param nodes A list of data nodes that are newly selected. */ void ChangeSelection(NodeList nodes); /* * @brief Set a new selection mode and send this new selection mode to connected * QmitkSynchronizedNodeSelectionWidgets using the 'SelectionModeChanged'-signal. * * This slot itself is connected to the 'SelectionModeChanged'-signal of each * QmitkSynchronizedNodeSelectionWidget to receive a new selection mode. * * @param selectAll True, if the selection mode is changed to "select all" nodes. * False otherwise. */ void ChangeSelectionMode(bool selectAll); private: NodeList m_InternalSelection; bool m_SelectAll; }; #endif diff --git a/Modules/QtWidgets/src/QmitkMxNMultiWidget.cpp b/Modules/QtWidgets/src/QmitkMxNMultiWidget.cpp index d3efda2364..a4f43d3581 100644 --- a/Modules/QtWidgets/src/QmitkMxNMultiWidget.cpp +++ b/Modules/QtWidgets/src/QmitkMxNMultiWidget.cpp @@ -1,392 +1,448 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkMxNMultiWidget.h" -#include "QmitkRenderWindowWidget.h" // mitk core #include #include #include +#include +#include +#include + +// mitk qt widget +#include +#include // qt #include #include QmitkMxNMultiWidget::QmitkMxNMultiWidget(QWidget* parent, Qt::WindowFlags f/* = 0*/, const QString& multiWidgetName/* = "mxnmulti"*/) : QmitkAbstractMultiWidget(parent, f, multiWidgetName) , m_TimeNavigationController(nullptr) + , m_SynchronizedWidgetConnector(std::make_unique()) , m_CrosshairVisibility(false) { m_TimeNavigationController = mitk::RenderingManager::GetInstance()->GetTimeNavigationController(); } QmitkMxNMultiWidget::~QmitkMxNMultiWidget() { auto allRenderWindows = this->GetRenderWindows(); for (auto& renderWindow : allRenderWindows) { m_TimeNavigationController->Disconnect(renderWindow->GetSliceNavigationController()); } } void QmitkMxNMultiWidget::InitializeMultiWidget() { SetLayout(1, 1); SetDisplayActionEventHandler(std::make_unique()); auto displayActionEventHandler = GetDisplayActionEventHandler(); if (nullptr != displayActionEventHandler) { displayActionEventHandler->InitActions(); } + + this->SetInitialSelection(); } void QmitkMxNMultiWidget::Synchronize(bool synchronized) { if (synchronized) { SetDisplayActionEventHandler(std::make_unique()); } else { SetDisplayActionEventHandler(std::make_unique()); } auto displayActionEventHandler = GetDisplayActionEventHandler(); if (nullptr != displayActionEventHandler) { displayActionEventHandler->InitActions(); } } QmitkRenderWindow* QmitkMxNMultiWidget::GetRenderWindow(const QString& widgetName) const { if ("axial" == widgetName || "sagittal" == widgetName || "coronal" == widgetName || "3d" == widgetName) { return GetActiveRenderWindowWidget()->GetRenderWindow(); } return QmitkAbstractMultiWidget::GetRenderWindow(widgetName); } QmitkRenderWindow* QmitkMxNMultiWidget::GetRenderWindow(const mitk::AnatomicalPlane& /*orientation*/) const { // currently no mapping between plane orientation and render windows // simply return the currently active render window return GetActiveRenderWindowWidget()->GetRenderWindow(); } void QmitkMxNMultiWidget::SetActiveRenderWindowWidget(RenderWindowWidgetPointer activeRenderWindowWidget) { auto currentActiveRenderWindowWidget = GetActiveRenderWindowWidget(); if (currentActiveRenderWindowWidget == activeRenderWindowWidget) { return; } // reset the decoration color of the previously active render window widget if (nullptr != currentActiveRenderWindowWidget) { auto decorationColor = currentActiveRenderWindowWidget->GetDecorationColor(); QColor hexColor(decorationColor[0] * 255, decorationColor[1] * 255, decorationColor[2] * 255); currentActiveRenderWindowWidget->setStyleSheet("QmitkRenderWindowWidget { border: 2px solid " + hexColor.name(QColor::HexRgb) + "; }"); } // set the new decoration color of the currently active render window widget if (nullptr != activeRenderWindowWidget) { activeRenderWindowWidget->setStyleSheet("QmitkRenderWindowWidget { border: 2px solid #FF6464; }"); } QmitkAbstractMultiWidget::SetActiveRenderWindowWidget(activeRenderWindowWidget); } void QmitkMxNMultiWidget::InitializeViews(const mitk::TimeGeometry* geometry, bool resetCamera) { auto* renderingManager = mitk::RenderingManager::GetInstance(); mitk::Point3D currentPosition = mitk::Point3D(); unsigned int imageTimeStep = 0; if (!resetCamera) { // store the current position to set it again later, if the camera should not be reset currentPosition = this->GetSelectedPosition(""); // store the current time step to set it again later, if the camera should not be reset const auto currentTimePoint = renderingManager->GetTimeNavigationController()->GetSelectedTimePoint(); if (geometry->IsValidTimePoint(currentTimePoint)) { imageTimeStep = geometry->TimePointToTimeStep(currentTimePoint); } } // initialize active render window renderingManager->InitializeView( this->GetActiveRenderWindowWidget()->GetRenderWindow()->GetVtkRenderWindow(), geometry, resetCamera); if (!resetCamera) { this->SetSelectedPosition(currentPosition, ""); renderingManager->GetTimeNavigationController()->GetTime()->SetPos(imageTimeStep); } } void QmitkMxNMultiWidget::SetInteractionReferenceGeometry(const mitk::TimeGeometry* referenceGeometry) { // Set the interaction reference referenceGeometry for all render windows. auto allRenderWindows = this->GetRenderWindows(); for (auto& renderWindow : allRenderWindows) { auto* baseRenderer = mitk::BaseRenderer::GetInstance(renderWindow->GetRenderWindow()); baseRenderer->SetInteractionReferenceGeometry(referenceGeometry); } } bool QmitkMxNMultiWidget::HasCoupledRenderWindows() const { return false; } void QmitkMxNMultiWidget::SetSelectedPosition(const mitk::Point3D& newPosition, const QString& widgetName) { RenderWindowWidgetPointer renderWindowWidget; if (widgetName.isNull() || widgetName.isEmpty()) { renderWindowWidget = GetActiveRenderWindowWidget(); } else { renderWindowWidget = GetRenderWindowWidget(widgetName); } if (nullptr != renderWindowWidget) { renderWindowWidget->GetSliceNavigationController()->SelectSliceByPoint(newPosition); return; } MITK_ERROR << "Position can not be set for an unknown render window widget."; } const mitk::Point3D QmitkMxNMultiWidget::GetSelectedPosition(const QString& widgetName) const { RenderWindowWidgetPointer renderWindowWidget; if (widgetName.isNull() || widgetName.isEmpty()) { renderWindowWidget = GetActiveRenderWindowWidget(); } else { renderWindowWidget = GetRenderWindowWidget(widgetName); } if (nullptr != renderWindowWidget) { return renderWindowWidget->GetCrosshairPosition(); } MITK_ERROR << "Crosshair position can not be retrieved."; return mitk::Point3D(0.0); } void QmitkMxNMultiWidget::SetCrosshairVisibility(bool visible) { // get the specific render window that sent the signal QmitkRenderWindow* renderWindow = qobject_cast(sender()); if (nullptr == renderWindow) { return; } auto renderWindowWidget = this->GetRenderWindowWidget(renderWindow); renderWindowWidget->SetCrosshairVisibility(visible); } bool QmitkMxNMultiWidget::GetCrosshairVisibility() const { // get the specific render window that sent the signal QmitkRenderWindow* renderWindow = qobject_cast(sender()); if (nullptr == renderWindow) { return false; } auto renderWindowWidget = this->GetRenderWindowWidget(renderWindow); return renderWindowWidget->GetCrosshairVisibility(); } void QmitkMxNMultiWidget::SetCrosshairGap(unsigned int gapSize) { auto renderWindowWidgets = this->GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { renderWindowWidget.second->SetCrosshairGap(gapSize); } } void QmitkMxNMultiWidget::ResetCrosshair() { auto dataStorage = GetDataStorage(); if (nullptr == dataStorage) { return; } // get the specific render window that sent the signal QmitkRenderWindow* renderWindow = qobject_cast(sender()); if (nullptr == renderWindow) { return; } mitk::RenderingManager::GetInstance()->InitializeViewByBoundingObjects(renderWindow->GetRenderWindow(), dataStorage); SetWidgetPlaneMode(mitk::InteractionSchemeSwitcher::MITKStandard); } void QmitkMxNMultiWidget::SetWidgetPlaneMode(int userMode) { MITK_DEBUG << "Changing crosshair mode to " << userMode; switch (userMode) { case 0: SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKStandard); break; case 1: SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKRotationUncoupled); break; case 2: SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKRotationCoupled); break; case 3: SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKSwivel); break; } } mitk::SliceNavigationController* QmitkMxNMultiWidget::GetTimeNavigationController() { return m_TimeNavigationController; } void QmitkMxNMultiWidget::AddPlanesToDataStorage() { auto renderWindowWidgets = this->GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { renderWindowWidget.second->AddPlanesToDataStorage(); } } void QmitkMxNMultiWidget::RemovePlanesFromDataStorage() { auto renderWindowWidgets = this->GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { renderWindowWidget.second->RemovePlanesFromDataStorage(); } } ////////////////////////////////////////////////////////////////////////// // PUBLIC SLOTS // MOUSE EVENTS ////////////////////////////////////////////////////////////////////////// void QmitkMxNMultiWidget::wheelEvent(QWheelEvent* e) { emit WheelMoved(e); } void QmitkMxNMultiWidget::mousePressEvent(QMouseEvent*) { // nothing here, but necessary for mouse interactions (.xml-configuration files) } void QmitkMxNMultiWidget::moveEvent(QMoveEvent* e) { QWidget::moveEvent(e); // it is necessary to readjust the position of the overlays as the MultiWidget has moved // unfortunately it's not done by QmitkRenderWindow::moveEvent -> must be done here emit Moved(); } void QmitkMxNMultiWidget::RemoveRenderWindowWidget() { auto renderWindowWidgets = this->GetRenderWindowWidgets(); auto iterator = renderWindowWidgets.find(this->GetNameFromIndex(this->GetNumberOfRenderWindowWidgets() - 1)); if (iterator == renderWindowWidgets.end()) { return; } // disconnect each signal of this render window widget RenderWindowWidgetPointer renderWindowWidgetToRemove = iterator->second; m_TimeNavigationController->Disconnect(renderWindowWidgetToRemove->GetSliceNavigationController()); QmitkAbstractMultiWidget::RemoveRenderWindowWidget(); } ////////////////////////////////////////////////////////////////////////// // PRIVATE ////////////////////////////////////////////////////////////////////////// void QmitkMxNMultiWidget::SetLayoutImpl() { int requiredRenderWindowWidgets = GetRowCount() * GetColumnCount(); int existingRenderWindowWidgets = GetRenderWindowWidgets().size(); int difference = requiredRenderWindowWidgets - existingRenderWindowWidgets; while (0 < difference) { // more render window widgets needed CreateRenderWindowWidget(); --difference; } while (0 > difference) { // less render window widgets needed RemoveRenderWindowWidget(); ++difference; } auto firstRenderWindowWidget = GetFirstRenderWindowWidget(); if (nullptr != firstRenderWindowWidget) { SetActiveRenderWindowWidget(firstRenderWindowWidget); } GetMultiWidgetLayoutManager()->SetLayoutDesign(QmitkMultiWidgetLayoutManager::LayoutDesign::DEFAULT); } void QmitkMxNMultiWidget::CreateRenderWindowWidget() { // create the render window widget and connect signal / slot QString renderWindowWidgetName = GetNameFromIndex(GetNumberOfRenderWindowWidgets()); - RenderWindowWidgetPointer renderWindowWidget = std::make_shared(this, renderWindowWidgetName, GetDataStorage(), true); + RenderWindowWidgetPointer renderWindowWidget = std::make_shared(this, renderWindowWidgetName, GetDataStorage()); renderWindowWidget->SetCornerAnnotationText(renderWindowWidgetName.toStdString()); AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget); auto renderWindow = renderWindowWidget->GetRenderWindow(); + + QmitkRenderWindowUtilityWidget* utilityWidget = new QmitkRenderWindowUtilityWidget(this, renderWindow, GetDataStorage()); + renderWindowWidget->AddUtilityWidget(utilityWidget); + + connect(utilityWidget, &QmitkRenderWindowUtilityWidget::SynchronizationToggled, + this, &QmitkMxNMultiWidget::ToggleSynchronization); + + // needs to be done after 'QmitkRenderWindowUtilityWidget::ToggleSynchronization' has been connected + // initially synchronize the node selection widget + utilityWidget->ToggleSynchronization(true); + auto layoutManager = GetMultiWidgetLayoutManager(); connect(renderWindow, &QmitkRenderWindow::LayoutDesignChanged, layoutManager, &QmitkMultiWidgetLayoutManager::SetLayoutDesign); connect(renderWindow, &QmitkRenderWindow::ResetView, this, &QmitkMxNMultiWidget::ResetCrosshair); connect(renderWindow, &QmitkRenderWindow::CrosshairVisibilityChanged, this, &QmitkMxNMultiWidget::SetCrosshairVisibility); connect(renderWindow, &QmitkRenderWindow::CrosshairRotationModeChanged, this, &QmitkMxNMultiWidget::SetWidgetPlaneMode); // connect time navigation controller to react on referenceGeometry time events with the render window's slice naviation controller m_TimeNavigationController->ConnectGeometryTimeEvent(renderWindow->GetSliceNavigationController()); // reverse connection between the render window's slice navigation controller and the time navigation controller renderWindow->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController); } + +void QmitkMxNMultiWidget::SetInitialSelection() +{ + auto dataStorage = this->GetDataStorage(); + if (nullptr == dataStorage) + { + return; + } + + mitk::NodePredicateAnd::Pointer noHelperObjects = mitk::NodePredicateAnd::New(); + noHelperObjects->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); + noHelperObjects->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("hidden object"))); + auto allNodes = dataStorage->GetSubset(noHelperObjects); + QmitkSynchronizedNodeSelectionWidget::NodeList currentSelection; + for (auto& node : *allNodes) + { + currentSelection.append(node); + } + + m_SynchronizedWidgetConnector->ChangeSelection(currentSelection); +} + +void QmitkMxNMultiWidget::ToggleSynchronization(QmitkSynchronizedNodeSelectionWidget* synchronizedWidget) +{ + bool synchronized = synchronizedWidget->IsSynchronized(); + + if (synchronized) + { + m_SynchronizedWidgetConnector->ConnectWidget(synchronizedWidget); + m_SynchronizedWidgetConnector->SynchronizeWidget(synchronizedWidget); + } + else + { + m_SynchronizedWidgetConnector->DisconnectWidget(synchronizedWidget); + } +} diff --git a/Modules/QtWidgets/src/QmitkRenderWindowUtilityWidget.cpp b/Modules/QtWidgets/src/QmitkRenderWindowUtilityWidget.cpp index 8fc6d892a7..50bedcae3a 100644 --- a/Modules/QtWidgets/src/QmitkRenderWindowUtilityWidget.cpp +++ b/Modules/QtWidgets/src/QmitkRenderWindowUtilityWidget.cpp @@ -1,95 +1,175 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkRenderWindowUtilityWidget.h" #include +// mitk core +#include +#include +#include +#include + +// mitk qt widgets +#include +#include + +// itk +#include + QmitkRenderWindowUtilityWidget::QmitkRenderWindowUtilityWidget( QWidget* parent/* = nullptr */, QmitkRenderWindow* renderWindow/* = nullptr */, mitk::DataStorage* dataStorage/* = nullptr */) - : m_Layout(nullptr) - , m_MenuBar(nullptr) - , m_RenderWindow(renderWindow) - , m_DataStorage(dataStorage) - , m_RenderWindowInspector(nullptr) + : m_NodeSelectionWidget(nullptr) , m_SliceNavigationWidget(nullptr) , m_StepperAdapter(nullptr) , m_ViewDirectionSelector(nullptr) { - m_Layout = new QHBoxLayout(this); - m_Layout->setMargin(0); - - auto* baseRenderer = mitk::BaseRenderer::GetInstance(m_RenderWindow->GetVtkRenderWindow()); - auto* sliceNavigationController = m_RenderWindow->GetSliceNavigationController(); - m_RenderWindowInspector = new QmitkRenderWindowContextDataStorageInspector(parent, baseRenderer); - m_RenderWindowInspector->SetDataStorage(m_DataStorage); - m_RenderWindowInspector->setObjectName(QStringLiteral("m_RenderWindowManipulatorWidget")); - connect(m_RenderWindowInspector, &QmitkRenderWindowContextDataStorageInspector::ReinitAction, - this, &QmitkRenderWindowUtilityWidget::ReinitAction); - connect(m_RenderWindowInspector, &QmitkRenderWindowContextDataStorageInspector::ResetAction, - this, &QmitkRenderWindowUtilityWidget::ResetAction); - - m_MenuBar = new QMenuBar(this); - m_MenuBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); - auto menu = m_MenuBar->addMenu("Data"); - QWidgetAction* newAct = new QWidgetAction(menu); - newAct->setDefaultWidget(m_RenderWindowInspector); - menu->addAction(newAct); - m_Layout->addWidget(m_MenuBar); + this->setParent(parent); + auto layout = new QHBoxLayout(this); + layout->setMargin(0); + + mitk::NodePredicateAnd::Pointer noHelperObjects = mitk::NodePredicateAnd::New(); + noHelperObjects->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); + noHelperObjects->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("hidden object"))); + + m_BaseRenderer = mitk::BaseRenderer::GetInstance(renderWindow->GetVtkRenderWindow()); + m_NodeSelectionWidget = new QmitkSynchronizedNodeSelectionWidget(parent); + m_NodeSelectionWidget->SetBaseRenderer(m_BaseRenderer); + m_NodeSelectionWidget->SetDataStorage(dataStorage); + m_NodeSelectionWidget->SetNodePredicate(noHelperObjects); + + auto menuBar = new QMenuBar(this); + menuBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); + auto dataMenu = menuBar->addMenu("Data"); + QWidgetAction* dataAction = new QWidgetAction(dataMenu); + dataAction->setDefaultWidget(m_NodeSelectionWidget); + dataMenu->addAction(dataAction); + layout->addWidget(menuBar); + + auto* synchPushButton = new QPushButton(this); + auto* synchIcon = new QIcon(); + auto synchronizeSvg = QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/lock.svg")); + auto desynchronizeSvg = QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/unlock.svg")); + synchIcon->addPixmap(synchronizeSvg.pixmap(64), QIcon::Normal, QIcon::On); + synchIcon->addPixmap(desynchronizeSvg.pixmap(64), QIcon::Normal, QIcon::Off); + synchPushButton->setIcon(*synchIcon); + synchPushButton->setToolTip("Synchronize / desynchronize data management"); + synchPushButton->setCheckable(true); + synchPushButton->setChecked(true); + connect(synchPushButton, &QPushButton::clicked, + this, &QmitkRenderWindowUtilityWidget::ToggleSynchronization); + layout->addWidget(synchPushButton); + + auto* sliceNavigationController = m_BaseRenderer->GetSliceNavigationController(); m_SliceNavigationWidget = new QmitkSliceNavigationWidget(this); m_StepperAdapter = new QmitkStepperAdapter(m_SliceNavigationWidget, sliceNavigationController->GetSlice()); - m_Layout->addWidget(m_SliceNavigationWidget); + layout->addWidget(m_SliceNavigationWidget); - mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer{ baseRenderer }; + mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer{ m_BaseRenderer }; m_RenderWindowViewDirectionController = std::make_unique(); m_RenderWindowViewDirectionController->SetControlledRenderer(controlledRenderer); m_RenderWindowViewDirectionController->SetDataStorage(dataStorage); m_ViewDirectionSelector = new QComboBox(this); QStringList viewDirections{ "axial", "coronal", "sagittal"}; m_ViewDirectionSelector->insertItems(0, viewDirections); connect(m_ViewDirectionSelector, &QComboBox::currentTextChanged, this, &QmitkRenderWindowUtilityWidget::ChangeViewDirection); auto viewDirection = sliceNavigationController->GetDefaultViewDirection(); switch (viewDirection) { case mitk::AnatomicalPlane::Axial: m_ViewDirectionSelector->setCurrentIndex(0); break; case mitk::AnatomicalPlane::Coronal: m_ViewDirectionSelector->setCurrentIndex(1); break; case mitk::AnatomicalPlane::Sagittal: m_ViewDirectionSelector->setCurrentIndex(2); break; default: break; } - m_Layout->addWidget(m_ViewDirectionSelector); + + layout->addWidget(m_ViewDirectionSelector); + + // finally add observer, after all relevant objects have been created / initialized + sliceNavigationController->ConnectGeometrySendEvent(this); } QmitkRenderWindowUtilityWidget::~QmitkRenderWindowUtilityWidget() { } -void QmitkRenderWindowUtilityWidget::SetInvertedSliceNavigation(bool inverted) +void QmitkRenderWindowUtilityWidget::ToggleSynchronization(bool synchronized) { - m_SliceNavigationWidget->SetInverseDirection(inverted); + m_NodeSelectionWidget->SetSynchronized(synchronized); + emit SynchronizationToggled(m_NodeSelectionWidget); +} + +void QmitkRenderWindowUtilityWidget::SetGeometry(const itk::EventObject& event) +{ + if (!mitk::SliceNavigationController::GeometrySendEvent(nullptr, 0).CheckEvent(&event)) + { + return; + } + + const auto* sliceNavigationController = m_BaseRenderer->GetSliceNavigationController(); + auto viewDirection = sliceNavigationController->GetViewDirection(); + unsigned int axis = 0; + switch (viewDirection) + { + case mitk::AnatomicalPlane::Original: + return; + case mitk::AnatomicalPlane::Axial: + { + axis = 2; + break; + } + case mitk::AnatomicalPlane::Coronal: + { + axis = 1; + break; + } + case mitk::AnatomicalPlane::Sagittal: + { + axis = 0; + break; + } + } + + const auto* inputTimeGeometry = sliceNavigationController->GetInputWorldTimeGeometry(); + const mitk::BaseGeometry* rendererGeometry = m_BaseRenderer->GetCurrentWorldGeometry(); + + mitk::TimeStepType timeStep = sliceNavigationController->GetTime()->GetPos(); + mitk::BaseGeometry::ConstPointer geometry = inputTimeGeometry->GetGeometryForTimeStep(timeStep); + + mitk::AffineTransform3D::MatrixType matrix = geometry->GetIndexToWorldTransform()->GetMatrix(); + matrix.GetVnlMatrix().normalize_columns(); + mitk::AffineTransform3D::MatrixType::InternalMatrixType inverseMatrix = matrix.GetInverse(); + + int dominantAxis = itk::Function::Max3(inverseMatrix[0][axis], inverseMatrix[1][axis], inverseMatrix[2][axis]); + + bool referenceGeometryAxisInverted = inverseMatrix[dominantAxis][axis] < 0; + bool rendererZAxisInverted = rendererGeometry->GetAxisVector(2)[axis] < 0; + + m_SliceNavigationWidget->SetInverseDirection(referenceGeometryAxisInverted != rendererZAxisInverted); } void QmitkRenderWindowUtilityWidget::ChangeViewDirection(const QString& viewDirection) { m_RenderWindowViewDirectionController->SetViewDirectionOfRenderer(viewDirection.toStdString()); } diff --git a/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp b/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp index fa26a2dc61..20df5b5f9d 100644 --- a/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp +++ b/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp @@ -1,439 +1,319 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkRenderWindowWidget.h" -#include -#include -#include - -// itk -#include - // vtk #include #include QmitkRenderWindowWidget::QmitkRenderWindowWidget(QWidget* parent/* = nullptr*/, const QString& widgetName/* = ""*/, - mitk::DataStorage* dataStorage/* = nullptr*/, - bool windowControls/* = false */) + mitk::DataStorage* dataStorage/* = nullptr*/) : QFrame(parent) , m_WidgetName(widgetName) , m_DataStorage(dataStorage) , m_RenderWindow(nullptr) , m_CrosshairManager(nullptr) - , m_UtilityWidget(nullptr) - , m_WindowControls(windowControls) { this->InitializeGUI(); } QmitkRenderWindowWidget::~QmitkRenderWindowWidget() { auto sliceNavigationController = this->GetSliceNavigationController(); if (nullptr != sliceNavigationController) { sliceNavigationController->SetCrosshairEvent.RemoveListener( mitk::MessageDelegate1( this, &QmitkRenderWindowWidget::SetCrosshairPosition)); } } void QmitkRenderWindowWidget::SetDataStorage(mitk::DataStorage* dataStorage) { if (dataStorage == m_DataStorage) { return; } m_DataStorage = dataStorage; if (nullptr != m_RenderWindow) { mitk::BaseRenderer::GetInstance(m_RenderWindow->renderWindow())->SetDataStorage(dataStorage); } m_CrosshairManager->SetDataStorage(m_DataStorage); } mitk::SliceNavigationController* QmitkRenderWindowWidget::GetSliceNavigationController() const { return m_RenderWindow->GetSliceNavigationController(); } void QmitkRenderWindowWidget::RequestUpdate() { mitk::RenderingManager::GetInstance()->RequestUpdate(m_RenderWindow->renderWindow()); } void QmitkRenderWindowWidget::ForceImmediateUpdate() { mitk::RenderingManager::GetInstance()->ForceImmediateUpdate(m_RenderWindow->renderWindow()); } +void QmitkRenderWindowWidget::AddUtilityWidget(QWidget* utilityWidget) +{ + m_Layout->insertWidget(0, utilityWidget); +} + void QmitkRenderWindowWidget::SetGradientBackgroundColors(const mitk::Color& upper, const mitk::Color& lower) { vtkRenderer* vtkRenderer = m_RenderWindow->GetRenderer()->GetVtkRenderer(); if (nullptr == vtkRenderer) { return; } m_GradientBackgroundColors.first = upper; m_GradientBackgroundColors.second = lower; vtkRenderer->SetBackground(lower[0], lower[1], lower[2]); vtkRenderer->SetBackground2(upper[0], upper[1], upper[2]); ShowGradientBackground(true); } void QmitkRenderWindowWidget::ShowGradientBackground(bool show) { m_RenderWindow->GetRenderer()->GetVtkRenderer()->SetGradientBackground(show); } bool QmitkRenderWindowWidget::IsGradientBackgroundOn() const { return m_RenderWindow->GetRenderer()->GetVtkRenderer()->GetGradientBackground(); } void QmitkRenderWindowWidget::SetDecorationColor(const mitk::Color& color) { m_DecorationColor = color; m_CornerAnnotation->GetTextProperty()->SetColor(m_DecorationColor[0], m_DecorationColor[1], m_DecorationColor[2]); QColor hexColor(m_DecorationColor[0] * 255, m_DecorationColor[1] * 255, m_DecorationColor[2] * 255); setStyleSheet("QmitkRenderWindowWidget { border: 2px solid " + hexColor.name(QColor::HexRgb) + "; }"); } void QmitkRenderWindowWidget::ShowColoredRectangle(bool show) { if (show) { setFrameStyle(QFrame::Box | QFrame::Plain); } else { setFrameStyle(NoFrame); } } bool QmitkRenderWindowWidget::IsColoredRectangleVisible() const { return frameStyle() > 0; } void QmitkRenderWindowWidget::ShowCornerAnnotation(bool show) { m_CornerAnnotation->SetVisibility(show); } bool QmitkRenderWindowWidget::IsCornerAnnotationVisible() const { return m_CornerAnnotation->GetVisibility() > 0; } void QmitkRenderWindowWidget::SetCornerAnnotationText(const std::string& cornerAnnotation) { m_CornerAnnotation->SetText(0, cornerAnnotation.c_str()); } std::string QmitkRenderWindowWidget::GetCornerAnnotationText() const { return std::string(m_CornerAnnotation->GetText(0)); } bool QmitkRenderWindowWidget::IsRenderWindowMenuActivated() const { return m_RenderWindow->GetActivateMenuWidgetFlag(); } void QmitkRenderWindowWidget::SetCrosshairVisibility(bool visible) { m_CrosshairManager->SetCrosshairVisibility(visible); this->RequestUpdate(); } bool QmitkRenderWindowWidget::GetCrosshairVisibility() { return m_CrosshairManager->GetCrosshairVisibility(); } void QmitkRenderWindowWidget::SetCrosshairGap(unsigned int gapSize) { m_CrosshairManager->SetCrosshairGap(gapSize); } void QmitkRenderWindowWidget::AddPlanesToDataStorage() { m_CrosshairManager->AddPlanesToDataStorage(); } void QmitkRenderWindowWidget::RemovePlanesFromDataStorage() { m_CrosshairManager->RemovePlanesFromDataStorage(); } void QmitkRenderWindowWidget::InitializeGUI() { m_Layout = new QVBoxLayout(this); m_Layout->setMargin(0); setLayout(m_Layout); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); setContentsMargins(0, 0, 0, 0); if (nullptr == m_DataStorage) { return; } mitk::RenderingManager::GetInstance()->SetDataStorage(m_DataStorage); // create render window for this render window widget m_RenderWindow = new QmitkRenderWindow(this, m_WidgetName, nullptr); m_RenderWindow->SetLayoutIndex(mitk::AnatomicalPlane::Sagittal); connect(m_RenderWindow, &QmitkRenderWindow::ResetGeometry, this, &QmitkRenderWindowWidget::OnResetGeometry); auto sliceNavigationController = this->GetSliceNavigationController(); sliceNavigationController->SetDefaultViewDirection(mitk::AnatomicalPlane::Sagittal); - if (m_WindowControls) - { - m_UtilityWidget = new QmitkRenderWindowUtilityWidget(this, m_RenderWindow, m_DataStorage); - m_Layout->addWidget(m_UtilityWidget); - connect(m_UtilityWidget, &QmitkRenderWindowUtilityWidget::ReinitAction, - this, &QmitkRenderWindowWidget::OnReinitAction); - connect(m_UtilityWidget, &QmitkRenderWindowUtilityWidget::ResetAction, - this, &QmitkRenderWindowWidget::OnResetAction); - } - m_Layout->addWidget(m_RenderWindow); // set colors and corner annotation InitializeDecorations(); // use crosshair manager m_CrosshairManager = mitk::CrosshairManager::New(m_DataStorage, m_RenderWindow->GetRenderer()); sliceNavigationController->SetCrosshairEvent.AddListener( mitk::MessageDelegate1( this, &QmitkRenderWindowWidget::SetCrosshairPosition)); // finally add observer, after all relevant objects have been created / initialized sliceNavigationController->ConnectGeometrySendEvent(this); sliceNavigationController->ConnectGeometrySliceEvent(this); mitk::TimeGeometry::ConstPointer timeGeometry = m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll()); mitk::RenderingManager::GetInstance()->InitializeView(m_RenderWindow->GetVtkRenderWindow(), timeGeometry); } void QmitkRenderWindowWidget::InitializeDecorations() { vtkRenderer* vtkRenderer = m_RenderWindow->GetRenderer()->GetVtkRenderer(); if (nullptr == vtkRenderer) { return; } // initialize background color gradients float black[3] = { 0.0f, 0.0f, 0.0f }; SetGradientBackgroundColors(black, black); // initialize annotation text and decoration color setFrameStyle(QFrame::Box | QFrame::Plain); m_CornerAnnotation = vtkSmartPointer::New(); m_CornerAnnotation->SetText(0, "Sagittal"); m_CornerAnnotation->SetMaximumFontSize(12); if (0 == vtkRenderer->HasViewProp(m_CornerAnnotation)) { vtkRenderer->AddViewProp(m_CornerAnnotation); } float white[3] = { 1.0f, 1.0f, 1.0f }; SetDecorationColor(mitk::Color(white)); } void QmitkRenderWindowWidget::SetCrosshairPosition(const mitk::Point3D& newPosition) { m_CrosshairManager->SetCrosshairPosition(newPosition); this->RequestUpdate(); } mitk::Point3D QmitkRenderWindowWidget::GetCrosshairPosition() const { return m_CrosshairManager->GetCrosshairPosition(); } void QmitkRenderWindowWidget::SetGeometry(const itk::EventObject& event) { if (!mitk::SliceNavigationController::GeometrySendEvent(nullptr, 0).CheckEvent(&event)) { return; } auto sliceNavigationController = this->GetSliceNavigationController(); const auto* inputTimeGeometry = sliceNavigationController->GetInputWorldTimeGeometry(); m_CrosshairManager->ComputeOrientedTimeGeometries(inputTimeGeometry); - - if (m_WindowControls) - { - this->ComputeInvertedSliceNavigation(); - } } void QmitkRenderWindowWidget::SetGeometrySlice(const itk::EventObject& event) { if (!mitk::SliceNavigationController::GeometrySliceEvent(nullptr, 0).CheckEvent(&event)) { return; } auto sliceNavigationController = this->GetSliceNavigationController(); m_CrosshairManager->UpdateSlice(sliceNavigationController); } -void QmitkRenderWindowWidget::ComputeInvertedSliceNavigation() -{ - auto sliceNavigationController = this->GetSliceNavigationController(); - auto viewDirection = sliceNavigationController->GetViewDirection(); - unsigned int axis = 0; - switch (viewDirection) - { - case mitk::AnatomicalPlane::Original: - return; - case mitk::AnatomicalPlane::Axial: - { - axis = 2; - break; - } - case mitk::AnatomicalPlane::Coronal: - { - axis = 1; - break; - } - case mitk::AnatomicalPlane::Sagittal: - { - axis = 0; - break; - } - } - - const auto* inputTimeGeometry = sliceNavigationController->GetInputWorldTimeGeometry(); - const mitk::BaseGeometry* rendererGeometry = m_RenderWindow->GetRenderer()->GetCurrentWorldGeometry(); - - // todo: check timepoint / timestep - mitk::TimeStepType timeStep = sliceNavigationController->GetTime()->GetPos(); - mitk::BaseGeometry::ConstPointer geometry = inputTimeGeometry->GetGeometryForTimeStep(timeStep); - - mitk::AffineTransform3D::MatrixType matrix = geometry->GetIndexToWorldTransform()->GetMatrix(); - matrix.GetVnlMatrix().normalize_columns(); - mitk::AffineTransform3D::MatrixType::InternalMatrixType inverseMatrix = matrix.GetInverse(); - - int dominantAxis = itk::Function::Max3(inverseMatrix[0][axis], inverseMatrix[1][axis], inverseMatrix[2][axis]); - - bool referenceGeometryAxisInverted = inverseMatrix[dominantAxis][axis] < 0; - bool rendererZAxisInverted = rendererGeometry->GetAxisVector(2)[axis] < 0; - - m_UtilityWidget->SetInvertedSliceNavigation(referenceGeometryAxisInverted != rendererZAxisInverted); -} - -void QmitkRenderWindowWidget::OnReinitAction(QList selectedNodes) -{ - if (selectedNodes.empty()) - { - return; - } - - auto* baseRenderer = mitk::BaseRenderer::GetInstance(m_RenderWindow->renderWindow()); - auto boundingBoxPredicate = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("includeInBoundingBox", mitk::BoolProperty::New(false), baseRenderer)); - mitk::DataStorage::SetOfObjects::Pointer nodes = mitk::DataStorage::SetOfObjects::New(); - for (const auto& dataNode : selectedNodes) - { - if (boundingBoxPredicate->CheckNode(dataNode)) - { - nodes->InsertElement(nodes->Size(), dataNode); - } - } - - if (nodes->empty()) - { - return; - } - - if (1 == nodes->Size()) - { - auto selectedImage = dynamic_cast(nodes->ElementAt(0)->GetData()); - - if (nullptr != selectedImage) - { - mitk::RenderingManager::GetInstance()->InitializeView(baseRenderer->GetRenderWindow(), selectedImage->GetTimeGeometry()); - return; - } - } - - auto boundingGeometry = m_DataStorage->ComputeBoundingGeometry3D(nodes, "visible", baseRenderer); - mitk::RenderingManager::GetInstance()->InitializeView(baseRenderer->GetRenderWindow(), boundingGeometry); -} - -void QmitkRenderWindowWidget::OnResetAction(QList selectedNodes) -{ - if (selectedNodes.empty()) - { - return; - } - - auto selectedImage = dynamic_cast(selectedNodes.front()->GetData()); - if (nullptr == selectedImage) - { - return; - } - - const mitk::TimeGeometry* referenceGeometry = selectedImage->GetTimeGeometry(); - this->ResetGeometry(referenceGeometry); -} - void QmitkRenderWindowWidget::OnResetGeometry() { auto* baseRenderer = mitk::BaseRenderer::GetInstance(m_RenderWindow->GetRenderWindow()); const auto* interactionReferenceGeometry = baseRenderer->GetInteractionReferenceGeometry(); this->ResetGeometry(interactionReferenceGeometry); m_RenderWindow->ShowOverlayMessage(false); } void QmitkRenderWindowWidget::ResetGeometry(const mitk::TimeGeometry* referenceGeometry) { if (nullptr == referenceGeometry) { return; } mitk::TimeStepType imageTimeStep = 0; // store the current position to set it again later, if the camera should not be reset mitk::Point3D currentPosition = this->GetCrosshairPosition(); // store the current time step to set it again later, if the camera should not be reset auto* renderingManager = mitk::RenderingManager::GetInstance(); const auto currentTimePoint = renderingManager->GetTimeNavigationController()->GetSelectedTimePoint(); if (referenceGeometry->IsValidTimePoint(currentTimePoint)) { imageTimeStep = referenceGeometry->TimePointToTimeStep(currentTimePoint); } auto* baseRenderer = mitk::BaseRenderer::GetInstance(m_RenderWindow->renderWindow()); renderingManager->InitializeView(baseRenderer->GetRenderWindow(), referenceGeometry, false); // reset position and time step this->GetSliceNavigationController()->SelectSliceByPoint(currentPosition); renderingManager->GetTimeNavigationController()->GetTime()->SetPos(imageTimeStep); }