diff --git a/Modules/Core/include/mitkSliceNavigationController.h b/Modules/Core/include/mitkSliceNavigationController.h index 93682b25fe..13c4a6aaf4 100644 --- a/Modules/Core/include/mitkSliceNavigationController.h +++ b/Modules/Core/include/mitkSliceNavigationController.h @@ -1,518 +1,518 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef SLICENAVIGATIONCONTROLLER_H_HEADER_INCLUDED_C1C55A2F #define SLICENAVIGATIONCONTROLLER_H_HEADER_INCLUDED_C1C55A2F #include "mitkBaseController.h" #include "mitkMessage.h" #include "mitkRenderingManager.h" #include "mitkTimeGeometry.h" #include #pragma GCC visibility push(default) #include #pragma GCC visibility pop #include "mitkDataStorage.h" #include "mitkRestorePlanePositionOperation.h" #include #include // DEPRECATED #include namespace mitk { #define mitkTimeSlicedGeometryEventMacro(classname, super) \ class MITKCORE_EXPORT DEPRECATED(classname) : public super \ { \ public: \ typedef classname Self; \ typedef super Superclass; \ classname(TimeGeometry *aTimeGeometry, unsigned int aPos) : Superclass(aTimeGeometry, aPos) {} \ virtual ~classname() {} \ virtual const char *GetEventName() const { return #classname; } \ virtual bool CheckEvent(const ::itk::EventObject *e) const { return dynamic_cast(e); } \ virtual ::itk::EventObject *MakeObject() const { return new Self(GetTimeGeometry(), GetPos()); } \ private: \ void operator=(const Self &); \ } #define mitkTimeGeometryEventMacro(classname, super) \ class MITKCORE_EXPORT classname : public super \ { \ public: \ typedef classname Self; \ typedef super Superclass; \ classname(TimeGeometry *aTimeGeometry, unsigned int aPos) : Superclass(aTimeGeometry, aPos) {} \ virtual ~classname() {} \ virtual const char *GetEventName() const { return #classname; } \ virtual bool CheckEvent(const ::itk::EventObject *e) const { return dynamic_cast(e); } \ virtual ::itk::EventObject *MakeObject() const { return new Self(GetTimeGeometry(), GetPos()); } \ private: \ void operator=(const Self &); \ } class PlaneGeometry; class BaseGeometry; class BaseRenderer; /** * \brief Controls the selection of the slice the associated BaseRenderer * will display * * A SliceNavigationController takes a BaseGeometry or a TimeGeometry as input world geometry * (TODO what are the exact requirements?) and generates a TimeGeometry * as output. The TimeGeometry holds a number of SlicedGeometry3Ds and * these in turn hold a series of PlaneGeometries. One of these PlaneGeometries is * selected as world geometry for the BaseRenderers associated to 2D views. * * The SliceNavigationController holds has Steppers (one for the slice, a * second for the time step), which control the selection of a single * PlaneGeometry from the TimeGeometry. SliceNavigationController generates * ITK events to tell observers, like a BaseRenderer, when the selected slice * or timestep changes. * * Example: * \code * // Initialization * sliceCtrl = mitk::SliceNavigationController::New(); * * // Tell the navigator the geometry to be sliced (with geometry a * // BaseGeometry::ConstPointer) * sliceCtrl->SetInputWorldGeometry(geometry.GetPointer()); * * // Tell the navigator in which direction it shall slice the data * sliceCtrl->SetViewDirection(mitk::SliceNavigationController::Axial); * * // Connect one or more BaseRenderer to this navigator, i.e.: events sent * // by the navigator when stepping through the slices (e.g. by * // sliceCtrl->GetSlice()->Next()) will be received by the BaseRenderer * // (in this example only slice-changes, see also ConnectGeometryTimeEvent * // and ConnectGeometryEvents.) * sliceCtrl->ConnectGeometrySliceEvent(renderer.GetPointer()); * * //create a world geometry and send the information to the connected renderer(s) * sliceCtrl->Update(); * \endcode * * * You can connect visible navigators to a SliceNavigationController, e.g., a * QmitkSliderNavigator (for Qt): * * \code * // Create the visible navigator (a slider with a spin-box) * QmitkSliderNavigator* navigator = * new QmitkSliderNavigator(parent, "slidernavigator"); * * // Connect the navigator to the slice-stepper of the * // SliceNavigationController. For initialization (position, mininal and * // maximal values) the values of the SliceNavigationController are used. * // Thus, accessing methods of a navigator is normally not necessary, since * // everything can be set via the (Qt-independent) SliceNavigationController. * // The QmitkStepperAdapter converts the Qt-signals to Qt-independent * // itk-events. * new QmitkStepperAdapter(navigator, sliceCtrl->GetSlice(), "navigatoradaptor"); * \endcode * * If you do not want that all renderwindows are updated when a new slice is * selected, you can use a specific RenderingManager, which updates only those * renderwindows that should be updated. This is sometimes useful when a 3D view * does not need to be updated when the slices in some 2D views are changed. * QmitkSliderNavigator (for Qt): * * \code * // create a specific RenderingManager * mitk::RenderingManager::Pointer myManager = mitk::RenderingManager::New(); * * // tell the RenderingManager to update only renderwindow1 and renderwindow2 * myManager->AddRenderWindow(renderwindow1); * myManager->AddRenderWindow(renderwindow2); * * // tell the SliceNavigationController of renderwindow1 and renderwindow2 * // to use the specific RenderingManager instead of the global one * renderwindow1->GetSliceNavigationController()->SetRenderingManager(myManager); * renderwindow2->GetSliceNavigationController()->SetRenderingManager(myManager); * \endcode * * \todo implement for non-evenly-timed geometry! * \ingroup NavigationControl */ class MITKCORE_EXPORT SliceNavigationController : public BaseController { public: mitkClassMacro(SliceNavigationController, BaseController); // itkFactorylessNewMacro(Self) // mitkNewMacro1Param(Self, const char *); itkNewMacro(Self); // itkCloneMacro(Self) /** * \brief Possible view directions, \a Original will uses * the PlaneGeometry instances in a SlicedGeometry3D provided * as input world geometry (by SetInputWorldGeometry). */ enum ViewDirection { Axial, Sagittal, Frontal, Original }; /** * \brief Set the input world geometry3D out of which the * geometries for slicing will be created. * * Any previous previous set input geometry (3D or Time) will * be ignored in future. */ void SetInputWorldGeometry3D(const mitk::BaseGeometry *geometry); itkGetConstObjectMacro(InputWorldGeometry3D, mitk::BaseGeometry); /** * \brief Set the input world geometry3D out of which the * geometries for slicing will be created. * * Any previous previous set input geometry (3D or Time) will * be ignored in future. * \deprecatedSince{2013_09} Please use TimeGeometry instead of TimeSlicedGeometry. For more information see * http://www.mitk.org/Development/Refactoring%20of%20the%20Geometry%20Classes%20-%20Part%201 */ DEPRECATED(void SetInputWorldGeometry(const mitk::TimeSlicedGeometry *geometry)); /** * \deprecatedSince{2013_09} Please use TimeGeometry instead of TimeSlicedGeometry. For more information see * http://www.mitk.org/Development/Refactoring%20of%20the%20Geometry%20Classes%20-%20Part%201 */ DEPRECATED(TimeSlicedGeometry *GetInputWorldGeometry()); void SetInputWorldTimeGeometry(const mitk::TimeGeometry *geometry); itkGetConstObjectMacro(InputWorldTimeGeometry, mitk::TimeGeometry); /** * \brief Access the created geometry */ itkGetConstObjectMacro(CreatedWorldGeometry, mitk::TimeGeometry); /** * \brief Set the desired view directions * * \sa ViewDirection * \sa Update(ViewDirection viewDirection, bool top = true, * bool frontside = true, bool rotated = false) */ itkSetEnumMacro(ViewDirection, ViewDirection); itkGetEnumMacro(ViewDirection, ViewDirection); /** * \brief Set the default view direction * * This is used to re-initialize the view direction of the SNC to the * default value with SetViewDirectionToDefault() * * \sa ViewDirection * \sa Update(ViewDirection viewDirection, bool top = true, * bool frontside = true, bool rotated = false) */ itkSetEnumMacro(DefaultViewDirection, ViewDirection); itkGetEnumMacro(DefaultViewDirection, ViewDirection); const char *GetViewDirectionAsString() const; virtual void SetViewDirectionToDefault(); /** * \brief Do the actual creation and send it to the connected * observers (renderers) * */ virtual void Update(); /** * \brief Extended version of Update, additionally allowing to * specify the direction/orientation of the created geometry. * */ virtual void Update(ViewDirection viewDirection, bool top = true, bool frontside = true, bool rotated = false); /** * \brief Send the created geometry to the connected * observers (renderers) * * Called by Update(). */ virtual void SendCreatedWorldGeometry(); /** * \brief Tell observers to re-read the currently selected 2D geometry * */ virtual void SendCreatedWorldGeometryUpdate(); /** * \brief Send the currently selected slice to the connected * observers (renderers) * * Called by Update(). */ virtual void SendSlice(); /** * \brief Send the currently selected time to the connected * observers (renderers) * * Called by Update(). */ virtual void SendTime(); /** * \brief Set the RenderingManager to be used * * If \a nullptr, the default RenderingManager will be used. */ itkSetObjectMacro(RenderingManager, RenderingManager); mitk::RenderingManager *GetRenderingManager() const; #pragma GCC visibility push(default) itkEventMacro(UpdateEvent, itk::AnyEvent); #pragma GCC visibility pop class MITKCORE_EXPORT TimeGeometryEvent : public itk::AnyEvent { public: typedef TimeGeometryEvent Self; typedef itk::AnyEvent Superclass; TimeGeometryEvent(TimeGeometry *aTimeGeometry, unsigned int aPos) : m_TimeGeometry(aTimeGeometry), m_Pos(aPos) {} virtual ~TimeGeometryEvent() {} virtual const char *GetEventName() const override { return "TimeGeometryEvent"; } virtual bool CheckEvent(const ::itk::EventObject *e) const override { return dynamic_cast(e); } virtual ::itk::EventObject *MakeObject() const override { return new Self(m_TimeGeometry, m_Pos); } TimeGeometry *GetTimeGeometry() const { return m_TimeGeometry; } unsigned int GetPos() const { return m_Pos; } private: TimeGeometry::Pointer m_TimeGeometry; unsigned int m_Pos; // TimeGeometryEvent(const Self&); void operator=(const Self &); // just hide }; /** * \deprecatedSince{2013_09} Please use TimeGeometryEvent instead: For additional information see * http://www.mitk.org/Development/Refactoring%20of%20the%20Geometry%20Classes%20-%20Part%201 */ DEPRECATED(typedef TimeGeometryEvent TimeSlicedGeometryEvent); mitkTimeGeometryEventMacro(GeometrySendEvent, TimeGeometryEvent); mitkTimeGeometryEventMacro(GeometryUpdateEvent, TimeGeometryEvent); mitkTimeGeometryEventMacro(GeometryTimeEvent, TimeGeometryEvent); mitkTimeGeometryEventMacro(GeometrySliceEvent, TimeGeometryEvent); template void ConnectGeometrySendEvent(T *receiver) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::SetGeometry); unsigned long tag = AddObserver(GeometrySendEvent(nullptr, 0), eventReceptorCommand); m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); } template void ConnectGeometryUpdateEvent(T *receiver) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::UpdateGeometry); unsigned long tag = AddObserver(GeometryUpdateEvent(nullptr, 0), eventReceptorCommand); m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); } template void ConnectGeometrySliceEvent(T *receiver, bool connectSendEvent = true) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::SetGeometrySlice); unsigned long tag = AddObserver(GeometrySliceEvent(nullptr, 0), eventReceptorCommand); m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); if (connectSendEvent) ConnectGeometrySendEvent(receiver); } template void ConnectGeometryTimeEvent(T *receiver, bool connectSendEvent = true) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::SetGeometryTime); unsigned long tag = AddObserver(GeometryTimeEvent(nullptr, 0), eventReceptorCommand); m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); if (connectSendEvent) ConnectGeometrySendEvent(receiver); } template void ConnectGeometryEvents(T *receiver) { // connect sendEvent only once ConnectGeometrySliceEvent(receiver, false); ConnectGeometryTimeEvent(receiver); } // use a templated method to get the right offset when casting to void* template void Disconnect(T *receiver) { auto i = m_ReceiverToObserverTagsMap.find(static_cast(receiver)); if (i == m_ReceiverToObserverTagsMap.end()) return; const std::list &tags = i->second; for (auto tagIter = tags.begin(); tagIter != tags.end(); ++tagIter) { RemoveObserver(*tagIter); } m_ReceiverToObserverTagsMap.erase(i); } - Message<> crosshairPositionEvent; + Message1 SetCrosshairEvent; /** * \brief To connect multiple SliceNavigationController, we can * act as an observer ourselves: implemented interface * \warning not implemented */ virtual void SetGeometry(const itk::EventObject &geometrySliceEvent); /** * \brief To connect multiple SliceNavigationController, we can * act as an observer ourselves: implemented interface */ virtual void SetGeometrySlice(const itk::EventObject &geometrySliceEvent); /** * \brief To connect multiple SliceNavigationController, we can * act as an observer ourselves: implemented interface */ virtual void SetGeometryTime(const itk::EventObject &geometryTimeEvent); /** \brief Positions the SNC according to the specified point */ void SelectSliceByPoint(const mitk::Point3D &point); /** \brief Returns the TimeGeometry created by the SNC. */ mitk::TimeGeometry *GetCreatedWorldGeometry(); /** \brief Returns the BaseGeometry of the currently selected time step. */ const mitk::BaseGeometry *GetCurrentGeometry3D(); /** \brief Returns the currently selected Plane in the current * BaseGeometry (if existent). */ const mitk::PlaneGeometry *GetCurrentPlaneGeometry(); /** \brief Sets the BaseRenderer associated with this SNC (if any). While * the BaseRenderer is not directly used by SNC, this is a convenience * method to enable BaseRenderer access via the SNC. */ void SetRenderer(BaseRenderer *renderer); /** \brief Gets the BaseRenderer associated with this SNC (if any). While * the BaseRenderer is not directly used by SNC, this is a convenience * method to enable BaseRenderer access via the SNC. Returns nullptr if no * BaseRenderer has been specified*/ BaseRenderer *GetRenderer() const; /** \brief Re-orients the slice stack. All slices will be oriented to the given normal vector. The given point (world coordinates) defines the selected slice. Careful: The resulting axis vectors are not clearly defined this way. If you want to define them clearly, use ReorientSlices (const mitk::Point3D &point, const mitk::Vector3D &axisVec0, const mitk::Vector3D &axisVec1). */ void ReorientSlices(const mitk::Point3D &point, const mitk::Vector3D &normal); /** \brief Re-orients the slice stack so that all planes are oriented according to the * given axis vectors. The given Point eventually defines selected slice. */ void ReorientSlices(const mitk::Point3D &point, const mitk::Vector3D &axisVec0, const mitk::Vector3D &axisVec1); void ExecuteOperation(Operation *operation) override; /** * \brief Feature option to lock planes during mouse interaction. * This option flag disables the mouse event which causes the center * cross to move near by. */ itkSetMacro(SliceLocked, bool); itkGetMacro(SliceLocked, bool); itkBooleanMacro(SliceLocked); /** * \brief Feature option to lock slice rotation. * * This option flag disables separately the rotation of a slice which is * implemented in mitkSliceRotator. */ itkSetMacro(SliceRotationLocked, bool); itkGetMacro(SliceRotationLocked, bool); itkBooleanMacro(SliceRotationLocked); /** * \brief Adjusts the numerical range of the slice stepper according to * the current geometry orientation of this SNC's SlicedGeometry. */ void AdjustSliceStepperRange(); protected: SliceNavigationController(); virtual ~SliceNavigationController(); mitk::BaseGeometry::ConstPointer m_InputWorldGeometry3D; mitk::TimeGeometry::ConstPointer m_InputWorldTimeGeometry; mitk::TimeGeometry::Pointer m_CreatedWorldGeometry; ViewDirection m_ViewDirection; ViewDirection m_DefaultViewDirection; mitk::RenderingManager::Pointer m_RenderingManager; mitk::BaseRenderer *m_Renderer; itkSetMacro(Top, bool); itkGetMacro(Top, bool); itkBooleanMacro(Top); itkSetMacro(FrontSide, bool); itkGetMacro(FrontSide, bool); itkBooleanMacro(FrontSide); itkSetMacro(Rotated, bool); itkGetMacro(Rotated, bool); itkBooleanMacro(Rotated); bool m_Top; bool m_FrontSide; bool m_Rotated; bool m_BlockUpdate; bool m_SliceLocked; bool m_SliceRotationLocked; unsigned int m_OldPos; typedef std::map> ObserverTagsMapType; ObserverTagsMapType m_ReceiverToObserverTagsMap; }; } // namespace mitk #endif /* SLICENAVIGATIONCONTROLLER_H_HEADER_INCLUDED_C1C55A2F */ diff --git a/Modules/Core/src/Controllers/mitkSliceNavigationController.cpp b/Modules/Core/src/Controllers/mitkSliceNavigationController.cpp index d3d4d1adcd..d486476efe 100644 --- a/Modules/Core/src/Controllers/mitkSliceNavigationController.cpp +++ b/Modules/Core/src/Controllers/mitkSliceNavigationController.cpp @@ -1,659 +1,661 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkSliceNavigationController.h" #include "mitkAction.h" #include "mitkBaseRenderer.h" #include "mitkCrosshairPositionEvent.h" #include "mitkInteractionConst.h" #include "mitkOperation.h" #include "mitkOperationActor.h" #include "mitkPlaneGeometry.h" #include "mitkProportionalTimeGeometry.h" #include "mitkArbitraryTimeGeometry.h" #include "mitkRenderingManager.h" #include "mitkSlicedGeometry3D.h" #include "mitkVtkPropRenderer.h" #include "mitkImage.h" #include "mitkImagePixelReadAccessor.h" #include "mitkInteractionConst.h" #include "mitkNodePredicateDataType.h" #include "mitkOperationEvent.h" #include "mitkPixelTypeMultiplex.h" #include "mitkPlaneOperation.h" #include "mitkPointOperation.h" #include "mitkStatusBar.h" #include "mitkUndoController.h" #include "mitkApplyTransformMatrixOperation.h" #include "mitkMemoryUtilities.h" #include namespace mitk { SliceNavigationController::SliceNavigationController() : BaseController(), m_InputWorldGeometry3D( mitk::BaseGeometry::ConstPointer() ), m_InputWorldTimeGeometry( mitk::TimeGeometry::ConstPointer() ), m_CreatedWorldGeometry( mitk::TimeGeometry::Pointer() ), m_ViewDirection(Axial), m_DefaultViewDirection(Axial), m_RenderingManager( mitk::RenderingManager::Pointer() ), m_Renderer( nullptr ), m_Top(false), m_FrontSide(false), m_Rotated(false), m_BlockUpdate(false), m_SliceLocked(false), m_SliceRotationLocked(false), m_OldPos(0) { typedef itk::SimpleMemberCommand SNCCommandType; SNCCommandType::Pointer sliceStepperChangedCommand, timeStepperChangedCommand; sliceStepperChangedCommand = SNCCommandType::New(); timeStepperChangedCommand = SNCCommandType::New(); sliceStepperChangedCommand->SetCallbackFunction(this, &SliceNavigationController::SendSlice); timeStepperChangedCommand->SetCallbackFunction(this, &SliceNavigationController::SendTime); m_Slice->AddObserver(itk::ModifiedEvent(), sliceStepperChangedCommand); m_Time->AddObserver(itk::ModifiedEvent(), timeStepperChangedCommand); m_Slice->SetUnitName("mm"); m_Time->SetUnitName("ms"); m_Top = false; m_FrontSide = false; m_Rotated = false; } SliceNavigationController::~SliceNavigationController() {} void SliceNavigationController::SetInputWorldGeometry3D(const BaseGeometry *geometry) { if ( geometry != nullptr ) { if (const_cast(geometry->GetBoundingBox())->GetDiagonalLength2() < eps) { itkWarningMacro("setting an empty bounding-box"); geometry = nullptr; } } if (m_InputWorldGeometry3D != geometry) { m_InputWorldGeometry3D = geometry; m_InputWorldTimeGeometry = mitk::TimeGeometry::ConstPointer(); this->Modified(); } } void SliceNavigationController::SetInputWorldTimeGeometry(const TimeGeometry *geometry) { if ( geometry != nullptr ) { if (const_cast(geometry->GetBoundingBoxInWorld())->GetDiagonalLength2() < eps) { itkWarningMacro("setting an empty bounding-box"); geometry = nullptr; } } if (m_InputWorldTimeGeometry != geometry) { m_InputWorldTimeGeometry = geometry; m_InputWorldGeometry3D = mitk::BaseGeometry::ConstPointer(); this->Modified(); } } RenderingManager *SliceNavigationController::GetRenderingManager() const { mitk::RenderingManager *renderingManager = m_RenderingManager.GetPointer(); if (renderingManager != nullptr) return renderingManager; if ( m_Renderer != nullptr ) { renderingManager = m_Renderer->GetRenderingManager(); if (renderingManager != nullptr) return renderingManager; } return mitk::RenderingManager::GetInstance(); } void SliceNavigationController::SetViewDirectionToDefault() { m_ViewDirection = m_DefaultViewDirection; } const char *SliceNavigationController::GetViewDirectionAsString() const { const char *viewDirectionString; switch (m_ViewDirection) { case SliceNavigationController::Axial: viewDirectionString = "Axial"; break; case SliceNavigationController::Sagittal: viewDirectionString = "Sagittal"; break; case SliceNavigationController::Frontal: viewDirectionString = "Coronal"; break; case SliceNavigationController::Original: viewDirectionString = "Original"; break; default: viewDirectionString = "No View Direction Available"; break; } return viewDirectionString; } void SliceNavigationController::Update() { if (!m_BlockUpdate) { if (m_ViewDirection == Sagittal) { this->Update(Sagittal, true, true, false); } else if (m_ViewDirection == Frontal) { this->Update(Frontal, false, true, false); } else if (m_ViewDirection == Axial) { this->Update(Axial, false, false, true); } else { this->Update(m_ViewDirection); } } } void SliceNavigationController::Update(SliceNavigationController::ViewDirection viewDirection, bool top, bool frontside, bool rotated) { TimeGeometry::ConstPointer worldTimeGeometry = m_InputWorldTimeGeometry; if (m_BlockUpdate || (m_InputWorldTimeGeometry.IsNull() && m_InputWorldGeometry3D.IsNull()) || ((worldTimeGeometry.IsNotNull()) && (worldTimeGeometry->CountTimeSteps() == 0))) { return; } m_BlockUpdate = true; if (m_InputWorldTimeGeometry.IsNotNull() && m_LastUpdateTime < m_InputWorldTimeGeometry->GetMTime()) { Modified(); } if (m_InputWorldGeometry3D.IsNotNull() && m_LastUpdateTime < m_InputWorldGeometry3D->GetMTime()) { Modified(); } this->SetViewDirection(viewDirection); this->SetTop(top); this->SetFrontSide(frontside); this->SetRotated(rotated); if (m_LastUpdateTime < GetMTime()) { m_LastUpdateTime = GetMTime(); // initialize the viewplane SlicedGeometry3D::Pointer slicedWorldGeometry = SlicedGeometry3D::Pointer(); BaseGeometry::ConstPointer currentGeometry = BaseGeometry::ConstPointer(); if (m_InputWorldTimeGeometry.IsNotNull()) if (m_InputWorldTimeGeometry->IsValidTimeStep(GetTime()->GetPos())) currentGeometry = m_InputWorldTimeGeometry->GetGeometryForTimeStep(GetTime()->GetPos()); else currentGeometry = m_InputWorldTimeGeometry->GetGeometryForTimeStep(0); else currentGeometry = m_InputWorldGeometry3D; m_CreatedWorldGeometry = mitk::TimeGeometry::Pointer(); switch (viewDirection) { case Original: if (worldTimeGeometry.IsNotNull()) { m_CreatedWorldGeometry = worldTimeGeometry->Clone(); worldTimeGeometry = m_CreatedWorldGeometry.GetPointer(); slicedWorldGeometry = dynamic_cast( m_CreatedWorldGeometry->GetGeometryForTimeStep(this->GetTime()->GetPos()).GetPointer()); if (slicedWorldGeometry.IsNotNull()) { break; } } else { const auto *worldSlicedGeometry = dynamic_cast(currentGeometry.GetPointer()); if ( worldSlicedGeometry != nullptr ) { slicedWorldGeometry = static_cast(currentGeometry->Clone().GetPointer()); break; } } slicedWorldGeometry = SlicedGeometry3D::New(); slicedWorldGeometry->InitializePlanes(currentGeometry, PlaneGeometry::None, top, frontside, rotated); slicedWorldGeometry->SetSliceNavigationController(this); break; case Axial: slicedWorldGeometry = SlicedGeometry3D::New(); slicedWorldGeometry->InitializePlanes(currentGeometry, PlaneGeometry::Axial, top, frontside, rotated); slicedWorldGeometry->SetSliceNavigationController(this); break; case Frontal: slicedWorldGeometry = SlicedGeometry3D::New(); slicedWorldGeometry->InitializePlanes(currentGeometry, PlaneGeometry::Frontal, top, frontside, rotated); slicedWorldGeometry->SetSliceNavigationController(this); break; case Sagittal: slicedWorldGeometry = SlicedGeometry3D::New(); slicedWorldGeometry->InitializePlanes(currentGeometry, PlaneGeometry::Sagittal, top, frontside, rotated); slicedWorldGeometry->SetSliceNavigationController(this); break; default: itkExceptionMacro("unknown ViewDirection"); } m_Slice->SetPos(0); m_Slice->SetSteps((int)slicedWorldGeometry->GetSlices()); if ( worldTimeGeometry.IsNull() ) { auto createdTimeGeometry = ProportionalTimeGeometry::New(); createdTimeGeometry->Initialize( slicedWorldGeometry, 1 ); m_CreatedWorldGeometry = createdTimeGeometry; m_Time->SetSteps(0); m_Time->SetPos(0); m_Time->InvalidateRange(); } else { m_BlockUpdate = true; m_Time->SetSteps(worldTimeGeometry->CountTimeSteps()); m_Time->SetPos(0); const TimeBounds &timeBounds = worldTimeGeometry->GetTimeBounds(); m_Time->SetRange(timeBounds[0], timeBounds[1]); m_BlockUpdate = false; const auto currentTemporalPosition = this->GetTime()->GetPos(); assert( worldTimeGeometry->GetGeometryForTimeStep( currentTemporalPosition ).IsNotNull() ); if ( dynamic_cast( worldTimeGeometry.GetPointer() ) != nullptr ) { const TimePointType minimumTimePoint = worldTimeGeometry->TimeStepToTimePoint( currentTemporalPosition ); const TimePointType stepDuration = worldTimeGeometry->TimeStepToTimePoint( currentTemporalPosition + 1 ) - minimumTimePoint; auto createdTimeGeometry = ProportionalTimeGeometry::New(); createdTimeGeometry->Initialize( slicedWorldGeometry, worldTimeGeometry->CountTimeSteps() ); createdTimeGeometry->SetFirstTimePoint( minimumTimePoint ); createdTimeGeometry->SetStepDuration( stepDuration ); m_CreatedWorldGeometry = createdTimeGeometry; } else { auto createdTimeGeometry = mitk::ArbitraryTimeGeometry::New(); const TimeStepType numberOfTimeSteps = worldTimeGeometry->CountTimeSteps(); createdTimeGeometry->ReserveSpaceForGeometries( numberOfTimeSteps ); for ( TimeStepType i = 0; i < numberOfTimeSteps; ++i ) { const BaseGeometry::Pointer clonedGeometry = slicedWorldGeometry->Clone().GetPointer(); const auto bounds = worldTimeGeometry->GetTimeBounds( i ); createdTimeGeometry->AppendNewTimeStep( clonedGeometry, bounds[0], bounds[1]); } createdTimeGeometry->Update(); m_CreatedWorldGeometry = createdTimeGeometry; } } } // unblock update; we may do this now, because if m_BlockUpdate was already // true before this method was entered, then we will never come here. m_BlockUpdate = false; // Send the geometry. Do this even if nothing was changed, because maybe // Update() was only called to re-send the old geometry and time/slice data. this->SendCreatedWorldGeometry(); this->SendSlice(); this->SendTime(); // Adjust the stepper range of slice stepper according to geometry this->AdjustSliceStepperRange(); } void SliceNavigationController::SendCreatedWorldGeometry() { // Send the geometry. Do this even if nothing was changed, because maybe // Update() was only called to re-send the old geometry. if (!m_BlockUpdate) { this->InvokeEvent(GeometrySendEvent(m_CreatedWorldGeometry, 0)); } } void SliceNavigationController::SendCreatedWorldGeometryUpdate() { if (!m_BlockUpdate) { this->InvokeEvent(GeometryUpdateEvent(m_CreatedWorldGeometry, m_Slice->GetPos())); } } void SliceNavigationController::SendSlice() { if (!m_BlockUpdate) { if (m_CreatedWorldGeometry.IsNotNull()) { this->InvokeEvent(GeometrySliceEvent(m_CreatedWorldGeometry, m_Slice->GetPos())); // send crosshair event - crosshairPositionEvent.Send(); + //SetCrosshairEvent.Send(); // Request rendering update for all views this->GetRenderingManager()->RequestUpdateAll(); } } } void SliceNavigationController::SendTime() { if (!m_BlockUpdate) { if (m_CreatedWorldGeometry.IsNotNull()) { this->InvokeEvent(GeometryTimeEvent(m_CreatedWorldGeometry, m_Time->GetPos())); // Request rendering update for all views this->GetRenderingManager()->RequestUpdateAll(); } } } void SliceNavigationController::SetGeometry(const itk::EventObject &) {} void SliceNavigationController::SetGeometryTime(const itk::EventObject &geometryTimeEvent) { if (m_CreatedWorldGeometry.IsNull()) { return; } const auto *timeEvent = dynamic_cast< const SliceNavigationController::GeometryTimeEvent * >(&geometryTimeEvent); assert( timeEvent != nullptr ); TimeGeometry *timeGeometry = timeEvent->GetTimeGeometry(); assert( timeGeometry != nullptr ); auto timeStep = (int)timeEvent->GetPos(); ScalarType timeInMS; timeInMS = timeGeometry->TimeStepToTimePoint(timeStep); timeStep = m_CreatedWorldGeometry->TimePointToTimeStep(timeInMS); this->GetTime()->SetPos(timeStep); } void SliceNavigationController::SetGeometrySlice(const itk::EventObject &geometrySliceEvent) { const auto *sliceEvent = dynamic_cast(&geometrySliceEvent); assert(sliceEvent!=nullptr); this->GetSlice()->SetPos(sliceEvent->GetPos()); } void SliceNavigationController::SelectSliceByPoint(const Point3D &point) { if (m_CreatedWorldGeometry.IsNull()) { return; } //@todo add time to PositionEvent and use here!! SlicedGeometry3D *slicedWorldGeometry = dynamic_cast( m_CreatedWorldGeometry->GetGeometryForTimeStep(this->GetTime()->GetPos()).GetPointer()); if (slicedWorldGeometry) { int bestSlice = -1; double bestDistance = itk::NumericTraits::max(); int s, slices; slices = slicedWorldGeometry->GetSlices(); if (slicedWorldGeometry->GetEvenlySpaced()) { mitk::PlaneGeometry *plane = slicedWorldGeometry->GetPlaneGeometry(0); const Vector3D &direction = slicedWorldGeometry->GetDirectionVector(); Point3D projectedPoint; plane->Project(point, projectedPoint); // Check whether the point is somewhere within the slice stack volume; // otherwise, the default slice (0) will be selected if (direction[0] * (point[0] - projectedPoint[0]) + direction[1] * (point[1] - projectedPoint[1]) + direction[2] * (point[2] - projectedPoint[2]) >= 0) { bestSlice = (int)(plane->Distance(point) / slicedWorldGeometry->GetSpacing()[2] + 0.5); } } else { Point3D projectedPoint; for (s = 0; s < slices; ++s) { slicedWorldGeometry->GetPlaneGeometry(s)->Project(point, projectedPoint); const Vector3D distance = projectedPoint - point; ScalarType currentDistance = distance.GetSquaredNorm(); if (currentDistance < bestDistance) { bestDistance = currentDistance; bestSlice = s; } } } if (bestSlice >= 0) { this->GetSlice()->SetPos(bestSlice); } else { this->GetSlice()->SetPos(0); } this->SendCreatedWorldGeometryUpdate(); + // send crosshair event + SetCrosshairEvent.Send(point); } } void SliceNavigationController::ReorientSlices(const Point3D &point, const Vector3D &normal) { if (m_CreatedWorldGeometry.IsNull()) { return; } PlaneOperation op(OpORIENT, point, normal); m_CreatedWorldGeometry->ExecuteOperation(&op); this->SendCreatedWorldGeometryUpdate(); } void SliceNavigationController::ReorientSlices(const mitk::Point3D &point, const mitk::Vector3D &axisVec0, const mitk::Vector3D &axisVec1) { if (m_CreatedWorldGeometry) { PlaneOperation op(OpORIENT, point, axisVec0, axisVec1); m_CreatedWorldGeometry->ExecuteOperation(&op); this->SendCreatedWorldGeometryUpdate(); } } mitk::TimeGeometry *SliceNavigationController::GetCreatedWorldGeometry() { return m_CreatedWorldGeometry; } const mitk::BaseGeometry *SliceNavigationController::GetCurrentGeometry3D() { if (m_CreatedWorldGeometry.IsNotNull()) { return m_CreatedWorldGeometry->GetGeometryForTimeStep(this->GetTime()->GetPos()); } else { return nullptr; } } const mitk::PlaneGeometry *SliceNavigationController::GetCurrentPlaneGeometry() { const auto *slicedGeometry = dynamic_cast(this->GetCurrentGeometry3D()); if (slicedGeometry) { const mitk::PlaneGeometry *planeGeometry = (slicedGeometry->GetPlaneGeometry(this->GetSlice()->GetPos())); return planeGeometry; } else { return nullptr; } } void SliceNavigationController::SetRenderer(BaseRenderer *renderer) { m_Renderer = renderer; } BaseRenderer *SliceNavigationController::GetRenderer() const { return m_Renderer; } void SliceNavigationController::AdjustSliceStepperRange() { const auto *slicedGeometry = dynamic_cast(this->GetCurrentGeometry3D()); const Vector3D &direction = slicedGeometry->GetDirectionVector(); int c = 0; int i, k = 0; for (i = 0; i < 3; ++i) { if (fabs(direction[i]) < 0.000000001) { ++c; } else { k = i; } } if (c == 2) { ScalarType min = slicedGeometry->GetOrigin()[k]; ScalarType max = min + slicedGeometry->GetExtentInMM(k); m_Slice->SetRange(min, max); } else { m_Slice->InvalidateRange(); } } void SliceNavigationController::ExecuteOperation(Operation *operation) { // switch on type // - select best slice for a given point // - rotate created world geometry according to Operation->SomeInfo() if (!operation || m_CreatedWorldGeometry.IsNull()) { return; } switch (operation->GetOperationType()) { case OpMOVE: // should be a point operation { if (!m_SliceLocked) // do not move the cross position { // select a slice auto *po = dynamic_cast(operation); if (po && po->GetIndex() == -1) { this->SelectSliceByPoint(po->GetPoint()); } else if (po && po->GetIndex() != -1) // undo case because index != -1, index holds the old position of this slice { this->GetSlice()->SetPos(po->GetIndex()); } } break; } case OpRESTOREPLANEPOSITION: { m_CreatedWorldGeometry->ExecuteOperation(operation); this->SendCreatedWorldGeometryUpdate(); break; } case OpAPPLYTRANSFORMMATRIX: { m_CreatedWorldGeometry->ExecuteOperation(operation); this->SendCreatedWorldGeometryUpdate(); break; } default: { // do nothing break; } } } } // namespace diff --git a/Modules/Core/src/Interactions/mitkDisplayActionEventFunctions.cpp b/Modules/Core/src/Interactions/mitkDisplayActionEventFunctions.cpp index 3c10673025..71bf9fe76f 100644 --- a/Modules/Core/src/Interactions/mitkDisplayActionEventFunctions.cpp +++ b/Modules/Core/src/Interactions/mitkDisplayActionEventFunctions.cpp @@ -1,337 +1,330 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDisplayActionEventFunctions.h" // mitk core #include "mitkBaseRenderer.h" #include "mitkCameraController.h" #include "mitkDisplayActionEvents.h" #include "mitkInteractionPositionEvent.h" #include "mitkLevelWindow.h" #include "mitkLevelWindowProperty.h" #include "mitkNodePredicateDataType.h" ////////////////////////////////////////////////////////////////////////// // STANDARD FUNCTIONS ////////////////////////////////////////////////////////////////////////// mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::MoveSenderCameraAction() { mitk::StdFunctionCommand::ActionFunction actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplayMoveEvent().CheckEvent(&displayInteractorEvent)) { const DisplayMoveEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); if (nullptr == sendingRenderer) { return; } // concrete action sendingRenderer->GetCameraController()->MoveBy(displayActionEvent->GetMoveVector()); sendingRenderer->GetRenderingManager()->RequestUpdate(sendingRenderer->GetRenderWindow()); } }; return actionFunction; } mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::SetCrosshairAction() { auto actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplaySetCrosshairEvent().CheckEvent(&displayInteractorEvent)) { const DisplaySetCrosshairEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); if (nullptr == sendingRenderer) { return; } // concrete action - auto allRenderWindows = sendingRenderer->GetRenderingManager()->GetAllRegisteredRenderWindows(); - for (auto renderWindow : allRenderWindows) - { - if (BaseRenderer::GetInstance(renderWindow)->GetMapperID() == BaseRenderer::Standard2D && renderWindow != sendingRenderer->GetRenderWindow()) - { - BaseRenderer::GetInstance(renderWindow)->GetSliceNavigationController()->SelectSliceByPoint(displayActionEvent->GetPosition()); - } - } + BaseRenderer::GetInstance(sendingRenderer->GetRenderWindow())->GetSliceNavigationController()->SelectSliceByPoint(displayActionEvent->GetPosition()); } }; return actionFunction; } mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::ZoomSenderCameraAction() { auto actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplayZoomEvent().CheckEvent(&displayInteractorEvent)) { const DisplayZoomEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); if (nullptr == sendingRenderer) { return; } // concrete action if (1.0 != displayActionEvent->GetZoomFactor()) { sendingRenderer->GetCameraController()->Zoom(displayActionEvent->GetZoomFactor(), displayActionEvent->GetStartCoordinate()); sendingRenderer->GetRenderingManager()->RequestUpdate(sendingRenderer->GetRenderWindow()); } } }; return actionFunction; } mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::ScrollSliceStepperAction() { auto actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplayScrollEvent().CheckEvent(&displayInteractorEvent)) { const DisplayScrollEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); if (nullptr == sendingRenderer) { return; } // concrete action mitk::SliceNavigationController* sliceNavigationController = sendingRenderer->GetSliceNavigationController(); if (nullptr == sliceNavigationController) { return; } if (sliceNavigationController->GetSliceLocked()) { return; } mitk::Stepper* sliceStepper = sliceNavigationController->GetSlice(); if (nullptr == sliceStepper) { return; } // if only a single slice image was loaded, scrolling will affect the time steps if (sliceStepper->GetSteps() <= 1) { sliceStepper = sliceNavigationController->GetTime(); } sliceStepper->MoveSlice(displayActionEvent->GetSliceDelta()); } }; return actionFunction; } mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::SetLevelWindowAction() { auto actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplaySetLevelWindowEvent().CheckEvent(&displayInteractorEvent)) { const DisplaySetLevelWindowEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); if (nullptr == sendingRenderer) { return; } // concrete action // get the the topmost visible image of the sending renderer DataStorage::Pointer storage = sendingRenderer->GetDataStorage(); DataStorage::SetOfObjects::ConstPointer allImageNodes = storage->GetSubset(NodePredicateDataType::New("Image")); Point3D worldposition; const auto* positionEvent = dynamic_cast(displayActionEvent->GetInteractionEvent()); sendingRenderer->DisplayToWorld(positionEvent->GetPointerPositionOnScreen(), worldposition); DataNode::Pointer node = storage->GetTopLayerNode(allImageNodes, worldposition, sendingRenderer); if (node.IsNull()) { return; } LevelWindow levelWindow = LevelWindow(); node->GetLevelWindow(levelWindow); ScalarType level = levelWindow.GetLevel(); ScalarType window = levelWindow.GetWindow(); level += displayActionEvent->GetLevel(); window += displayActionEvent->GetWindow(); levelWindow.SetLevelWindow(level, window); auto* levelWindowProperty = dynamic_cast(node->GetProperty("levelwindow")); if (nullptr != levelWindowProperty) { levelWindowProperty->SetLevelWindow(levelWindow); sendingRenderer->GetRenderingManager()->RequestUpdateAll(); } } }; return actionFunction; } ////////////////////////////////////////////////////////////////////////// // SYNCHRONIZED FUNCTIONS ////////////////////////////////////////////////////////////////////////// mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::MoveCameraSynchronizedAction() { mitk::StdFunctionCommand::ActionFunction actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplayMoveEvent().CheckEvent(&displayInteractorEvent)) { const DisplayMoveEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); if (nullptr == sendingRenderer) { return; } // concrete action auto allRenderWindows = sendingRenderer->GetRenderingManager()->GetAllRegisteredRenderWindows(); for (auto renderWindow : allRenderWindows) { if (BaseRenderer::GetInstance(renderWindow)->GetMapperID() == BaseRenderer::Standard2D) { BaseRenderer* currentRenderer = BaseRenderer::GetInstance(renderWindow); currentRenderer->GetCameraController()->MoveBy(displayActionEvent->GetMoveVector()); currentRenderer->GetRenderingManager()->RequestUpdate(currentRenderer->GetRenderWindow()); } } } }; return actionFunction; } mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::SetCrosshairSynchronizedAction() { auto actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplaySetCrosshairEvent().CheckEvent(&displayInteractorEvent)) { const DisplaySetCrosshairEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); if (nullptr == sendingRenderer) { return; } // concrete action auto allRenderWindows = sendingRenderer->GetRenderingManager()->GetAllRegisteredRenderWindows(); for (auto renderWindow : allRenderWindows) { if (BaseRenderer::GetInstance(renderWindow)->GetMapperID() == BaseRenderer::Standard2D) { BaseRenderer::GetInstance(renderWindow)->GetSliceNavigationController()->SelectSliceByPoint(displayActionEvent->GetPosition()); } } } }; return actionFunction; } mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::ZoomCameraSynchronizedAction() { auto actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplayZoomEvent().CheckEvent(&displayInteractorEvent)) { const DisplayZoomEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); if (nullptr == sendingRenderer) { return; } // concrete action if (1.0 != displayActionEvent->GetZoomFactor()) { auto allRenderWindows = sendingRenderer->GetRenderingManager()->GetAllRegisteredRenderWindows(); for (auto renderWindow : allRenderWindows) { if (BaseRenderer::GetInstance(renderWindow)->GetMapperID() == BaseRenderer::Standard2D) { BaseRenderer* currentRenderer = BaseRenderer::GetInstance(renderWindow); currentRenderer->GetCameraController()->Zoom(displayActionEvent->GetZoomFactor(), displayActionEvent->GetStartCoordinate()); currentRenderer->GetRenderingManager()->RequestUpdate(currentRenderer->GetRenderWindow()); } } } } }; return actionFunction; } mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::ScrollSliceStepperSynchronizedAction() { auto actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplayScrollEvent().CheckEvent(&displayInteractorEvent)) { const DisplayScrollEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); if (nullptr == sendingRenderer) { return; } // concrete action auto allRenderWindows = sendingRenderer->GetRenderingManager()->GetAllRegisteredRenderWindows(); for (auto renderWindow : allRenderWindows) { if (BaseRenderer::GetInstance(renderWindow)->GetMapperID() == BaseRenderer::Standard2D) { mitk::SliceNavigationController* sliceNavigationController = BaseRenderer::GetInstance(renderWindow)->GetSliceNavigationController(); if (nullptr == sliceNavigationController) { return; } if (sliceNavigationController->GetSliceLocked()) { return; } mitk::Stepper* sliceStepper = sliceNavigationController->GetSlice(); if (nullptr == sliceStepper) { return; } // if only a single slice image was loaded, scrolling will affect the time steps if (sliceStepper->GetSteps() <= 1) { sliceStepper = sliceNavigationController->GetTime(); } sliceStepper->MoveSlice(displayActionEvent->GetSliceDelta()); } } } }; return actionFunction; } diff --git a/Modules/QtWidgets/include/QmitkRenderWindowWidget.h b/Modules/QtWidgets/include/QmitkRenderWindowWidget.h index 0e26f67cc5..40146bfeae 100644 --- a/Modules/QtWidgets/include/QmitkRenderWindowWidget.h +++ b/Modules/QtWidgets/include/QmitkRenderWindowWidget.h @@ -1,116 +1,122 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKRENDERWINDOWWIDGET_H #define QMITKRENDERWINDOWWIDGET_H // qt widgets module #include "MitkQtWidgetsExports.h" -#include -#include +#include "QmitkRenderWindow.h" +#include "QmitkLevelWindowWidget.h" // mitk core #include +#include #include #include #include // qt #include #include /** * @brief * * */ class MITKQTWIDGETS_EXPORT QmitkRenderWindowWidget : public QWidget { Q_OBJECT public: QmitkRenderWindowWidget( QWidget* parent = nullptr, const QString& UID = "", mitk::DataStorage* dataStorage = nullptr, mitk::BaseRenderer::RenderingMode::Type renderingMode = mitk::BaseRenderer::RenderingMode::Standard ); ~QmitkRenderWindowWidget() override; void SetDataStorage(mitk::DataStorage* dataStorage); const QString& GetUID() const { return m_UID; }; QmitkRenderWindow* GetRenderWindow() const { return m_RenderWindow; }; QmitkLevelWindowWidget* GetlevelWindowWidget() const { return m_LevelWindowWidget; }; 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 ShowLevelWindowWidget(bool enable); 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; /** * @brief Create a corner annotation and a colored rectangle for this widget. * * @par text The text of the corner annotation. * @par color The color of the text and the rectangle. */ void SetDecorationProperties(std::string text, mitk::Color color); bool IsRenderWindowMenuActivated() const; private: void InitializeGUI(); void InitializeDecorations(); + void SetCrosshair(mitk::Point3D selectedPoint); + QString m_UID; QHBoxLayout* m_Layout; mitk::DataStorage* m_DataStorage; QmitkRenderWindow* m_RenderWindow; QmitkLevelWindowWidget* m_LevelWindowWidget; + mitk::DataNode::Pointer m_PointSetNode; + mitk::PointSet::Pointer m_PointSet; + mitk::RenderingManager::Pointer m_RenderingManager; mitk::BaseRenderer::RenderingMode::Type m_RenderingMode; mitk::SliceNavigationController *m_TimeNavigationController; std::pair m_GradientBackgroundColors; mitk::Color m_DecorationColor; vtkSmartPointer m_RectangleProp; vtkSmartPointer m_CornerAnnotation; }; #endif // QMITKRENDERWINDOWWIDGET_H diff --git a/Modules/QtWidgets/src/QmitkCustomMultiWidget.cpp b/Modules/QtWidgets/src/QmitkCustomMultiWidget.cpp index 78e6ad4a0b..5fd62ccd7e 100644 --- a/Modules/QtWidgets/src/QmitkCustomMultiWidget.cpp +++ b/Modules/QtWidgets/src/QmitkCustomMultiWidget.cpp @@ -1,568 +1,564 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkCustomMultiWidget.h" #include #include #include #include // mitk core #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // qt #include QmitkCustomMultiWidget::QmitkCustomMultiWidget(QWidget* parent, Qt::WindowFlags f/* = 0*/, mitk::RenderingManager* renderingManager/* = nullptr*/, mitk::BaseRenderer::RenderingMode::Type renderingMode/* = mitk::BaseRenderer::RenderingMode::Standard*/, const QString& multiWidgetName/* = "custommulti"*/) : QWidget(parent, f) , m_CustomMultiWidgetLayout(nullptr) , m_RenderingManager(renderingManager) , m_RenderingMode(renderingMode) , m_MultiWidgetName(multiWidgetName) , m_PendingCrosshairPositionEvent(false) , m_CrosshairNavigationEnabled(false) , m_DisplayActionEventBroadcast(nullptr) , m_DisplayActionEventHandler(nullptr) , m_DataStorage(nullptr) { // create widget manually // create and set layout InitializeGUI(); InitializeWidget(); InitializeDisplayActionEventHandling(); resize(QSize(364, 477).expandedTo(minimumSizeHint())); } QmitkCustomMultiWidget::~QmitkCustomMultiWidget() { // nothing here } void QmitkCustomMultiWidget::SetDataStorage(mitk::DataStorage* dataStorage) { if (dataStorage == m_DataStorage) { return; } m_DataStorage = dataStorage; // set new data storage for the render window widgets for (const auto& renderWindowWidget : m_RenderWindowWidgets) { renderWindowWidget.second->SetDataStorage(m_DataStorage); } } void QmitkCustomMultiWidget::InitializeRenderWindowWidgets() { // create render window (widgets) initially - QString UID = CreateRenderWindowWidget("2015-01-14 - CT"); - AddToMultiWidgetLayout(0, 0, UID); + //QString UID = CreateRenderWindowWidget("2015-01-14 - CT"); + //AddToMultiWidgetLayout(0, 0, UID); /* AddRenderWindowWidget(0, 1, "2015-08-19 - CT"); AddRenderWindowWidget(0, 2, "2016-06-29 - CT"); AddRenderWindowWidget(1, 0, "2015-01-14 - MR"); AddRenderWindowWidget(1, 1, "2015-08-19 - MR"); AddRenderWindowWidget(1, 2, "2016-06-29 - MR"); */ } void QmitkCustomMultiWidget::ResetLayout(int row, int column) { int neededRenderWindowWidgets = (row + 1) * (column + 1); int existingRenderWindowWidgets = m_RenderWindowWidgets.size(); int difference = neededRenderWindowWidgets - existingRenderWindowWidgets; while(0 < difference) { // more render window widgets needed CreateRenderWindowWidget(); --difference; } while(0 > difference) { // less render window widgets needed RemoveRenderWindowWidget(m_RenderWindowWidgets.rbegin()->first); ++difference; } InitializeGUI(); if (0 == difference) { FillLayout(row, column); } } void QmitkCustomMultiWidget::Synchronize(bool synchronized) { auto allObserverTags = m_DisplayActionEventHandler->GetAllObserverTags(); for (auto observerTag : allObserverTags) { m_DisplayActionEventHandler->DisconnectObserver(observerTag); } if (synchronized) { mitk::StdFunctionCommand::ActionFunction actionFunction = mitk::DisplayActionEventFunctions::MoveCameraSynchronizedAction(); m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayMoveEvent(nullptr, mitk::Vector2D()), actionFunction); actionFunction = mitk::DisplayActionEventFunctions::SetCrosshairSynchronizedAction(); m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplaySetCrosshairEvent(nullptr, mitk::Point3D()), actionFunction); actionFunction = mitk::DisplayActionEventFunctions::ZoomCameraSynchronizedAction(); m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayZoomEvent(nullptr, 0.0, mitk::Point2D()), actionFunction); actionFunction = mitk::DisplayActionEventFunctions::ScrollSliceStepperSynchronizedAction(); m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayScrollEvent(nullptr, 0), actionFunction); } else { mitk::StdFunctionCommand::ActionFunction actionFunction = mitk::DisplayActionEventFunctions::MoveSenderCameraAction(); m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayMoveEvent(nullptr, mitk::Vector2D()), actionFunction); actionFunction = mitk::DisplayActionEventFunctions::SetCrosshairAction(); m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplaySetCrosshairEvent(nullptr, mitk::Point3D()), actionFunction); actionFunction = mitk::DisplayActionEventFunctions::ZoomSenderCameraAction(); m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayZoomEvent(nullptr, 0.0, mitk::Point2D()), actionFunction); actionFunction = mitk::DisplayActionEventFunctions::ScrollSliceStepperAction(); m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayScrollEvent(nullptr, 0), actionFunction); } // use the standard 'set level window' action for both modes mitk::StdFunctionCommand::ActionFunction actionFunction = mitk::DisplayActionEventFunctions::SetLevelWindowAction(); m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplaySetLevelWindowEvent(nullptr, mitk::ScalarType(), mitk::ScalarType()), actionFunction); } QmitkCustomMultiWidget::RenderWindowWidgetMap QmitkCustomMultiWidget::GetRenderWindowWidgets() const { return m_RenderWindowWidgets; } std::shared_ptr QmitkCustomMultiWidget::GetRenderWindowWidget(const QString& widgetID) const { RenderWindowWidgetMap::const_iterator it = m_RenderWindowWidgets.find(widgetID); if (it == m_RenderWindowWidgets.end()) { return nullptr; } return it->second; } QString QmitkCustomMultiWidget::CreateRenderWindowWidget(const std::string& cornerAnnotation/* = ""*/) { // create the render window widget and connect signals / slots mitk::UIDGenerator generator; std::string renderWindowUID = generator.GetUID(); QString UID = m_MultiWidgetName + "_" + QString::fromStdString(renderWindowUID); std::shared_ptr renderWindowWidget = std::make_shared(this, UID, m_DataStorage); renderWindowWidget->SetCornerAnnotationText(cornerAnnotation); - // create connections - //connect(renderWindowWidget.get(), SIGNAL(ResetView()), this, SLOT(ResetCrosshair())); - //connect(renderWindowWidget.get(), SIGNAL(ChangeCrosshairRotationMode(int)), this, SLOT(SetWidgetPlaneMode(int))); - // store the newly created render window widget with the UID m_RenderWindowWidgets.insert(std::make_pair(UID, renderWindowWidget)); return UID; } void QmitkCustomMultiWidget::AddToMultiWidgetLayout(int row, int column, const QString& widgetID) { std::shared_ptr renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { m_CustomMultiWidgetLayout->addWidget(renderWindowWidget.get(), row, column); } } void QmitkCustomMultiWidget::RemoveRenderWindowWidget(const QString& widgetID) { auto iterator = m_RenderWindowWidgets.find(widgetID); if (iterator == m_RenderWindowWidgets.end()) { return; } std::shared_ptr renderWindowWidgetToRemove = iterator->second; disconnect(renderWindowWidgetToRemove.get(), 0, 0, 0); // erase the render window from the map m_RenderWindowWidgets.erase(iterator); // remove from layout // #TODO } QmitkRenderWindow* QmitkCustomMultiWidget::GetRenderWindow(const QString& widgetID) const { std::shared_ptr renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { return renderWindowWidget->GetRenderWindow(); } return nullptr; } std::shared_ptr QmitkCustomMultiWidget::GetActiveRenderWindowWidget() const { //return m_ActiveRenderWindowWidget; return m_RenderWindowWidgets.begin()->second; } std::shared_ptr QmitkCustomMultiWidget::GetFirstRenderWindowWidget() const { if (!m_RenderWindowWidgets.empty()) { return m_RenderWindowWidgets.begin()->second; } else { return nullptr; } } std::shared_ptr QmitkCustomMultiWidget::GetLastRenderWindowWidget() const { if (!m_RenderWindowWidgets.empty()) { return m_RenderWindowWidgets.rbegin()->second; } else { return nullptr; } } unsigned int QmitkCustomMultiWidget::GetNumberOfRenderWindowWidgets() const { return m_RenderWindowWidgets.size(); } void QmitkCustomMultiWidget::RequestUpdate(const QString& widgetID) { std::shared_ptr renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { return renderWindowWidget->RequestUpdate(); } } void QmitkCustomMultiWidget::RequestUpdateAll() { for (const auto& renderWindowWidget : m_RenderWindowWidgets) { renderWindowWidget.second->RequestUpdate(); } } void QmitkCustomMultiWidget::ForceImmediateUpdate(const QString& widgetID) { std::shared_ptr renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->ForceImmediateUpdate(); } } void QmitkCustomMultiWidget::ForceImmediateUpdateAll() { for (const auto& renderWindowWidget : m_RenderWindowWidgets) { renderWindowWidget.second->ForceImmediateUpdate(); } } const mitk::Point3D QmitkCustomMultiWidget::GetCrossPosition(const QString& widgetID) const { /* const mitk::PlaneGeometry *plane1 = mitkWidget1->GetSliceNavigationController()->GetCurrentPlaneGeometry(); const mitk::PlaneGeometry *plane2 = mitkWidget2->GetSliceNavigationController()->GetCurrentPlaneGeometry(); const mitk::PlaneGeometry *plane3 = mitkWidget3->GetSliceNavigationController()->GetCurrentPlaneGeometry(); mitk::Line3D line; if ((plane1 != NULL) && (plane2 != NULL) && (plane1->IntersectionLine(plane2, line))) { mitk::Point3D point; if ((plane3 != NULL) && (plane3->IntersectionPoint(line, point))) { return point; } } // TODO BUG POSITIONTRACKER; mitk::Point3D p; return p; // return m_LastLeftClickPositionSupplier->GetCurrentPoint(); */ return mitk::Point3D(); } ////////////////////////////////////////////////////////////////////////// // PUBLIC SLOTS ////////////////////////////////////////////////////////////////////////// void QmitkCustomMultiWidget::ShowLevelWindowWidget(const QString& widgetID, bool show) { std::shared_ptr renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->ShowLevelWindowWidget(show); return; } MITK_ERROR << "Level window widget can not be shown for an unknown widget."; } void QmitkCustomMultiWidget::ShowAllLevelWindowWidgets(bool show) { for (const auto& renderWindowWidget : m_RenderWindowWidgets) { renderWindowWidget.second->ShowLevelWindowWidget(show); } } void QmitkCustomMultiWidget::HandleCrosshairPositionEvent() { /* if (!m_PendingCrosshairPositionEvent) { m_PendingCrosshairPositionEvent = true; QTimer::singleShot(0, this, SLOT(HandleCrosshairPositionEventDelayed())); } */ } void QmitkCustomMultiWidget::HandleCrosshairPositionEventDelayed() { /* m_PendingCrosshairPositionEvent = false; // find image with highest layer mitk::TNodePredicateDataType::Pointer isImageData = mitk::TNodePredicateDataType::New(); mitk::DataStorage::SetOfObjects::ConstPointer nodes = this->m_DataStorage->GetSubset(isImageData).GetPointer(); mitk::DataNode::Pointer node; mitk::DataNode::Pointer topSourceNode; mitk::Image::Pointer image; bool isBinary = false; node = this->GetTopLayerNode(nodes); int component = 0; if (node.IsNotNull()) { node->GetBoolProperty("binary", isBinary); if (isBinary) { mitk::DataStorage::SetOfObjects::ConstPointer sourcenodes = m_DataStorage->GetSources(node, NULL, true); if (!sourcenodes->empty()) { topSourceNode = this->GetTopLayerNode(sourcenodes); } if (topSourceNode.IsNotNull()) { image = dynamic_cast(topSourceNode->GetData()); topSourceNode->GetIntProperty("Image.Displayed Component", component); } else { image = dynamic_cast(node->GetData()); node->GetIntProperty("Image.Displayed Component", component); } } else { image = dynamic_cast(node->GetData()); node->GetIntProperty("Image.Displayed Component", component); } } mitk::Point3D crosshairPos = this->GetCrossPosition(); std::string statusText; std::stringstream stream; itk::Index<3> p; mitk::BaseRenderer *baseRenderer = GetRenderWindow()->GetSliceNavigationController()->GetRenderer(); unsigned int timestep = baseRenderer->GetTimeStep(); if (image.IsNotNull() && (image->GetTimeSteps() > timestep)) { image->GetGeometry()->WorldToIndex(crosshairPos, p); stream.precision(2); stream << "Position: <" << std::fixed << crosshairPos[0] << ", " << std::fixed << crosshairPos[1] << ", " << std::fixed << crosshairPos[2] << "> mm"; stream << "; Index: <" << p[0] << ", " << p[1] << ", " << p[2] << "> "; mitk::ScalarType pixelValue; mitkPixelTypeMultiplex5(mitk::FastSinglePixelAccess, image->GetChannelDescriptor().GetPixelType(), image, image->GetVolumeData(baseRenderer->GetTimeStep()), p, pixelValue, component); if (fabs(pixelValue) > 1000000 || fabs(pixelValue) < 0.01) { stream << "; Time: " << baseRenderer->GetTime() << " ms; Pixelvalue: " << std::scientific << pixelValue << " "; } else { stream << "; Time: " << baseRenderer->GetTime() << " ms; Pixelvalue: " << pixelValue << " "; } } else { stream << "No image information at this position!"; } statusText = stream.str(); mitk::StatusBar::GetInstance()->DisplayGreyValueText(statusText.c_str()); */ } void QmitkCustomMultiWidget::MoveCrossToPosition(const QString& widgetID, const mitk::Point3D& newPosition) { std::shared_ptr renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->GetSliceNavigationController()->SelectSliceByPoint(newPosition); renderWindowWidget->RequestUpdate(); return; } MITK_ERROR << "Geometry plane can not be shown for an unknown widget."; } void QmitkCustomMultiWidget::ResetCrosshair() { // #TODO: new concept: we do not want to initialize all views; // we do not want to rely on the geometry planes /* if (m_DataStorage.IsNotNull()) { m_RenderingManager->InitializeViewsByBoundingObjects(m_DataStorage); // m_RenderingManager->InitializeViews( m_DataStorage->ComputeVisibleBoundingGeometry3D() ); // reset interactor to normal slicing SetWidgetPlaneMode(PLANE_MODE_SLICING); } */ } ////////////////////////////////////////////////////////////////////////// // MOUSE EVENTS ////////////////////////////////////////////////////////////////////////// void QmitkCustomMultiWidget::wheelEvent(QWheelEvent* e) { emit WheelMoved(e); } void QmitkCustomMultiWidget::mousePressEvent(QMouseEvent* e) { } void QmitkCustomMultiWidget::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(); } ////////////////////////////////////////////////////////////////////////// // PRIVATE ////////////////////////////////////////////////////////////////////////// void QmitkCustomMultiWidget::InitializeGUI() { delete m_CustomMultiWidgetLayout; m_CustomMultiWidgetLayout = new QGridLayout(this); m_CustomMultiWidgetLayout->setContentsMargins(0, 0, 0, 0); setLayout(m_CustomMultiWidgetLayout); } void QmitkCustomMultiWidget::InitializeWidget() { // #TODO: some things have to be handled globally (hold for all render window (widgets) // analyse those things and design a controlling mechanism } void QmitkCustomMultiWidget::InitializeDisplayActionEventHandling() { m_DisplayActionEventBroadcast = mitk::DisplayActionEventBroadcast::New(); m_DisplayActionEventBroadcast->LoadStateMachine("DisplayInteraction.xml"); m_DisplayActionEventBroadcast->SetEventConfig("DisplayConfigPACS.xml"); m_DisplayActionEventHandler = std::make_unique(); m_DisplayActionEventHandler->SetObservableBroadcast(m_DisplayActionEventBroadcast); Synchronize(true); } void QmitkCustomMultiWidget::FillLayout(int row, int column) { int r = 0; int c = 0; for (const auto& renderWindowWidget : m_RenderWindowWidgets) { AddToMultiWidgetLayout(r, c, renderWindowWidget.first); c += 1; if (c > column) { // first column c = 0; // next row r += 1; if (r > row) { return; } } } } mitk::DataNode::Pointer QmitkCustomMultiWidget::GetTopLayerNode(mitk::DataStorage::SetOfObjects::ConstPointer nodes) { // #TODO: see T24173 return nodes->front(); } diff --git a/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp b/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp index 582801ac25..35185aa10f 100644 --- a/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp +++ b/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp @@ -1,230 +1,253 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkRenderWindowWidget.h" +// mitk qt widgets +#include + // vtk #include -// qt widgets module -#include - QmitkRenderWindowWidget::QmitkRenderWindowWidget(QWidget* parent/* = nullptr*/, const QString& UID/* = ""*/, mitk::DataStorage* dataStorage/* = nullptr*/, mitk::BaseRenderer::RenderingMode::Type renderingMode/* = mitk::BaseRenderer::RenderingMode::Standard*/) : QWidget(parent) , m_UID(UID) , m_DataStorage(dataStorage) , m_RenderingMode(renderingMode) , m_RenderWindow(nullptr) , m_LevelWindowWidget(nullptr) + , m_PointSetNode(nullptr) + , m_PointSet(nullptr) { InitializeGUI(); - // TODO: signals / slots } QmitkRenderWindowWidget::~QmitkRenderWindowWidget() { - // nothing here + m_RenderWindow->GetSliceNavigationController()->SetCrosshairEvent.RemoveListener(mitk::MessageDelegate1(this, &QmitkRenderWindowWidget::SetCrosshair)); + m_DataStorage->Remove(m_PointSetNode); } void QmitkRenderWindowWidget::SetDataStorage(mitk::DataStorage* dataStorage) { if (dataStorage == m_DataStorage) { return; } m_DataStorage = dataStorage; if (nullptr != m_RenderWindow) { mitk::BaseRenderer::GetInstance(m_RenderWindow->GetRenderWindow())->SetDataStorage(dataStorage); } } mitk::SliceNavigationController* QmitkRenderWindowWidget::GetSliceNavigationController() const { if (nullptr == m_RenderWindow) { return nullptr; } return m_RenderWindow->GetSliceNavigationController(); } void QmitkRenderWindowWidget::RequestUpdate() { m_RenderingManager->RequestUpdate(m_RenderWindow->GetRenderWindow()); } void QmitkRenderWindowWidget::ForceImmediateUpdate() { m_RenderingManager->ForceImmediateUpdate(m_RenderWindow->GetRenderWindow()); } 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::ShowLevelWindowWidget(bool show) { /* #TODO: level window will currently be managed by the PACS mode m_LevelWindowWidget->disconnect(this); if (show) { m_LevelWindowWidget->SetDataStorage(m_DataStorage); m_LevelWindowWidget->show(); } else { m_LevelWindowWidget->disconnect(this); m_LevelWindowWidget->hide(); } */ } void QmitkRenderWindowWidget::SetDecorationColor(const mitk::Color& color) { m_DecorationColor = color; m_RectangleProp->SetColor(m_DecorationColor[0], m_DecorationColor[1], m_DecorationColor[2]); m_CornerAnnotation->GetTextProperty()->SetColor(color[0], color[1], color[2]); } void QmitkRenderWindowWidget::ShowColoredRectangle(bool show) { m_RectangleProp->SetVisibility(show); } bool QmitkRenderWindowWidget::IsColoredRectangleVisible() const { return m_RectangleProp->GetVisibility() > 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::InitializeGUI() { m_Layout = new QHBoxLayout(this); m_Layout->setMargin(0); setLayout(m_Layout); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); // create render window for this render window widget m_RenderingManager = mitk::RenderingManager::GetInstance(); //m_RenderingManager = mitk::RenderingManager::New(); m_RenderingManager->SetDataStorage(m_DataStorage); m_RenderWindow = new QmitkRenderWindow(this, m_UID, nullptr, m_RenderingManager, m_RenderingMode); m_RenderWindow->SetLayoutIndex(QmitkCustomMultiWidget::SAGITTAL); // TODO: allow to change layout type later m_RenderWindow->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); m_RenderWindow->GetSliceNavigationController()->SetRenderingManager(m_RenderingManager); + m_RenderWindow->GetSliceNavigationController()->SetCrosshairEvent.AddListener(mitk::MessageDelegate1(this, &QmitkRenderWindowWidget::SetCrosshair)); mitk::TimeGeometry::Pointer timeGeometry = m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll()); m_RenderingManager->InitializeViews(timeGeometry); // create level window widget for this render window widget m_LevelWindowWidget = new QmitkLevelWindowWidget(this); QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); sizePolicy.setHorizontalStretch(0); sizePolicy.setVerticalStretch(0); sizePolicy.setHeightForWidth(m_LevelWindowWidget->sizePolicy().hasHeightForWidth()); m_LevelWindowWidget->setSizePolicy(sizePolicy); m_LevelWindowWidget->setMaximumWidth(50); m_Layout->addWidget(m_RenderWindow); //m_Layout->addWidget(m_LevelWindowWidget); + // add point set as a crosshair + m_PointSetNode = mitk::DataNode::New(); + m_PointSetNode->SetProperty("name", mitk::StringProperty::New("Crosshair of render window " + m_UID.toStdString())); + m_PointSetNode->SetProperty("helper object", mitk::BoolProperty::New(true)); // crosshair-node should typically be invisible + + // set the crosshair only visible for this specific renderer + m_PointSetNode->SetBoolProperty("fixedLayer", true, m_RenderWindow->GetRenderer()); + m_PointSetNode->SetVisibility(true, m_RenderWindow->GetRenderer()); + m_PointSetNode->SetVisibility(false); + + m_PointSet = mitk::PointSet::New(); + m_PointSetNode->SetData(m_PointSet); + m_DataStorage->Add(m_PointSetNode); + // set colors and corner annotation InitializeDecorations(); } 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 decoration color, rectangle and annotation text float white[3] = { 1.0f, 1.0f, 1.0f }; m_DecorationColor = white; m_RectangleProp = vtkSmartPointer::New(); m_RectangleProp->SetColor(m_DecorationColor[0], m_DecorationColor[1], m_DecorationColor[2]); if (0 == vtkRenderer->HasViewProp(m_RectangleProp)) { vtkRenderer->AddViewProp(m_RectangleProp); } m_CornerAnnotation = vtkSmartPointer::New(); m_CornerAnnotation->SetText(0, "Sagittal"); m_CornerAnnotation->SetMaximumFontSize(12); m_CornerAnnotation->GetTextProperty()->SetColor(m_DecorationColor[0], m_DecorationColor[1], m_DecorationColor[2]); if (0 == vtkRenderer->HasViewProp(m_CornerAnnotation)) { vtkRenderer->AddViewProp(m_CornerAnnotation); } -} \ No newline at end of file +} + +void QmitkRenderWindowWidget::SetCrosshair(mitk::Point3D selectedPoint) +{ + m_PointSet->SetPoint(1, selectedPoint, 0); + mitk::RenderingManager::GetInstance()->RequestUpdate(m_RenderWindow->GetRenderWindow()); +} diff --git a/Plugins/org.mitk.gui.qt.custommultiwidgeteditor/src/QmitkCustomMultiWidgetEditor.cpp b/Plugins/org.mitk.gui.qt.custommultiwidgeteditor/src/QmitkCustomMultiWidgetEditor.cpp index 15691268c3..22ad689ebc 100644 --- a/Plugins/org.mitk.gui.qt.custommultiwidgeteditor/src/QmitkCustomMultiWidgetEditor.cpp +++ b/Plugins/org.mitk.gui.qt.custommultiwidgeteditor/src/QmitkCustomMultiWidgetEditor.cpp @@ -1,263 +1,267 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkCustomMultiWidgetEditor.h" #include #include #include #include #include // mitk core #include #include const QString QmitkCustomMultiWidgetEditor::EDITOR_ID = "org.mitk.editors.custommultiwidget"; QmitkCustomMultiWidgetEditor::QmitkCustomMultiWidgetEditor() : m_CustomMultiWidget(nullptr) , m_InteractionSchemeToolBar(nullptr) , m_ConfigurationToolBar(nullptr) { // nothing here } QmitkCustomMultiWidgetEditor::~QmitkCustomMultiWidgetEditor() { // nothing here } void QmitkCustomMultiWidgetEditor::Activated() { // nothing here } void QmitkCustomMultiWidgetEditor::Deactivated() { // nothing here } void QmitkCustomMultiWidgetEditor::Visible() { // nothing here } void QmitkCustomMultiWidgetEditor::Hidden() { // nothing here } QmitkRenderWindow* QmitkCustomMultiWidgetEditor::GetActiveQmitkRenderWindow() const { if (nullptr != m_CustomMultiWidget) { return m_CustomMultiWidget->GetActiveRenderWindowWidget()->GetRenderWindow(); } return nullptr; } QHash QmitkCustomMultiWidgetEditor::GetQmitkRenderWindows() const { QHash result; if (nullptr == m_CustomMultiWidget) { return result; } // create QHash on demand QmitkCustomMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_CustomMultiWidget->GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { result.insert(renderWindowWidget.first, renderWindowWidget.second->GetRenderWindow()); } return result; } QmitkRenderWindow* QmitkCustomMultiWidgetEditor::GetQmitkRenderWindow(const QString& id) const { if (nullptr == m_CustomMultiWidget) { return nullptr; } return m_CustomMultiWidget->GetRenderWindow(id); } mitk::Point3D QmitkCustomMultiWidgetEditor::GetSelectedPosition(const QString& id) const { if (nullptr == m_CustomMultiWidget) { return mitk::Point3D(); } return m_CustomMultiWidget->GetCrossPosition(id); } void QmitkCustomMultiWidgetEditor::SetSelectedPosition(const mitk::Point3D& pos, const QString& id) { if (nullptr != m_CustomMultiWidget) { m_CustomMultiWidget->MoveCrossToPosition(id, pos); } } void QmitkCustomMultiWidgetEditor::EnableDecorations(bool enable, const QStringList& decorations) { m_MultiWidgetDecorationManager->ShowDecorations(enable, decorations); } bool QmitkCustomMultiWidgetEditor::IsDecorationEnabled(const QString& decoration) const { return m_MultiWidgetDecorationManager->IsDecorationVisible(decoration); } QStringList QmitkCustomMultiWidgetEditor::GetDecorations() const { return m_MultiWidgetDecorationManager->GetDecorations(); } void QmitkCustomMultiWidgetEditor::EnableSlicingPlanes(bool enable) { // #TODO: nothing here } bool QmitkCustomMultiWidgetEditor::IsSlicingPlanesEnabled() const { // #TODO: nothing here return false; } QmitkCustomMultiWidget* QmitkCustomMultiWidgetEditor::GetCustomMultiWidget() { return m_CustomMultiWidget; } void QmitkCustomMultiWidgetEditor::OnLayoutSet(int row, int column) { m_CustomMultiWidget->ResetLayout(row, column); SetControlledRenderer(); } void QmitkCustomMultiWidgetEditor::OnSynchronize(bool synchronized) { m_CustomMultiWidget->Synchronize(synchronized); } void QmitkCustomMultiWidgetEditor::OnViewDirectionChanged(mitk::SliceNavigationController::ViewDirection viewDirection) { m_RenderWindowViewDirectionController->SetViewDirectionOfRenderer(viewDirection); } ////////////////////////////////////////////////////////////////////////// // PRIVATE ////////////////////////////////////////////////////////////////////////// void QmitkCustomMultiWidgetEditor::SetFocus() { if (nullptr != m_CustomMultiWidget) { m_CustomMultiWidget->setFocus(); } } void QmitkCustomMultiWidgetEditor::CreateQtPartControl(QWidget* parent) { if (nullptr == m_CustomMultiWidget) { QHBoxLayout* layout = new QHBoxLayout(parent); layout->setContentsMargins(0, 0, 0, 0); berry::IBerryPreferences* preferences = dynamic_cast(GetPreferences().GetPointer()); mitk::BaseRenderer::RenderingMode::Type renderingMode = static_cast(preferences->GetInt("Rendering Mode", 0)); m_CustomMultiWidget = new QmitkCustomMultiWidget(parent, 0, 0, renderingMode); // create left toolbar: interaction scheme toolbar to switch how the render window navigation behaves if (nullptr == m_InteractionSchemeToolBar) { m_InteractionSchemeToolBar = new QmitkInteractionSchemeToolBar(parent); layout->addWidget(m_InteractionSchemeToolBar); } m_InteractionSchemeToolBar->SetInteractionEventHandler(m_CustomMultiWidget->GetInteractionEventHandler()); // add center widget: the custom multi widget layout->addWidget(m_CustomMultiWidget); m_CustomMultiWidget->SetDataStorage(GetDataStorage()); m_CustomMultiWidget->InitializeRenderWindowWidgets(); // create right toolbar: configuration toolbar to change the render window widget layout if (nullptr == m_ConfigurationToolBar) { m_ConfigurationToolBar = new QmitkMultiWidgetConfigurationToolBar(m_CustomMultiWidget); layout->addWidget(m_ConfigurationToolBar); } connect(m_ConfigurationToolBar, SIGNAL(LayoutSet(int, int)), SLOT(OnLayoutSet(int, int))); connect(m_ConfigurationToolBar, SIGNAL(Synchronized(bool)), SLOT(OnSynchronize(bool))); connect(m_ConfigurationToolBar, SIGNAL(ViewDirectionChanged(mitk::SliceNavigationController::ViewDirection)), SLOT(OnViewDirectionChanged(mitk::SliceNavigationController::ViewDirection))); m_MultiWidgetDecorationManager = std::make_unique(m_CustomMultiWidget); m_RenderWindowViewDirectionController = std::make_unique(); m_RenderWindowViewDirectionController->SetDataStorage(GetDataStorage()); SetControlledRenderer(); OnPreferencesChanged(preferences); } } void QmitkCustomMultiWidgetEditor::OnPreferencesChanged(const berry::IBerryPreferences* preferences) { + if (m_CustomMultiWidget->GetRenderWindowWidgets().empty()) + { + return; + } // update decoration preferences m_MultiWidgetDecorationManager->DecorationPreferencesChanged(preferences); // zooming and panning preferences bool constrainedZooming = preferences->GetBool("Use constrained zooming and panning", true); mitk::RenderingManager::GetInstance()->SetConstrainedPanningZooming(constrainedZooming); // level window preferences bool showLevelWindowWidget = preferences->GetBool("Show level-window widget", true); m_CustomMultiWidget->ShowAllLevelWindowWidgets(showLevelWindowWidget); mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(GetDataStorage()); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkCustomMultiWidgetEditor::SetControlledRenderer() { if (nullptr == m_RenderWindowViewDirectionController || nullptr == m_CustomMultiWidget) { return; } RenderWindowLayerUtilities::RendererVector controlledRenderer; auto renderWindowWidgets = m_CustomMultiWidget->GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { auto renderWindow = renderWindowWidget.second->GetRenderWindow(); auto vtkRenderWindow = renderWindow->GetRenderWindow(); mitk::BaseRenderer* baseRenderer = mitk::BaseRenderer::GetInstance(vtkRenderWindow); if (nullptr != baseRenderer) { controlledRenderer.push_back(baseRenderer); } } m_RenderWindowViewDirectionController->SetControlledRenderer(controlledRenderer); } diff --git a/Plugins/org.mitk.gui.qt.custommultiwidgeteditor/src/QmitkMultiWidgetDecorationManager.cpp b/Plugins/org.mitk.gui.qt.custommultiwidgeteditor/src/QmitkMultiWidgetDecorationManager.cpp index 80597f578f..6ef9f3d0c8 100644 --- a/Plugins/org.mitk.gui.qt.custommultiwidgeteditor/src/QmitkMultiWidgetDecorationManager.cpp +++ b/Plugins/org.mitk.gui.qt.custommultiwidgeteditor/src/QmitkMultiWidgetDecorationManager.cpp @@ -1,458 +1,458 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkMultiWidgetDecorationManager.h" // org_mitk_gui_common #include // mitk annotation #include // vtk #include // qt #include QmitkMultiWidgetDecorationManager::QmitkMultiWidgetDecorationManager(QmitkCustomMultiWidget* customMultiWidget) : m_CustomMultiWidget(customMultiWidget) , m_LogoAnnotation(mitk::LogoAnnotation::New()) { // nothing here } void QmitkMultiWidgetDecorationManager::DecorationPreferencesChanged(const berry::IBerryPreferences* preferences) { // Enable change of logo. If no DepartmentLogo was set explicitly, MBILogo is used. // Set new department logo by prefs->Set("DepartmentLogo", "PathToImage"); // If no logo was set for this plug-in specifically, walk the parent preference nodes // and lookup a logo value there. // Disable the logo first, otherwise setting a new logo will have no effect due to how mitkManufacturerLogo works ShowLogo(false); SetupLogo(qPrintable(":/org.mitk.gui.qt.stdmultiwidgeteditor/defaultWatermark.png")); ShowLogo(true); const berry::IPreferences* currentNode = preferences; while (currentNode) { bool logoFound = false; foreach(const QString& key, currentNode->Keys()) { if (key == "DepartmentLogo") { ShowLogo(false); QString departmentLogoLocation = currentNode->Get("DepartmentLogo", ""); if (!departmentLogoLocation.isEmpty()) { SetupLogo(qPrintable(departmentLogoLocation)); ShowLogo(true); } logoFound = true; break; } } if (logoFound) { break; } currentNode = currentNode->Parent().GetPointer(); } QmitkMultiWidgetDecorationManager::Colormap colormap = static_cast(preferences->GetInt("Render window widget colormap", 0)); SetColormap(colormap); // show colored rectangle ShowAllColoredRectangles(true); // show corner annotations ShowAllCornerAnnotations(true); } void QmitkMultiWidgetDecorationManager::ShowDecorations(bool show, const QStringList& decorations) { if (nullptr != m_CustomMultiWidget) { return; } if (decorations.isEmpty() || decorations.contains(mitk::IRenderWindowPart::DECORATION_BORDER)) { ShowAllColoredRectangles(show); } if (decorations.isEmpty() || decorations.contains(mitk::IRenderWindowPart::DECORATION_LOGO)) { ShowLogo(show); } if (decorations.isEmpty() || decorations.contains(mitk::IRenderWindowPart::DECORATION_MENU)) { //m_CustomMultiWidget->ActivateAllRenderWindowMenus(show); } if (decorations.isEmpty() || decorations.contains(mitk::IRenderWindowPart::DECORATION_BACKGROUND)) { ShowAllGradientBackgrounds(show); } if (decorations.isEmpty() || decorations.contains(mitk::IRenderWindowPart::DECORATION_CORNER_ANNOTATION)) { ShowAllCornerAnnotations(show); } } bool QmitkMultiWidgetDecorationManager::IsDecorationVisible(const QString& decoration) const { if (mitk::IRenderWindowPart::DECORATION_BORDER == decoration) { return AreAllColoredRectanglesVisible(); } else if (mitk::IRenderWindowPart::DECORATION_LOGO == decoration) { return IsLogoVisible(); } else if (mitk::IRenderWindowPart::DECORATION_MENU == decoration) { //return IsMenuWidgetEnabled(); } else if (mitk::IRenderWindowPart::DECORATION_BACKGROUND == decoration) { return AreAllGradientBackgroundsOn(); } else if (mitk::IRenderWindowPart::DECORATION_CORNER_ANNOTATION == decoration) { return AreAllCornerAnnotationsVisible(); } return false; } QStringList QmitkMultiWidgetDecorationManager::GetDecorations() const { QStringList decorations; decorations << mitk::IRenderWindowPart::DECORATION_BORDER << mitk::IRenderWindowPart::DECORATION_LOGO << mitk::IRenderWindowPart::DECORATION_MENU << mitk::IRenderWindowPart::DECORATION_BACKGROUND << mitk::IRenderWindowPart::DECORATION_CORNER_ANNOTATION; return decorations; } ////////////////////////////////////////////////////////////////////////// // PRIVATE ////////////////////////////////////////////////////////////////////////// void QmitkMultiWidgetDecorationManager::SetupLogo(const char* path) { m_LogoAnnotation->SetOpacity(0.5); mitk::Point2D offset; offset.Fill(0.03); m_LogoAnnotation->SetOffsetVector(offset); m_LogoAnnotation->SetRelativeSize(0.25); m_LogoAnnotation->SetCornerPosition(1); vtkSmartPointer vtkLogo = GetVtkLogo(path); SetLogo(vtkLogo); } vtkSmartPointer QmitkMultiWidgetDecorationManager::GetVtkLogo(const char* path) { QImage* qimage = new QImage(path); vtkSmartPointer qImageToVtk; qImageToVtk = vtkSmartPointer::New(); qImageToVtk->SetQImage(qimage); qImageToVtk->Update(); vtkSmartPointer vtkLogo = qImageToVtk->GetOutput(); return vtkLogo; } void QmitkMultiWidgetDecorationManager::SetLogo(vtkSmartPointer vtkLogo) { std::shared_ptr renderWindowWidget = m_CustomMultiWidget->GetLastRenderWindowWidget(); if (nullptr != renderWindowWidget && m_LogoAnnotation.IsNotNull()) { mitk::ManualPlacementAnnotationRenderer::AddAnnotation(m_LogoAnnotation.GetPointer(), renderWindowWidget->GetRenderWindow()->GetRenderer()); m_LogoAnnotation->SetLogoImage(vtkLogo); mitk::BaseRenderer *renderer = mitk::BaseRenderer::GetInstance(renderWindowWidget->GetRenderWindow()->GetVtkRenderWindow()); m_LogoAnnotation->Update(renderer); renderWindowWidget->RequestUpdate(); return; } MITK_ERROR << "Logo can not be set for an unknown widget."; } void QmitkMultiWidgetDecorationManager::ShowLogo(bool show) { std::shared_ptr renderWindowWidget = m_CustomMultiWidget->GetLastRenderWindowWidget(); if (nullptr != renderWindowWidget) { m_LogoAnnotation->SetVisibility(show); renderWindowWidget->RequestUpdate(); return; } - MITK_ERROR << "Department logo can not be shown for an unknown widget."; + MITK_ERROR << "Logo can not be shown for an unknown widget."; } bool QmitkMultiWidgetDecorationManager::IsLogoVisible() const { return m_LogoAnnotation->IsVisible(); } void QmitkMultiWidgetDecorationManager::SetColormap(QmitkMultiWidgetDecorationManager::Colormap colormap) { switch (colormap) { case Colormap::BlackAndWhite: { FillAllGradientBackgroundColorsWithBlack(); float white[3] = { 1.0f, 1.0f, 1.0f }; SetAllDecorationColors(white); break; } } } void QmitkMultiWidgetDecorationManager::SetDecorationColor(const QString& widgetID, const mitk::Color& color) { std::shared_ptr renderWindowWidget = m_CustomMultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->SetDecorationColor(color); return; } MITK_ERROR << "Decoration color can not be set for an unknown widget."; } void QmitkMultiWidgetDecorationManager::SetAllDecorationColors(const mitk::Color& color) { QmitkCustomMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_CustomMultiWidget->GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { renderWindowWidget.second->SetDecorationColor(color); } } mitk::Color QmitkMultiWidgetDecorationManager::GetDecorationColor(const QString& widgetID) const { std::shared_ptr renderWindowWidget = m_CustomMultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { return renderWindowWidget->GetDecorationColor(); } MITK_ERROR << "Decoration color can not be retrieved for an unknown widget. Returning black color!"; float black[3] = { 0.0f, 0.0f, 0.0f }; return mitk::Color(black); } void QmitkMultiWidgetDecorationManager::ShowColoredRectangle(const QString& widgetID, bool show) { std::shared_ptr renderWindowWidget = m_CustomMultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->ShowColoredRectangle(show); return; } MITK_ERROR << "Colored rectangle can not be set for an unknown widget."; } void QmitkMultiWidgetDecorationManager::ShowAllColoredRectangles(bool show) { QmitkCustomMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_CustomMultiWidget->GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { renderWindowWidget.second->ShowColoredRectangle(show); } } bool QmitkMultiWidgetDecorationManager::IsColoredRectangleVisible(const QString& widgetID) const { std::shared_ptr renderWindowWidget = m_CustomMultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { return renderWindowWidget->IsColoredRectangleVisible(); } MITK_ERROR << "Colored rectangle visibility can not be retrieved for an unknown widget. Returning 'false'."; return false; } bool QmitkMultiWidgetDecorationManager::AreAllColoredRectanglesVisible() const { QmitkCustomMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_CustomMultiWidget->GetRenderWindowWidgets(); bool allTrue = true; for (const auto& renderWindowWidget : renderWindowWidgets) { allTrue = allTrue && renderWindowWidget.second->IsColoredRectangleVisible(); } return allTrue; } void QmitkMultiWidgetDecorationManager::SetGradientBackgroundColors(const mitk::Color& upper, const mitk::Color& lower, const QString& widgetID) { std::shared_ptr renderWindowWidget = m_CustomMultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->SetGradientBackgroundColors(upper, lower); return; } MITK_ERROR << "Background color gradient can not be set for an unknown widget."; } void QmitkMultiWidgetDecorationManager::SetAllGradientBackgroundColors(const mitk::Color& upper, const mitk::Color& lower) { QmitkCustomMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_CustomMultiWidget->GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { renderWindowWidget.second->SetGradientBackgroundColors(upper, lower); } } void QmitkMultiWidgetDecorationManager::FillAllGradientBackgroundColorsWithBlack() { float black[3] = { 0.0f, 0.0f, 0.0f }; SetAllGradientBackgroundColors(black, black); } void QmitkMultiWidgetDecorationManager::ShowGradientBackground(const QString& widgetID, bool show) { std::shared_ptr renderWindowWidget = m_CustomMultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->ShowGradientBackground(show); return; } MITK_ERROR << "Background color gradient can not be shown for an unknown widget."; } void QmitkMultiWidgetDecorationManager::ShowAllGradientBackgrounds(bool show) { QmitkCustomMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_CustomMultiWidget->GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { renderWindowWidget.second->ShowGradientBackground(show); } } std::pair QmitkMultiWidgetDecorationManager::GetGradientBackgroundColors(const QString& widgetID) const { std::shared_ptr renderWindowWidget = m_CustomMultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { return renderWindowWidget->GetGradientBackgroundColors(); } MITK_ERROR << "Background color gradient can not be retrieved for an unknown widget. Returning black color pair."; float black[3] = { 0.0f, 0.0f, 0.0f }; return std::make_pair(mitk::Color(black), mitk::Color(black)); } bool QmitkMultiWidgetDecorationManager::IsGradientBackgroundOn(const QString& widgetID) const { std::shared_ptr renderWindowWidget = m_CustomMultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { return renderWindowWidget->IsGradientBackgroundOn(); } MITK_ERROR << "Background color gradient flag can not be retrieved for an unknown widget. Returning 'false'."; return false; } bool QmitkMultiWidgetDecorationManager::AreAllGradientBackgroundsOn() const { QmitkCustomMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_CustomMultiWidget->GetRenderWindowWidgets(); bool allTrue = true; for (const auto& renderWindowWidget : renderWindowWidgets) { allTrue = allTrue && renderWindowWidget.second->IsGradientBackgroundOn(); } return allTrue; } void QmitkMultiWidgetDecorationManager::SetCornerAnnotationText(const QString& widgetID, const std::string& cornerAnnotation) { std::shared_ptr renderWindowWidget = m_CustomMultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->SetCornerAnnotationText(cornerAnnotation); return; } MITK_ERROR << "Corner annotation text can not be retrieved for an unknown widget."; } std::string QmitkMultiWidgetDecorationManager::GetCornerAnnotationText(const QString& widgetID) const { std::shared_ptr renderWindowWidget = m_CustomMultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { return renderWindowWidget->GetCornerAnnotationText(); } MITK_ERROR << "Corner annotation text can not be retrieved for an unknown widget."; return ""; } void QmitkMultiWidgetDecorationManager::ShowCornerAnnotation(const QString& widgetID, bool show) { std::shared_ptr renderWindowWidget = m_CustomMultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->ShowCornerAnnotation(show); return; } MITK_ERROR << "Corner annotation can not be set for an unknown widget."; } void QmitkMultiWidgetDecorationManager::ShowAllCornerAnnotations(bool show) { QmitkCustomMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_CustomMultiWidget->GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { renderWindowWidget.second->ShowCornerAnnotation(show); } } bool QmitkMultiWidgetDecorationManager::IsCornerAnnotationVisible(const QString& widgetID) const { std::shared_ptr renderWindowWidget = m_CustomMultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { return renderWindowWidget->IsCornerAnnotationVisible(); } MITK_ERROR << "Corner annotation visibility can not be retrieved for an unknown widget. Returning 'false'."; return false; } bool QmitkMultiWidgetDecorationManager::AreAllCornerAnnotationsVisible() const { QmitkCustomMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_CustomMultiWidget->GetRenderWindowWidgets(); bool allTrue = true; for (const auto& renderWindowWidget : renderWindowWidgets) { allTrue = allTrue && renderWindowWidget.second->IsCornerAnnotationVisible(); } return allTrue; }