diff --git a/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.cpp b/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.cpp index 7af9997751..3195aa55ef 100644 --- a/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.cpp +++ b/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.cpp @@ -1,206 +1,211 @@ /*============================================================================ 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 "SimpleRenderWindowView.h" #include #include "org_mitk_example_gui_customviewer_views_Activator.h" #include #include #include #include #include /** * \brief Helper class adapted from QmitkAbstractRenderEditor by defining the correct plugin context. * * This helper class adapted from QmitkAbstractRenderEditor provides the rendering manager interface. */ // //! [SimpleRenderWindowViewHelper] class AbstractRenderWindowViewPrivate { public: AbstractRenderWindowViewPrivate() : m_RenderingManagerInterface(mitk::MakeRenderingManagerInterface(mitk::RenderingManager::GetInstance())) // //! [SimpleRenderWindowViewHelper] { } ~AbstractRenderWindowViewPrivate() { delete m_RenderingManagerInterface; } mitk::IRenderingManager *m_RenderingManagerInterface; }; const std::string SimpleRenderWindowView::VIEW_ID = "org.mitk.customviewer.views.simplerenderwindowview"; SimpleRenderWindowView::SimpleRenderWindowView() : m_RenderWindow(nullptr), d(new AbstractRenderWindowViewPrivate) { } SimpleRenderWindowView::~SimpleRenderWindowView() { } QmitkRenderWindow *SimpleRenderWindowView::GetActiveQmitkRenderWindow() const { return m_RenderWindow; } QHash SimpleRenderWindowView::GetRenderWindows() const { QHash wnds; wnds.insert("axial", m_RenderWindow); return wnds; } QHash SimpleRenderWindowView::GetQmitkRenderWindows() const { QHash wnds; wnds.insert("axial", m_RenderWindow); return wnds; } QmitkRenderWindow *SimpleRenderWindowView::GetRenderWindow(const QString &id) const { if (id == "axial") { return m_RenderWindow; } return nullptr; } QmitkRenderWindow *SimpleRenderWindowView::GetQmitkRenderWindow(const QString &id) const { if (id == "axial") { return m_RenderWindow; } return nullptr; } QmitkRenderWindow *SimpleRenderWindowView::GetQmitkRenderWindow(const mitk::AnatomicalPlane& orientation) const { if (orientation == mitk::AnatomicalPlane::Axial) { return m_RenderWindow; } return 0; } void SimpleRenderWindowView::SetFocus() { m_RenderWindow->setFocus(); } // //! [SimpleRenderWindowViewCreatePartControl] void SimpleRenderWindowView::CreateQtPartControl(QWidget *parent) { QVBoxLayout *layout = new QVBoxLayout(parent); layout->setContentsMargins(0, 0, 0, 0); m_RenderWindow = new QmitkRenderWindow(parent); layout->addWidget(m_RenderWindow); mitk::DataStorage::Pointer ds = this->GetDataStorage(); m_RenderWindow->GetRenderer()->SetDataStorage(ds); this->RequestUpdate(); } // //! [SimpleRenderWindowViewCreatePartControl] mitk::IRenderingManager *SimpleRenderWindowView::GetRenderingManager() const { // we use the global rendering manager here. This should maybe replaced // by a local one, managing only the render windows specific for the view return d->m_RenderingManagerInterface; } void SimpleRenderWindowView::RequestUpdate(mitk::RenderingManager::RequestType requestType) { if (GetRenderingManager()) GetRenderingManager()->RequestUpdateAll(requestType); } void SimpleRenderWindowView::ForceImmediateUpdate(mitk::RenderingManager::RequestType requestType) { if (GetRenderingManager()) GetRenderingManager()->ForceImmediateUpdateAll(requestType); } -void SimpleRenderWindowView::SetReferenceGeometry(const mitk::TimeGeometry* /*referenceGeometry*/, bool /*resetCamera*/) +void SimpleRenderWindowView::InitializeViews(const mitk::TimeGeometry* /*geometry*/, bool /*resetCamera*/) +{ + // not implemented +} + +void SimpleRenderWindowView::SetInteractionReferenceGeometry(const mitk::TimeGeometry* /*referenceGeometry*/) { // not implemented } bool SimpleRenderWindowView::HasCoupledRenderWindows() const { return false; } mitk::SliceNavigationController *SimpleRenderWindowView::GetTimeNavigationController() const { if (GetRenderingManager()) return GetRenderingManager()->GetTimeNavigationController(); return nullptr; } mitk::Point3D SimpleRenderWindowView::GetSelectedPosition(const QString& /*id*/) const { const mitk::PlaneGeometry* pg = m_RenderWindow->GetSliceNavigationController()->GetCurrentPlaneGeometry(); if (pg) { return pg->GetCenter(); } else { return mitk::Point3D(); } } void SimpleRenderWindowView::SetSelectedPosition(const mitk::Point3D&, const QString&) { } mitk::TimePointType SimpleRenderWindowView::GetSelectedTimePoint(const QString& /*id*/) const { auto timeNavigator = this->GetTimeNavigationController(); if (nullptr != timeNavigator) { return timeNavigator->GetSelectedTimePoint(); } return 0; } void SimpleRenderWindowView::EnableDecorations(bool enable, const QStringList& decorations) { if (decorations.isEmpty() || decorations.contains(DECORATION_MENU)) { m_RenderWindow->ActivateMenuWidget(enable); } } bool SimpleRenderWindowView::IsDecorationEnabled(const QString& decoration) const { if (decoration == DECORATION_MENU) { return m_RenderWindow->GetActivateMenuWidgetFlag(); } return false; } QStringList SimpleRenderWindowView::GetDecorations() const { QStringList decorations; decorations << DECORATION_MENU; return decorations; } diff --git a/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.h b/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.h index 1c3ff52d3e..7f055389b9 100644 --- a/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.h +++ b/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.h @@ -1,157 +1,162 @@ /*============================================================================ 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 SimpleRenderWindowView_H_ #define SimpleRenderWindowView_H_ #include #include #include class QmitkRenderWindow; class AbstractRenderWindowViewPrivate; /** * \brief A view class suited for the ViewerPerspective within the custom viewer plug-in. * * This view class contributes data node rendering functionality to the ViewerPerspective. * Being a subclass of QmitkAbstractView, this class yields access to the data storage and * thus is interconnected with the mitk::QmitkDataManagerView present in the same perspective. * As a subclass of mitk::IRenderWindowPart, this class provides an instance of QmitkRenderWindow. * A SimpleRenderWindowView instance is part of the ViewerPerspective for data visualization. */ // //! [SimpleRenderWindowViewDeclaration] class SimpleRenderWindowView : public QmitkAbstractView, public mitk::IRenderWindowPart // //! [SimpleRenderWindowViewDeclaration] { Q_OBJECT public: /** * Standard constructor. */ SimpleRenderWindowView(); ~SimpleRenderWindowView() override; /** * String based view identifier. */ static const std::string VIEW_ID; berryObjectMacro(SimpleRenderWindowView); // ------------------- mitk::IRenderWindowPart ---------------------- /** * \see mitk::IRenderWindowPart::GetActiveQmitkRenderWindow() */ QmitkRenderWindow *GetActiveQmitkRenderWindow() const override; QHash GetRenderWindows() const; /** * \see mitk::IRenderWindowPart::GetQmitkRenderWindows() */ QHash GetQmitkRenderWindows() const override; QmitkRenderWindow *GetRenderWindow(const QString &id) const; /** * \see mitk::IRenderWindowPart::GetQmitkRenderWindow(QString) */ QmitkRenderWindow *GetQmitkRenderWindow(const QString &id) const override; /** * \see mitk::IRenderWindowPart::GetQmitkRenderWindow(mitk::AnatomicalPlane) */ QmitkRenderWindow *GetQmitkRenderWindow(const mitk::AnatomicalPlane &orientation) const override; /** * \see mitk::QmitkAbstractRenderEditor::GetRenderingManager() */ mitk::IRenderingManager *GetRenderingManager() const override; /** * \see mitk::QmitkAbstractRenderEditor::RequestUpdate() */ void RequestUpdate( mitk::RenderingManager::RequestType requestType = mitk::RenderingManager::REQUEST_UPDATE_ALL) override; /** * \see mitk::QmitkAbstractRenderEditor::ForceImmediateUpdate() */ void ForceImmediateUpdate(mitk::RenderingManager::RequestType) override; /** - * \see mitk::IRenderWindowPart::SetReferenceGeometry() + * \see mitk::IRenderWindowPart::InitializeViews() */ - void SetReferenceGeometry(const mitk::TimeGeometry* referenceGeometry, bool resetCamera) override; + void InitializeViews(const mitk::TimeGeometry* geometry, bool resetCamera) override; + + /** + * \see mitk::IRenderWindowPart::SetInteractionReferenceGeometry() + */ + void SetInteractionReferenceGeometry(const mitk::TimeGeometry* referenceGeometry) override; /** * \see mitk::IRenderWindowPart::HasCoupledRenderWindows */ bool HasCoupledRenderWindows() const override; /** * \see mitk::IRenderWindowPart::GetTimeNavigationController() */ mitk::SliceNavigationController *GetTimeNavigationController() const override; /** * \see mitk::IRenderWindowPart::GetSelectionPosition() */ mitk::Point3D GetSelectedPosition(const QString& id = QString()) const override; /** * \see mitk::IRenderWindowPart::SetSelectedPosition() */ void SetSelectedPosition(const mitk::Point3D& pos, const QString& id = QString()) override; /** * \see mitk::IRenderWindowPart::GetSelectedTimePoint() */ mitk::TimePointType GetSelectedTimePoint(const QString& id = QString()) const override; /** * \see mitk::IRenderWindowPart::EnableDecorations() */ void EnableDecorations(bool enable, const QStringList& decorations = QStringList()) override; /** * \see mitk::IRenderWindowPart::IsDecorationEnabled() */ bool IsDecorationEnabled(const QString& decoration) const override; /** * \see mitk::IRenderWindowPart::GetDecorations() */ QStringList GetDecorations() const override; protected: void SetFocus() override; /** * Creates the QmitkRenderWindow whose renderer is being connected to the view's data storage. */ void CreateQtPartControl(QWidget *parent) override; private: /** * The view's render window. */ QmitkRenderWindow *m_RenderWindow; QScopedPointer d; }; #endif /*SimpleRenderWindowView_H_*/ diff --git a/Modules/Core/include/mitkBaseRenderer.h b/Modules/Core/include/mitkBaseRenderer.h index 3a1efb7f18..f89e5bac0c 100644 --- a/Modules/Core/include/mitkBaseRenderer.h +++ b/Modules/Core/include/mitkBaseRenderer.h @@ -1,471 +1,505 @@ /*============================================================================ 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 mitkBaseRenderer_h #define mitkBaseRenderer_h #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mitk { class Mapper; class BaseLocalStorageHandler; #pragma GCC visibility push(default) itkEventMacroDeclaration(RendererResetEvent, itk::AnyEvent); #pragma GCC visibility pop /* * \brief Organizes the rendering process * * A BaseRenderer contains a reference to a given vtkRenderWindow * and a corresponding vtkRenderer. * The BaseRenderer defines which mapper should be used (2D / 3D) * and which view direction should be rendered. * * All existing BaseRenderer are stored in a static variable * that can be accessed / modified via the static functions. * VtkPropRenderer is a concrete implementation of a BaseRenderer. */ class MITKCORE_EXPORT BaseRenderer : public itk::Object { public: typedef std::map BaseRendererMapType; static BaseRendererMapType baseRendererMap; /** * \brief Defines which kind of mapper (e.g. 2D or 3D) should be used. */ enum StandardMapperSlot { Standard2D = 1, Standard3D = 2 }; static BaseRenderer* GetInstance(vtkRenderWindow* renderWindow); static void AddInstance(vtkRenderWindow* renderWindow, BaseRenderer* baseRenderer); static void RemoveInstance(vtkRenderWindow* renderWindow); static BaseRenderer* GetByName(const std::string& name); static vtkRenderWindow* GetRenderWindowByName(const std::string& name); /** * \brief Get a map of specific RenderWindows */ static BaseRendererMapType GetSpecificRenderWindows(MapperSlotId mapper); /** * \brief Convenience function: Get a map of all 2D RenderWindows */ static BaseRendererMapType GetAll2DRenderWindows(); /** * \brief Convenience function: Get a map of all 3D RenderWindows */ static BaseRendererMapType GetAll3DRenderWindows(); mitkClassMacroItkParent(BaseRenderer, itk::Object); BaseRenderer(const char* name = nullptr, vtkRenderWindow* renderWindow = nullptr); void RemoveAllLocalStorages(); void RegisterLocalStorageHandler(BaseLocalStorageHandler* lsh); void UnregisterLocalStorageHandler(BaseLocalStorageHandler* lsh); virtual void SetDataStorage(DataStorage* storage); virtual DataStorage::Pointer GetDataStorage() const { return m_DataStorage.GetPointer(); } vtkRenderWindow* GetRenderWindow() const { return m_RenderWindow; } vtkRenderer* GetVtkRenderer() const { return m_VtkRenderer; } /** * \brief Get the dispatcher, which handles events for this base renderer. */ Dispatcher::Pointer GetDispatcher() const; /** * \brief Set a new size for the render window. */ virtual void Resize(int w, int h); /** * \brief Initialize the base renderer with a vtk render window. * Set the new renderer for the camera controller. */ virtual void InitRenderer(vtkRenderWindow* renderwindow); /** * \brief Set the initial size for the render window. */ virtual void InitSize(int w, int h); virtual void DrawOverlayMouse(Point2D&) { MITK_INFO << "BaseRenderer::DrawOverlayMouse() should be in concret implementation OpenGLRenderer." << std::endl; } /** * \brief Set the world time geometry using the given TimeGeometry. * * Setting a new world time geometry updates the current world geometry and the * curent world plane geometry, using the currently selected slice and timestep. */ - virtual void SetWorldTimeGeometry(const mitk::TimeGeometry* geometry); + virtual void SetWorldTimeGeometry(const TimeGeometry* geometry); itkGetConstObjectMacro(WorldTimeGeometry, TimeGeometry); + /** + * \brief Set the interaction reference world time geometry using the given TimeGeometry. + * + * Setting a new interaction reference world time geometry also updates the + * alignment status of the reference geometry, which can be retrieved using + * 'GetReferenceGeometryAligned'. + * Using a nullptr as the interaction reference geomertry implies that + * no requirements on the geometry exist, thus in this case any check + * will result in 'ReferenceGeometryAligned' being true. + * + * \param geometry The reference geometry used for render window interaction. + */ + virtual void SetInteractionReferenceGeometry(const TimeGeometry* geometry); + + /** + * \brief Get the current interaction reference geometry. + */ + itkGetConstObjectMacro(InteractionReferenceGeometry, TimeGeometry); + + /** + * \brief Return if the reference geometry aligns with the base renderer's world geometry. + * If true, the interaction reference geometry aligns with the base renderer's + * current world geometry. False otherwise. + */ + itkGetMacro(ReferenceGeometryAligned, bool); + /** * \brief Get the current time-extracted 3D-geometry. */ itkGetConstObjectMacro(CurrentWorldGeometry, BaseGeometry); /** * \brief Get the current slice-extracted 2D-geometry. */ itkGetConstObjectMacro(CurrentWorldPlaneGeometry, PlaneGeometry); virtual bool SetWorldGeometryToDataStorageBounds() { return false; } /** * \brief Set the slice that should be used for geometry extraction. * * The slice defines the current slice-extracted 2D-geometry (CurrentWorldPlaneGeometry). * Setting a new slice will update the current world geometry and the * curent world plane geometry. */ virtual void SetSlice(unsigned int slice); itkGetConstMacro(Slice, unsigned int); /** * \brief Set the timestep that should be used for geometry extraction. * * The timestep defines the current time-extracted 3D-geometry (CurrentWorldGeometry). * Setting a new timestep will update the current world geometry and the * curent world plane geometry. */ virtual void SetTimeStep(unsigned int timeStep); itkGetConstMacro(TimeStep, unsigned int); /** * \brief Get the timestep of a BaseData object which * exists at the time of the currently displayed content. * * Returns -1 if there is no data at the current time. */ TimeStepType GetTimeStep(const BaseData* data) const; /** * \brief Get the time in ms of the currently display content (geometry). */ ScalarType GetTime() const; /** * \brief Set the world time geometry using the geometry of the given event. * * The function is triggered by a SliceNavigationController::GeometrySendEvent. */ virtual void SetGeometry(const itk::EventObject& geometrySliceEvent); /** * \brief Set the current world plane geometry using the existing current world geometry. * * The function is triggered by a SliceNavigationController::GeometryUpdateEvent. */ virtual void UpdateGeometry(const itk::EventObject& geometrySliceEvent); /** * \brief Set the current slice using "SetSlice" and update the current world geometry * and the current world plane geometry. * * The function is triggered by a SliceNavigationController::GeometrySliceEvent. */ virtual void SetGeometrySlice(const itk::EventObject& geometrySliceEvent); /** * \brief Set the current time using "SetTimeStep" and update the current world geometry * and the current world plane geometry. * * The function is triggered by a TimeNavigationController::TimeEvent. */ virtual void SetGeometryTime(const itk::EventObject& geometryTimeEvent); itkGetObjectMacro(CurrentWorldPlaneGeometryNode, DataNode); /** * \brief Modify the update time of the current world plane geometry and force reslicing. */ void SendUpdateSlice(); /** * \brief Get timestamp of the update time of the current world plane geometry. */ itkGetMacro(CurrentWorldPlaneGeometryUpdateTime, unsigned long); /** * \brief Get timestamp of the update time of the current timestep. */ itkGetMacro(TimeStepUpdateTime, unsigned long); /** * \brief Pick a world coordinate (x,y,z) given a display coordinate (x,y). * * \warning Not implemented; has to be overwritten in subclasses. */ virtual void PickWorldPoint(const Point2D& diplayPosition, Point3D& worldPosition) const = 0; /** * \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 nullptr; } /** * \brief Get the currently used mapperID. */ itkGetMacro(MapperID, MapperSlotId); itkGetConstMacro(MapperID, MapperSlotId); /** * \brief Set the used mapperID. */ virtual void SetMapperID(MapperSlotId id); virtual int* GetSize() const; virtual int* GetViewportSize() const; void SetSliceNavigationController(SliceNavigationController* SlicenavigationController); itkGetObjectMacro(CameraController, CameraController); itkGetObjectMacro(SliceNavigationController, SliceNavigationController); itkGetObjectMacro(CameraRotationController, CameraRotationController); itkGetMacro(EmptyWorldGeometry, bool); /** * \brief Getter/Setter for defining if the displayed region should be shifted * or rescaled if the render window is resized. */ itkGetMacro(KeepDisplayedRegion, bool); itkSetMacro(KeepDisplayedRegion, bool); /** * \brief Return the name of the base renderer */ const char* GetName() const { return m_Name.c_str(); } /** * \brief Return the size in x-direction of the base renderer. */ int GetSizeX() const { return this->GetSize()[0]; } /** * \brief Return the size in y-direction of the base renderer. */ int GetSizeY() const { return this->GetSize()[1]; } /** * \brief Return the bounds of the bounding box of the * current world geometry (time-extracted 3D-geometry). * * If the geometry is empty, the bounds are set to zero. */ const double* GetBounds() const; void RequestUpdate(); void ForceImmediateUpdate(); /** * \brief Return the number of mappers which are visible and have * level-of-detail rendering enabled. */ unsigned int GetNumberOfVisibleLODEnabledMappers() const; /** * \brief Convert a display point to the 3D world index * using the geometry of the renderWindow. */ void DisplayToWorld(const Point2D& displayPoint, Point3D& worldIndex) const; /** * \brief Convert a display point to the 2D world index, mapped onto the display plane * using the geometry of the renderWindow. */ void DisplayToPlane(const Point2D& displayPoint, Point2D& planePointInMM) const; /** * \brief Convert a 3D world index to the display point * using the geometry of the renderWindow. */ void WorldToDisplay(const Point3D& worldIndex, Point2D& displayPoint) const; /** * \brief Convert a 3D world index to the point on the viewport * using the geometry of the renderWindow. */ void WorldToView(const Point3D& worldIndex, Point2D& viewPoint) const; /** * \brief Convert a 2D plane coordinate to the display point * using the geometry of the renderWindow. */ void PlaneToDisplay(const Point2D& planePointInMM, Point2D& displayPoint) const; /** * \brief Convert a 2D plane coordinate to the point on the viewport * using the geometry of the renderWindow. */ void PlaneToView(const Point2D& planePointInMM, Point2D& viewPoint) const; double GetScaleFactorMMPerDisplayUnit() const; Point2D GetDisplaySizeInMM() const; Point2D GetViewportSizeInMM() const; Point2D GetOriginInMM() const; itkGetConstMacro(ConstrainZoomingAndPanning, bool) virtual void SetConstrainZoomingAndPanning(bool constrain); protected: ~BaseRenderer() override; virtual void Update() = 0; vtkRenderWindow* m_RenderWindow; vtkRenderer* m_VtkRenderer; MapperSlotId m_MapperID; DataStorage::Pointer m_DataStorage; unsigned long m_LastUpdateTime; CameraController::Pointer m_CameraController; CameraRotationController::Pointer m_CameraRotationController; SliceNavigationController::Pointer m_SliceNavigationController; void UpdateCurrentGeometries(); virtual void SetCurrentWorldPlaneGeometry(const PlaneGeometry* geometry2d); virtual void SetCurrentWorldGeometry(const BaseGeometry *geometry); private: /** * \brief Pointer to the current TimeGeometry. * * This WorldTimeGeometry is used to extract a SlicedGeometry3D, * using the current timestep (set via SetTimeStep). - * The time-extracted 3D-geometry is used as the "CurrentWorldgeometry". - * It will be set using the "SetCurrentWorldGeometry"-function. + * The time-extracted 3D-geometry is used as the "CurrentWorldGeometry". * A PlaneGeometry can further be extracted using the current slice (set via SetSlice). * The slice-extracted 2D-geometry is used as the "CurrentWorldPlaneGeometry". - * It will be set using the "SetCurrentWorldPlaneGeometry"-function. */ TimeGeometry::ConstPointer m_WorldTimeGeometry; + /** + * \brief Pointer to the interaction reference geometry used for interaction. + * + * This InteractionReferenceGeometry is used to decide if a base renderer / + * render window is able to correctly handle display interaction, e.g. drawing. + * It will be set using the "SetInteractionReferenceGeometry"-function. + */ + TimeGeometry::ConstPointer m_InteractionReferenceGeometry; + /** * \brief Pointer to the current time-extracted 3D-geometry. * * This CurrentWorldGeometry is used to define the bounds for this * BaseRenderer. * It will be set using the "SetCurrentWorldGeometry"-function. */ BaseGeometry::ConstPointer m_CurrentWorldGeometry; /** * \brief Pointer to the current slice-extracted 2D-geometry. * * This CurrentWorldPlaneGeometry is used to define the maximal * area (2D manifold) to be rendered in case we are doing 2D-rendering. * It will be set using the "SetCurrentWorldPlaneGeometry"-function. */ PlaneGeometry::Pointer m_CurrentWorldPlaneGeometry; unsigned int m_Slice; unsigned int m_TimeStep; itk::TimeStamp m_CurrentWorldPlaneGeometryUpdateTime; itk::TimeStamp m_TimeStepUpdateTime; BindDispatcherInteractor* m_BindDispatcherInteractor; bool m_KeepDisplayedRegion; + bool m_ReferenceGeometryAligned; protected: void PrintSelf(std::ostream& os, itk::Indent indent) const override; PlaneGeometryData::Pointer m_CurrentWorldPlaneGeometryData; DataNode::Pointer m_CurrentWorldPlaneGeometryNode; unsigned long m_CurrentWorldPlaneGeometryTransformTime; std::string m_Name; double m_Bounds[6]; bool m_EmptyWorldGeometry; typedef std::set LODEnabledMappersType; unsigned int m_NumberOfVisibleLODEnabledMappers; std::list m_RegisteredLocalStorageHandlers; bool m_ConstrainZoomingAndPanning; }; } // namespace mitk #endif diff --git a/Modules/Core/include/mitkBaseRendererHelper.h b/Modules/Core/include/mitkBaseRendererHelper.h index f555e1981b..c410ae4da9 100644 --- a/Modules/Core/include/mitkBaseRendererHelper.h +++ b/Modules/Core/include/mitkBaseRendererHelper.h @@ -1,31 +1,39 @@ /*============================================================================ 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 mitkBaseRendererHelper_h #define mitkBaseRendererHelper_h #include #include namespace mitk { namespace BaseRendererHelper { /* - * \brief + * \brief Test if the given time geometry aligns with the current world geometry of the given base renderer. + * To compare the two geometries the given time geometry is first converted into a oriented time geometry, + * depending on the current view direction of the base renderer. + * A time-extracted 3D geometry is created by using the current timepoint of the global time navigation + * controller. + * If the bounding boxes of these two geometries are equal (within a small epsilon), the function returns true, + * otherwise false. + * If the given time geometry is a nullptr, the function returns true as well, since a nullptr implies that + * no requirements on the geometry exist. */ - MITKCORE_EXPORT bool IsRendererAlignedWithSegmentation(BaseRenderer* renderer, const TimeGeometry* timeGeometry); + MITKCORE_EXPORT bool IsRendererGeometryAlignedWithGeometry(BaseRenderer* renderer, const TimeGeometry* timeGeometry); } // namespace BaseRendererHelper } // namespace mitk #endif diff --git a/Modules/Core/src/Rendering/mitkBaseRenderer.cpp b/Modules/Core/src/Rendering/mitkBaseRenderer.cpp index e692289a1d..e4777c3b35 100644 --- a/Modules/Core/src/Rendering/mitkBaseRenderer.cpp +++ b/Modules/Core/src/Rendering/mitkBaseRenderer.cpp @@ -1,756 +1,772 @@ /*============================================================================ 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 "mitkBaseRenderer.h" +#include "mitkBaseRendererHelper.h" + #include "mitkMapper.h" #include "mitkResliceMethodProperty.h" // Geometries #include "mitkSlicedGeometry3D.h" #include "mitkVtkLayerController.h" #include "mitkInteractionConst.h" #include "mitkProperties.h" #include "mitkWeakPointerProperty.h" // VTK #include #include #include #include #include namespace mitk { itkEventMacroDefinition(RendererResetEvent, itk::AnyEvent); } mitk::BaseRenderer::BaseRendererMapType mitk::BaseRenderer::baseRendererMap; mitk::BaseRenderer *mitk::BaseRenderer::GetInstance(vtkRenderWindow *renWin) { for (auto mapit = baseRendererMap.begin(); mapit != baseRendererMap.end(); ++mapit) { if ((*mapit).first == renWin) return (*mapit).second; } return nullptr; } void mitk::BaseRenderer::AddInstance(vtkRenderWindow *renWin, BaseRenderer *baseRenderer) { if (renWin == nullptr || baseRenderer == nullptr) 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) { auto mapit = baseRendererMap.find(renWin); if (mapit != baseRendererMap.end()) baseRendererMap.erase(mapit); } mitk::BaseRenderer *mitk::BaseRenderer::GetByName(const std::string &name) { for (auto mapit = baseRendererMap.begin(); mapit != baseRendererMap.end(); ++mapit) { if ((*mapit).second->m_Name == name) return (*mapit).second; } return nullptr; } vtkRenderWindow *mitk::BaseRenderer::GetRenderWindowByName(const std::string &name) { for (auto mapit = baseRendererMap.begin(); mapit != baseRendererMap.end(); ++mapit) { if ((*mapit).second->m_Name == name) return (*mapit).first; } return nullptr; } mitk::BaseRenderer::BaseRendererMapType mitk::BaseRenderer::GetSpecificRenderWindows(MapperSlotId mapper) { BaseRendererMapType allRenderWindows; for (auto mapit = baseRendererMap.begin(); mapit != baseRendererMap.end(); ++mapit) { if (mapper == mapit->second->GetMapperID()) { allRenderWindows.insert(BaseRendererMapType::value_type(mapit->first, mapit->second)); } } return allRenderWindows; } mitk::BaseRenderer::BaseRendererMapType mitk::BaseRenderer::GetAll2DRenderWindows() { return GetSpecificRenderWindows(BaseRenderer::Standard2D); } mitk::BaseRenderer::BaseRendererMapType mitk::BaseRenderer::GetAll3DRenderWindows() { return GetSpecificRenderWindows(BaseRenderer::Standard3D); } mitk::BaseRenderer::BaseRenderer(const char *name, vtkRenderWindow *renWin) : m_RenderWindow(nullptr), m_VtkRenderer(nullptr), m_MapperID(StandardMapperSlot::Standard2D), m_DataStorage(nullptr), m_LastUpdateTime(0), m_CameraController(nullptr), m_CameraRotationController(nullptr), m_SliceNavigationController(nullptr), m_WorldTimeGeometry(nullptr), m_CurrentWorldGeometry(nullptr), m_CurrentWorldPlaneGeometry(nullptr), m_Slice(0), m_TimeStep(), m_CurrentWorldPlaneGeometryUpdateTime(), m_TimeStepUpdateTime(), m_KeepDisplayedRegion(true), m_CurrentWorldPlaneGeometryData(nullptr), m_CurrentWorldPlaneGeometryNode(nullptr), m_CurrentWorldPlaneGeometryTransformTime(0), m_Name(name), m_EmptyWorldGeometry(true), 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 != nullptr) { m_Name = name; } else { m_Name = "unnamed renderer"; itkWarningMacro(<< "Created unnamed renderer. Bad for serialization. Please choose a name."); } if (renWin != nullptr) { m_RenderWindow = renWin; m_RenderWindow->Register(nullptr); } else { itkWarningMacro(<< "Created mitkBaseRenderer without vtkRenderWindow present."); } // instances.insert( this ); // adding this BaseRenderer to the List of all BaseRenderer m_BindDispatcherInteractor = new mitk::BindDispatcherInteractor(GetName()); WeakPointerProperty::Pointer rendererProp = WeakPointerProperty::New((itk::Object *)this); m_CurrentWorldPlaneGeometry = mitk::PlaneGeometry::New(); m_CurrentWorldPlaneGeometryData = mitk::PlaneGeometryData::New(); m_CurrentWorldPlaneGeometryData->SetPlaneGeometry(m_CurrentWorldPlaneGeometry); m_CurrentWorldPlaneGeometryNode = mitk::DataNode::New(); m_CurrentWorldPlaneGeometryNode->SetData(m_CurrentWorldPlaneGeometryData); m_CurrentWorldPlaneGeometryNode->GetPropertyList()->SetProperty("renderer", rendererProp); m_CurrentWorldPlaneGeometryNode->GetPropertyList()->SetProperty("layer", IntProperty::New(1000)); m_CurrentWorldPlaneGeometryNode->SetProperty("reslice.thickslices", mitk::ResliceMethodProperty::New()); m_CurrentWorldPlaneGeometryNode->SetProperty("reslice.thickslices.num", mitk::IntProperty::New(1)); m_CurrentWorldPlaneGeometryTransformTime = m_CurrentWorldPlaneGeometryNode->GetVtkTransform()->GetMTime(); m_SliceNavigationController = mitk::SliceNavigationController::New(); m_SliceNavigationController->SetRenderer(this); m_SliceNavigationController->ConnectGeometrySendEvent(this); m_SliceNavigationController->ConnectGeometryUpdateEvent(this); m_SliceNavigationController->ConnectGeometrySliceEvent(this); m_SliceNavigationController->ConnectGeometryTimeEvent(this); m_CameraRotationController = mitk::CameraRotationController::New(); m_CameraRotationController->SetRenderWindow(m_RenderWindow); m_CameraRotationController->AcquireCamera(); m_CameraController = mitk::CameraController::New(); m_CameraController->SetRenderer(this); m_VtkRenderer = vtkRenderer::New(); m_VtkRenderer->SetMaximumNumberOfPeels(16); if (AntiAliasing::FastApproximate == RenderingManager::GetInstance()->GetAntiAliasing()) m_VtkRenderer->UseFXAAOn(); if (nullptr == mitk::VtkLayerController::GetInstance(m_RenderWindow)) mitk::VtkLayerController::AddInstance(m_RenderWindow, m_VtkRenderer); mitk::VtkLayerController::GetInstance(m_RenderWindow)->InsertSceneRenderer(m_VtkRenderer); } mitk::BaseRenderer::~BaseRenderer() { if (m_VtkRenderer != nullptr) { m_VtkRenderer->Delete(); m_VtkRenderer = nullptr; } if (m_CameraController.IsNotNull()) m_CameraController->SetRenderer(nullptr); mitk::VtkLayerController::RemoveInstance(m_RenderWindow); RemoveAllLocalStorages(); m_DataStorage = nullptr; if (m_BindDispatcherInteractor != nullptr) { delete m_BindDispatcherInteractor; } if (m_RenderWindow != nullptr) { m_RenderWindow->Delete(); m_RenderWindow = nullptr; } } void mitk::BaseRenderer::RemoveAllLocalStorages() { this->InvokeEvent(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); } void mitk::BaseRenderer::UnregisterLocalStorageHandler(mitk::BaseLocalStorageHandler *lsh) { m_RegisteredLocalStorageHandlers.remove(lsh); } void mitk::BaseRenderer::SetDataStorage(DataStorage *storage) { if (storage != m_DataStorage && storage != nullptr) { m_DataStorage = storage; m_BindDispatcherInteractor->SetDataStorage(m_DataStorage); this->Modified(); } } mitk::Dispatcher::Pointer mitk::BaseRenderer::GetDispatcher() const { return m_BindDispatcherInteractor->GetDispatcher(); } void mitk::BaseRenderer::Resize(int w, int h) { m_RenderWindow->SetSize(w, h); } void mitk::BaseRenderer::InitRenderer(vtkRenderWindow *renderwindow) { if (m_RenderWindow != renderwindow) { if (m_RenderWindow != nullptr) { m_RenderWindow->Delete(); } m_RenderWindow = renderwindow; if (m_RenderWindow != nullptr) { m_RenderWindow->Register(nullptr); } } RemoveAllLocalStorages(); if (m_CameraController.IsNotNull()) { m_CameraController->SetRenderer(this); } } void mitk::BaseRenderer::InitSize(int w, int h) { m_RenderWindow->SetSize(w, h); } void mitk::BaseRenderer::SetWorldTimeGeometry(const mitk::TimeGeometry* geometry) { if (m_WorldTimeGeometry == geometry) { return; } m_WorldTimeGeometry = geometry; this->UpdateCurrentGeometries(); } +void mitk::BaseRenderer::SetInteractionReferenceGeometry(const TimeGeometry* geometry) +{ + if (m_InteractionReferenceGeometry == geometry) + { + return; + } + + m_InteractionReferenceGeometry = geometry; + + this->UpdateCurrentGeometries(); +} + void mitk::BaseRenderer::SetSlice(unsigned int slice) { if (m_Slice == slice) { return; } m_Slice = slice; this->UpdateCurrentGeometries(); } void mitk::BaseRenderer::SetTimeStep(unsigned int timeStep) { if (m_TimeStep == timeStep) { return; } m_TimeStep = timeStep; m_TimeStepUpdateTime.Modified(); this->UpdateCurrentGeometries(); } mitk::TimeStepType mitk::BaseRenderer::GetTimeStep(const mitk::BaseData* data) const { if ((data == nullptr) || (data->IsInitialized() == false)) { return -1; } return data->GetTimeGeometry()->TimePointToTimeStep(GetTime()); } mitk::ScalarType mitk::BaseRenderer::GetTime() const { if (m_WorldTimeGeometry.IsNull()) { return 0; } else { ScalarType timeInMS = m_WorldTimeGeometry->TimeStepToTimePoint(GetTimeStep()); if (timeInMS == itk::NumericTraits::NonpositiveMin()) return 0; else return timeInMS; } } void mitk::BaseRenderer::SetGeometry(const itk::EventObject& geometrySendEvent) { const auto* sendEvent = dynamic_cast(&geometrySendEvent); if (nullptr == sendEvent) { return; } SetWorldTimeGeometry(sendEvent->GetTimeGeometry()); } void mitk::BaseRenderer::UpdateGeometry(const itk::EventObject& geometryUpdateEvent) { const auto* updateEvent = dynamic_cast(&geometryUpdateEvent); if (nullptr == updateEvent) { return; } if (m_CurrentWorldGeometry.IsNull()) { return; } const auto* slicedWorldGeometry = dynamic_cast(m_CurrentWorldGeometry.GetPointer()); if (slicedWorldGeometry) { PlaneGeometry* geometry2D = slicedWorldGeometry->GetPlaneGeometry(m_Slice); SetCurrentWorldPlaneGeometry(geometry2D); // calls Modified() } } void mitk::BaseRenderer::SetGeometrySlice(const itk::EventObject& geometrySliceEvent) { const auto* sliceEvent = dynamic_cast(&geometrySliceEvent); if (nullptr == sliceEvent) { return; } this->SetSlice(sliceEvent->GetPos()); } void mitk::BaseRenderer::SetGeometryTime(const itk::EventObject& geometryTimeEvent) { const auto* timeEvent = dynamic_cast(&geometryTimeEvent); if (nullptr == timeEvent) { return; } this->SetTimeStep(timeEvent->GetPos()); } void mitk::BaseRenderer::SendUpdateSlice() { m_CurrentWorldPlaneGeometryUpdateTime.Modified(); } void mitk::BaseRenderer::SetMapperID(MapperSlotId id) { if (m_MapperID != id) { bool useDepthPeeling = Standard3D == id; m_VtkRenderer->SetUseDepthPeeling(useDepthPeeling); m_VtkRenderer->SetUseDepthPeelingForVolumes(useDepthPeeling); m_MapperID = id; this->Modified(); } } int* mitk::BaseRenderer::GetSize() const { return m_RenderWindow->GetSize(); } int* mitk::BaseRenderer::GetViewportSize() const { return m_VtkRenderer->GetSize(); } const double* mitk::BaseRenderer::GetBounds() const { return m_Bounds; } void mitk::BaseRenderer::RequestUpdate() { SetConstrainZoomingAndPanning(true); RenderingManager::GetInstance()->RequestUpdate(m_RenderWindow); } void mitk::BaseRenderer::ForceImmediateUpdate() { RenderingManager::GetInstance()->ForceImmediateUpdate(m_RenderWindow); } unsigned int mitk::BaseRenderer::GetNumberOfVisibleLODEnabledMappers() const { return m_NumberOfVisibleLODEnabledMappers; } void mitk::BaseRenderer::SetSliceNavigationController(mitk::SliceNavigationController *SlicenavigationController) { if (SlicenavigationController == nullptr) return; // copy worldgeometry SlicenavigationController->SetInputWorldTimeGeometry(SlicenavigationController->GetCreatedWorldGeometry()); SlicenavigationController->Update(); // set new m_SliceNavigationController = SlicenavigationController; m_SliceNavigationController->SetRenderer(this); if (m_SliceNavigationController.IsNotNull()) { m_SliceNavigationController->ConnectGeometrySendEvent(this); m_SliceNavigationController->ConnectGeometryUpdateEvent(this); m_SliceNavigationController->ConnectGeometrySliceEvent(this); m_SliceNavigationController->ConnectGeometryTimeEvent(this); } } void mitk::BaseRenderer::DisplayToWorld(const Point2D& displayPoint, Point3D& worldIndex) const { if (m_MapperID == BaseRenderer::Standard2D) { double display[3], * world; // For the right z-position in display coordinates, take the focal point, convert it to display and use it for // correct depth. double* displayCoord; double cameraFP[4]; // Get camera focal point and position. Convert to display (screen) // coordinates. We need a depth value for z-buffer. this->GetVtkRenderer()->GetActiveCamera()->GetFocalPoint(cameraFP); cameraFP[3] = 0.0; this->GetVtkRenderer()->SetWorldPoint(cameraFP[0], cameraFP[1], cameraFP[2], cameraFP[3]); this->GetVtkRenderer()->WorldToDisplay(); displayCoord = this->GetVtkRenderer()->GetDisplayPoint(); // now convert the display point to world coordinates display[0] = displayPoint[0]; display[1] = displayPoint[1]; display[2] = displayCoord[2]; this->GetVtkRenderer()->SetDisplayPoint(display); this->GetVtkRenderer()->DisplayToWorld(); world = this->GetVtkRenderer()->GetWorldPoint(); for (int i = 0; i < 3; i++) { worldIndex[i] = world[i] / world[3]; } } else if (m_MapperID == BaseRenderer::Standard3D) { // Seems to be the same code as above, but subclasses may contain different implementations. PickWorldPoint(displayPoint, worldIndex); } return; } void mitk::BaseRenderer::DisplayToPlane(const Point2D &displayPoint, Point2D &planePointInMM) const { if (m_MapperID == BaseRenderer::Standard2D) { Point3D worldPoint; this->DisplayToWorld(displayPoint, worldPoint); m_CurrentWorldPlaneGeometry->Map(worldPoint, planePointInMM); } else if (m_MapperID == BaseRenderer::Standard3D) { MITK_WARN << "No conversion possible with 3D mapper."; return; } return; } void mitk::BaseRenderer::WorldToDisplay(const Point3D &worldIndex, Point2D &displayPoint) const { double world[4], *display; world[0] = worldIndex[0]; world[1] = worldIndex[1]; world[2] = worldIndex[2]; world[3] = 1.0; this->GetVtkRenderer()->SetWorldPoint(world); this->GetVtkRenderer()->WorldToDisplay(); display = this->GetVtkRenderer()->GetDisplayPoint(); displayPoint[0] = display[0]; displayPoint[1] = display[1]; return; } void mitk::BaseRenderer::WorldToView(const mitk::Point3D &worldIndex, mitk::Point2D &viewPoint) const { double world[4], *view; world[0] = worldIndex[0]; world[1] = worldIndex[1]; world[2] = worldIndex[2]; world[3] = 1.0; this->GetVtkRenderer()->SetWorldPoint(world); this->GetVtkRenderer()->WorldToView(); view = this->GetVtkRenderer()->GetViewPoint(); this->GetVtkRenderer()->ViewToNormalizedViewport(view[0], view[1], view[2]); viewPoint[0] = view[0] * this->GetViewportSize()[0]; viewPoint[1] = view[1] * this->GetViewportSize()[1]; return; } void mitk::BaseRenderer::PlaneToDisplay(const Point2D &planePointInMM, Point2D &displayPoint) const { Point3D worldPoint; m_CurrentWorldPlaneGeometry->Map(planePointInMM, worldPoint); this->WorldToDisplay(worldPoint, displayPoint); return; } void mitk::BaseRenderer::PlaneToView(const Point2D &planePointInMM, Point2D &viewPoint) const { Point3D worldPoint; m_CurrentWorldPlaneGeometry->Map(planePointInMM, worldPoint); this->WorldToView(worldPoint,viewPoint); return; } double mitk::BaseRenderer::GetScaleFactorMMPerDisplayUnit() const { if (this->GetMapperID() == BaseRenderer::Standard2D) { // GetParallelScale returns half of the height of the render window in mm. // Divided by the half size of the Display size in pixel givest the mm per pixel. return this->GetVtkRenderer()->GetActiveCamera()->GetParallelScale() * 2.0 / GetViewportSize()[1]; } else return 1.0; } mitk::Point2D mitk::BaseRenderer::GetDisplaySizeInMM() const { Point2D dispSizeInMM; dispSizeInMM[0] = GetSizeX() * GetScaleFactorMMPerDisplayUnit(); dispSizeInMM[1] = GetSizeY() * GetScaleFactorMMPerDisplayUnit(); return dispSizeInMM; } mitk::Point2D mitk::BaseRenderer::GetViewportSizeInMM() const { Point2D dispSizeInMM; dispSizeInMM[0] = GetViewportSize()[0] * GetScaleFactorMMPerDisplayUnit(); dispSizeInMM[1] = GetViewportSize()[1] * GetScaleFactorMMPerDisplayUnit(); return dispSizeInMM; } mitk::Point2D mitk::BaseRenderer::GetOriginInMM() const { Point2D originPx; originPx[0] = m_VtkRenderer->GetOrigin()[0]; originPx[1] = m_VtkRenderer->GetOrigin()[1]; Point2D displayGeometryOriginInMM; DisplayToPlane(originPx, displayGeometryOriginInMM); // top left of the render window (Origin) return displayGeometryOriginInMM; } void mitk::BaseRenderer::SetConstrainZoomingAndPanning(bool constrain) { m_ConstrainZoomingAndPanning = constrain; if (m_ConstrainZoomingAndPanning) { this->GetCameraController()->AdjustCameraToPlane(); } } void mitk::BaseRenderer::UpdateCurrentGeometries() { if (m_WorldTimeGeometry.IsNull()) { // simply mark the base renderer as modified Modified(); + return; } if (m_TimeStep >= m_WorldTimeGeometry->CountTimeSteps()) { m_TimeStep = m_WorldTimeGeometry->CountTimeSteps() - 1; } auto slicedWorldGeometry = dynamic_cast(m_WorldTimeGeometry->GetGeometryForTimeStep(m_TimeStep).GetPointer()); if (slicedWorldGeometry != nullptr) { if (m_Slice >= slicedWorldGeometry->GetSlices()) { m_Slice = slicedWorldGeometry->GetSlices() - 1; } SetCurrentWorldGeometry(slicedWorldGeometry); SetCurrentWorldPlaneGeometry(slicedWorldGeometry->GetPlaneGeometry(m_Slice)); + m_ReferenceGeometryAligned = BaseRendererHelper::IsRendererGeometryAlignedWithGeometry(this, m_InteractionReferenceGeometry); } } void mitk::BaseRenderer::SetCurrentWorldPlaneGeometry(const mitk::PlaneGeometry* geometry2d) { if (m_CurrentWorldPlaneGeometry == geometry2d) { return; } m_CurrentWorldPlaneGeometry = geometry2d->Clone(); m_CurrentWorldPlaneGeometryData->SetPlaneGeometry(m_CurrentWorldPlaneGeometry); m_CurrentWorldPlaneGeometryUpdateTime.Modified(); Modified(); } void mitk::BaseRenderer::SetCurrentWorldGeometry(const mitk::BaseGeometry* geometry) { if (m_CurrentWorldGeometry == geometry) { return; } m_CurrentWorldGeometry = geometry; if (geometry == nullptr) { 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(nullptr); 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::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 << " CurrentWorldPlaneGeometry: "; if (m_CurrentWorldPlaneGeometry.IsNull()) os << "nullptr" << std::endl; else m_CurrentWorldPlaneGeometry->Print(os, indent); os << indent << " CurrentWorldPlaneGeometryUpdateTime: " << m_CurrentWorldPlaneGeometryUpdateTime << std::endl; os << indent << " CurrentWorldPlaneGeometryTransformTime: " << m_CurrentWorldPlaneGeometryTransformTime << std::endl; Superclass::PrintSelf(os, indent); } diff --git a/Modules/Core/src/Rendering/mitkBaseRendererHelper.cpp b/Modules/Core/src/Rendering/mitkBaseRendererHelper.cpp index 2bd9efb531..0a641f42e0 100644 --- a/Modules/Core/src/Rendering/mitkBaseRendererHelper.cpp +++ b/Modules/Core/src/Rendering/mitkBaseRendererHelper.cpp @@ -1,77 +1,87 @@ /*============================================================================ 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 "mitkBaseRendererHelper.h" #include -bool mitk::BaseRendererHelper::IsRendererAlignedWithSegmentation(BaseRenderer* renderer, const TimeGeometry* timeGeometry) +bool mitk::BaseRendererHelper::IsRendererGeometryAlignedWithGeometry(BaseRenderer* renderer, const TimeGeometry* timeGeometry) { - const BaseGeometry* renderWindowGeometry = renderer->GetCurrentWorldGeometry(); + if (nullptr == renderer) + { + return false; + } - if (nullptr == renderWindowGeometry || nullptr == timeGeometry) + const BaseGeometry* renderWindowGeometry = renderer->GetCurrentWorldGeometry(); + if (nullptr == renderWindowGeometry) { return false; } + if (nullptr == timeGeometry) + { + // no reference geometry given, so everything is fine + return true; + } + auto viewDirection = renderer->GetSliceNavigationController()->GetViewDirection(); TimeGeometry::Pointer orientedTimeGeometry; try { switch (viewDirection) { case mitk::AnatomicalPlane::Original: break; case mitk::AnatomicalPlane::Axial: { orientedTimeGeometry = SliceNavigationHelper::CreateOrientedTimeGeometry( timeGeometry, viewDirection, false, false, true); break; } case mitk::AnatomicalPlane::Coronal: { orientedTimeGeometry = SliceNavigationHelper::CreateOrientedTimeGeometry( timeGeometry, viewDirection, false, true, false); break; } case mitk::AnatomicalPlane::Sagittal: { orientedTimeGeometry = SliceNavigationHelper::CreateOrientedTimeGeometry( timeGeometry, viewDirection, true, true, false); break; } } } catch (mitk::Exception& e) { mitkReThrow(e); } if (nullptr == orientedTimeGeometry) { return false; } auto selectedTimePoint = RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); const BaseGeometry* workingImageBaseGeometry = orientedTimeGeometry->GetGeometryForTimePoint(selectedTimePoint); if (nullptr == workingImageBaseGeometry) { // time point not valid for the time geometry mitkThrow() << "Cannot extract a base geometry. A time point is selected that is not covered by" << "the given time geometry. Selected time point: " << selectedTimePoint; } bool geometryIsEqual = Equal(*workingImageBaseGeometry->GetBoundingBox(), *renderWindowGeometry->GetBoundingBox(), eps, true); return geometryIsEqual; } diff --git a/Modules/QtWidgets/files.cmake b/Modules/QtWidgets/files.cmake index c895814bf1..cc23808ef6 100644 --- a/Modules/QtWidgets/files.cmake +++ b/Modules/QtWidgets/files.cmake @@ -1,172 +1,174 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES QmitkAbstractDataStorageModel.cpp QmitkAbstractMultiWidget.cpp QmitkAbstractNodeSelectionWidget.cpp QmitkApplicationCursor.cpp QmitkDataStorageComboBox.cpp QmitkDataStorageDefaultListModel.cpp QmitkDataStorageHistoryModel.cpp QmitkDataStorageListModel.cpp QmitkDataStorageTableModel.cpp QmitkDataStorageSimpleTreeModel.cpp QmitkDataStorageTreeModel.cpp QmitkDataStorageTreeModelInternalItem.cpp QmitkDnDDataNodeWidget.cpp QmitkFileReaderOptionsDialog.cpp QmitkFileReaderWriterOptionsWidget.cpp QmitkFileWriterOptionsDialog.cpp QmitkInteractionSchemeToolBar.cpp QmitkIOUtil.cpp QmitkLevelWindowPresetDefinitionDialog.cpp QmitkLevelWindowRangeChangeDialog.cpp QmitkLevelWindowWidgetContextMenu.cpp QmitkLevelWindowWidget.cpp QmitkLineEditLevelWindowWidget.cpp QmitkMemoryUsageIndicatorView.cpp QmitkMimeTypes.cpp QmitkMultiNodeSelectionWidget.cpp QmitkMultiWidgetConfigurationToolBar.cpp QmitkMultiWidgetLayoutManager.cpp QmitkMultiWidgetLayoutSelectionWidget.cpp QmitkNodeDescriptor.cpp QmitkNodeSelectionButton.cpp QmitkNodeSelectionConstants.cpp QmitkNodeSelectionDialog.cpp QmitkNodeSelectionListItemWidget.cpp QmitkNodeSelectionPreferenceHelper.cpp QmitkNodeDescriptor.cpp QmitkColoredNodeDescriptor.cpp QmitkNodeDescriptorManager.cpp QmitkProgressBar.cpp QmitkPropertiesTableEditor.cpp QmitkPropertiesTableModel.cpp QmitkPropertyDelegate.cpp QmitkRegisterClasses.cpp QmitkRenderingManager.cpp QmitkRenderWindowDataStorageTreeModel.cpp QmitkRenderingManagerFactory.cpp QmitkRenderWindow.cpp QmitkRenderWindowMenu.cpp QmitkRenderWindowUtilityWidget.cpp QmitkRenderWindowWidget.cpp QmitkRenderWindowContextDataStorageInspector.cpp mitkRenderWindowLayerController.cpp mitkRenderWindowLayerUtilities.cpp mitkRenderWindowViewDirectionController.cpp QmitkServiceListWidget.cpp QmitkSingleNodeSelectionWidget.cpp QmitkSliceNavigationWidget.cpp QmitkSliderLevelWindowWidget.cpp QmitkStdMultiWidget.cpp QmitkStepperAdapter.cpp QmitkMxNMultiWidget.cpp QmitkDataStorageComboBoxWithSelectNone.cpp QmitkDataStorageFilterProxyModel.cpp QmitkPropertyItem.cpp QmitkPropertyItemDelegate.cpp QmitkPropertyItemModel.cpp QmitkStyleManager.cpp QmitkAbstractDataStorageInspector.cpp QmitkDataStorageFavoriteNodesInspector.cpp QmitkDataStorageListInspector.cpp QmitkDataStorageTreeInspector.cpp QmitkDataStorageSelectionHistoryInspector.cpp QmitkModelViewSelectionConnector.cpp mitkIDataStorageInspectorProvider.cpp mitkQtWidgetsActivator.cpp mitkDataStorageInspectorGenerator.cpp QmitkOverlayWidget.cpp QmitkSimpleTextOverlayWidget.cpp + QmitkButtonOverlayWidget.cpp QmitkNodeDetailsDialog.cpp ) set(MOC_H_FILES include/QmitkAbstractDataStorageModel.h include/QmitkAbstractMultiWidget.h include/QmitkAbstractNodeSelectionWidget.h include/QmitkDataStorageComboBox.h include/QmitkDataStorageTableModel.h include/QmitkDataStorageTreeModel.h include/QmitkDataStorageSimpleTreeModel.h include/QmitkDataStorageDefaultListModel.h include/QmitkDnDDataNodeWidget.h include/QmitkFileReaderOptionsDialog.h include/QmitkFileReaderWriterOptionsWidget.h include/QmitkFileWriterOptionsDialog.h include/QmitkInteractionSchemeToolBar.h include/QmitkLevelWindowPresetDefinitionDialog.h include/QmitkLevelWindowRangeChangeDialog.h include/QmitkLevelWindowWidgetContextMenu.h include/QmitkLevelWindowWidget.h include/QmitkLineEditLevelWindowWidget.h include/QmitkMemoryUsageIndicatorView.h include/QmitkMultiNodeSelectionWidget.h include/QmitkMultiWidgetConfigurationToolBar.h include/QmitkMultiWidgetLayoutManager.h include/QmitkMultiWidgetLayoutSelectionWidget.h include/QmitkNodeDescriptor.h include/QmitkNodeSelectionButton.h include/QmitkNodeSelectionDialog.h include/QmitkNodeSelectionListItemWidget.h include/QmitkColoredNodeDescriptor.h include/QmitkNodeDescriptorManager.h include/QmitkProgressBar.h include/QmitkPropertiesTableEditor.h include/QmitkPropertyDelegate.h include/QmitkRenderingManager.h include/QmitkRenderWindow.h include/QmitkRenderWindowDataStorageTreeModel.h include/QmitkRenderWindowMenu.h include/QmitkRenderWindowUtilityWidget.h include/QmitkRenderWindowWidget.h include/QmitkRenderWindowContextDataStorageInspector.h include/mitkRenderWindowLayerController.h include/mitkRenderWindowLayerUtilities.h include/mitkRenderWindowViewDirectionController.h include/QmitkServiceListWidget.h include/QmitkSingleNodeSelectionWidget.h include/QmitkSliceNavigationWidget.h include/QmitkSliderLevelWindowWidget.h include/QmitkStdMultiWidget.h include/QmitkMxNMultiWidget.h include/QmitkStepperAdapter.h include/QmitkDataStorageComboBoxWithSelectNone.h include/QmitkPropertyItemDelegate.h include/QmitkPropertyItemModel.h include/QmitkAbstractDataStorageInspector.h include/QmitkDataStorageFavoriteNodesInspector.h include/QmitkDataStorageListInspector.h include/QmitkDataStorageTreeInspector.h include/QmitkDataStorageHistoryModel.h include/QmitkDataStorageSelectionHistoryInspector.h include/QmitkModelViewSelectionConnector.h include/QmitkOverlayWidget.h include/QmitkSimpleTextOverlayWidget.h + include/QmitkButtonOverlayWidget.h include/QmitkNodeDetailsDialog.h ) set(UI_FILES src/QmitkFileReaderOptionsDialog.ui src/QmitkFileWriterOptionsDialog.ui src/QmitkLevelWindowPresetDefinition.ui src/QmitkLevelWindowWidget.ui src/QmitkLevelWindowRangeChange.ui src/QmitkMemoryUsageIndicator.ui src/QmitkMultiNodeSelectionWidget.ui src/QmitkMultiWidgetLayoutSelectionWidget.ui src/QmitkNodeSelectionDialog.ui src/QmitkNodeSelectionListItemWidget.ui src/QmitkRenderWindowContextDataStorageInspector.ui src/QmitkServiceListWidgetControls.ui src/QmitkSingleNodeSelectionWidget.ui src/QmitkSliceNavigationWidget.ui src/QmitkDataStorageListInspector.ui src/QmitkDataStorageTreeInspector.ui src/QmitkDataStorageSelectionHistoryInspector.ui ) set(QRC_FILES resource/Qmitk.qrc ) diff --git a/Modules/QtWidgets/include/QmitkAbstractMultiWidget.h b/Modules/QtWidgets/include/QmitkAbstractMultiWidget.h index b8af62f790..1b927645c3 100644 --- a/Modules/QtWidgets/include/QmitkAbstractMultiWidget.h +++ b/Modules/QtWidgets/include/QmitkAbstractMultiWidget.h @@ -1,181 +1,191 @@ /*============================================================================ 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 QmitkAbstractMultiWidget_h #define QmitkAbstractMultiWidget_h // mitk qt widgets module #include "MitkQtWidgetsExports.h" // mitk core #include #include #include #include // qt #include // c++ #include #include class QmitkMultiWidgetLayoutManager; class QmitkRenderWindow; class QmitkRenderWindowWidget; namespace mitk { class DataStorage; class InteractionEventHandler; } /** * @brief The 'QmitkAbstractMultiWidget' is a 'QWidget' that can be subclassed to display multiple render windows at once. * Render windows can dynamically be added and removed to change the layout of the multi widget. * A subclass of this multi widget can be used inside a 'QmitkAbstractMultiWidgetEditor'. * * The class uses the 'DisplayActionEventBroadcast' and 'DisplayActionEventHandler' classes to * load a state machine and set an event configuration. * * Using the 'Synchronize' function the user can enable or disable the synchronization of display action events. * See 'DisplayActionEventFunctions'-class for the different synchronized and non-synchronized functions used. */ class MITKQTWIDGETS_EXPORT QmitkAbstractMultiWidget : public QWidget { Q_OBJECT public: using RenderWindowWidgetPointer = std::shared_ptr; using RenderWindowWidgetMap = std::map>; using RenderWindowHash = QHash; QmitkAbstractMultiWidget(QWidget* parent = 0, Qt::WindowFlags f = 0, const QString& multiWidgetName = "multiwidget"); virtual ~QmitkAbstractMultiWidget(); virtual void InitializeMultiWidget() = 0; virtual void MultiWidgetOpened() { } virtual void MultiWidgetClosed() { } virtual void SetDataStorage(mitk::DataStorage* dataStorage); mitk::DataStorage* GetDataStorage() const; int GetRowCount() const; int GetColumnCount() const; virtual void SetLayout(int row, int column); virtual void Synchronize(bool) { }; virtual void SetInteractionScheme(mitk::InteractionSchemeSwitcher::InteractionScheme scheme); mitk::InteractionEventHandler* GetInteractionEventHandler(); void SetDisplayActionEventHandler(std::unique_ptr displayActionEventHandler); mitk::DisplayActionEventHandler* GetDisplayActionEventHandler(); RenderWindowWidgetMap GetRenderWindowWidgets() const; RenderWindowWidgetMap Get2DRenderWindowWidgets() const; RenderWindowWidgetMap Get3DRenderWindowWidgets() const; RenderWindowWidgetPointer GetRenderWindowWidget(int row, int column) const; RenderWindowWidgetPointer GetRenderWindowWidget(const QString& widgetName) const; RenderWindowWidgetPointer GetRenderWindowWidget(const QmitkRenderWindow* renderWindow) const; RenderWindowHash GetRenderWindows() const; QmitkRenderWindow* GetRenderWindow(int row, int column) const; virtual QmitkRenderWindow* GetRenderWindow(const QString& widgetName) const; virtual QmitkRenderWindow* GetRenderWindow(const mitk::AnatomicalPlane& orientation) const = 0; virtual void SetActiveRenderWindowWidget(RenderWindowWidgetPointer activeRenderWindowWidget); RenderWindowWidgetPointer GetActiveRenderWindowWidget() const; RenderWindowWidgetPointer GetFirstRenderWindowWidget() const; RenderWindowWidgetPointer GetLastRenderWindowWidget() const; virtual QString GetNameFromIndex(int row, int column) const; virtual QString GetNameFromIndex(size_t index) const; unsigned int GetNumberOfRenderWindowWidgets() const; void RequestUpdate(const QString& widgetName); void RequestUpdateAll(); void ForceImmediateUpdate(const QString& widgetName); void ForceImmediateUpdateAll(); /** - * @brief Set the reference geometry for interaction inside the render windows of the render window part. - * - * The concrete implementation is subclass-specific, no default implementation is provided here. - * - * @param referenceGeometry The reference geometry which is used for updating the - * time geometry inside the render windows. - * @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. - */ - virtual void SetReferenceGeometry(const mitk::TimeGeometry* referenceGeometry, bool resetCamera) = 0; + * @brief Initialize the render windows of the concrete multi widget to the given geometry. + * + * The concrete implementation is subclass-specific, no default implementation is provided here. + * + * @param geometry The geometry to be used to initialize / update the + * 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. + */ + virtual void InitializeViews(const mitk::TimeGeometry* geometry, bool resetCamera) = 0; + + /** + * @brief Define the reference geometry for interaction withing a render window. + * + * The concrete implementation is subclass-specific, no default implementation is provided here. + * + * @param referenceGeometry The interaction reference geometry for the base renderer of the concrete multi widget. + * For more details, see 'BaseRenderer::SetInteractionReferenceGeometry'. + */ + virtual void SetInteractionReferenceGeometry(const mitk::TimeGeometry* referenceGeometry) = 0; /** * @brief Returns true if the render windows are coupled; false if not. * * Render windows are coupled if the slice navigation controller of the render windows * are connected which means that always the same geometry is used for the render windows. */ virtual bool HasCoupledRenderWindows() const = 0; virtual void SetSelectedPosition(const mitk::Point3D& newPosition, const QString& widgetName) = 0; virtual const mitk::Point3D GetSelectedPosition(const QString& widgetName) const = 0; virtual void SetCrosshairVisibility(bool visible) = 0; virtual bool GetCrosshairVisibility() const = 0; virtual void SetCrosshairGap(unsigned int gapSize) = 0; virtual void ResetCrosshair() = 0; virtual void SetWidgetPlaneMode(int mode) = 0; virtual void ActivateMenuWidget(bool state); virtual bool IsMenuWidgetEnabled() const; QmitkMultiWidgetLayoutManager* GetMultiWidgetLayoutManager() const; signals: void ActiveRenderWindowChanged(); private slots: void OnFocusChanged(itk::Object*, const itk::EventObject& event); protected: virtual void AddRenderWindowWidget(const QString& widgetName, RenderWindowWidgetPointer renderWindowWidget); virtual void RemoveRenderWindowWidget(); private: /** * @brief This function will be called by the function 'SetLayout' and * can be implemented and customized in the subclasses. */ virtual void SetLayoutImpl() = 0; /** * @brief This function will be called by the function 'SetInteractionScheme' and * can be implemented and customized in the subclasses. */ virtual void SetInteractionSchemeImpl() = 0; struct Impl; std::unique_ptr m_Impl; }; #endif diff --git a/Modules/QtWidgets/include/QmitkButtonOverlayWidget.h b/Modules/QtWidgets/include/QmitkButtonOverlayWidget.h new file mode 100644 index 0000000000..bba776b344 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkButtonOverlayWidget.h @@ -0,0 +1,54 @@ +/*============================================================================ + +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 QMITKBUTTONOVERLAYWIDGET_H +#define QMITKBUTTONOVERLAYWIDGET_H + +#include "QmitkOverlayWidget.h" +#include +#include +#include +#include + +/** Overlay that renders a passed string and draws an icon as a push button. + You may pass an html string that will be rendered accordingly + respecting the current application style sheet. + The button will return the 'Clicked' signal which can be connected to + a slot in the calling class.*/ +class MITKQTWIDGETS_EXPORT QmitkButtonOverlayWidget : public QmitkOverlayWidget +{ + Q_OBJECT + +public: + + explicit QmitkButtonOverlayWidget(QWidget* parent = nullptr); + ~QmitkButtonOverlayWidget() override; + + QString GetOverlayText() const; + void SetOverlayText(const QString& text); + QString GetButtonText() const; + void SetButtonText(const QString& text); + QIcon GetButtonIcon() const; + void SetButtonIcon(const QIcon& icon); + +Q_SIGNALS: + + void Clicked(); + +private: + + QLabel* m_MessageLabel; + QPushButton* m_PushButton; + +}; + +#endif diff --git a/Modules/QtWidgets/include/QmitkMxNMultiWidget.h b/Modules/QtWidgets/include/QmitkMxNMultiWidget.h index 4e4ea29284..dbc9613c5d 100644 --- a/Modules/QtWidgets/include/QmitkMxNMultiWidget.h +++ b/Modules/QtWidgets/include/QmitkMxNMultiWidget.h @@ -1,109 +1,119 @@ /*============================================================================ 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" #include "QmitkAbstractMultiWidget.h" /** * @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 Set the reference geometry for interaction inside the active render windows of the MxNMultiWidget. - * - * @param referenceGeometry The reference geometry which is used for updating the - * time geometry inside the active render window. - * @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 SetReferenceGeometry(const mitk::TimeGeometry* referenceGeometry, 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(); mitk::SliceNavigationController* m_TimeNavigationController; bool m_CrosshairVisibility; }; #endif diff --git a/Modules/QtWidgets/include/QmitkRenderWindow.h b/Modules/QtWidgets/include/QmitkRenderWindow.h index 51de81e8b9..8194a8ddc0 100644 --- a/Modules/QtWidgets/include/QmitkRenderWindow.h +++ b/Modules/QtWidgets/include/QmitkRenderWindow.h @@ -1,163 +1,165 @@ /*============================================================================ 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 QmitkRenderWindow_h #define QmitkRenderWindow_h #include "mitkRenderWindowBase.h" #include "QmitkRenderWindowMenu.h" #include #include #include #include "mitkBaseRenderer.h" #include "mitkInteractionEventConst.h" -#include +#include class QDragEnterEvent; class QDropEvent; class QInputEvent; class QMouseEvent; /** * \ingroup QmitkModule * \brief MITK implementation of the QVTKWidget */ class MITKQTWIDGETS_EXPORT QmitkRenderWindow : public QVTKOpenGLNativeWidget, public mitk::RenderWindowBase { Q_OBJECT public: QmitkRenderWindow( QWidget *parent = nullptr, const QString &name = "unnamed renderwindow", mitk::VtkPropRenderer *renderer = nullptr); ~QmitkRenderWindow() override; /** * \brief Whether Qt events should be passed to parent (default: true) * * With introduction of the QVTKWidget the behaviour regarding Qt events changed. * QVTKWidget "accepts" Qt events like mouse clicks (i.e. set an "accepted" flag). * When this flag is set, Qt fininshed handling of this event -- otherwise it is * reached through to the widget's parent. * * This reaching through to the parent was implicitly required by QmitkMaterialWidget / QmitkMaterialShowCase. * * The default behaviour of QmitkRenderWindow is now to clear the "accepted" flag * of Qt events after they were handled by QVTKWidget. This way parents can also * handle events. * * If you don't want this behaviour, call SetResendQtEvents(true) on your render window. */ virtual void SetResendQtEvents(bool resend); // Set Layout Index to define the Layout Type void SetLayoutIndex(QmitkRenderWindowMenu::LayoutIndex layoutIndex); // Get Layout Index to define the Layout Type QmitkRenderWindowMenu::LayoutIndex GetLayoutIndex(); // MenuWidget need to update the Layout Design List when Layout had changed void UpdateLayoutDesignList(QmitkRenderWindowMenu::LayoutDesign layoutDesign); void UpdateCrosshairVisibility(bool); void UpdateCrosshairRotationMode(int); // Activate or Deactivate MenuWidget. void ActivateMenuWidget(bool state); bool GetActivateMenuWidgetFlag() { return m_MenuWidgetActivated; } void ShowOverlayMessage(bool show); // Get it from the QVTKWidget parent vtkRenderWindow *GetVtkRenderWindow() override { return this->renderWindow(); } vtkRenderWindowInteractor *GetVtkRenderWindowInteractor() override { return nullptr; } protected: // catch-all event handler bool event(QEvent *e) override; // overloaded move handler void moveEvent(QMoveEvent *event) override; // overloaded show handler void showEvent(QShowEvent *event) override; // overloaded enter handler void enterEvent(QEvent *) override; // overloaded leave handler void leaveEvent(QEvent *) override; // Overloaded resize handler, see decs in QVTKOpenGLWidget. // Basically, we have to ensure the VTK rendering is updated for each change in window size. void resizeGL(int w, int h) override; /// \brief Simply says we accept the event type. void dragEnterEvent(QDragEnterEvent *event) override; /// \brief If the dropped type is application/x-mitk-datanodes we process the request by converting to mitk::DataNode /// pointers and emitting the NodesDropped signal. void dropEvent(QDropEvent *event) override; Q_SIGNALS: void LayoutDesignChanged(QmitkRenderWindowMenu::LayoutDesign); void ResetView(); + void ResetGeometry(); + void CrosshairRotationModeChanged(int); void CrosshairVisibilityChanged(bool); void moved(); /// \brief Emits a signal to say that this window has had the following nodes dropped on it. void NodesDropped(QmitkRenderWindow *thisWindow, std::vector nodes); private Q_SLOTS: void DeferredHideMenu(); private: // Helper Functions to Convert Qt-Events to Mitk-Events mitk::Point2D GetMousePosition(QMouseEvent *me) const; mitk::Point2D GetMousePosition(QWheelEvent *we) const; mitk::InteractionEvent::MouseButtons GetEventButton(QMouseEvent *me) const; mitk::InteractionEvent::MouseButtons GetButtonState(QMouseEvent *me) const; mitk::InteractionEvent::ModifierKeys GetModifiers(QInputEvent *me) const; mitk::InteractionEvent::MouseButtons GetButtonState(QWheelEvent *we) const; std::string GetKeyLetter(QKeyEvent *ke) const; int GetDelta(QWheelEvent *we) const; void UpdateStatusBar(mitk::Point2D pointerPositionOnScreen); bool m_ResendQtEvents; QmitkRenderWindowMenu *m_MenuWidget; bool m_MenuWidgetActivated; QmitkRenderWindowMenu::LayoutIndex m_LayoutIndex; vtkSmartPointer m_InternalRenderWindow; - QmitkSimpleTextOverlayWidget* m_GeometryViolationWarningOverlay; + QmitkButtonOverlayWidget* m_GeometryViolationWarningOverlay; }; #endif diff --git a/Modules/QtWidgets/include/QmitkRenderWindowWidget.h b/Modules/QtWidgets/include/QmitkRenderWindowWidget.h index c7ab1cf7ed..c3420b49ef 100644 --- a/Modules/QtWidgets/include/QmitkRenderWindowWidget.h +++ b/Modules/QtWidgets/include/QmitkRenderWindowWidget.h @@ -1,126 +1,130 @@ /*============================================================================ 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" // mitk core #include #include #include // qt #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); ~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 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); + 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/QmitkStdMultiWidget.h b/Modules/QtWidgets/include/QmitkStdMultiWidget.h index 1a3574097d..ce22931e50 100644 --- a/Modules/QtWidgets/include/QmitkStdMultiWidget.h +++ b/Modules/QtWidgets/include/QmitkStdMultiWidget.h @@ -1,169 +1,176 @@ /*============================================================================ 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 QmitkStdMultiWidget_h #define QmitkStdMultiWidget_h // qt widgets module #include "MitkQtWidgetsExports.h" #include "QmitkAbstractMultiWidget.h" /** * @brief The 'QmitkStdMultiWidget' is a 'QmitkAbstractMultiWidget' that is used to display multiple render windows at once. * Render windows are predefined in a 2x2 design with 3 different 2D view planes and a 3D render window. */ class MITKQTWIDGETS_EXPORT QmitkStdMultiWidget : public QmitkAbstractMultiWidget { Q_OBJECT public: QmitkStdMultiWidget( QWidget *parent = nullptr, Qt::WindowFlags f = nullptr, const QString &name = "stdmulti"); ~QmitkStdMultiWidget() override; virtual void InitializeMultiWidget() override; virtual QmitkRenderWindow* GetRenderWindow(const QString& widgetName) const override; virtual QmitkRenderWindow* GetRenderWindow(const mitk::AnatomicalPlane& orientation) const override; /** - * @brief Set the reference geometry for interaction inside all render windows of the StdMultiWidget. - * - * @param referenceGeometry The reference geometry which is used for updating the - * time geometry inside all four render windows. - * @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 SetReferenceGeometry(const mitk::TimeGeometry* referenceGeometry, bool resetCamera) override; + * @brief Initialize all render windows of the StdMultiWidget to the given geometry. + * Overridem from 'QmitkAbstractMultiWidget'. + * + * @param geometry The geometry to be used to initialize / update all + * 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 Not implemented in this class. + * Overridem from 'QmitkAbstractMultiWidget'. + */ + void SetInteractionReferenceGeometry(const mitk::TimeGeometry* referenceGeometry) override; /** * @brief Returns true if the render windows are coupled; false if not. * * For the StdMultiWidget the render windows are typically coupled. */ bool HasCoupledRenderWindows() const override; virtual void SetSelectedPosition(const mitk::Point3D& newPosition, const QString& widgetName) override; virtual const mitk::Point3D GetSelectedPosition(const QString& widgetName) const override; virtual void SetCrosshairVisibility(bool) override; virtual bool GetCrosshairVisibility() const override; void SetCrosshairGap(unsigned int gapSize) override; virtual void ResetCrosshair() override; virtual void SetWidgetPlaneMode(int mode) override; mitk::SliceNavigationController* GetTimeNavigationController(); void AddPlanesToDataStorage(); void RemovePlanesFromDataStorage(); /** * @brief Convenience method to get a render window widget. * @param number of the widget (0-3) * @return The render window widget */ QmitkRenderWindow* GetRenderWindow(unsigned int number) const; QmitkRenderWindow* GetRenderWindow1() const; QmitkRenderWindow* GetRenderWindow2() const; QmitkRenderWindow* GetRenderWindow3() const; QmitkRenderWindow* GetRenderWindow4() const; /** * @brief Convenience method to get a widget plane. * @param number of the widget plane (1-3) * @return The widget plane as data node */ mitk::DataNode::Pointer GetWidgetPlane(unsigned int number) const; mitk::DataNode::Pointer GetWidgetPlane1() const; mitk::DataNode::Pointer GetWidgetPlane2() const; mitk::DataNode::Pointer GetWidgetPlane3() const; /** * @brief SetDecorationColor Set the color of the decoration of the 4 widgets. * * This is used to color the frame of the renderwindow and the corner annatation. * For the first 3 widgets, this color is a property of the helper object nodes * which contain the respective plane geometry. For widget 4, this is a member, * since there is no data node for this widget. */ void SetDecorationColor(unsigned int widgetNumber, mitk::Color color); /** * @brief GetDecorationColorForWidget Get the color for annotation, crosshair and rectangle. * @param widgetNumber Number of the renderwindow (0-3). * @return Color in mitk format. */ mitk::Color GetDecorationColor(unsigned int widgetNumber); public Q_SLOTS: // mouse events virtual void mousePressEvent(QMouseEvent*) override; virtual void moveEvent(QMoveEvent* e) override; virtual void wheelEvent(QWheelEvent* e) override; void Fit(); void AddDisplayPlaneSubTree(); void EnsureDisplayContainsPoint(mitk::BaseRenderer *renderer, const mitk::Point3D &p); void SetWidgetPlaneVisibility(const char *widgetName, bool visible, mitk::BaseRenderer *renderer = nullptr); void SetWidgetPlanesVisibility(bool visible, mitk::BaseRenderer *renderer = nullptr); Q_SIGNALS: void NotifyCrosshairVisibilityChanged(bool visible); void NotifyCrosshairRotationModeChanged(int mode); void WheelMoved(QWheelEvent *); void Moved(); private: virtual void SetLayoutImpl() override; virtual void SetInteractionSchemeImpl() override { } void CreateRenderWindowWidgets(); mitk::SliceNavigationController* m_TimeNavigationController; /** * @brief The 3 helper objects which contain the plane geometry. */ mitk::DataNode::Pointer m_PlaneNode1; mitk::DataNode::Pointer m_PlaneNode2; mitk::DataNode::Pointer m_PlaneNode3; /** * @brief m_ParentNodeForGeometryPlanes This helper object is added to the datastorage * and contains the 3 planes for displaying the image geometry (crosshair and 3D planes). */ mitk::DataNode::Pointer m_ParentNodeForGeometryPlanes; /** * @brief m_DecorationColorWidget4 color for annotation and rectangle of widget 4. * * For other widgets1-3, the color is a property of the respective data node. * There is no node for widget 4, hence, we need an extra member. */ mitk::Color m_DecorationColorWidget4; }; #endif diff --git a/Modules/QtWidgets/resource/Qmitk.qrc b/Modules/QtWidgets/resource/Qmitk.qrc index cdfc70682c..f38e7de208 100644 --- a/Modules/QtWidgets/resource/Qmitk.qrc +++ b/Modules/QtWidgets/resource/Qmitk.qrc @@ -1,28 +1,29 @@ Binaerbilder_48.png Images_48.png PointSet_48.png Segmentation_48.png Surface_48.png mm_pointer.png mm_scroll.png mm_zoom.png mm_contrast.png mm_pan.png LabelSetImage_48.png mwLayout.png mwSynchronized.png mwDesynchronized.png mwMITK.png mwPACS.png star-solid.svg history-solid.svg tree_inspector.svg list-solid.svg favorite_add.svg favorite_remove.svg hourglass-half-solid.svg times.svg + reset.svg diff --git a/Modules/QtWidgets/resource/reset.svg b/Modules/QtWidgets/resource/reset.svg new file mode 100644 index 0000000000..f659f3aaaa --- /dev/null +++ b/Modules/QtWidgets/resource/reset.svg @@ -0,0 +1,48 @@ + +image/svg+xml \ No newline at end of file diff --git a/Modules/QtWidgets/src/QmitkButtonOverlayWidget.cpp b/Modules/QtWidgets/src/QmitkButtonOverlayWidget.cpp new file mode 100644 index 0000000000..29b2c36c85 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkButtonOverlayWidget.cpp @@ -0,0 +1,73 @@ +/*============================================================================ + +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 "QmitkButtonOverlayWidget.h" + +#include + +#include + +QmitkButtonOverlayWidget::QmitkButtonOverlayWidget(QWidget* parent) + : QmitkOverlayWidget(parent) +{ + m_MessageLabel = new QLabel(this); + m_MessageLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + + m_PushButton = new QPushButton(this); + connect(m_PushButton, &QPushButton::clicked, + this, &QmitkButtonOverlayWidget::Clicked); + m_PushButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + + auto* layout = new QVBoxLayout(this); + layout->setAlignment(Qt::AlignCenter); + layout->addStretch(); + layout->addWidget(m_MessageLabel); + layout->addWidget(m_PushButton); + layout->addStretch(); + + this->setAttribute(Qt::WA_TransparentForMouseEvents, false); + this->setAttribute(Qt::WA_NoMousePropagation); +} + +QmitkButtonOverlayWidget::~QmitkButtonOverlayWidget() +{ +} + +QString QmitkButtonOverlayWidget::GetOverlayText() const +{ + return m_MessageLabel->text(); +} + +void QmitkButtonOverlayWidget::SetOverlayText(const QString& text) +{ + m_MessageLabel->setText(text); +} + +QString QmitkButtonOverlayWidget::GetButtonText() const +{ + return m_PushButton->text(); +} + +void QmitkButtonOverlayWidget::SetButtonText(const QString& text) +{ + m_PushButton->setText(text); +} + +QIcon QmitkButtonOverlayWidget::GetButtonIcon() const +{ + return m_PushButton->icon(); +} + +void QmitkButtonOverlayWidget::SetButtonIcon(const QIcon& icon) +{ + m_PushButton->setIcon(icon); +} diff --git a/Modules/QtWidgets/src/QmitkMxNMultiWidget.cpp b/Modules/QtWidgets/src/QmitkMxNMultiWidget.cpp index b0eafd2806..d3efda2364 100644 --- a/Modules/QtWidgets/src/QmitkMxNMultiWidget.cpp +++ b/Modules/QtWidgets/src/QmitkMxNMultiWidget.cpp @@ -1,381 +1,392 @@ /*============================================================================ 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 // qt #include #include QmitkMxNMultiWidget::QmitkMxNMultiWidget(QWidget* parent, Qt::WindowFlags f/* = 0*/, const QString& multiWidgetName/* = "mxnmulti"*/) : QmitkAbstractMultiWidget(parent, f, multiWidgetName) , m_TimeNavigationController(nullptr) , 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(); } } 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::SetReferenceGeometry(const mitk::TimeGeometry* referenceGeometry, bool resetCamera) +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 (referenceGeometry->IsValidTimePoint(currentTimePoint)) + if (geometry->IsValidTimePoint(currentTimePoint)) { - imageTimeStep = referenceGeometry->TimePointToTimeStep(currentTimePoint); + imageTimeStep = geometry->TimePointToTimeStep(currentTimePoint); } } // initialize active render window renderingManager->InitializeView( - this->GetActiveRenderWindowWidget()->GetRenderWindow()->GetVtkRenderWindow(), referenceGeometry, resetCamera); + 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); renderWindowWidget->SetCornerAnnotationText(renderWindowWidgetName.toStdString()); AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget); auto renderWindow = renderWindowWidget->GetRenderWindow(); 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 geometry time events with the render window's slice naviation controller + // 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); } diff --git a/Modules/QtWidgets/src/QmitkRenderWindow.cpp b/Modules/QtWidgets/src/QmitkRenderWindow.cpp index be434f645b..3776aeabf5 100644 --- a/Modules/QtWidgets/src/QmitkRenderWindow.cpp +++ b/Modules/QtWidgets/src/QmitkRenderWindow.cpp @@ -1,505 +1,507 @@ /*============================================================================ 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 "QmitkRenderWindow.h" #include "mitkInteractionKeyEvent.h" #include "mitkInternalEvent.h" #include "mitkMouseDoubleClickEvent.h" #include "mitkMouseMoveEvent.h" #include "mitkMousePressEvent.h" #include "mitkMouseReleaseEvent.h" #include "mitkMouseWheelEvent.h" #include #include #include #include #include #include #include #include #include #include #include -#include "QmitkMimeTypes.h" -#include "QmitkRenderWindowMenu.h" +#include +#include +#include QmitkRenderWindow::QmitkRenderWindow(QWidget *parent, const QString &name, mitk::VtkPropRenderer *) : QVTKOpenGLNativeWidget(parent) , m_ResendQtEvents(true) , m_MenuWidget(nullptr) , m_MenuWidgetActivated(false) , m_LayoutIndex(QmitkRenderWindowMenu::LayoutIndex::Axial) , m_GeometryViolationWarningOverlay(nullptr) { m_InternalRenderWindow = vtkSmartPointer::New(); m_InternalRenderWindow->SetMultiSamples(0); m_InternalRenderWindow->SetAlphaBitPlanes(0); setRenderWindow(m_InternalRenderWindow); Initialize(name.toStdString().c_str()); setFocusPolicy(Qt::StrongFocus); setMouseTracking(true); QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); setSizePolicy(sizePolicy); - // setup overlay widget to show a warning message - m_GeometryViolationWarningOverlay = new QmitkSimpleTextOverlayWidget(this); + // setup overlay widget to show a warning message with a button + m_GeometryViolationWarningOverlay = new QmitkButtonOverlayWidget(this); m_GeometryViolationWarningOverlay->setVisible(false); m_GeometryViolationWarningOverlay->SetOverlayText( - QStringLiteral("

Interaction is not possible because the " - "render window is not aligned.

")); + QStringLiteral("

Interaction is not possible because the " + "render window geometry
does not match the interaction reference geometry.

")); + m_GeometryViolationWarningOverlay->SetButtonText("Reset geometry"); + m_GeometryViolationWarningOverlay->SetButtonIcon(QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/reset.svg"))); + + connect(m_GeometryViolationWarningOverlay, &QmitkButtonOverlayWidget::Clicked, + this, &QmitkRenderWindow::ResetGeometry); } QmitkRenderWindow::~QmitkRenderWindow() { Destroy(); // Destroy mitkRenderWindowBase } void QmitkRenderWindow::SetResendQtEvents(bool resend) { m_ResendQtEvents = resend; } void QmitkRenderWindow::SetLayoutIndex(QmitkRenderWindowMenu::LayoutIndex layoutIndex) { m_LayoutIndex = layoutIndex; if (nullptr != m_MenuWidget) { m_MenuWidget->SetLayoutIndex(layoutIndex); } } QmitkRenderWindowMenu::LayoutIndex QmitkRenderWindow::GetLayoutIndex() { if (nullptr != m_MenuWidget) { return m_MenuWidget->GetLayoutIndex(); } else { return QmitkRenderWindowMenu::LayoutIndex::Axial; } } void QmitkRenderWindow::UpdateLayoutDesignList(QmitkRenderWindowMenu::LayoutDesign layoutDesign) { if (nullptr != m_MenuWidget) { m_MenuWidget->UpdateLayoutDesignList(layoutDesign); } } void QmitkRenderWindow::UpdateCrosshairVisibility(bool visible) { m_MenuWidget->UpdateCrosshairVisibility(visible); } void QmitkRenderWindow::UpdateCrosshairRotationMode(int mode) { m_MenuWidget->UpdateCrosshairRotationMode(mode); } void QmitkRenderWindow::ActivateMenuWidget(bool state) { if (nullptr == m_MenuWidget) { m_MenuWidget = new QmitkRenderWindowMenu(this, nullptr, m_Renderer); m_MenuWidget->SetLayoutIndex(m_LayoutIndex); } m_MenuWidgetActivated = state; if (m_MenuWidgetActivated) { connect(m_MenuWidget, &QmitkRenderWindowMenu::LayoutDesignChanged, this, &QmitkRenderWindow::LayoutDesignChanged); connect(m_MenuWidget, &QmitkRenderWindowMenu::ResetView, this, &QmitkRenderWindow::ResetView); connect(m_MenuWidget, &QmitkRenderWindowMenu::CrosshairVisibilityChanged, this, &QmitkRenderWindow::CrosshairVisibilityChanged); connect(m_MenuWidget, &QmitkRenderWindowMenu::CrosshairRotationModeChanged, this, &QmitkRenderWindow::CrosshairRotationModeChanged); } else { disconnect(m_MenuWidget, &QmitkRenderWindowMenu::LayoutDesignChanged, this, &QmitkRenderWindow::LayoutDesignChanged); disconnect(m_MenuWidget, &QmitkRenderWindowMenu::ResetView, this, &QmitkRenderWindow::ResetView); disconnect(m_MenuWidget, &QmitkRenderWindowMenu::CrosshairVisibilityChanged, this, &QmitkRenderWindow::CrosshairVisibilityChanged); disconnect(m_MenuWidget, &QmitkRenderWindowMenu::CrosshairRotationModeChanged, this, &QmitkRenderWindow::CrosshairRotationModeChanged); m_MenuWidget->hide(); } } void QmitkRenderWindow::ShowOverlayMessage(bool show) { m_GeometryViolationWarningOverlay->setVisible(show); } void QmitkRenderWindow::moveEvent(QMoveEvent *event) { QVTKOpenGLNativeWidget::moveEvent(event); // after a move the overlays need to be positioned emit moved(); } void QmitkRenderWindow::showEvent(QShowEvent *event) { QVTKOpenGLNativeWidget::showEvent(event); // this singleshot is necessary to have the overlays positioned correctly after initial show // simple call of moved() is no use here!! QTimer::singleShot(0, this, SIGNAL(moved())); } bool QmitkRenderWindow::event(QEvent* e) { mitk::InteractionEvent::Pointer mitkEvent = nullptr; mitk::Point2D mousePosition; bool updateStatusBar = false; switch (e->type()) { case QEvent::MouseMove: { auto me = static_cast(e); mousePosition = this->GetMousePosition(me); mitkEvent = mitk::MouseMoveEvent::New(m_Renderer, mousePosition, GetButtonState(me), GetModifiers(me)); updateStatusBar = true; break; } case QEvent::MouseButtonPress: { auto me = static_cast(e); mitkEvent = mitk::MousePressEvent::New( m_Renderer, GetMousePosition(me), GetButtonState(me), GetModifiers(me), GetEventButton(me)); break; } case QEvent::MouseButtonRelease: { auto me = static_cast(e); mitkEvent = mitk::MouseReleaseEvent::New( m_Renderer, GetMousePosition(me), GetButtonState(me), GetModifiers(me), GetEventButton(me)); break; } case QEvent::MouseButtonDblClick: { auto me = static_cast(e); mitkEvent = mitk::MouseDoubleClickEvent::New( m_Renderer, GetMousePosition(me), GetButtonState(me), GetModifiers(me), GetEventButton(me)); break; } case QEvent::Wheel: { auto we = static_cast(e); mousePosition = this->GetMousePosition(we); mitkEvent = mitk::MouseWheelEvent::New(m_Renderer, mousePosition, GetButtonState(we), GetModifiers(we), GetDelta(we)); updateStatusBar = true; break; } case QEvent::KeyPress: { auto ke = static_cast(e); mitkEvent = mitk::InteractionKeyEvent::New(m_Renderer, GetKeyLetter(ke), GetModifiers(ke)); break; } case QEvent::Resize: { if (nullptr != m_MenuWidget) m_MenuWidget->MoveWidgetToCorrectPos(); } default: { break; } } if (mitkEvent != nullptr) { if (this->HandleEvent(mitkEvent.GetPointer())) { return m_ResendQtEvents ? false : true; } } if (updateStatusBar) { this->UpdateStatusBar(mousePosition); } return QVTKOpenGLNativeWidget::event(e); } void QmitkRenderWindow::enterEvent(QEvent *e) { - mitk::InternalEvent::Pointer internalEvent = mitk::InternalEvent::New(m_Renderer, nullptr, "EnterRenderWindow"); - - this->HandleEvent(internalEvent.GetPointer()); + auto* baseRenderer = mitk::BaseRenderer::GetInstance(this->GetRenderWindow()); + this->ShowOverlayMessage(!baseRenderer->GetReferenceGeometryAligned()); if (nullptr != m_MenuWidget) m_MenuWidget->ShowMenu(); QVTKOpenGLNativeWidget::enterEvent(e); } void QmitkRenderWindow::leaveEvent(QEvent *e) { auto statusBar = mitk::StatusBar::GetInstance(); statusBar->DisplayGreyValueText(""); - - mitk::InternalEvent::Pointer internalEvent = mitk::InternalEvent::New(m_Renderer, nullptr, "LeaveRenderWindow"); - - this->HandleEvent(internalEvent.GetPointer()); + this->ShowOverlayMessage(false); if (nullptr != m_MenuWidget) m_MenuWidget->HideMenu(); QVTKOpenGLNativeWidget::leaveEvent(e); } void QmitkRenderWindow::resizeGL(int w, int h) { QVTKOpenGLNativeWidget::resizeGL(w, h); mitk::RenderingManager::GetInstance()->ForceImmediateUpdate(renderWindow()); } void QmitkRenderWindow::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasFormat("application/x-mitk-datanodes")) { event->accept(); } } void QmitkRenderWindow::dropEvent(QDropEvent *event) { QList dataNodeList = QmitkMimeTypes::ToDataNodePtrList(event->mimeData()); if (!dataNodeList.empty()) { emit NodesDropped(this, dataNodeList.toVector().toStdVector()); } } void QmitkRenderWindow::DeferredHideMenu() { MITK_DEBUG << "QmitkRenderWindow::DeferredHideMenu"; if (nullptr != m_MenuWidget) { m_MenuWidget->HideMenu(); } } mitk::Point2D QmitkRenderWindow::GetMousePosition(QMouseEvent *me) const { mitk::Point2D point; point[0] = me->x(); // We need to convert the y component, as the display and vtk have other definitions for the y direction point[1] = m_Renderer->GetSizeY() - me->y(); return point; } mitk::Point2D QmitkRenderWindow::GetMousePosition(QWheelEvent *we) const { mitk::Point2D point; point[0] = we->x(); // We need to convert the y component, as the display and vtk have other definitions for the y direction point[1] = m_Renderer->GetSizeY() - we->y(); return point; } mitk::InteractionEvent::MouseButtons QmitkRenderWindow::GetEventButton(QMouseEvent *me) const { mitk::InteractionEvent::MouseButtons eventButton; switch (me->button()) { case Qt::LeftButton: eventButton = mitk::InteractionEvent::LeftMouseButton; break; case Qt::RightButton: eventButton = mitk::InteractionEvent::RightMouseButton; break; case Qt::MidButton: eventButton = mitk::InteractionEvent::MiddleMouseButton; break; default: eventButton = mitk::InteractionEvent::NoButton; break; } return eventButton; } mitk::InteractionEvent::MouseButtons QmitkRenderWindow::GetButtonState(QMouseEvent *me) const { mitk::InteractionEvent::MouseButtons buttonState = mitk::InteractionEvent::NoButton; if (me->buttons() & Qt::LeftButton) { buttonState = buttonState | mitk::InteractionEvent::LeftMouseButton; } if (me->buttons() & Qt::RightButton) { buttonState = buttonState | mitk::InteractionEvent::RightMouseButton; } if (me->buttons() & Qt::MidButton) { buttonState = buttonState | mitk::InteractionEvent::MiddleMouseButton; } return buttonState; } mitk::InteractionEvent::ModifierKeys QmitkRenderWindow::GetModifiers(QInputEvent *me) const { mitk::InteractionEvent::ModifierKeys modifiers = mitk::InteractionEvent::NoKey; if (me->modifiers() & Qt::ALT) { modifiers = modifiers | mitk::InteractionEvent::AltKey; } if (me->modifiers() & Qt::CTRL) { modifiers = modifiers | mitk::InteractionEvent::ControlKey; } if (me->modifiers() & Qt::SHIFT) { modifiers = modifiers | mitk::InteractionEvent::ShiftKey; } return modifiers; } mitk::InteractionEvent::MouseButtons QmitkRenderWindow::GetButtonState(QWheelEvent *we) const { mitk::InteractionEvent::MouseButtons buttonState = mitk::InteractionEvent::NoButton; if (we->buttons() & Qt::LeftButton) { buttonState = buttonState | mitk::InteractionEvent::LeftMouseButton; } if (we->buttons() & Qt::RightButton) { buttonState = buttonState | mitk::InteractionEvent::RightMouseButton; } if (we->buttons() & Qt::MidButton) { buttonState = buttonState | mitk::InteractionEvent::MiddleMouseButton; } return buttonState; } std::string QmitkRenderWindow::GetKeyLetter(QKeyEvent *ke) const { // Converting Qt Key Event to string element. std::string key = ""; int tkey = ke->key(); if (tkey < 128) { // standard ascii letter key = (char)toupper(tkey); } else { // special keys switch (tkey) { case Qt::Key_Return: key = mitk::InteractionEvent::KeyReturn; break; case Qt::Key_Enter: key = mitk::InteractionEvent::KeyEnter; break; case Qt::Key_Escape: key = mitk::InteractionEvent::KeyEsc; break; case Qt::Key_Delete: key = mitk::InteractionEvent::KeyDelete; break; case Qt::Key_Up: key = mitk::InteractionEvent::KeyArrowUp; break; case Qt::Key_Down: key = mitk::InteractionEvent::KeyArrowDown; break; case Qt::Key_Left: key = mitk::InteractionEvent::KeyArrowLeft; break; case Qt::Key_Right: key = mitk::InteractionEvent::KeyArrowRight; break; case Qt::Key_F1: key = mitk::InteractionEvent::KeyF1; break; case Qt::Key_F2: key = mitk::InteractionEvent::KeyF2; break; case Qt::Key_F3: key = mitk::InteractionEvent::KeyF3; break; case Qt::Key_F4: key = mitk::InteractionEvent::KeyF4; break; case Qt::Key_F5: key = mitk::InteractionEvent::KeyF5; break; case Qt::Key_F6: key = mitk::InteractionEvent::KeyF6; break; case Qt::Key_F7: key = mitk::InteractionEvent::KeyF7; break; case Qt::Key_F8: key = mitk::InteractionEvent::KeyF8; break; case Qt::Key_F9: key = mitk::InteractionEvent::KeyF9; break; case Qt::Key_F10: key = mitk::InteractionEvent::KeyF10; break; case Qt::Key_F11: key = mitk::InteractionEvent::KeyF11; break; case Qt::Key_F12: key = mitk::InteractionEvent::KeyF12; break; case Qt::Key_End: key = mitk::InteractionEvent::KeyEnd; break; case Qt::Key_Home: key = mitk::InteractionEvent::KeyPos1; break; case Qt::Key_Insert: key = mitk::InteractionEvent::KeyInsert; break; case Qt::Key_PageDown: key = mitk::InteractionEvent::KeyPageDown; break; case Qt::Key_PageUp: key = mitk::InteractionEvent::KeyPageUp; break; case Qt::Key_Space: key = mitk::InteractionEvent::KeySpace; break; } } return key; } int QmitkRenderWindow::GetDelta(QWheelEvent *we) const { return we->delta(); } void QmitkRenderWindow::UpdateStatusBar(mitk::Point2D pointerPositionOnScreen) { mitk::Point3D worldPosition; m_Renderer->ForceImmediateUpdate(); m_Renderer->DisplayToWorld(pointerPositionOnScreen, worldPosition); auto statusBar = mitk::StatusBar::GetInstance(); statusBar->DisplayRendererInfo(worldPosition, m_Renderer->GetTime()); } diff --git a/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp b/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp index 9679e85137..fa26a2dc61 100644 --- a/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp +++ b/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp @@ -1,424 +1,439 @@ /*============================================================================ 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 */) : 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::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); } diff --git a/Modules/QtWidgets/src/QmitkStdMultiWidget.cpp b/Modules/QtWidgets/src/QmitkStdMultiWidget.cpp index 3a82a7778e..3e0da23893 100644 --- a/Modules/QtWidgets/src/QmitkStdMultiWidget.cpp +++ b/Modules/QtWidgets/src/QmitkStdMultiWidget.cpp @@ -1,737 +1,742 @@ /*============================================================================ 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. ============================================================================*/ #define SMW_INFO MITK_INFO("widget.stdmulti") #include "QmitkStdMultiWidget.h" #include "QmitkRenderWindowWidget.h" // mitk core #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // qt #include #include #include // vtk #include // c++ #include QmitkStdMultiWidget::QmitkStdMultiWidget(QWidget *parent, Qt::WindowFlags f/* = 0*/, const QString &name/* = "stdmulti"*/) : QmitkAbstractMultiWidget(parent, f, name) , m_TimeNavigationController(nullptr) { m_TimeNavigationController = mitk::RenderingManager::GetInstance()->GetTimeNavigationController(); } QmitkStdMultiWidget::~QmitkStdMultiWidget() { auto allRenderWindows = this->GetRenderWindows(); for (auto& renderWindow : allRenderWindows) { m_TimeNavigationController->Disconnect(renderWindow->GetSliceNavigationController()); } } void QmitkStdMultiWidget::InitializeMultiWidget() { // yellow is default color for widget4 m_DecorationColorWidget4[0] = 1.0f; m_DecorationColorWidget4[1] = 1.0f; m_DecorationColorWidget4[2] = 0.0f; SetLayout(2, 2); // transfer colors in WorldGeometry-Nodes of the associated Renderer // of widget 1 m_PlaneNode1 = mitk::BaseRenderer::GetInstance(GetRenderWindow1()->renderWindow())->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode1->SetColor(GetDecorationColor(0)); // of widget 2 m_PlaneNode2 = mitk::BaseRenderer::GetInstance(GetRenderWindow2()->renderWindow())->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode2->SetColor(GetDecorationColor(1)); // of widget 3 m_PlaneNode3 = mitk::BaseRenderer::GetInstance(GetRenderWindow3()->renderWindow())->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode3->SetColor(GetDecorationColor(2)); // the parent node m_ParentNodeForGeometryPlanes = mitk::BaseRenderer::GetInstance(GetRenderWindow4()->renderWindow())->GetCurrentWorldPlaneGeometryNode(); AddDisplayPlaneSubTree(); SetDisplayActionEventHandler(std::make_unique()); auto displayActionEventHandler = GetDisplayActionEventHandler(); if (nullptr != displayActionEventHandler) { displayActionEventHandler->InitActions(); } } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow(const QString& widgetName) const { if ("axial" == widgetName) { return GetRenderWindow1(); } if ("sagittal" == widgetName) { return GetRenderWindow2(); } if ("coronal" == widgetName) { return GetRenderWindow3(); } if ("3d" == widgetName) { return GetRenderWindow4(); } return QmitkAbstractMultiWidget::GetRenderWindow(widgetName); } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow(const mitk::AnatomicalPlane& orientation) const { return GetRenderWindow(static_cast(orientation)); } -void QmitkStdMultiWidget::SetReferenceGeometry(const mitk::TimeGeometry* referenceGeometry, bool resetCamera) +void QmitkStdMultiWidget::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 (referenceGeometry->IsValidTimePoint(currentTimePoint)) + if (geometry->IsValidTimePoint(currentTimePoint)) { - imageTimeStep = referenceGeometry->TimePointToTimeStep(currentTimePoint); + imageTimeStep = geometry->TimePointToTimeStep(currentTimePoint); } } // initialize render windows - renderingManager->InitializeViews(referenceGeometry, mitk::RenderingManager::REQUEST_UPDATE_ALL, resetCamera); + renderingManager->InitializeViews(geometry, mitk::RenderingManager::REQUEST_UPDATE_ALL, resetCamera); if (!resetCamera) { this->SetSelectedPosition(currentPosition, ""); renderingManager->GetTimeNavigationController()->GetTime()->SetPos(imageTimeStep); } } +void QmitkStdMultiWidget::SetInteractionReferenceGeometry(const mitk::TimeGeometry* /*referenceGeometry*/) +{ + // not implemented on purpose +} + bool QmitkStdMultiWidget::HasCoupledRenderWindows() const { return true; } void QmitkStdMultiWidget::SetSelectedPosition(const mitk::Point3D& newPosition, const QString& /*widgetName*/) { GetRenderWindow1()->GetSliceNavigationController()->SelectSliceByPoint(newPosition); GetRenderWindow2()->GetSliceNavigationController()->SelectSliceByPoint(newPosition); GetRenderWindow3()->GetSliceNavigationController()->SelectSliceByPoint(newPosition); RequestUpdateAll(); } const mitk::Point3D QmitkStdMultiWidget::GetSelectedPosition(const QString& /*widgetName*/) const { const mitk::PlaneGeometry* plane1 = GetRenderWindow1()->GetSliceNavigationController()->GetCurrentPlaneGeometry(); const mitk::PlaneGeometry* plane2 = GetRenderWindow2()->GetSliceNavigationController()->GetCurrentPlaneGeometry(); const mitk::PlaneGeometry* plane3 = GetRenderWindow3()->GetSliceNavigationController()->GetCurrentPlaneGeometry(); mitk::Line3D line; if ((plane1 != nullptr) && (plane2 != nullptr) && (plane1->IntersectionLine(plane2, line))) { mitk::Point3D point; if ((plane3 != nullptr) && (plane3->IntersectionPoint(line, point))) { return point; } } return mitk::Point3D(); } void QmitkStdMultiWidget::SetCrosshairVisibility(bool visible) { if (m_PlaneNode1.IsNotNull()) { m_PlaneNode1->SetVisibility(visible); } if (m_PlaneNode2.IsNotNull()) { m_PlaneNode2->SetVisibility(visible); } if (m_PlaneNode3.IsNotNull()) { m_PlaneNode3->SetVisibility(visible); } emit NotifyCrosshairVisibilityChanged(visible); RequestUpdateAll(); } bool QmitkStdMultiWidget::GetCrosshairVisibility() const { bool crosshairVisibility = true; if (m_PlaneNode1.IsNotNull()) { bool visibilityProperty = false; m_PlaneNode1->GetVisibility(visibilityProperty, nullptr); crosshairVisibility &= visibilityProperty; } if (m_PlaneNode2.IsNotNull()) { bool visibilityProperty = false; crosshairVisibility &= m_PlaneNode2->GetVisibility(visibilityProperty, nullptr); crosshairVisibility &= visibilityProperty; } if (m_PlaneNode3.IsNotNull()) { bool visibilityProperty = false; crosshairVisibility &= m_PlaneNode3->GetVisibility(visibilityProperty, nullptr); crosshairVisibility &= visibilityProperty; } return crosshairVisibility; } void QmitkStdMultiWidget::SetCrosshairGap(unsigned int gapSize) { m_PlaneNode1->SetIntProperty("Crosshair.Gap Size", gapSize); m_PlaneNode2->SetIntProperty("Crosshair.Gap Size", gapSize); m_PlaneNode3->SetIntProperty("Crosshair.Gap Size", gapSize); } void QmitkStdMultiWidget::ResetCrosshair() { auto dataStorage = GetDataStorage(); if (nullptr == dataStorage) { return; } mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(dataStorage); SetWidgetPlaneMode(mitk::InteractionSchemeSwitcher::MITKStandard); } void QmitkStdMultiWidget::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; } emit NotifyCrosshairRotationModeChanged(userMode); } mitk::SliceNavigationController* QmitkStdMultiWidget::GetTimeNavigationController() { return m_TimeNavigationController; } void QmitkStdMultiWidget::AddPlanesToDataStorage() { auto dataStorage = GetDataStorage(); if (nullptr == dataStorage) { return; } if (m_PlaneNode1.IsNotNull() && m_PlaneNode2.IsNotNull() && m_PlaneNode3.IsNotNull() && m_ParentNodeForGeometryPlanes.IsNotNull()) { dataStorage->Add(m_ParentNodeForGeometryPlanes); dataStorage->Add(m_PlaneNode1, m_ParentNodeForGeometryPlanes); dataStorage->Add(m_PlaneNode2, m_ParentNodeForGeometryPlanes); dataStorage->Add(m_PlaneNode3, m_ParentNodeForGeometryPlanes); } } void QmitkStdMultiWidget::RemovePlanesFromDataStorage() { auto dataStorage = GetDataStorage(); if (nullptr == dataStorage) { return; } if (m_PlaneNode1.IsNotNull() && m_PlaneNode2.IsNotNull() && m_PlaneNode3.IsNotNull() && m_ParentNodeForGeometryPlanes.IsNotNull()) { dataStorage->Remove(m_PlaneNode1); dataStorage->Remove(m_PlaneNode2); dataStorage->Remove(m_PlaneNode3); dataStorage->Remove(m_ParentNodeForGeometryPlanes); } } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow(unsigned int number) const { switch (number) { case 0: return GetRenderWindow1(); case 1: return GetRenderWindow2(); case 2: return GetRenderWindow3(); case 3: return GetRenderWindow4(); default: MITK_ERROR << "Requested unknown render window"; break; } return nullptr; } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow1() const { return QmitkAbstractMultiWidget::GetRenderWindow(GetNameFromIndex(0, 0)); } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow2() const { return QmitkAbstractMultiWidget::GetRenderWindow(GetNameFromIndex(0, 1)); } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow3() const { return QmitkAbstractMultiWidget::GetRenderWindow(GetNameFromIndex(1, 0)); } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow4() const { return QmitkAbstractMultiWidget::GetRenderWindow(GetNameFromIndex(1, 1)); } mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane1() const { return m_PlaneNode1; } mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane2() const { return m_PlaneNode2; } mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane3() const { return m_PlaneNode3; } mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane(unsigned number) const { switch (number) { case 1: return m_PlaneNode1; case 2: return m_PlaneNode2; case 3: return m_PlaneNode3; default: MITK_ERROR << "Requested unknown render window"; break; } return nullptr; } void QmitkStdMultiWidget::SetDecorationColor(unsigned int widgetNumber, mitk::Color color) { switch (widgetNumber) { case 0: if (m_PlaneNode1.IsNotNull()) { m_PlaneNode1->SetColor(color); } break; case 1: if (m_PlaneNode2.IsNotNull()) { m_PlaneNode2->SetColor(color); } break; case 2: if (m_PlaneNode3.IsNotNull()) { m_PlaneNode3->SetColor(color); } break; case 3: m_DecorationColorWidget4 = color; break; default: MITK_ERROR << "Decoration color for unknown widget!"; break; } } mitk::Color QmitkStdMultiWidget::GetDecorationColor(unsigned int widgetNumber) { // The implementation looks a bit messy here, but it avoids // synchronization of the color of the geometry nodes and an // internal member here. // Default colors were chosen for decent visibility. // Feel free to change your preferences in the workbench. float tmp[3] = { 0.0f, 0.0f, 0.0f }; switch (widgetNumber) { case 0: { if (m_PlaneNode1.IsNotNull()) { if (m_PlaneNode1->GetColor(tmp)) { return dynamic_cast(m_PlaneNode1->GetProperty("color"))->GetColor(); } } float red[3] = { 0.753f, 0.0f, 0.0f }; // This is #C00000 in hex return mitk::Color(red); } case 1: { if (m_PlaneNode2.IsNotNull()) { if (m_PlaneNode2->GetColor(tmp)) { return dynamic_cast(m_PlaneNode2->GetProperty("color"))->GetColor(); } } float green[3] = { 0.0f, 0.69f, 0.0f }; // This is #00B000 in hex return mitk::Color(green); } case 2: { if (m_PlaneNode3.IsNotNull()) { if (m_PlaneNode3->GetColor(tmp)) { return dynamic_cast(m_PlaneNode3->GetProperty("color"))->GetColor(); } } float blue[3] = { 0.0, 0.502f, 1.0f }; // This is #0080FF in hex return mitk::Color(blue); } case 3: { return m_DecorationColorWidget4; } default: MITK_ERROR << "Decoration color for unknown widget!"; float black[3] = { 0.0f, 0.0f, 0.0f }; return mitk::Color(black); } } void QmitkStdMultiWidget::mousePressEvent(QMouseEvent*) { // nothing here, but necessary for mouse interactions (.xml-configuration files) } void QmitkStdMultiWidget::moveEvent(QMoveEvent* e) { QWidget::moveEvent(e); // it is necessary to readjust the position of the Annotation as the StdMultiWidget has moved // unfortunately it's not done by QmitkRenderWindow::moveEvent -> must be done here emit Moved(); } void QmitkStdMultiWidget::wheelEvent(QWheelEvent* e) { emit WheelMoved(e); } void QmitkStdMultiWidget::Fit() { vtkSmartPointer vtkrenderer; vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow1()->renderWindow())->GetVtkRenderer(); if (nullptr != vtkrenderer) { vtkrenderer->ResetCamera(); } vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow2()->renderWindow())->GetVtkRenderer(); if (nullptr != vtkrenderer) { vtkrenderer->ResetCamera(); } vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow3()->renderWindow())->GetVtkRenderer(); if (nullptr != vtkrenderer) { vtkrenderer->ResetCamera(); } vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow4()->renderWindow())->GetVtkRenderer(); if (nullptr != vtkrenderer) { vtkrenderer->ResetCamera(); } mitk::BaseRenderer::GetInstance(GetRenderWindow1()->renderWindow())->GetCameraController()->Fit(); mitk::BaseRenderer::GetInstance(GetRenderWindow2()->renderWindow())->GetCameraController()->Fit(); mitk::BaseRenderer::GetInstance(GetRenderWindow3()->renderWindow())->GetCameraController()->Fit(); mitk::BaseRenderer::GetInstance(GetRenderWindow4()->renderWindow())->GetCameraController()->Fit(); int w = vtkObject::GetGlobalWarningDisplay(); vtkObject::GlobalWarningDisplayOff(); vtkObject::SetGlobalWarningDisplay(w); } void QmitkStdMultiWidget::AddDisplayPlaneSubTree() { // add the displayed planes of the multiwidget to a node to which the subtree // @a planesSubTree points ... mitk::PlaneGeometryDataMapper2D::Pointer mapper; // ... of widget 1 mitk::BaseRenderer* renderer1 = mitk::BaseRenderer::GetInstance(GetRenderWindow1()->renderWindow()); m_PlaneNode1 = renderer1->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode1->SetProperty("visible", mitk::BoolProperty::New(true)); m_PlaneNode1->SetProperty("name", mitk::StringProperty::New(std::string(renderer1->GetName()) + ".plane")); m_PlaneNode1->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_PlaneNode1->SetProperty("helper object", mitk::BoolProperty::New(true)); mapper = mitk::PlaneGeometryDataMapper2D::New(); m_PlaneNode1->SetMapper(mitk::BaseRenderer::Standard2D, mapper); // ... of widget 2 mitk::BaseRenderer* renderer2 = mitk::BaseRenderer::GetInstance(GetRenderWindow2()->renderWindow()); m_PlaneNode2 = renderer2->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode2->SetProperty("visible", mitk::BoolProperty::New(true)); m_PlaneNode2->SetProperty("name", mitk::StringProperty::New(std::string(renderer2->GetName()) + ".plane")); m_PlaneNode2->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_PlaneNode2->SetProperty("helper object", mitk::BoolProperty::New(true)); mapper = mitk::PlaneGeometryDataMapper2D::New(); m_PlaneNode2->SetMapper(mitk::BaseRenderer::Standard2D, mapper); // ... of widget 3 mitk::BaseRenderer *renderer3 = mitk::BaseRenderer::GetInstance(GetRenderWindow3()->renderWindow()); m_PlaneNode3 = renderer3->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode3->SetProperty("visible", mitk::BoolProperty::New(true)); m_PlaneNode3->SetProperty("name", mitk::StringProperty::New(std::string(renderer3->GetName()) + ".plane")); m_PlaneNode3->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_PlaneNode3->SetProperty("helper object", mitk::BoolProperty::New(true)); mapper = mitk::PlaneGeometryDataMapper2D::New(); m_PlaneNode3->SetMapper(mitk::BaseRenderer::Standard2D, mapper); m_ParentNodeForGeometryPlanes = mitk::DataNode::New(); m_ParentNodeForGeometryPlanes->SetProperty("name", mitk::StringProperty::New("Widgets")); m_ParentNodeForGeometryPlanes->SetProperty("helper object", mitk::BoolProperty::New(true)); } void QmitkStdMultiWidget::EnsureDisplayContainsPoint(mitk::BaseRenderer *renderer, const mitk::Point3D &p) { mitk::Point2D pointOnDisplay; renderer->WorldToDisplay(p, pointOnDisplay); if (pointOnDisplay[0] < renderer->GetVtkRenderer()->GetOrigin()[0] || pointOnDisplay[1] < renderer->GetVtkRenderer()->GetOrigin()[1] || pointOnDisplay[0] > renderer->GetVtkRenderer()->GetOrigin()[0] + renderer->GetViewportSize()[0] || pointOnDisplay[1] > renderer->GetVtkRenderer()->GetOrigin()[1] + renderer->GetViewportSize()[1]) { mitk::Point2D pointOnPlane; renderer->GetCurrentWorldPlaneGeometry()->Map(p, pointOnPlane); renderer->GetCameraController()->MoveCameraToPoint(pointOnPlane); } } void QmitkStdMultiWidget::SetWidgetPlaneVisibility(const char *widgetName, bool visible, mitk::BaseRenderer *renderer) { auto dataStorage = GetDataStorage(); if (nullptr != dataStorage) { mitk::DataNode* dataNode = dataStorage->GetNamedNode(widgetName); if (dataNode != nullptr) { dataNode->SetVisibility(visible, renderer); } } } void QmitkStdMultiWidget::SetWidgetPlanesVisibility(bool visible, mitk::BaseRenderer *renderer) { if (m_PlaneNode1.IsNotNull()) { m_PlaneNode1->SetVisibility(visible, renderer); } if (m_PlaneNode2.IsNotNull()) { m_PlaneNode2->SetVisibility(visible, renderer); } if (m_PlaneNode3.IsNotNull()) { m_PlaneNode3->SetVisibility(visible, renderer); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } ////////////////////////////////////////////////////////////////////////// // PRIVATE ////////////////////////////////////////////////////////////////////////// void QmitkStdMultiWidget::SetLayoutImpl() { CreateRenderWindowWidgets(); GetMultiWidgetLayoutManager()->SetLayoutDesign(QmitkMultiWidgetLayoutManager::LayoutDesign::DEFAULT); // Initialize views as axial, sagittal, coronal to all data objects in DataStorage auto geo = GetDataStorage()->ComputeBoundingGeometry3D(GetDataStorage()->GetAll()); mitk::RenderingManager::GetInstance()->InitializeViews(geo); } void QmitkStdMultiWidget::CreateRenderWindowWidgets() { // create axial render window (widget) QString renderWindowWidgetName = GetNameFromIndex(0, 0); RenderWindowWidgetPointer renderWindowWidget1 = std::make_shared(this, renderWindowWidgetName, GetDataStorage()); auto renderWindow1 = renderWindowWidget1->GetRenderWindow(); renderWindow1->GetSliceNavigationController()->SetDefaultViewDirection(mitk::AnatomicalPlane::Axial); renderWindowWidget1->SetDecorationColor(GetDecorationColor(0)); renderWindowWidget1->SetCornerAnnotationText("Axial"); renderWindowWidget1->GetRenderWindow()->SetLayoutIndex(mitk::AnatomicalPlane::Axial); AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget1); // create sagittal render window (widget) renderWindowWidgetName = GetNameFromIndex(0, 1); RenderWindowWidgetPointer renderWindowWidget2 = std::make_shared(this, renderWindowWidgetName, GetDataStorage()); auto renderWindow2 = renderWindowWidget2->GetRenderWindow(); renderWindow2->GetSliceNavigationController()->SetDefaultViewDirection(mitk::AnatomicalPlane::Sagittal); renderWindowWidget2->SetDecorationColor(GetDecorationColor(1)); renderWindowWidget2->setStyleSheet("border: 0px"); renderWindowWidget2->SetCornerAnnotationText("Sagittal"); renderWindowWidget2->GetRenderWindow()->SetLayoutIndex(mitk::AnatomicalPlane::Sagittal); AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget2); // create coronal render window (widget) renderWindowWidgetName = GetNameFromIndex(1, 0); RenderWindowWidgetPointer renderWindowWidget3 = std::make_shared(this, renderWindowWidgetName, GetDataStorage()); auto renderWindow3 = renderWindowWidget3->GetRenderWindow(); renderWindow3->GetSliceNavigationController()->SetDefaultViewDirection(mitk::AnatomicalPlane::Coronal); renderWindowWidget3->SetDecorationColor(GetDecorationColor(2)); renderWindowWidget3->SetCornerAnnotationText("Coronal"); renderWindowWidget3->GetRenderWindow()->SetLayoutIndex(mitk::AnatomicalPlane::Coronal); AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget3); // create 3D render window (widget) renderWindowWidgetName = GetNameFromIndex(1, 1); RenderWindowWidgetPointer renderWindowWidget4 = std::make_shared(this, renderWindowWidgetName, GetDataStorage()); auto renderWindow4 = renderWindowWidget4->GetRenderWindow(); renderWindow4->GetSliceNavigationController()->SetDefaultViewDirection(mitk::AnatomicalPlane::Original); renderWindowWidget4->SetDecorationColor(GetDecorationColor(3)); renderWindowWidget4->SetCornerAnnotationText("3D"); renderWindowWidget4->GetRenderWindow()->SetLayoutIndex(mitk::AnatomicalPlane::Original); mitk::BaseRenderer::GetInstance(renderWindowWidget4->GetRenderWindow()->renderWindow())->SetMapperID(mitk::BaseRenderer::Standard3D); AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget4); SetActiveRenderWindowWidget(renderWindowWidget1); // connect to the "time navigation controller": send time via sliceNavigationControllers m_TimeNavigationController->ConnectGeometryTimeEvent(renderWindow1->GetSliceNavigationController()); m_TimeNavigationController->ConnectGeometryTimeEvent(renderWindow2->GetSliceNavigationController()); m_TimeNavigationController->ConnectGeometryTimeEvent(renderWindow3->GetSliceNavigationController()); m_TimeNavigationController->ConnectGeometryTimeEvent(renderWindow4->GetSliceNavigationController()); renderWindow1->GetSliceNavigationController()->ConnectGeometrySendEvent( mitk::BaseRenderer::GetInstance(renderWindow4->renderWindow())); // reverse connection between sliceNavigationControllers and timeNavigationController renderWindow1->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController); renderWindow2->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController); renderWindow3->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController); //renderWindow4->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController); auto layoutManager = GetMultiWidgetLayoutManager(); connect(renderWindow1, &QmitkRenderWindow::ResetView, this, &QmitkStdMultiWidget::ResetCrosshair); connect(renderWindow1, &QmitkRenderWindow::CrosshairVisibilityChanged, this, &QmitkStdMultiWidget::SetCrosshairVisibility); connect(renderWindow1, &QmitkRenderWindow::CrosshairRotationModeChanged, this, &QmitkStdMultiWidget::SetWidgetPlaneMode); connect(renderWindow1, &QmitkRenderWindow::LayoutDesignChanged, layoutManager, &QmitkMultiWidgetLayoutManager::SetLayoutDesign); connect(this, &QmitkStdMultiWidget::NotifyCrosshairVisibilityChanged, renderWindow1, &QmitkRenderWindow::UpdateCrosshairVisibility); connect(this, &QmitkStdMultiWidget::NotifyCrosshairRotationModeChanged, renderWindow1, &QmitkRenderWindow::UpdateCrosshairRotationMode); connect(renderWindow2, &QmitkRenderWindow::ResetView, this, &QmitkStdMultiWidget::ResetCrosshair); connect(renderWindow2, &QmitkRenderWindow::CrosshairVisibilityChanged, this, &QmitkStdMultiWidget::SetCrosshairVisibility); connect(renderWindow2, &QmitkRenderWindow::CrosshairRotationModeChanged, this, &QmitkStdMultiWidget::SetWidgetPlaneMode); connect(renderWindow2, &QmitkRenderWindow::LayoutDesignChanged, layoutManager, &QmitkMultiWidgetLayoutManager::SetLayoutDesign); connect(this, &QmitkStdMultiWidget::NotifyCrosshairVisibilityChanged, renderWindow2, &QmitkRenderWindow::UpdateCrosshairVisibility); connect(this, &QmitkStdMultiWidget::NotifyCrosshairRotationModeChanged, renderWindow2, &QmitkRenderWindow::UpdateCrosshairRotationMode); connect(renderWindow3, &QmitkRenderWindow::ResetView, this, &QmitkStdMultiWidget::ResetCrosshair); connect(renderWindow3, &QmitkRenderWindow::CrosshairVisibilityChanged, this, &QmitkStdMultiWidget::SetCrosshairVisibility); connect(renderWindow3, &QmitkRenderWindow::CrosshairRotationModeChanged, this, &QmitkStdMultiWidget::SetWidgetPlaneMode); connect(renderWindow3, &QmitkRenderWindow::LayoutDesignChanged, layoutManager, &QmitkMultiWidgetLayoutManager::SetLayoutDesign); connect(this, &QmitkStdMultiWidget::NotifyCrosshairVisibilityChanged, renderWindow3, &QmitkRenderWindow::UpdateCrosshairVisibility); connect(this, &QmitkStdMultiWidget::NotifyCrosshairRotationModeChanged, renderWindow3, &QmitkRenderWindow::UpdateCrosshairRotationMode); connect(renderWindow4, &QmitkRenderWindow::ResetView, this, &QmitkStdMultiWidget::ResetCrosshair); connect(renderWindow4, &QmitkRenderWindow::CrosshairVisibilityChanged, this, &QmitkStdMultiWidget::SetCrosshairVisibility); connect(renderWindow4, &QmitkRenderWindow::CrosshairRotationModeChanged, this, &QmitkStdMultiWidget::SetWidgetPlaneMode); connect(renderWindow4, &QmitkRenderWindow::LayoutDesignChanged, layoutManager, &QmitkMultiWidgetLayoutManager::SetLayoutDesign); connect(this, &QmitkStdMultiWidget::NotifyCrosshairVisibilityChanged, renderWindow4, &QmitkRenderWindow::UpdateCrosshairVisibility); connect(this, &QmitkStdMultiWidget::NotifyCrosshairRotationModeChanged, renderWindow4, &QmitkRenderWindow::UpdateCrosshairRotationMode); } diff --git a/Modules/Segmentation/Interactions/mitkSegmentationInteractionEvents.h b/Modules/Segmentation/Interactions/mitkSegmentationInteractionEvents.h deleted file mode 100644 index 61a124b0c6..0000000000 --- a/Modules/Segmentation/Interactions/mitkSegmentationInteractionEvents.h +++ /dev/null @@ -1,65 +0,0 @@ -/*============================================================================ - -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 mitkSegmentationInteractionEvents_h -#define mitkSegmentationInteractionEvents_h - -#include - -// mitk core -#include "mitkInteractionEvent.h" - -// itk -#include - -namespace mitk -{ - class MITKSEGMENTATION_EXPORT SegmentationInteractionEvent : public itk::AnyEvent - { - public: - - typedef SegmentationInteractionEvent Self; - typedef itk::AnyEvent Superclass; - - SegmentationInteractionEvent() : m_InteractionEvent(nullptr) {} - SegmentationInteractionEvent(InteractionEvent* interactionEvent, bool enteredRenderWindow) - : m_InteractionEvent(interactionEvent) - , m_EnteredRenderWindow(enteredRenderWindow) - { - } - ~SegmentationInteractionEvent() override {} - const char* GetEventName() const override { return "SegmentationInteractionEvent"; } - bool CheckEvent(const itk::EventObject* e) const override { return dynamic_cast(e) != nullptr; } - itk::EventObject* MakeObject() const override { return new Self(m_InteractionEvent, m_EnteredRenderWindow); } - InteractionEvent* GetInteractionEvent() const { return m_InteractionEvent; } - bool HasEnteredRenderWindow() const { return m_EnteredRenderWindow; } - BaseRenderer* GetSender() const - { - return m_InteractionEvent != nullptr ? m_InteractionEvent->GetSender() : nullptr; - } - SegmentationInteractionEvent(const Self& s) - : Superclass(s) - , m_InteractionEvent(s.GetInteractionEvent()) - , m_EnteredRenderWindow(s.m_EnteredRenderWindow) - { - }; - - private: - - InteractionEvent* m_InteractionEvent; - bool m_EnteredRenderWindow; - void operator=(const Self &); - }; - -} // end namespace - -#endif diff --git a/Modules/Segmentation/Interactions/mitkSegmentationInteractor.cpp b/Modules/Segmentation/Interactions/mitkSegmentationInteractor.cpp deleted file mode 100644 index 5b3c74b5c3..0000000000 --- a/Modules/Segmentation/Interactions/mitkSegmentationInteractor.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/*============================================================================ - -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 "mitkSegmentationInteractor.h" - -#include "mitkInteractionPositionEvent.h" -#include -#include - -// us -#include "usGetModuleContext.h" -#include "usModuleContext.h" - -#include - -mitk::SegmentationInteractor::SegmentationInteractor() -{ - // register the class (itself) as an interaction event observer via micro services - us::ServiceProperties props; - props["name"] = std::string("SegmentationInteractor"); - m_ServiceRegistration = us::GetModuleContext()->RegisterService(this, props); - - auto contextModule = us::GetModuleContext()->GetModule(); - - this->LoadStateMachine("SegmentationInteraction.xml", contextModule); - this->SetEventConfig("SegmentationConfig.xml", contextModule); -} - -mitk::SegmentationInteractor::~SegmentationInteractor() -{ - m_ServiceRegistration.Unregister(); -} - -void mitk::SegmentationInteractor::ConnectActionsAndFunctions() -{ - Superclass::ConnectActionsAndFunctions(); - - // CONNECT_FUNCTION("change_active_label", ChangeActiveLabel); - CONNECT_FUNCTION("EnterRenderWindow", OnEnterRenderWindow); - CONNECT_FUNCTION("LeaveRenderWindow", OnLeaveRenderWindow); -} - -void mitk::SegmentationInteractor::OnEnterRenderWindow(StateMachineAction*, InteractionEvent* interactionEvent) -{ - if (this->IsEnabled()) - { - auto* internalEvent = dynamic_cast(interactionEvent); - if (nullptr == internalEvent) - { - return; - } - - this->InvokeEvent(SegmentationInteractionEvent(interactionEvent, true)); - } -} - -void mitk::SegmentationInteractor::OnLeaveRenderWindow(StateMachineAction*, InteractionEvent* interactionEvent) -{ - if (this->IsEnabled()) - { - auto* internalEvent = dynamic_cast(interactionEvent); - if (nullptr == internalEvent) - { - return; - } - - this->InvokeEvent(SegmentationInteractionEvent(interactionEvent, false)); - } -} diff --git a/Modules/Segmentation/Interactions/mitkSegmentationInteractor.h b/Modules/Segmentation/Interactions/mitkSegmentationInteractor.h deleted file mode 100644 index 6a93a7d63d..0000000000 --- a/Modules/Segmentation/Interactions/mitkSegmentationInteractor.h +++ /dev/null @@ -1,60 +0,0 @@ -/*============================================================================ - -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 mitkSegmentationInteractor_h -#define mitkSegmentationInteractor_h - -#include "MitkSegmentationExports.h" -#include - -namespace mitk -{ - /** - *\class SegmentationInteractor - *@brief Observer that adds interaction with a multi-label segmentation session to the default display interaction. - * - * At the moment, this includes changing the active label. - * - * @ingroup Interaction - **/ - - class MITKSEGMENTATION_EXPORT SegmentationInteractor : public DisplayActionEventBroadcast - { - public: - - mitkClassMacro(SegmentationInteractor, DisplayActionEventBroadcast); - itkNewMacro(Self); - - protected: - - SegmentationInteractor(); - ~SegmentationInteractor() override; - - /** - * Derived function. - * Connects the action names used in the state machine pattern with functions implemented within - * this InteractionEventObserver. This is only necessary here because the events are processed by the state machine. - */ - void ConnectActionsAndFunctions() override; - - private: - /** - * @brief Reference to the service registration of the observer. - * This is needed to unregister the observer on unload. - */ - us::ServiceRegistration m_ServiceRegistration; - - void OnEnterRenderWindow(StateMachineAction*, InteractionEvent* interactionEvent); - void OnLeaveRenderWindow(StateMachineAction*, InteractionEvent* interactionEvent); - }; -} -#endif diff --git a/Modules/Segmentation/files.cmake b/Modules/Segmentation/files.cmake index 4520f0edc0..c00c78c696 100644 --- a/Modules/Segmentation/files.cmake +++ b/Modules/Segmentation/files.cmake @@ -1,117 +1,116 @@ set(CPP_FILES Algorithms/mitkCalculateSegmentationVolume.cpp Algorithms/mitkContourModelSetToImageFilter.cpp Algorithms/mitkContourSetToPointSetFilter.cpp Algorithms/mitkContourUtils.cpp Algorithms/mitkCorrectorAlgorithm.cpp Algorithms/mitkDiffImageApplier.cpp Algorithms/mitkDiffSliceOperation.cpp Algorithms/mitkDiffSliceOperationApplier.cpp Algorithms/mitkFeatureBasedEdgeDetectionFilter.cpp Algorithms/mitkGrowCutSegmentationFilter.cpp Algorithms/mitkImageLiveWireContourModelFilter.cpp Algorithms/mitkImageToContourFilter.cpp #Algorithms/mitkImageToContourModelFilter.cpp Algorithms/mitkImageToLiveWireContourFilter.cpp Algorithms/mitkManualSegmentationToSurfaceFilter.cpp Algorithms/mitkOtsuSegmentationFilter.cpp Algorithms/mitkSegmentationHelper.cpp Algorithms/mitkSegmentationObjectFactory.cpp Algorithms/mitkShapeBasedInterpolationAlgorithm.cpp Algorithms/mitkShowSegmentationAsSmoothedSurface.cpp Algorithms/mitkShowSegmentationAsSurface.cpp Algorithms/mitkVtkImageOverwrite.cpp Controllers/mitkSegmentationInterpolationController.cpp Controllers/mitkToolManager.cpp Controllers/mitkSegmentationModuleActivator.cpp Controllers/mitkToolManagerProvider.cpp DataManagement/mitkContour.cpp DataManagement/mitkContourSet.cpp DataManagement/mitkExtrudedContour.cpp Interactions/mitkAddContourTool.cpp Interactions/mitkAutoCropTool.cpp Interactions/mitkSegWithPreviewTool.cpp Interactions/mitkBinaryThresholdBaseTool.cpp Interactions/mitkBinaryThresholdTool.cpp Interactions/mitkBinaryThresholdULTool.cpp Interactions/mitkCloseRegionTool.cpp Interactions/mitkContourModelInteractor.cpp Interactions/mitkContourModelLiveWireInteractor.cpp Interactions/mitkEditableContourTool.cpp Interactions/mitkLiveWireTool2D.cpp Interactions/mitkLassoTool.cpp Interactions/mitkContourTool.cpp Interactions/mitkDrawPaintbrushTool.cpp Interactions/mitkErasePaintbrushTool.cpp Interactions/mitkEraseRegionTool.cpp Interactions/mitkFeedbackContourTool.cpp Interactions/mitkFillRegionBaseTool.cpp Interactions/mitkFillRegionTool.cpp Interactions/mitkGrowCutTool.cpp Interactions/mitkOtsuTool3D.cpp Interactions/mitkPaintbrushTool.cpp Interactions/mitkRegionGrowingTool.cpp Interactions/mitkSegmentationsProcessingTool.cpp Interactions/mitkSegTool2D.cpp Interactions/mitkSubtractContourTool.cpp Interactions/mitkTool.cpp Interactions/mitkToolCommand.cpp Interactions/mitkPickingTool.cpp Interactions/mitknnUnetTool.cpp - Interactions/mitkSegmentationInteractor.cpp #SO Interactions/mitkProcessExecutor.cpp Rendering/mitkContourMapper2D.cpp Rendering/mitkContourSetMapper2D.cpp Rendering/mitkContourSetVtkMapper3D.cpp Rendering/mitkContourVtkMapper3D.cpp SegmentationUtilities/BooleanOperations/mitkBooleanOperation.cpp SegmentationUtilities/MorphologicalOperations/mitkMorphologicalOperations.cpp #Added from ML Controllers/mitkSliceBasedInterpolationController.cpp Algorithms/mitkSurfaceStampImageFilter.cpp ) set(RESOURCE_FILES Add.svg Add_Cursor.svg AI.svg AI_Cursor.svg Close.svg Close_Cursor.svg Erase.svg Erase_Cursor.svg Fill.svg Fill_Cursor.svg LiveWire.svg LiveWire_Cursor.svg Lasso.svg GrowCut.svg Lasso_Cursor.svg Otsu.svg Paint.svg Paint_Cursor.svg Picking.svg RegionGrowing.svg RegionGrowing_Cursor.svg Subtract.svg Subtract_Cursor.svg Threshold.svg ULThreshold.svg Wipe.svg Wipe_Cursor.svg Interactions/dummy.xml Interactions/EditableContourTool.xml Interactions/PickingTool.xml Interactions/MouseReleaseOnly.xml Interactions/PressMoveRelease.xml Interactions/PressMoveReleaseAndPointSetting.xml Interactions/PressMoveReleaseWithCTRLInversion.xml Interactions/PressMoveReleaseWithCTRLInversionAllMouseMoves.xml Interactions/SegmentationConfig.xml Interactions/SegmentationInteraction.xml Interactions/SegmentationToolsConfig.xml Interactions/ContourModelModificationConfig.xml Interactions/ContourModelModificationInteractor.xml ) diff --git a/Plugins/org.mitk.gui.common/src/mitkIRenderWindowPart.h b/Plugins/org.mitk.gui.common/src/mitkIRenderWindowPart.h index 8efd623a67..f8726b2183 100644 --- a/Plugins/org.mitk.gui.common/src/mitkIRenderWindowPart.h +++ b/Plugins/org.mitk.gui.common/src/mitkIRenderWindowPart.h @@ -1,218 +1,230 @@ /*============================================================================ 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 mitkIRenderWindowPart_h #define mitkIRenderWindowPart_h #include #include #include #include #include #include #include #include class QmitkRenderWindow; namespace mitk { struct IRenderingManager; class SliceNavigationController; /** * \ingroup org_mitk_gui_common * * \brief Interface for a MITK Workbench Part providing a render window. * * This interface allows generic access to Workbench parts which provide some * kind of render window. The interface is intended to be implemented by * subclasses of berry::IWorkbenchPart. Usually, the interface is implemented * by a Workbench editor. * * A IRenderWindowPart provides zero or more QmitkRenderWindow instances which can * be controlled via this interface. QmitkRenderWindow instances have an associated * \e id, which is implementation specific. * Additionally the defined values Axial, Sagittal, Coronal and Original from mitk::AnatomicalPlane * can be used to retrieve a specific QmitkRenderWindow. * * \see ILinkedRenderWindowPart * \see IRenderWindowPartListener * \see QmitkAbstractRenderEditor */ struct MITK_GUI_COMMON_PLUGIN IRenderWindowPart { static const QString DECORATION_BORDER; // = "border" static const QString DECORATION_LOGO; // = "logo" static const QString DECORATION_MENU; // = "menu" static const QString DECORATION_BACKGROUND; // = "background" static const QString DECORATION_CORNER_ANNOTATION; // = "corner annotation" virtual ~IRenderWindowPart(); /** * Get the currently active (focused) render window. * Focus handling is implementation specific. * * \return The active QmitkRenderWindow instance; nullptr * if no render window is active. */ virtual QmitkRenderWindow* GetActiveQmitkRenderWindow() const = 0; /** * Get all render windows with their ids. * * \return A hash map mapping the render window id to the QmitkRenderWindow instance. */ virtual QHash GetQmitkRenderWindows() const = 0; /** * Get a render window with a specific id. * * \param id The render window id. * \return The QmitkRenderWindow instance for id */ virtual QmitkRenderWindow* GetQmitkRenderWindow(const QString& id) const = 0; /** * Get a render window with a specific plane orientation. * * \param orientation The render window plane orientation. * \return The QmitkRenderWindow instance for orientation */ virtual QmitkRenderWindow* GetQmitkRenderWindow(const mitk::AnatomicalPlane& orientation) const = 0; /** * Get the rendering manager used by this render window part. * * \return The current IRenderingManager instance or nullptr * if no rendering manager is used. */ virtual mitk::IRenderingManager* GetRenderingManager() const = 0; /** * Request an update of all render windows. * * \param requestType Specifies the type of render windows for which an update * will be requested. */ virtual void RequestUpdate(mitk::RenderingManager::RequestType requestType = mitk::RenderingManager::REQUEST_UPDATE_ALL) = 0; /** * Force an immediate update of all render windows. * * \param requestType Specifies the type of render windows for which an immediate update * will be requested. */ virtual void ForceImmediateUpdate(mitk::RenderingManager::RequestType requestType = mitk::RenderingManager::REQUEST_UPDATE_ALL) = 0; /** - * @brief Set the reference geometry for interaction inside the render windows of the render window part. - * - * @param referenceGeometry The reference geometry which is used for updating the - * time geometry inside the render windows. - * @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. + * @brief Initialize the render windows of this render window part to the given geometry. + * + * @param geometry The geometry to be used to initialize / update a + * 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. */ - virtual void SetReferenceGeometry(const mitk::TimeGeometry* referenceGeometry, bool resetCamera) = 0; + virtual void InitializeViews(const mitk::TimeGeometry* geometry, bool resetCamera) = 0; + + /** + * @brief Define the reference geometry for interaction withing a render window. + * + * The concrete implementation is subclass-specific, no default implementation is provided here. + * An implementation can be found in 'QmitkAbstractMultiWidgetEditor' and will just + * forward the argument to the contained multi widget. + * + * @param referenceGeometry The interaction reference geometry for the concrete multi widget. + * For more details, see 'BaseRenderer::SetInteractionReferenceGeometry'. + */ + virtual void SetInteractionReferenceGeometry(const mitk::TimeGeometry* referenceGeometry) = 0; /** * @brief Returns true if the render windows are coupled; false if not. * * Render windows are coupled if the slice navigation controller of the render windows * are connected which means that always the same geometry is used for the render windows. */ virtual bool HasCoupledRenderWindows() const = 0; /** * Get the SliceNavigationController for controlling time positions. * * \return A SliceNavigationController if the render window supports this * operation; otherwise returns nullptr. */ virtual mitk::SliceNavigationController* GetTimeNavigationController() const = 0; /** * Get the selected position in the render window with id id * or in the active render window if id is an empty string. * * \param id The render window id. * \return The currently selected position in world coordinates. */ virtual mitk::Point3D GetSelectedPosition(const QString& id = QString()) const = 0; /** * Set the selected position in the render window with id id * or in the active render window if id is nullptr. * * \param pos The position in world coordinates which should be selected. * \param id The render window id in which the selection should take place. */ virtual void SetSelectedPosition(const mitk::Point3D& pos, const QString& id = QString()) = 0; /** * Get the time point selected in the render window with id id * or in the active render window if id is an empty string. * * \param id The render window id. * \return The currently selected position in world coordinates. */ virtual TimePointType GetSelectedTimePoint(const QString& id = QString()) const = 0; /** * Enable \e decorations like colored borders, menu widgets, logos, text annotations, etc. * * Decorations are implementation specific. A set of standardized decoration names is listed * in GetDecorations(). * * \param enable If true enable the decorations specified in decorations, * otherwise disable them. * \param decorations A list of decoration names. If empty, all supported decorations are affected. * * \see GetDecorations() */ virtual void EnableDecorations(bool enable, const QStringList& decorations = QStringList()) = 0; /** * Return if a specific decoration is enabled. * * \return true if the decoration is enabled, false if it is disabled * or unknown. * * \see GetDecorations() */ virtual bool IsDecorationEnabled(const QString& decoration) const = 0; /** * Get a list of supported decorations. * * The following decoration names are standardized and should not be used for other decoration types: *
    *
  • \e DECORATION_BORDER Any border decorations like colored rectangles, etc. *
  • \e DECORATION_MENU Menus associated with render windows *
  • \e DECORATION_BACKGROUND All kinds of backgrounds (patterns, gradients, etc.) except for solid colored backgrounds *
  • \e DECORATION_LOGO Any kind of logo overlayed on the rendered scene *
* * \return A list of supported decoration names. */ virtual QStringList GetDecorations() const = 0; }; } Q_DECLARE_INTERFACE(mitk::IRenderWindowPart, "org.mitk.ui.IRenderWindowPart") #endif diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractMultiWidgetEditor.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractMultiWidgetEditor.cpp index 916ffd34a6..9a3ff2d024 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractMultiWidgetEditor.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractMultiWidgetEditor.cpp @@ -1,241 +1,252 @@ /*============================================================================ 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 "QmitkAbstractMultiWidgetEditor.h" // mitk qt widgets module #include #include // mitk gui qt common plugin #include "QmitkMultiWidgetDecorationManager.h" // berry #include const QString QmitkAbstractMultiWidgetEditor::EDITOR_ID = "org.mitk.editors.abstractmultiwidget"; struct QmitkAbstractMultiWidgetEditor::Impl final { Impl(); ~Impl() = default; QmitkAbstractMultiWidget* m_MultiWidget; std::unique_ptr m_MultiWidgetDecorationManager; }; QmitkAbstractMultiWidgetEditor::Impl::Impl() : m_MultiWidget(nullptr) { // nothing here } QmitkAbstractMultiWidgetEditor::QmitkAbstractMultiWidgetEditor() : m_Impl(std::make_unique()) { // nothing here } QmitkAbstractMultiWidgetEditor::~QmitkAbstractMultiWidgetEditor() {} QmitkRenderWindow* QmitkAbstractMultiWidgetEditor::GetActiveQmitkRenderWindow() const { const auto& multiWidget = GetMultiWidget(); if (nullptr != multiWidget) { auto activeRenderWindowWidget = multiWidget->GetActiveRenderWindowWidget(); if (nullptr != activeRenderWindowWidget) { return activeRenderWindowWidget->GetRenderWindow(); } } return nullptr; } QHash QmitkAbstractMultiWidgetEditor::GetQmitkRenderWindows() const { QHash result; const auto& multiWidget = GetMultiWidget(); if (nullptr == multiWidget) { return result; } result = multiWidget->GetRenderWindows(); return result; } QmitkRenderWindow* QmitkAbstractMultiWidgetEditor::GetQmitkRenderWindow(const QString& id) const { const auto& multiWidget = GetMultiWidget(); if (nullptr == multiWidget) { return nullptr; } return multiWidget->GetRenderWindow(id); } QmitkRenderWindow* QmitkAbstractMultiWidgetEditor::GetQmitkRenderWindow(const mitk::AnatomicalPlane& orientation) const { const auto& multiWidget = GetMultiWidget(); if (nullptr == multiWidget) { return nullptr; } return multiWidget->GetRenderWindow(orientation); } -void QmitkAbstractMultiWidgetEditor::SetReferenceGeometry(const mitk::TimeGeometry* referenceGeometry, bool resetCamera) +void QmitkAbstractMultiWidgetEditor::InitializeViews(const mitk::TimeGeometry* geometry, bool resetCamera) { - const auto& multiWidget = GetMultiWidget(); + const auto& multiWidget = this->GetMultiWidget(); + if (nullptr == multiWidget) + { + return; + } + + multiWidget->InitializeViews(geometry, resetCamera); +} + +void QmitkAbstractMultiWidgetEditor::SetInteractionReferenceGeometry(const mitk::TimeGeometry* referenceGeometry) +{ + const auto& multiWidget = this->GetMultiWidget(); if (nullptr == multiWidget) { return; } - multiWidget->SetReferenceGeometry(referenceGeometry, resetCamera); + multiWidget->SetInteractionReferenceGeometry(referenceGeometry); } bool QmitkAbstractMultiWidgetEditor::HasCoupledRenderWindows() const { const auto& multiWidget = GetMultiWidget(); if (nullptr == multiWidget) { return false; } return multiWidget->HasCoupledRenderWindows(); } mitk::Point3D QmitkAbstractMultiWidgetEditor::GetSelectedPosition(const QString& id/* = QString()*/) const { const auto& multiWidget = GetMultiWidget(); if (nullptr == multiWidget) { return mitk::Point3D(); } return multiWidget->GetSelectedPosition(id); } void QmitkAbstractMultiWidgetEditor::SetSelectedPosition(const mitk::Point3D& pos, const QString& id/* = QString()*/) { const auto& multiWidget = GetMultiWidget(); if (nullptr != multiWidget) { return multiWidget->SetSelectedPosition(pos, id); } } void QmitkAbstractMultiWidgetEditor::EnableDecorations(bool enable, const QStringList& decorations) { m_Impl->m_MultiWidgetDecorationManager->ShowDecorations(enable, decorations); } bool QmitkAbstractMultiWidgetEditor::IsDecorationEnabled(const QString& decoration) const { return m_Impl->m_MultiWidgetDecorationManager->IsDecorationVisible(decoration); } QStringList QmitkAbstractMultiWidgetEditor::GetDecorations() const { return m_Impl->m_MultiWidgetDecorationManager->GetDecorations(); } QmitkRenderWindow* QmitkAbstractMultiWidgetEditor::GetQmitkRenderWindowByIndex(int index) const { const auto& multiWidget = GetMultiWidget(); if (nullptr == multiWidget) { return nullptr; } QString renderWindowName = multiWidget->GetNameFromIndex(index); return multiWidget->GetRenderWindow(renderWindowName); } QmitkRenderWindow* QmitkAbstractMultiWidgetEditor::GetQmitkRenderWindowByIndex(int row, int column) const { const auto& multiWidget = GetMultiWidget(); if (nullptr == multiWidget) { return nullptr; } QString renderWindowName = multiWidget->GetNameFromIndex(row, column); return multiWidget->GetRenderWindow(renderWindowName); } void QmitkAbstractMultiWidgetEditor::SetMultiWidget(QmitkAbstractMultiWidget* multiWidget) { m_Impl->m_MultiWidget = multiWidget; m_Impl->m_MultiWidgetDecorationManager.reset(new QmitkMultiWidgetDecorationManager(multiWidget)); } QmitkAbstractMultiWidget* QmitkAbstractMultiWidgetEditor::GetMultiWidget() const { return m_Impl->m_MultiWidget; } int QmitkAbstractMultiWidgetEditor::GetRowCount() const { const auto& multiWidget = GetMultiWidget(); if (nullptr == multiWidget) { return 0; } return multiWidget->GetRowCount(); } int QmitkAbstractMultiWidgetEditor::GetColumnCount() const { const auto& multiWidget = GetMultiWidget(); if (nullptr == multiWidget) { return 0; } return multiWidget->GetColumnCount(); } void QmitkAbstractMultiWidgetEditor::OnLayoutSet(int row, int column) { const auto& multiWidget = GetMultiWidget(); if (nullptr != multiWidget) { multiWidget->SetLayout(row, column); FirePropertyChange(berry::IWorkbenchPartConstants::PROP_INPUT); } } void QmitkAbstractMultiWidgetEditor::OnSynchronize(bool synchronized) { const auto& multiWidget = GetMultiWidget(); if (nullptr != multiWidget) { multiWidget->Synchronize(synchronized); } } void QmitkAbstractMultiWidgetEditor::OnInteractionSchemeChanged(mitk::InteractionSchemeSwitcher::InteractionScheme scheme) { const auto& multiWidget = GetMultiWidget(); if (nullptr != multiWidget) { multiWidget->SetInteractionScheme(scheme); } } diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractMultiWidgetEditor.h b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractMultiWidgetEditor.h index 02fa08054f..4485beaf66 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractMultiWidgetEditor.h +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractMultiWidgetEditor.h @@ -1,135 +1,139 @@ /*============================================================================ 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 QmitkAbstractMultiWidgetEditor_h #define QmitkAbstractMultiWidgetEditor_h #include // org mitk gui qt common plugin #include // mitk core #include // berry #include // c++ #include class QmitkAbstractMultiWidget; class QmitkLevelWindowWidget; class MITK_QT_COMMON QmitkAbstractMultiWidgetEditor : public QmitkAbstractRenderEditor, public berry::IPartListener { Q_OBJECT public: berryObjectMacro(QmitkAbstractMultiWidgetEditor, QmitkAbstractRenderEditor, IPartListener); static const QString EDITOR_ID; QmitkAbstractMultiWidgetEditor(); virtual ~QmitkAbstractMultiWidgetEditor() override; /** * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart */ virtual QmitkRenderWindow* GetActiveQmitkRenderWindow() const override; /** * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart */ virtual QHash GetQmitkRenderWindows() const override; /** * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart */ virtual QmitkRenderWindow* GetQmitkRenderWindow(const QString& id) const override; /** * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart */ virtual QmitkRenderWindow* GetQmitkRenderWindow(const mitk::AnatomicalPlane& orientation) const override; /** * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart */ - void SetReferenceGeometry(const mitk::TimeGeometry* referenceGeometry, bool resetCamera) override; + void InitializeViews(const mitk::TimeGeometry* geometry, bool resetCamera) override; + /** + * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart + */ + void SetInteractionReferenceGeometry(const mitk::TimeGeometry* referenceGeometry) override; /** * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart */ bool HasCoupledRenderWindows() const override; /** * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart */ virtual mitk::Point3D GetSelectedPosition(const QString& id = QString()) const override; /** * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart */ virtual void SetSelectedPosition(const mitk::Point3D& pos, const QString& id = QString()) override; /** * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart */ virtual void EnableDecorations(bool enable, const QStringList& decorations = QStringList()) override; /** * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart */ virtual bool IsDecorationEnabled(const QString& decoration) const override; /** * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart */ virtual QStringList GetDecorations() const override; /** * @brief Retrieve a QmitkRenderWindow by its index. */ virtual QmitkRenderWindow* GetQmitkRenderWindowByIndex(int index) const; /** * @brief Retrieve a QmitkRenderWindow by the row and column position. */ virtual QmitkRenderWindow* GetQmitkRenderWindowByIndex(int row, int column) const; /** * @brief Set the current multi widget of this editor. */ virtual void SetMultiWidget(QmitkAbstractMultiWidget* multiWidget); /** * @brief Return the current multi widget of this editor. */ virtual QmitkAbstractMultiWidget* GetMultiWidget() const; /** * @brief Return the number of rows of the underlying multi widget. */ virtual int GetRowCount() const; /** * @brief Return the number of columns of the underlying multi widget. */ virtual int GetColumnCount() const; virtual QmitkLevelWindowWidget* GetLevelWindowWidget() const = 0; public Q_SLOTS: /** * @brief A slot that can be called if the layout has been changed. * This function will call the function 'SetLayout' of the multi widget where * custom behavior can be implemented. * Finally 'FirePropertyChange' is called to inform the workbench about an input change. */ virtual void OnLayoutSet(int row, int column); virtual void OnSynchronize(bool synchronized); virtual void OnInteractionSchemeChanged(mitk::InteractionSchemeSwitcher::InteractionScheme scheme); private: struct Impl; std::unique_ptr m_Impl; }; #endif diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp index ded0670f04..36720dfc03 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp @@ -1,1125 +1,1056 @@ /*============================================================================ 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 "QmitkSegmentationView.h" #include "mitkPluginActivator.h" // blueberry #include // mitk #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include // Qmitk #include #include #include // us #include #include // Qt #include #include #include // vtk #include #include const std::string QmitkSegmentationView::VIEW_ID = "org.mitk.views.segmentation"; QmitkSegmentationView::QmitkSegmentationView() : m_Parent(nullptr) , m_Controls(nullptr) , m_RenderWindowPart(nullptr) , m_ToolManager(nullptr) , m_ReferenceNode(nullptr) , m_WorkingNode(nullptr) , m_DrawOutline(true) , m_SelectionMode(false) , m_MouseCursorSet(false) , m_DefaultLabelNaming(true) , m_SelectionChangeIsAlreadyBeingHandled(false) { auto isImage = mitk::TNodePredicateDataType::New(); auto isDwi = mitk::NodePredicateDataType::New("DiffusionImage"); auto isDti = mitk::NodePredicateDataType::New("TensorImage"); auto isOdf = mitk::NodePredicateDataType::New("OdfImage"); auto isSegment = mitk::NodePredicateDataType::New("Segment"); auto validImages = mitk::NodePredicateOr::New(); validImages->AddPredicate(mitk::NodePredicateAnd::New(isImage, mitk::NodePredicateNot::New(isSegment))); validImages->AddPredicate(isDwi); validImages->AddPredicate(isDti); validImages->AddPredicate(isOdf); m_SegmentationPredicate = mitk::NodePredicateAnd::New(); m_SegmentationPredicate->AddPredicate(mitk::TNodePredicateDataType::New()); m_SegmentationPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); m_SegmentationPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("hidden object"))); m_ReferencePredicate = mitk::NodePredicateAnd::New(); m_ReferencePredicate->AddPredicate(validImages); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(m_SegmentationPredicate)); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("hidden object"))); - - m_SegmentationInteractor = mitk::SegmentationInteractor::New(); - // add observer for the 'SegmentationInteractionEvent' - itk::ReceptorMemberCommand::Pointer geometryNotAlignedCommand = - itk::ReceptorMemberCommand::New(); - geometryNotAlignedCommand->SetCallbackFunction(this, &QmitkSegmentationView::ValidateRendererGeometry); - m_SegmentationInteractor->AddObserver(mitk::SegmentationInteractionEvent(nullptr, true), geometryNotAlignedCommand); - m_SegmentationInteractor->Disable(); } QmitkSegmentationView::~QmitkSegmentationView() { if (nullptr != m_Controls) { this->LooseLabelSetConnection(); // deactivate all tools m_ToolManager->ActivateTool(-1); // removing all observers from working data for (NodeTagMapType::iterator dataIter = m_WorkingDataObserverTags.begin(); dataIter != m_WorkingDataObserverTags.end(); ++dataIter) { (*dataIter).first->GetProperty("visible")->RemoveObserver((*dataIter).second); } m_WorkingDataObserverTags.clear(); // removing all observers from reference data for (NodeTagMapType::iterator dataIter = m_ReferenceDataObserverTags.begin(); dataIter != m_ReferenceDataObserverTags.end(); ++dataIter) { (*dataIter).first->GetProperty("visible")->RemoveObserver((*dataIter).second); } m_ReferenceDataObserverTags.clear(); mitk::RenderingManager::GetInstance()->RemoveObserver(m_RenderingManagerObserverTag); ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); service->RemoveAllPlanePositions(); context->ungetService(ppmRef); m_ToolManager->SetReferenceData(nullptr); m_ToolManager->SetWorkingData(nullptr); } m_ToolManager->ActiveToolChanged -= mitk::MessageDelegate(this, &QmitkSegmentationView::ActiveToolChanged); delete m_Controls; } /**********************************************************************/ /* private Q_SLOTS */ /**********************************************************************/ void QmitkSegmentationView::OnReferenceSelectionChanged(QList) { this->OnAnySelectionChanged(); } void QmitkSegmentationView::OnSegmentationSelectionChanged(QList) { this->OnAnySelectionChanged(); } void QmitkSegmentationView::OnAnySelectionChanged() { // When only a segmentation has been selected and the method is then called by a reference image selection, // the already selected segmentation may not match the geometry predicate of the new reference image anymore. // This will trigger a recursive call of this method further below. While it would be resolved gracefully, we // can spare the extra call with an early-out. The original call of this method will handle the segmentation // selection change afterwards anyway. if (m_SelectionChangeIsAlreadyBeingHandled) return; auto selectedReferenceNode = m_Controls->referenceNodeSelector->GetSelectedNode(); bool referenceNodeChanged = false; m_ToolManager->ActivateTool(-1); if (m_ReferenceNode != selectedReferenceNode) { referenceNodeChanged = true; // Remove visibility observer for the current reference node if (m_ReferenceDataObserverTags.find(m_ReferenceNode) != m_ReferenceDataObserverTags.end()) { m_ReferenceNode->GetProperty("visible")->RemoveObserver(m_ReferenceDataObserverTags[m_ReferenceNode]); m_ReferenceDataObserverTags.erase(m_ReferenceNode); } // Set new reference node m_ReferenceNode = selectedReferenceNode; m_ToolManager->SetReferenceData(m_ReferenceNode); // Prepare for a potential recursive call when changing node predicates of the working node selector m_SelectionChangeIsAlreadyBeingHandled = true; if (m_ReferenceNode.IsNull()) { // Without a reference image, allow all segmentations to be selected m_Controls->workingNodeSelector->SetNodePredicate(m_SegmentationPredicate); m_SelectionChangeIsAlreadyBeingHandled = false; } else { // With a reference image, only allow segmentations that fit the geometry of the reference image to be selected. m_Controls->workingNodeSelector->SetNodePredicate(mitk::NodePredicateAnd::New( mitk::NodePredicateSubGeometry::New(m_ReferenceNode->GetData()->GetGeometry()), m_SegmentationPredicate.GetPointer())); m_SelectionChangeIsAlreadyBeingHandled = false; this->ApplySelectionModeOnReferenceNode(); // Add visibility observer for the new reference node auto command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::ValidateSelectionInput); m_ReferenceDataObserverTags[m_ReferenceNode] = m_ReferenceNode->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command); } } auto selectedWorkingNode = m_Controls->workingNodeSelector->GetSelectedNode(); bool workingNodeChanged = false; if (m_WorkingNode != selectedWorkingNode) { workingNodeChanged = true; // Remove visibility observer for the current working node if (m_WorkingDataObserverTags.find(m_WorkingNode) != m_WorkingDataObserverTags.end()) { m_WorkingNode->GetProperty("visible")->RemoveObserver(m_WorkingDataObserverTags[m_WorkingNode]); m_WorkingDataObserverTags.erase(m_WorkingNode); } // Disconnect from current label set image this->LooseLabelSetConnection(); // Set new working node m_WorkingNode = selectedWorkingNode; m_ToolManager->SetWorkingData(m_WorkingNode); if (m_WorkingNode.IsNotNull()) { this->ApplySelectionModeOnWorkingNode(); // Connect to new label set image this->EstablishLabelSetConnection(); m_Controls->labelSetWidget->ResetAllTableWidgetItems(); // Add visibility observer for the new segmentation node auto command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::ValidateSelectionInput); m_WorkingDataObserverTags[m_WorkingNode] = m_WorkingNode->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command); } } // Reset camera if any selection changed but only if both reference node and working node are set if ((referenceNodeChanged || workingNodeChanged) && (m_ReferenceNode.IsNotNull() && m_WorkingNode.IsNotNull())) { if (nullptr != m_RenderWindowPart) { - m_RenderWindowPart->SetReferenceGeometry(m_ReferenceNode->GetData()->GetTimeGeometry(), false); + m_RenderWindowPart->InitializeViews(m_ReferenceNode->GetData()->GetTimeGeometry(), false); } } this->UpdateGUI(); } void QmitkSegmentationView::OnVisibilityShortcutActivated() { if (m_WorkingNode.IsNull()) { return; } bool isVisible = false; m_WorkingNode->GetBoolProperty("visible", isVisible); m_WorkingNode->SetVisibility(!isVisible); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSegmentationView::OnLabelToggleShortcutActivated() { if (m_WorkingNode.IsNull()) { return; } auto workingImage = dynamic_cast(m_WorkingNode->GetData()); if (nullptr == workingImage) { return; } this->WaitCursorOn(); workingImage->GetActiveLabelSet()->SetNextActiveLabel(); workingImage->Modified(); this->WaitCursorOff(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSegmentationView::OnNewSegmentation() { m_ToolManager->ActivateTool(-1); if (m_ReferenceNode.IsNull()) { MITK_ERROR << "'Create new segmentation' button should never be clickable unless a reference image is selected."; return; } mitk::Image::ConstPointer referenceImage = dynamic_cast(m_ReferenceNode->GetData()); if (referenceImage.IsNull()) { QMessageBox::information( m_Parent, "New segmentation", "Please load and select an image before starting some action."); return; } if (referenceImage->GetDimension() <= 1) { QMessageBox::information( m_Parent, "New segmentation", "Segmentation is currently not supported for 2D images"); return; } auto segTemplateImage = referenceImage; if (referenceImage->GetDimension() > 3) { QmitkStaticDynamicSegmentationDialog dialog(m_Parent); dialog.SetReferenceImage(referenceImage.GetPointer()); dialog.exec(); segTemplateImage = dialog.GetSegmentationTemplate(); } mitk::DataNode::Pointer newSegmentationNode; try { this->WaitCursorOn(); newSegmentationNode = mitk::LabelSetImageHelper::CreateNewSegmentationNode(m_ReferenceNode, segTemplateImage); this->WaitCursorOff(); } catch (mitk::Exception& e) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::warning(m_Parent, "New segmentation", "Could not create a new segmentation."); return; } auto newLabelSetImage = dynamic_cast(newSegmentationNode->GetData()); if (nullptr == newLabelSetImage) { // something went wrong return; } const auto labelSetPreset = this->GetDefaultLabelSetPreset(); if (labelSetPreset.empty() || !mitk::LabelSetIOHelper::LoadLabelSetImagePreset(labelSetPreset, newLabelSetImage)) { auto newLabel = mitk::LabelSetImageHelper::CreateNewLabel(newLabelSetImage); if (!m_DefaultLabelNaming) { QmitkNewSegmentationDialog dialog(m_Parent); dialog.SetName(QString::fromStdString(newLabel->GetName())); dialog.SetColor(newLabel->GetColor()); if (QDialog::Rejected == dialog.exec()) return; auto name = dialog.GetName(); if (!name.isEmpty()) newLabel->SetName(name.toStdString()); newLabel->SetColor(dialog.GetColor()); } newLabelSetImage->GetActiveLabelSet()->AddLabel(newLabel); } if (!this->GetDataStorage()->Exists(newSegmentationNode)) { this->GetDataStorage()->Add(newSegmentationNode, m_ReferenceNode); } if (m_ToolManager->GetWorkingData(0)) { m_ToolManager->GetWorkingData(0)->SetSelected(false); } newSegmentationNode->SetSelected(true); m_Controls->workingNodeSelector->SetCurrentSelectedNode(newSegmentationNode); } std::string QmitkSegmentationView::GetDefaultLabelSetPreset() const { auto labelSetPreset = mitk::BaseApplication::instance().config().getString(mitk::BaseApplication::ARG_SEGMENTATION_LABELSET_PRESET.toStdString(), ""); if (labelSetPreset.empty()) labelSetPreset = m_LabelSetPresetPreference.toStdString(); return labelSetPreset; } void QmitkSegmentationView::OnManualTool2DSelected(int id) { this->ResetMouseCursor(); mitk::StatusBar::GetInstance()->DisplayText(""); if (id >= 0) { std::string text = "Active Tool: \""; text += m_ToolManager->GetToolById(id)->GetName(); text += "\""; mitk::StatusBar::GetInstance()->DisplayText(text.c_str()); us::ModuleResource resource = m_ToolManager->GetToolById(id)->GetCursorIconResource(); this->SetMouseCursor(resource, 0, 0); } } void QmitkSegmentationView::OnShowMarkerNodes(bool state) { mitk::SegTool2D::Pointer manualSegmentationTool; unsigned int numberOfExistingTools = m_ToolManager->GetTools().size(); for (unsigned int i = 0; i < numberOfExistingTools; i++) { manualSegmentationTool = dynamic_cast(m_ToolManager->GetToolById(i)); if (nullptr == manualSegmentationTool) { continue; } manualSegmentationTool->SetShowMarkerNodes(state); } } void QmitkSegmentationView::OnLayersChanged() { this->EstablishLabelSetConnection(); m_Controls->labelSetWidget->ResetAllTableWidgetItems(); } void QmitkSegmentationView::OnShowLabelTable(bool value) { m_Controls->labelSetWidget->setVisible(value); } void QmitkSegmentationView::OnGoToLabel(const mitk::Point3D& pos) { if (m_RenderWindowPart) { m_RenderWindowPart->SetSelectedPosition(pos); } } void QmitkSegmentationView::OnLabelSetWidgetReset() { this->ValidateSelectionInput(); } /**********************************************************************/ /* private */ /**********************************************************************/ void QmitkSegmentationView::CreateQtPartControl(QWidget* parent) { m_Parent = parent; m_Controls = new Ui::QmitkSegmentationViewControls; m_Controls->setupUi(parent); // *------------------------ // * SHORTCUTS // *------------------------ QShortcut* visibilityShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key::Key_H), parent); connect(visibilityShortcut, &QShortcut::activated, this, &QmitkSegmentationView::OnVisibilityShortcutActivated); QShortcut* labelToggleShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key::Key_L, Qt::CTRL | Qt::Key::Key_I), parent); connect(labelToggleShortcut, &QShortcut::activated, this, &QmitkSegmentationView::OnLabelToggleShortcutActivated); // *------------------------ // * DATA SELECTION WIDGETS // *------------------------ m_Controls->referenceNodeSelector->SetDataStorage(GetDataStorage()); m_Controls->referenceNodeSelector->SetNodePredicate(m_ReferencePredicate); m_Controls->referenceNodeSelector->SetInvalidInfo("Select an image"); m_Controls->referenceNodeSelector->SetPopUpTitel("Select an image"); m_Controls->referenceNodeSelector->SetPopUpHint("Select an image that should be used to define the geometry and bounds of the segmentation."); m_Controls->workingNodeSelector->SetDataStorage(GetDataStorage()); m_Controls->workingNodeSelector->SetNodePredicate(m_SegmentationPredicate); m_Controls->workingNodeSelector->SetInvalidInfo("Select a segmentation"); m_Controls->workingNodeSelector->SetPopUpTitel("Select a segmentation"); m_Controls->workingNodeSelector->SetPopUpHint("Select a segmentation that should be modified. Only segmentation with the same geometry and within the bounds of the reference image are selected."); connect(m_Controls->referenceNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkSegmentationView::OnReferenceSelectionChanged); connect(m_Controls->workingNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkSegmentationView::OnSegmentationSelectionChanged); // *------------------------ // * TOOLMANAGER // *------------------------ m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); m_ToolManager->SetDataStorage(*(this->GetDataStorage())); m_ToolManager->InitializeTools(); QString segTools2D = tr("Add Subtract Lasso Fill Erase Close Paint Wipe 'Region Growing' 'Live Wire'"); QString segTools3D = tr("Threshold 'UL Threshold' Otsu 'Region Growing 3D' Picking GrowCut"); #ifdef __linux__ segTools3D.append(" nnUNet"); // plugin not enabled for MacOS / Windows #endif std::regex extSegTool2DRegEx("SegTool2D$"); std::regex extSegTool3DRegEx("SegTool3D$"); auto tools = m_ToolManager->GetTools(); for (const auto &tool : tools) { if (std::regex_search(tool->GetNameOfClass(), extSegTool2DRegEx)) { segTools2D.append(QString(" '%1'").arg(tool->GetName())); } else if (std::regex_search(tool->GetNameOfClass(), extSegTool3DRegEx)) { segTools3D.append(QString(" '%1'").arg(tool->GetName())); } } // setup 2D tools m_Controls->toolSelectionBox2D->SetToolManager(*m_ToolManager); m_Controls->toolSelectionBox2D->SetGenerateAccelerators(true); m_Controls->toolSelectionBox2D->SetToolGUIArea(m_Controls->toolGUIArea2D); m_Controls->toolSelectionBox2D->SetDisplayedToolGroups(segTools2D.toStdString()); m_Controls->toolSelectionBox2D->SetLayoutColumns(3); connect(m_Controls->toolSelectionBox2D, &QmitkToolSelectionBox::ToolSelected, this, &QmitkSegmentationView::OnManualTool2DSelected); // setup 3D Tools m_Controls->toolSelectionBox3D->SetToolManager(*m_ToolManager); m_Controls->toolSelectionBox3D->SetGenerateAccelerators(true); m_Controls->toolSelectionBox3D->SetToolGUIArea(m_Controls->toolGUIArea3D); m_Controls->toolSelectionBox3D->SetDisplayedToolGroups(segTools3D.toStdString()); m_Controls->toolSelectionBox3D->SetLayoutColumns(3); m_Controls->slicesInterpolator->SetDataStorage(this->GetDataStorage()); // create general signal / slot connections connect(m_Controls->newSegmentationButton, &QToolButton::clicked, this, &QmitkSegmentationView::OnNewSegmentation); connect(m_Controls->slicesInterpolator, &QmitkSlicesInterpolator::SignalShowMarkerNodes, this, &QmitkSegmentationView::OnShowMarkerNodes); connect(m_Controls->layersWidget, &QmitkLayersWidget::LayersChanged, this, &QmitkSegmentationView::OnLayersChanged); connect(m_Controls->labelsWidget, &QmitkLabelsWidget::ShowLabelTable, this, &QmitkSegmentationView::OnShowLabelTable); // *------------------------ // * LABELSETWIDGET // *------------------------ connect(m_Controls->labelSetWidget, &QmitkLabelSetWidget::goToLabel, this, &QmitkSegmentationView::OnGoToLabel); connect(m_Controls->labelSetWidget, &QmitkLabelSetWidget::LabelSetWidgetReset, this, &QmitkSegmentationView::OnLabelSetWidgetReset); m_Controls->labelSetWidget->SetDataStorage(this->GetDataStorage()); m_Controls->labelSetWidget->hide(); auto command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::ValidateSelectionInput); m_RenderingManagerObserverTag = mitk::RenderingManager::GetInstance()->AddObserver(mitk::RenderingManagerViewsInitializedEvent(), command); m_RenderWindowPart = this->GetRenderWindowPart(); if (nullptr != m_RenderWindowPart) { this->RenderWindowPartActivated(m_RenderWindowPart); } // Make sure the GUI notices if appropriate data is already present on creation. // Should be done last, if everything else is configured because it triggers the autoselection of data. m_Controls->referenceNodeSelector->SetAutoSelectNewNodes(true); m_Controls->workingNodeSelector->SetAutoSelectNewNodes(true); this->UpdateGUI(); } void QmitkSegmentationView::ActiveToolChanged() { - auto activeTool = m_ToolManager->GetActiveTool(); - if (nullptr == activeTool) - { - // no tool activated, deactivate the segmentation interactor - m_SegmentationInteractor->Disable(); - return; - } - - // activate segmentation interactor to get informed about render window entered / left events - m_SegmentationInteractor->Enable(); -} - -void QmitkSegmentationView::ValidateRendererGeometry(const itk::EventObject& event) -{ - if (!mitk::SegmentationInteractionEvent().CheckEvent(&event)) - { - return; - } - - const auto* segmentationInteractionEvent = - dynamic_cast(&event); - - const mitk::BaseRenderer::Pointer sendingRenderer = segmentationInteractionEvent->GetSender(); - if (nullptr == sendingRenderer) + if (nullptr == m_RenderWindowPart) { return; } - bool entered = segmentationInteractionEvent->HasEnteredRenderWindow(); - if (entered) + mitk::TimeGeometry* interactionReferenceGeometry = nullptr; + auto activeTool = m_ToolManager->GetActiveTool(); + if (nullptr != activeTool && m_ReferenceNode.IsNotNull()) { - // mouse cursor of tool inside render window - // check if tool can be used: reference geometry needs to be aligned with renderer geometry - const auto* referenceDataNode = m_ToolManager->GetReferenceData(0); - if (nullptr != referenceDataNode) + mitk::Image::ConstPointer referenceImage = dynamic_cast(m_ReferenceNode->GetData()); + if (referenceImage.IsNotNull()) { - const auto workingImage = dynamic_cast(referenceDataNode->GetData()); - if (nullptr != workingImage) - { - const mitk::TimeGeometry* workingImageGeometry = workingImage->GetTimeGeometry(); - if (nullptr != workingImageGeometry) - { - bool isGeometryAligned = false; - try - { - isGeometryAligned = - mitk::BaseRendererHelper::IsRendererAlignedWithSegmentation(sendingRenderer, workingImageGeometry); - } - catch (const mitk::Exception& e) - { - MITK_ERROR << "Unable to validate renderer geometry\n" - << "Reason: " << e.GetDescription(); - this->ShowRenderWindowWarning(sendingRenderer, true); - this->UpdateWarningLabel( - tr("Unable to validate renderer geometry. Please see log!")); - return; - } - - if (!isGeometryAligned) - { - this->ShowRenderWindowWarning(sendingRenderer, true); - this->UpdateWarningLabel( - tr("Please perform a reinit on the segmentation image inside the entered Render Window!")); - return; - } - } - } + // tool activated, reference image available: set reference geometry + interactionReferenceGeometry = m_ReferenceNode->GetData()->GetTimeGeometry(); } } - this->ShowRenderWindowWarning(sendingRenderer, false); - this->UpdateWarningLabel(tr("")); -} - -void QmitkSegmentationView::ShowRenderWindowWarning(mitk::BaseRenderer* baseRenderer, bool show) -{ - const auto* rendererName = baseRenderer->GetName(); - auto* renderWindow = m_RenderWindowPart->GetQmitkRenderWindow(rendererName); - renderWindow->ShowOverlayMessage(show); + // set the interaction reference geometry for the render window part (might be nullptr) + m_RenderWindowPart->SetInteractionReferenceGeometry(interactionReferenceGeometry); } void QmitkSegmentationView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { if (m_RenderWindowPart != renderWindowPart) { m_RenderWindowPart = renderWindowPart; } if (nullptr != m_Parent) { m_Parent->setEnabled(true); } if (nullptr == m_Controls) { return; } if (nullptr != m_RenderWindowPart) { // tell the interpolation about tool manager, data storage and render window part QList controllers; controllers.push_back(m_RenderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()); controllers.push_back(m_RenderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()); controllers.push_back(m_RenderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()); m_Controls->slicesInterpolator->Initialize(m_ToolManager, controllers); if (!m_RenderWindowPart->HasCoupledRenderWindows()) { // react if the active tool changed, only if a render window part with decoupled render windows is used m_ToolManager->ActiveToolChanged += mitk::MessageDelegate(this, &QmitkSegmentationView::ActiveToolChanged); } } } void QmitkSegmentationView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* /*renderWindowPart*/) { m_RenderWindowPart = nullptr; if (nullptr != m_Parent) { m_Parent->setEnabled(false); } // remove message-connection to make sure no message is processed if no render window part is available m_ToolManager->ActiveToolChanged -= mitk::MessageDelegate(this, &QmitkSegmentationView::ActiveToolChanged); m_Controls->slicesInterpolator->Uninitialize(); } void QmitkSegmentationView::OnPreferencesChanged(const mitk::IPreferences* prefs) { auto labelSuggestions = mitk::BaseApplication::instance().config().getString(mitk::BaseApplication::ARG_SEGMENTATION_LABEL_SUGGESTIONS.toStdString(), ""); m_DefaultLabelNaming = labelSuggestions.empty() ? prefs->GetBool("default label naming", true) : false; // No default label naming when label suggestions are enforced via command-line argument if (nullptr != m_Controls) { m_Controls->labelsWidget->SetDefaultLabelNaming(m_DefaultLabelNaming); bool slimView = prefs->GetBool("slim view", false); m_Controls->toolSelectionBox2D->SetShowNames(!slimView); m_Controls->toolSelectionBox3D->SetShowNames(!slimView); } m_DrawOutline = prefs->GetBool("draw outline", true); m_SelectionMode = prefs->GetBool("selection mode", false); m_LabelSetPresetPreference = QString::fromStdString(prefs->Get("label set preset", "")); this->ApplyDisplayOptions(); this->ApplySelectionMode(); } void QmitkSegmentationView::NodeAdded(const mitk::DataNode* node) { if (m_SegmentationPredicate->CheckNode(node)) this->ApplyDisplayOptions(const_cast(node)); this->ApplySelectionMode(); } void QmitkSegmentationView::NodeRemoved(const mitk::DataNode* node) { if (!m_SegmentationPredicate->CheckNode(node)) { return; } // remove all possible contour markers of the segmentation mitk::DataStorage::SetOfObjects::ConstPointer allContourMarkers = this->GetDataStorage()->GetDerivations( node, mitk::NodePredicateProperty::New("isContourMarker", mitk::BoolProperty::New(true))); ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); for (mitk::DataStorage::SetOfObjects::ConstIterator it = allContourMarkers->Begin(); it != allContourMarkers->End(); ++it) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t + 1).c_str()) - 1; service->RemovePlanePosition(id); this->GetDataStorage()->Remove(it->Value()); } context->ungetService(ppmRef); service = nullptr; mitk::Image* image = dynamic_cast(node->GetData()); mitk::SurfaceInterpolationController::GetInstance()->RemoveInterpolationSession(image); } void QmitkSegmentationView::EstablishLabelSetConnection() { if (m_WorkingNode.IsNull()) return; auto workingImage = dynamic_cast(m_WorkingNode->GetData()); if (nullptr == workingImage) return; workingImage->GetActiveLabelSet()->AddLabelEvent += mitk::MessageDelegate( m_Controls->labelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->RemoveLabelEvent += mitk::MessageDelegate( m_Controls->labelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->ModifyLabelEvent += mitk::MessageDelegate( m_Controls->labelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->AllLabelsModifiedEvent += mitk::MessageDelegate( m_Controls->labelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->ActiveLabelEvent += mitk::MessageDelegate1(m_Controls->labelSetWidget, &QmitkLabelSetWidget::SelectLabelByPixelValue); workingImage->AfterChangeLayerEvent += mitk::MessageDelegate( this, &QmitkSegmentationView::UpdateGUI); } void QmitkSegmentationView::LooseLabelSetConnection() { if (m_WorkingNode.IsNull()) return; auto workingImage = dynamic_cast(m_WorkingNode->GetData()); if (nullptr == workingImage) return; workingImage->GetActiveLabelSet()->AddLabelEvent -= mitk::MessageDelegate( m_Controls->labelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->RemoveLabelEvent -= mitk::MessageDelegate( m_Controls->labelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->ModifyLabelEvent -= mitk::MessageDelegate( m_Controls->labelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->AllLabelsModifiedEvent -= mitk::MessageDelegate( m_Controls->labelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->ActiveLabelEvent -= mitk::MessageDelegate1(m_Controls->labelSetWidget, &QmitkLabelSetWidget::SelectLabelByPixelValue); workingImage->AfterChangeLayerEvent -= mitk::MessageDelegate( this, &QmitkSegmentationView::UpdateGUI); } void QmitkSegmentationView::ApplyDisplayOptions() { if (nullptr == m_Parent) { return; } if (nullptr == m_Controls) { return; // might happen on initialization (preferences loaded) } mitk::DataStorage::SetOfObjects::ConstPointer allImages = this->GetDataStorage()->GetSubset(m_SegmentationPredicate); for (mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter) { this->ApplyDisplayOptions(*iter); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSegmentationView::ApplyDisplayOptions(mitk::DataNode* node) { if (nullptr == node) { return; } auto labelSetImage = dynamic_cast(node->GetData()); if (nullptr == labelSetImage) { return; } // the outline property can be set in the segmentation preference page node->SetProperty("labelset.contour.active", mitk::BoolProperty::New(m_DrawOutline)); // force render window update to show outline mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSegmentationView::ApplySelectionMode() { if (!m_SelectionMode) return; this->ApplySelectionModeOnReferenceNode(); this->ApplySelectionModeOnWorkingNode(); } void QmitkSegmentationView::ApplySelectionModeOnReferenceNode() { this->ApplySelectionMode(m_ReferenceNode, m_ReferencePredicate); } void QmitkSegmentationView::ApplySelectionModeOnWorkingNode() { this->ApplySelectionMode(m_WorkingNode, m_SegmentationPredicate); } void QmitkSegmentationView::ApplySelectionMode(mitk::DataNode* node, mitk::NodePredicateBase* predicate) { if (!m_SelectionMode || node == nullptr || predicate == nullptr) return; auto nodes = this->GetDataStorage()->GetSubset(predicate); for (auto iter = nodes->begin(); iter != nodes->end(); ++iter) (*iter)->SetVisibility(*iter == node); } void QmitkSegmentationView::OnContourMarkerSelected(const mitk::DataNode* node) { QmitkRenderWindow* selectedRenderWindow = nullptr; auto* renderWindowPart = this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN); auto* axialRenderWindow = renderWindowPart->GetQmitkRenderWindow("axial"); auto* sagittalRenderWindow = renderWindowPart->GetQmitkRenderWindow("sagittal"); auto* coronalRenderWindow = renderWindowPart->GetQmitkRenderWindow("coronal"); auto* threeDRenderWindow = renderWindowPart->GetQmitkRenderWindow("3d"); bool PlanarFigureInitializedWindow = false; // find initialized renderwindow if (node->GetBoolProperty("PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, axialRenderWindow->GetRenderer())) { selectedRenderWindow = axialRenderWindow; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, sagittalRenderWindow->GetRenderer())) { selectedRenderWindow = sagittalRenderWindow; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, coronalRenderWindow->GetRenderer())) { selectedRenderWindow = coronalRenderWindow; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, threeDRenderWindow->GetRenderer())) { selectedRenderWindow = threeDRenderWindow; } // make node visible if (nullptr != selectedRenderWindow) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t + 1).c_str()) - 1; ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); selectedRenderWindow->GetSliceNavigationController()->ExecuteOperation(service->GetPlanePosition(id)); context->ungetService(ppmRef); selectedRenderWindow->GetRenderer()->GetCameraController()->Fit(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkSegmentationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { if (0 == nodes.size()) { return; } std::string markerName = "Position"; unsigned int numberOfNodes = nodes.size(); std::string nodeName = nodes.at(0)->GetName(); if ((numberOfNodes == 1) && (nodeName.find(markerName) == 0)) { this->OnContourMarkerSelected(nodes.at(0)); return; } } void QmitkSegmentationView::ResetMouseCursor() { if (m_MouseCursorSet) { mitk::ApplicationCursor::GetInstance()->PopCursor(); m_MouseCursorSet = false; } } void QmitkSegmentationView::SetMouseCursor(const us::ModuleResource& resource, int hotspotX, int hotspotY) { // Remove previously set mouse cursor if (m_MouseCursorSet) { this->ResetMouseCursor(); } if (resource) { us::ModuleResourceStream cursor(resource, std::ios::binary); mitk::ApplicationCursor::GetInstance()->PushCursor(cursor, hotspotX, hotspotY); m_MouseCursorSet = true; } } void QmitkSegmentationView::UpdateGUI() { mitk::DataNode* referenceNode = m_ToolManager->GetReferenceData(0); bool hasReferenceNode = referenceNode != nullptr; mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); bool hasWorkingNode = workingNode != nullptr; m_Controls->newSegmentationButton->setEnabled(false); if (hasReferenceNode) { m_Controls->newSegmentationButton->setEnabled(true); } if (hasWorkingNode && hasReferenceNode) { int layer = -1; referenceNode->GetIntProperty("layer", layer); workingNode->SetIntProperty("layer", layer + 1); } m_Controls->layersWidget->UpdateGUI(); m_Controls->labelsWidget->UpdateGUI(); this->ValidateSelectionInput(); } void QmitkSegmentationView::ValidateSelectionInput() { auto referenceNode = m_Controls->referenceNodeSelector->GetSelectedNode(); auto workingNode = m_Controls->workingNodeSelector->GetSelectedNode(); bool hasReferenceNode = referenceNode.IsNotNull(); bool hasWorkingNode = workingNode.IsNotNull(); bool hasBothNodes = hasReferenceNode && hasWorkingNode; QString warning; bool toolSelectionBoxesEnabled = hasReferenceNode && hasWorkingNode; unsigned int numberOfLabels = 0; m_Controls->layersWidget->setEnabled(hasWorkingNode); m_Controls->labelsWidget->setEnabled(hasWorkingNode); m_Controls->labelSetWidget->setEnabled(hasWorkingNode); m_Controls->toolSelectionBox2D->setEnabled(hasBothNodes); m_Controls->toolSelectionBox3D->setEnabled(hasBothNodes); m_Controls->slicesInterpolator->setEnabled(false); m_Controls->interpolatorWarningLabel->hide(); if (hasReferenceNode) { if (!referenceNode->IsVisible(nullptr)) { warning += tr("The selected reference image is currently not visible!"); toolSelectionBoxesEnabled = false; } } if (hasWorkingNode) { if (!workingNode->IsVisible(nullptr)) { warning += (!warning.isEmpty() ? "
" : "") + tr("The selected segmentation is currently not visible!"); toolSelectionBoxesEnabled = false; } m_ToolManager->SetReferenceData(referenceNode); m_ToolManager->SetWorkingData(workingNode); m_Controls->layersWidget->setEnabled(true); m_Controls->labelsWidget->setEnabled(true); m_Controls->labelSetWidget->setEnabled(true); m_Controls->toolSelectionBox2D->setEnabled(true); m_Controls->toolSelectionBox3D->setEnabled(true); auto labelSetImage = dynamic_cast(workingNode->GetData()); auto activeLayer = labelSetImage->GetActiveLayer(); numberOfLabels = labelSetImage->GetNumberOfLabels(activeLayer); if (numberOfLabels > 1) m_Controls->slicesInterpolator->setEnabled(true); } toolSelectionBoxesEnabled &= numberOfLabels > 1; // Here we need to check whether the geometry of the selected segmentation image (working image geometry) // is aligned with the geometry of the 3D render window. // It is not allowed to use a geometry different from the working image geometry for segmenting. // We only need to this if the tool selection box would be enabled without this check. if (toolSelectionBoxesEnabled && nullptr != m_RenderWindowPart && m_RenderWindowPart->HasCoupledRenderWindows()) { const mitk::BaseGeometry* workingNodeGeometry = workingNode->GetData()->GetGeometry(); const mitk::BaseGeometry* renderWindowGeometry = m_RenderWindowPart->GetQmitkRenderWindow("3d")->GetSliceNavigationController()->GetCurrentGeometry3D(); if (nullptr != workingNodeGeometry && nullptr != renderWindowGeometry) { if (!mitk::Equal(*workingNodeGeometry->GetBoundingBox(), *renderWindowGeometry->GetBoundingBox(), mitk::eps, true)) { warning += (!warning.isEmpty() ? "
" : "") + tr("Please reinitialize the selected segmentation image!"); toolSelectionBoxesEnabled = false; } } } m_Controls->toolSelectionBox2D->setEnabled(toolSelectionBoxesEnabled); m_Controls->toolSelectionBox3D->setEnabled(toolSelectionBoxesEnabled); this->UpdateWarningLabel(warning); m_ToolManager->SetReferenceData(referenceNode); m_ToolManager->SetWorkingData(workingNode); } void QmitkSegmentationView::UpdateWarningLabel(QString text) { if (text.isEmpty()) { m_Controls->selectionWarningLabel->hide(); } else { m_Controls->selectionWarningLabel->setText("" + text + ""); m_Controls->selectionWarningLabel->show(); } } \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h index 74a4d2249d..c3908f03a4 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h @@ -1,204 +1,188 @@ /*============================================================================ 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 QmitkSegmentationView_h #define QmitkSegmentationView_h #include "ui_QmitkSegmentationViewControls.h" #include #include -#include - /** * @brief The segmentation view provides a set of tool to use different segmentation algorithms. * It provides two selection widgets to load an image node and a segmentation node * on which to perform the segmentation. Creating new segmentation nodes is also possible. * The available segmentation tools are grouped into "2D"- and "3D"-tools. * * Most segmentation tools / algorithms need some kind of user interaction, where the * user is asked to draw something in the image display or set some seed points / start values. * The tools also often provide additional propeties so that a user can modify the * algorithm's behavior. * * This class additionally provides options to work with different layers (create new layers, * switch between layers). * Moreover, a multilabel widget displays all the existing labels of a multilabel segmentation * for the currently active layer. * The multilabel widget allows to control the labels by creatin new one, removing existing ones, * showing / hiding single labels, merging labels, (re-)naming them etc. * * Additionally the view provides an option to create "2D"- and "3D"-interpolations between * neighboring segmentation masks on unsegmented slices. * Interpolation for multilabel segmentations is currently not implemented. */ class QmitkSegmentationView : public QmitkAbstractView, public mitk::IRenderWindowPartListener { Q_OBJECT public: static const std::string VIEW_ID; QmitkSegmentationView(); ~QmitkSegmentationView() override; private Q_SLOTS: // reaction to the selection of a new reference image in the selection widget void OnReferenceSelectionChanged(QList nodes); // reaction to the selection of a new segmentation image in the selection widget void OnSegmentationSelectionChanged(QList nodes); // reaction to the shortcut ("CTRL+H") for toggling the visibility of the working node void OnVisibilityShortcutActivated(); // reaction to the shortcut ("CTRL+L") for iterating over all labels void OnLabelToggleShortcutActivated(); // reaction to the button "New segmentation" void OnNewSegmentation(); void OnManualTool2DSelected(int id); void OnShowMarkerNodes(bool); void OnLayersChanged(); void OnShowLabelTable(bool); void OnGoToLabel(const mitk::Point3D &pos); void OnLabelSetWidgetReset(); private: void CreateQtPartControl(QWidget* parent) override; void SetFocus() override {} /** * @brief Enable or disable the SegmentationInteractor. * * The active tool is retrieved from the tool manager. * If the active tool is valid, the SegmentationInteractor is enabled * to listen to 'SegmentationInteractionEvent's. */ void ActiveToolChanged(); /** * @brief Test whether the geometry of the reference image * fits the world geometry of the respective renderer. * * The respective renderer is retrieved from the given event, which * needs to be a 'SegmentationInteractionEvent'. * This event provides not only the sending base renderer but also a * bool that indicates whether the mouse cursor entered or left the * base renderer. * This information is used to compare the renderer's world geometry * with the oriented time geometry of the current reference image. * If the geometries align, the renderer is not blocked anymore and the * view's warning message is removed. * If the geometries do not align, 'ShowRenderWindowWarning' is called * and a warning message is added to the top of this plugin view. * * @param event The observed mitk::SegmentationInteractionEvent. */ void ValidateRendererGeometry(const itk::EventObject& event); - /** - * @brief Show a warning on the given base renderer. - * - * This function will show the overlay on the QmitkRenderWindow - * corresponding to the given base renderer to indicate that the - * renderer should not be used for interactive image segmentation. - * - * @param baseRenderer The base renderer to "block" - * @param show If true, the overlay widget will be shown. - * If false, the overlay widget will be hid. - */ - void ShowRenderWindowWarning(mitk::BaseRenderer* baseRenderer, bool show); void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) override; void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) override; void OnPreferencesChanged(const mitk::IPreferences* prefs) override; void NodeAdded(const mitk::DataNode* node) override; void NodeRemoved(const mitk::DataNode* node) override; void EstablishLabelSetConnection(); void LooseLabelSetConnection(); void OnAnySelectionChanged(); // make sure all images / segmentations look according to the user preference settings void ApplyDisplayOptions(); // decorates a DataNode according to the user preference settings void ApplyDisplayOptions(mitk::DataNode* node); void ApplySelectionMode(); void ApplySelectionModeOnReferenceNode(); void ApplySelectionModeOnWorkingNode(); void ApplySelectionMode(mitk::DataNode* node, mitk::NodePredicateBase* predicate); // If a contourmarker is selected, the plane in the related widget will be reoriented according to the marker`s geometry void OnContourMarkerSelected(const mitk::DataNode* node); void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &nodes) override; void ResetMouseCursor(); void SetMouseCursor(const us::ModuleResource&, int hotspotX, int hotspotY); void UpdateGUI(); void ValidateSelectionInput(); void UpdateWarningLabel(QString text); std::string GetDefaultLabelSetPreset() const; QWidget* m_Parent; Ui::QmitkSegmentationViewControls* m_Controls; mitk::IRenderWindowPart* m_RenderWindowPart; mitk::ToolManager* m_ToolManager; mitk::DataNode::Pointer m_ReferenceNode; mitk::DataNode::Pointer m_WorkingNode; - mitk::SegmentationInteractor::Pointer m_SegmentationInteractor; - typedef std::map NodeTagMapType; NodeTagMapType m_WorkingDataObserverTags; NodeTagMapType m_ReferenceDataObserverTags; unsigned int m_RenderingManagerObserverTag; mitk::NodePredicateAnd::Pointer m_ReferencePredicate; mitk::NodePredicateAnd::Pointer m_SegmentationPredicate; bool m_DrawOutline; bool m_SelectionMode; bool m_MouseCursorSet; QString m_LabelSetPresetPreference; bool m_DefaultLabelNaming; bool m_SelectionChangeIsAlreadyBeingHandled; }; #endif