diff --git a/Modules/Core/include/mitkDisplayActionEventBroadcast.h b/Modules/Core/include/mitkDisplayActionEventBroadcast.h index 5ce15ebadf..ec3e59ba11 100644 --- a/Modules/Core/include/mitkDisplayActionEventBroadcast.h +++ b/Modules/Core/include/mitkDisplayActionEventBroadcast.h @@ -1,224 +1,224 @@ /*=================================================================== 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 MITKDISPLAYACTIONEVENTBROADCAST_H #define MITKDISPLAYACTIONEVENTBROADCAST_H #include "mitkInteractionEventObserver.h" #include namespace mitk { /** * @brief This class serves as an event state machine while simultaneously observing interaction events. * It connects the actions from the event state machine .xml-file with concrete functions of this class. * * The observed interaction events are mouse events that trigger certain actions, according to an event configuration (e.g. PACS mode). * These actions are defined and connected inside this broadcast class. * They typically contain some preprocessing steps and use the results of the preprocessing to broadcast a specific display event. * * Any instance that wants to react on the invoked events can call 'AddObserver' on a specific broadcast instance, * given an itkEventObject and an itkCommand. */ class MITKCORE_EXPORT DisplayActionEventBroadcast : public EventStateMachine, public InteractionEventObserver { public: mitkClassMacro(DisplayActionEventBroadcast, EventStateMachine) itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** * By this function this observer is notified about about every 'InteractionEvent'. * The interaction event is passed to the state machine in order to use its infrastructure. * For more information see @see InteractionEventObserver. * * @par interactionEvent The event that was observed and triggered this notification. * @par isHandled Flag that indicates if a 'DataInteractor' has already handled the event. */ virtual void Notify(InteractionEvent* interactionEvent, bool isHandled) override; protected: DisplayActionEventBroadcast(); virtual ~DisplayActionEventBroadcast() override; /** * @brief Connects the action names used in the state machine pattern with functions implemented within this InteractionEventObserver. */ void ConnectActionsAndFunctions() override; /** * @brief This function is executed when a config object is set / changed (via 'SetEventConfig' or 'AddEventConfig' in 'InteractionEventObserver'). * It is used to read out the parameters set in the configuration file and to set the member variables accordingly. */ virtual void ConfigurationChanged() override; /** * @brief Filters the event resp. the sender of the event. * * @par interactionEvent The event whose sender has to be checked * @par data node The data node is ignored in this specific implementation. * * @return True, if the sender of the event is a valid sender and the sending renderer is a 2D-renderer. False, if not. */ virtual bool FilterEvents(InteractionEvent* interactionEvent, DataNode* dataNode) override; ////////////////////////////////////////////////////////////////////////// // Functions to react to interaction events (actions) ////////////////////////////////////////////////////////////////////////// /** * @brief Check if the given interaction event is actually an 'InteractionPositionEvent'. * * @par interactionEvent The interaction event that is checked. * * @return True, if the given event can be dynamically cast to an 'InteractionPositionEvent'. False, if not. */ bool CheckPositionEvent(const InteractionEvent* interactionEvent); bool CheckRotationPossible(const InteractionEvent* interactionEvent); bool CheckSwivelPossible(const InteractionEvent* interactionEvent); void Init(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); void Move(StateMachineAction* stateMachineAction , InteractionEvent* interactionEvent); void SetCrosshair(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); void Zoom(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); void Scroll(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); void ScrollOneUp(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); void ScrollOneDown(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); void AdjustLevelWindow(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); void StartRotation(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); void EndRotation(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); void Rotate(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); void Swivel(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); private: void UpdateStatusbar(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); - bool GetBoolProperty(mitk::PropertyList::Pointer propertyList, const char* propertyName, bool defaultValue); + bool GetBoolProperty(PropertyList::Pointer propertyList, const char* propertyName, bool defaultValue); /** * @brief Reference to the service registration of the observer. * This is needed to unregister the observer on unload. */ us::ServiceRegistration m_ServiceRegistration; /** * @brief Determines if this broadcast class reacts to events that already have been processed by a DataInteractor. * The default value is false. */ bool m_AlwaysReact; /** * @brief Coordinate of the mouse pointer at beginning of an interaction (translated to mm unit). */ - mitk::Point2D m_StartCoordinateInMM; + Point2D m_StartCoordinateInMM; /** * @brief Coordinate of the mouse pointer in the last step within an interaction. */ - mitk::Point2D m_LastDisplayCoordinate; + Point2D m_LastDisplayCoordinate; /** * @brief Coordinate of the mouse pointer in the last step within an interaction (translated to mm unit). */ - mitk::Point2D m_LastCoordinateInMM; + Point2D m_LastCoordinateInMM; /** * \brief Current coordinates of the pointer. */ - mitk::Point2D m_CurrentDisplayCoordinate; + Point2D m_CurrentDisplayCoordinate; /** * @brief Defines the behavior at the end of a data set. * If set to true, it will restart at end of data set from the beginning. */ bool m_AutoRepeat; /** * @brief Defines how many slices are scrolled per pixel that the mouse pointer was moved. * By default the modifier is 4. This means that when the user moves the cursor by 4 pixels in Y-direction, * the scene is scrolled by one slice. If the user has moved the the cursor by 20 pixels, the scene is * scrolled by 5 slices. * * If the cursor has moved less than m_IndexToSliceModifier pixels, the scene is scrolled by one slice. */ int m_IndexToSliceModifier; /** * @brief Defines the scroll behavior. * Default is up/down movement of pointer performs scrolling */ std::string m_ScrollDirection; /** * @brief Defines how the axis of interaction influences scroll behavior. */ bool m_InvertScrollDirection; /** * @brief Defines the zoom behavior. * Default is up/down movement of pointer performs zooming */ std::string m_ZoomDirection; /** * @brief Defines how the axis of interaction influences zoom behavior. */ bool m_InvertZoomDirection; /** * @brief Factor to adjust zooming speed. */ float m_ZoomFactor; /** * @brief Defines how the axis of interaction influences move behavior. */ bool m_InvertMoveDirection; /** * @brief Defines the level-window behavior. * Default is left/right movement of pointer modifies the level. */ std::string m_LevelDirection; /** * @brief Defines how the axis of interaction influences level-window behavior. */ bool m_InvertLevelWindowDirection; /** * @brief Determines if the angle between crosshair remains fixed when rotating. */ bool m_LinkPlanes; typedef std::vector SNCVector; SNCVector m_RotatableSNCs; SNCVector m_SNCsToBeRotated; Point3D m_LastCursorPosition; Point3D m_CenterOfRotation; Point2D m_ReferenceCursor; Vector3D m_RotationPlaneNormal; Vector3D m_RotationPlaneXVector; Vector3D m_RotationPlaneYVector; Vector3D m_PreviousRotationAxis; ScalarType m_PreviousRotationAngle; }; } // end namespace #endif // MITKDISPLAYACTIONEVENTBROADCAST_H diff --git a/Modules/Core/include/mitkDisplayActionEventHandler.h b/Modules/Core/include/mitkDisplayActionEventHandler.h index 28fd5324d4..a45d6acf85 100644 --- a/Modules/Core/include/mitkDisplayActionEventHandler.h +++ b/Modules/Core/include/mitkDisplayActionEventHandler.h @@ -1,99 +1,99 @@ /*=================================================================== 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 MITKDISPLAYACTIONEVENTHANDLER_H #define MITKDISPLAYACTIONEVENTHANDLER_H #include // mitk core #include "mitkDisplayActionEventBroadcast.h" #include "mitkDisplayActionEvents.h" #include "mitkStdFunctionCommand.h" namespace mitk { /** * @brief This class simplifies the process of adding an itkEventObject-itkCommand pair as an observer of a * DisplayActionEventBroadcast instance. * The 'SetObservableBroadcast'-function can be used to define the broadcast instance that should be observed. * The 'ConnectDisplayActionEvent'-function can be used to add a an observer to the broadcast. * Such an observer consists of a DisplayActionEvent (an itkEventObject) and a StdFunctionCommand (an itkCommand). * The StdFunctionCommand is created inside the function by the given two std::functions. */ class MITKCORE_EXPORT DisplayActionEventHandler { public: using OberserverTagType = unsigned long; /** * @brief Sets the display action event broadcast class that should be observed. * This class receives events from the given broadcast class and triggers the "corresponding functions" to perform the custom actions. * "Corresponding functions" are std::functions inside commands that observe the specific display action event. * * @post If the same broadcast class was already set, nothing changed * @post If a different broadcast class was already set, the observing commands are removed as observer. * Attention: All registered commands are removed from the list of observer. * * @par observableBroadcast The 'DisplayActionEventBroadcast'-class that should be observed. */ - void SetObservableBroadcast(mitk::DisplayActionEventBroadcast* observableBroadcast); + void SetObservableBroadcast(DisplayActionEventBroadcast* observableBroadcast); /** * @brief Uses the given std::functions to customize a command: * The display action event is used to define on which event the command should react. * The display action event broadcast class member is then observed by the newly created command. * A tag for the command is returned and stored in a member vector. * * @pre The class' observable (the display action event broadcast) has to be set to connect display events. * @throw mitk::Exception, if the class' observable is null. * * @par displayActionEvent The 'DisplayActionEvent' on which the command should react. * @par actionFunction A custom std::Function that will be executed if the command receives the correct event. * @par filterFunction A custom std::Function that will be checked before the execution of the action function. * If the filter function is not specified, a default filter always returning 'true' will be used. * * @return A tag to identify, receive or remove the newly created 'StdFunctionCommand'. */ - OberserverTagType ConnectDisplayActionEvent(const mitk::DisplayActionEvent& displayActionEvent, - const mitk::StdFunctionCommand::ActionFunction& actionFunction, - const mitk::StdFunctionCommand::FilterFunction& filterFunction = [](const itk::EventObject&) { return true; }); + OberserverTagType ConnectDisplayActionEvent(const DisplayActionEvent& displayActionEvent, + const StdFunctionCommand::ActionFunction& actionFunction, + const StdFunctionCommand::FilterFunction& filterFunction = [](const itk::EventObject&) { return true; }); /** * @brief Uses the given observer tag to remove the corresponding custom command as an observer of the observed * display action event broadcast class. * If the given tag is not contained in the member vector of observer tags, nothing happens. * * @pre The class' observable (the display action event broadcast) has to be set to connect display events. * @throw mitk::Exception, if the class' observable is null. * * @par observerTag The tag to identify the 'StdFunctionCommand' observer. */ void DisconnectObserver(OberserverTagType observerTag); const std::vector& GetAllObserverTags() { return m_ObserverTags; }; protected: - mitk::WeakPointer m_ObservableBroadcast; + WeakPointer m_ObservableBroadcast; std::vector m_ObserverTags; }; } // end namespace mitk #endif // MITKDISPLAYACTIONEVENTHANDLER_H diff --git a/Modules/Core/include/mitkDisplayActionEvents.h b/Modules/Core/include/mitkDisplayActionEvents.h index f56823720c..22c61e1248 100644 --- a/Modules/Core/include/mitkDisplayActionEvents.h +++ b/Modules/Core/include/mitkDisplayActionEvents.h @@ -1,188 +1,188 @@ /*=================================================================== 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 MITKDISPLAYACTIONEVENTS_H #define MITKDISPLAYACTIONEVENTS_H #include // mitk core #include "mitkInteractionEvent.h" // itk #include #include #include namespace mitk { class MITKCORE_EXPORT DisplayActionEvent : public itk::AnyEvent { public: typedef DisplayActionEvent Self; typedef itk::AnyEvent Superclass; DisplayActionEvent() : m_InteractionEvent(nullptr) {} DisplayActionEvent(InteractionEvent* interactionEvent) : m_InteractionEvent(interactionEvent) {} virtual ~DisplayActionEvent() {} virtual const char* GetEventName() const override { return "DisplayActionEvent"; } virtual bool CheckEvent(const itk::EventObject* e) const override { return dynamic_cast(e) != nullptr; } virtual itk::EventObject* MakeObject() const override { return new Self(m_InteractionEvent); } InteractionEvent* GetInteractionEvent() const { return m_InteractionEvent; } BaseRenderer* GetSender() const { return m_InteractionEvent != nullptr ? m_InteractionEvent->GetSender() : nullptr; } DisplayActionEvent(const Self& s) : Superclass(s), m_InteractionEvent(s.GetInteractionEvent()) {}; private: InteractionEvent* m_InteractionEvent; void operator=(const Self &); }; class MITKCORE_EXPORT DisplayMoveEvent : public DisplayActionEvent { public: typedef DisplayMoveEvent Self; typedef DisplayActionEvent Superclass; DisplayMoveEvent() : Superclass() {} DisplayMoveEvent(InteractionEvent* interactionEvent, const Vector2D& moveVector) : Superclass(interactionEvent) , m_MoveVector(moveVector) { } virtual ~DisplayMoveEvent() {} virtual const char* GetEventName() const override { return "DisplayMoveEvent"; } virtual bool CheckEvent(const itk::EventObject* e) const override { return dynamic_cast(e) != nullptr; } virtual itk::EventObject* MakeObject() const override { return new Self(GetInteractionEvent(), m_MoveVector); } const Vector2D& GetMoveVector() const { return m_MoveVector; } DisplayMoveEvent(const Self& s) : Superclass(s), m_MoveVector(s.GetMoveVector()) {}; private: Vector2D m_MoveVector; }; class MITKCORE_EXPORT DisplaySetCrosshairEvent : public DisplayActionEvent { public: typedef DisplaySetCrosshairEvent Self; typedef DisplayActionEvent Superclass; DisplaySetCrosshairEvent() : Superclass() {} DisplaySetCrosshairEvent(InteractionEvent* interactionEvent, const Point3D& position) : Superclass(interactionEvent) , m_Position(position) { } virtual ~DisplaySetCrosshairEvent() {} virtual const char* GetEventName() const override { return "DisplaySetCrosshairEvent"; } virtual bool CheckEvent(const itk::EventObject* e) const override { return dynamic_cast(e) != nullptr; } virtual itk::EventObject* MakeObject() const override { return new Self(GetInteractionEvent(), m_Position); } const Point3D& GetPosition() const { return m_Position; } DisplaySetCrosshairEvent(const Self& s) : Superclass(s), m_Position(s.GetPosition()) {}; private: Point3D m_Position; }; class MITKCORE_EXPORT DisplayZoomEvent : public DisplayActionEvent { public: typedef DisplayZoomEvent Self; typedef DisplayActionEvent Superclass; DisplayZoomEvent() : Superclass() {} DisplayZoomEvent(InteractionEvent* interactionEvent, float zoomFactor, const Point2D& startCoordinate) : Superclass(interactionEvent) , m_ZoomFactor(zoomFactor) , m_StartCoordinate(startCoordinate) { } virtual ~DisplayZoomEvent() {} virtual const char* GetEventName() const override { return "DisplayZoomEvent"; } virtual bool CheckEvent(const itk::EventObject* e) const override { return dynamic_cast(e) != nullptr; } virtual itk::EventObject* MakeObject() const override { return new Self(GetInteractionEvent(), m_ZoomFactor, m_StartCoordinate); } float GetZoomFactor() const { return m_ZoomFactor; } const Point2D& GetStartCoordinate() const { return m_StartCoordinate; } DisplayZoomEvent(const Self& s) : Superclass(s), m_ZoomFactor(s.GetZoomFactor()), m_StartCoordinate(s.GetStartCoordinate()) {}; private: float m_ZoomFactor; Point2D m_StartCoordinate; }; class MITKCORE_EXPORT DisplayScrollEvent : public DisplayActionEvent { public: typedef DisplayScrollEvent Self; typedef DisplayActionEvent Superclass; DisplayScrollEvent() : Superclass() {} DisplayScrollEvent(InteractionEvent* interactionEvent, int sliceDelta) : Superclass(interactionEvent) , m_SliceDelta(sliceDelta) { } virtual ~DisplayScrollEvent() {} virtual const char* GetEventName() const override { return "DisplayScrollEvent"; } virtual bool CheckEvent(const itk::EventObject* e) const override { return dynamic_cast(e) != nullptr; } virtual itk::EventObject* MakeObject() const override { return new Self(GetInteractionEvent(), m_SliceDelta); } int GetSliceDelta() const { return m_SliceDelta; } DisplayScrollEvent(const Self& s) : Superclass(s), m_SliceDelta(s.GetSliceDelta()) {}; private: int m_SliceDelta; }; class MITKCORE_EXPORT DisplaySetLevelWindowEvent : public DisplayActionEvent { public: typedef DisplaySetLevelWindowEvent Self; typedef DisplayActionEvent Superclass; DisplaySetLevelWindowEvent() : Superclass() {} - DisplaySetLevelWindowEvent(InteractionEvent* interactionEvent, mitk::ScalarType level, mitk::ScalarType window) + DisplaySetLevelWindowEvent(InteractionEvent* interactionEvent, ScalarType level, ScalarType window) : Superclass(interactionEvent) , m_Level(level) , m_Window(window) { } virtual ~DisplaySetLevelWindowEvent() {} virtual const char* GetEventName() const override { return "DisplaySetLevelWindowEvent"; } virtual bool CheckEvent(const itk::EventObject* e) const override { return dynamic_cast(e) != nullptr; } virtual itk::EventObject* MakeObject() const override { return new Self(GetInteractionEvent(), m_Level, m_Window); } - mitk::ScalarType GetLevel() const { return m_Level; } - mitk::ScalarType GetWindow() const { return m_Window; } + ScalarType GetLevel() const { return m_Level; } + ScalarType GetWindow() const { return m_Window; } DisplaySetLevelWindowEvent(const Self& s) : Superclass(s), m_Level(s.GetLevel()), m_Window(s.GetWindow()) {}; private: - mitk::ScalarType m_Level; - mitk::ScalarType m_Window; + ScalarType m_Level; + ScalarType m_Window; }; } // end namespace #endif // MITKDISPLAYACTIONEVENTS_H diff --git a/Modules/Core/src/Interactions/mitkDisplayActionEventBroadcast.cpp b/Modules/Core/src/Interactions/mitkDisplayActionEventBroadcast.cpp index d186374fc0..2ce458b7b5 100644 --- a/Modules/Core/src/Interactions/mitkDisplayActionEventBroadcast.cpp +++ b/Modules/Core/src/Interactions/mitkDisplayActionEventBroadcast.cpp @@ -1,786 +1,786 @@ /*=================================================================== 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 "mitkDisplayActionEventBroadcast.h" // us #include "usGetModuleContext.h" #include "usModuleContext.h" // mitk core module #include "mitkCompositePixelValueToString.h" #include "mitkDisplayActionEvents.h" #include "mitkImage.h" #include "mitkImagePixelReadAccessor.h" #include "mitkInteractionPositionEvent.h" #include "mitkLine.h" #include "mitkNodePredicateDataType.h" #include "mitkPixelTypeMultiplex.h" #include "mitkStatusBar.h" mitk::DisplayActionEventBroadcast::DisplayActionEventBroadcast() : m_AlwaysReact(false) , m_AutoRepeat(false) , m_IndexToSliceModifier(4) , m_InvertScrollDirection(false) , m_InvertZoomDirection(false) , m_ZoomFactor(2) , m_InvertMoveDirection(false) , m_InvertLevelWindowDirection(false) , m_LinkPlanes(true) { m_StartCoordinateInMM.Fill(0); m_LastDisplayCoordinate.Fill(0); m_LastCoordinateInMM.Fill(0); m_CurrentDisplayCoordinate.Fill(0); // register the broadcast class (itself) as an interaction event observer via micro services us::ServiceProperties props; props["name"] = std::string("DisplayActionEventBroadcast"); - m_ServiceRegistration = us::GetModuleContext()->RegisterService(this, props); + m_ServiceRegistration = us::GetModuleContext()->RegisterService(this, props); } mitk::DisplayActionEventBroadcast::~DisplayActionEventBroadcast() { m_ServiceRegistration.Unregister(); } void mitk::DisplayActionEventBroadcast::Notify(InteractionEvent* interactionEvent, bool isHandled) { // the event is passed to the state machine interface to be handled if (!isHandled || m_AlwaysReact) { HandleEvent(interactionEvent, nullptr); } } void mitk::DisplayActionEventBroadcast::ConnectActionsAndFunctions() { CONNECT_CONDITION("check_position_event", CheckPositionEvent); CONNECT_CONDITION("check_can_rotate", CheckRotationPossible); CONNECT_CONDITION("check_can_swivel", CheckSwivelPossible); CONNECT_FUNCTION("init", Init); CONNECT_FUNCTION("move", Move); CONNECT_FUNCTION("zoom", Zoom); CONNECT_FUNCTION("scroll", Scroll); CONNECT_FUNCTION("ScrollOneUp", ScrollOneUp); CONNECT_FUNCTION("ScrollOneDown", ScrollOneDown); CONNECT_FUNCTION("levelWindow", AdjustLevelWindow); CONNECT_FUNCTION("setCrosshair", SetCrosshair); CONNECT_FUNCTION("updateStatusbar", UpdateStatusbar) CONNECT_FUNCTION("startRotation", StartRotation); CONNECT_FUNCTION("endRotation", EndRotation); CONNECT_FUNCTION("rotate", Rotate); CONNECT_FUNCTION("swivel", Swivel); } void mitk::DisplayActionEventBroadcast::ConfigurationChanged() { - mitk::PropertyList::Pointer properties = GetAttributes(); + PropertyList::Pointer properties = GetAttributes(); // allwaysReact std::string strAlwaysReact = ""; m_AlwaysReact = false; if (properties->GetStringProperty("alwaysReact", strAlwaysReact)) { if (strAlwaysReact == "true") { m_AlwaysReact = true; } } // auto repeat std::string strAutoRepeat = ""; m_AutoRepeat = false; if (properties->GetStringProperty("autoRepeat", strAutoRepeat)) { if (strAutoRepeat == "true") { m_AutoRepeat = true; } } // pixel movement for scrolling one slice std::string strPixelPerSlice = ""; m_IndexToSliceModifier = 4; if (properties->GetStringProperty("pixelPerSlice", strPixelPerSlice)) { m_IndexToSliceModifier = atoi(strPixelPerSlice.c_str()); } // scroll direction if (!properties->GetStringProperty("scrollDirection", m_ScrollDirection)) { m_ScrollDirection = "updown"; } m_InvertScrollDirection = GetBoolProperty(properties, "invertScrollDirection", false); // zoom direction if (!properties->GetStringProperty("zoomDirection", m_ZoomDirection)) { m_ZoomDirection = "updown"; } m_InvertZoomDirection = GetBoolProperty(properties, "invertZoomDirection", false); m_InvertMoveDirection = GetBoolProperty(properties, "invertMoveDirection", false); if (!properties->GetStringProperty("levelWindowDirection", m_LevelDirection)) { m_LevelDirection = "leftright"; } m_InvertLevelWindowDirection = GetBoolProperty(properties, "invertLevelWindowDirection", false); // coupled rotation std::string strCoupled = ""; m_LinkPlanes = false; if (properties->GetStringProperty("coupled", strCoupled)) { if (strCoupled == "true") { m_LinkPlanes = true; } } // zoom factor std::string strZoomFactor = ""; properties->GetStringProperty("zoomFactor", strZoomFactor); m_ZoomFactor = .05; if (atoi(strZoomFactor.c_str()) > 0) { m_ZoomFactor = 1.0 + (atoi(strZoomFactor.c_str()) / 100.0); } } bool mitk::DisplayActionEventBroadcast::FilterEvents(InteractionEvent* interactionEvent, DataNode * /*dataNode*/) { - mitk::BaseRenderer* sendingRenderer = interactionEvent->GetSender(); + BaseRenderer* sendingRenderer = interactionEvent->GetSender(); if (nullptr == sendingRenderer) { return false; } if (BaseRenderer::Standard3D == sendingRenderer->GetMapperID()) { return false; } return true; } bool mitk::DisplayActionEventBroadcast::CheckPositionEvent(const InteractionEvent *interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return false; } return true; } bool mitk::DisplayActionEventBroadcast::CheckRotationPossible(const InteractionEvent *interactionEvent) { // Decide between moving and rotation slices. /* Detailed logic: 1. Find the SliceNavigationController that has sent the event: this one defines our rendering plane and will NOT be rotated. Needs not even be counted or checked. 2. Inspect every other SliceNavigationController - calculate the line intersection of this SliceNavigationController's plane with our rendering plane - if there is NO interesection, ignore and continue - IF there is an intersection - check the mouse cursor's distance from that line. 0. if the line is NOT near the cursor, remember the plane as "one of the other planes" (which can be rotated in "locked" mode) 1. on first line near the cursor, just remember this intersection line as THE other plane that we want to rotate 2. on every consecutive line near the cursor, check if the line is geometrically identical to the line that we want to rotate - if yes, we just push this line to the "other" lines and rotate it along - if no, then we have a situation where the mouse is near two other lines (e.g. crossing point) and don't want to rotate */ const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return false; } BaseRenderer* clickedRenderer = positionEvent->GetSender(); const PlaneGeometry* ourViewportGeometry = clickedRenderer->GetCurrentWorldPlaneGeometry(); if (nullptr == ourViewportGeometry) { return false; } Point3D cursorPosition = positionEvent->GetPositionInWorld(); const auto spacing = ourViewportGeometry->GetSpacing(); const PlaneGeometry *geometryToBeRotated = nullptr; // this one is under the mouse cursor const PlaneGeometry *anyOtherGeometry = nullptr; // this is also visible (for calculation of intersection ONLY) Line3D intersectionLineWithGeometryToBeRotated; bool hitMultipleLines(false); m_SNCsToBeRotated.clear(); const double threshholdDistancePixels = 12.0; auto renWindows = interactionEvent->GetSender()->GetRenderingManager()->GetAllRegisteredRenderWindows(); for (auto renWin : renWindows) { SliceNavigationController *snc = BaseRenderer::GetInstance(renWin)->GetSliceNavigationController(); // If the mouse cursor is in 3D Renderwindow, do not check for intersecting planes. if (BaseRenderer::GetInstance(renWin)->GetMapperID() == BaseRenderer::Standard3D) continue; const PlaneGeometry *otherRenderersRenderPlane = snc->GetCurrentPlaneGeometry(); if (nullptr == otherRenderersRenderPlane) { continue; // ignore, we don't see a plane } // check if there is an intersection Line3D intersectionLine; // between rendered/clicked geometry and the one being analyzed if (!ourViewportGeometry->IntersectionLine(otherRenderersRenderPlane, intersectionLine)) { continue; // we ignore this plane, it's parallel to our plane } // check distance from intersection line const double distanceFromIntersectionLine = intersectionLine.Distance(cursorPosition) / spacing[snc->GetDefaultViewDirection()]; // far away line, only remember for linked rotation if necessary if (distanceFromIntersectionLine > threshholdDistancePixels) { anyOtherGeometry = otherRenderersRenderPlane; // we just take the last one, so overwrite each iteration (we just // need some crossing point) // TODO what about multiple crossings? NOW we have undefined behavior / random crossing point is used if (m_LinkPlanes) { m_SNCsToBeRotated.push_back(snc); } } else // close to cursor { if (nullptr == geometryToBeRotated) // first one close to the cursor { geometryToBeRotated = otherRenderersRenderPlane; intersectionLineWithGeometryToBeRotated = intersectionLine; m_SNCsToBeRotated.push_back(snc); } else { // compare to the line defined by geometryToBeRotated: if identical, just rotate this otherRenderersRenderPlane // together with the primary one // if different, DON'T rotate if (intersectionLine.IsParallel(intersectionLineWithGeometryToBeRotated) && - intersectionLine.Distance(intersectionLineWithGeometryToBeRotated.GetPoint1()) < mitk::eps) + intersectionLine.Distance(intersectionLineWithGeometryToBeRotated.GetPoint1()) < eps) { m_SNCsToBeRotated.push_back(snc); } else { hitMultipleLines = true; } } } } bool moveSlices(true); if (geometryToBeRotated && anyOtherGeometry && ourViewportGeometry && !hitMultipleLines) { // assure all three are valid, so calculation of center of rotation can be done moveSlices = false; } // question in state machine is: "rotate?" if (moveSlices) // i.e. NOT rotate { return false; } else { // we DO have enough information for rotation // remember where the last cursor position ON THE LINE has been observed m_LastCursorPosition = intersectionLineWithGeometryToBeRotated.Project(cursorPosition); // find center of rotation by intersection with any of the OTHER lines if (anyOtherGeometry->IntersectionPoint(intersectionLineWithGeometryToBeRotated, m_CenterOfRotation)) { return true; } else { return false; } } return false; } bool mitk::DisplayActionEventBroadcast::CheckSwivelPossible(const InteractionEvent *interactionEvent) { const ScalarType ThresholdDistancePixels = 6.0; // Decide between moving and rotation: if we're close to the crossing // point of the planes, moving mode is entered, otherwise // rotation/swivel mode const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return false; } BaseRenderer *renderer = interactionEvent->GetSender(); if (nullptr == renderer) { return false; } const Point3D& cursor = positionEvent->GetPositionInWorld(); m_SNCsToBeRotated.clear(); const PlaneGeometry* clickedGeometry(nullptr); const PlaneGeometry* otherGeometry1(nullptr); const PlaneGeometry* otherGeometry2(nullptr); auto registeredRenderWindows = interactionEvent->GetSender()->GetRenderingManager()->GetAllRegisteredRenderWindows(); for (auto renWin : registeredRenderWindows) { SliceNavigationController* snc = BaseRenderer::GetInstance(renWin)->GetSliceNavigationController(); // If the mouse cursor is in 3D Renderwindow, do not check for intersecting planes. if (BaseRenderer::GetInstance(renWin)->GetMapperID() == BaseRenderer::Standard3D) continue; // unsigned int slice = (*iter)->GetSlice()->GetPos(); // unsigned int time = (*iter)->GetTime()->GetPos(); const PlaneGeometry *planeGeometry = snc->GetCurrentPlaneGeometry(); if (!planeGeometry) continue; if (snc == renderer->GetSliceNavigationController()) { clickedGeometry = planeGeometry; m_SNCsToBeRotated.push_back(snc); } else { if (otherGeometry1 == nullptr) { otherGeometry1 = planeGeometry; } else { otherGeometry2 = planeGeometry; } if (m_LinkPlanes) { // If planes are linked, apply rotation to all planes m_SNCsToBeRotated.push_back(snc); } } } Line3D line; Point3D point; if ((clickedGeometry != nullptr) && (otherGeometry1 != nullptr) && (otherGeometry2 != nullptr) && clickedGeometry->IntersectionLine(otherGeometry1, line) && otherGeometry2->IntersectionPoint(line, point)) { m_CenterOfRotation = point; if (m_CenterOfRotation.EuclideanDistanceTo(cursor) < ThresholdDistancePixels) { return false; } else { m_ReferenceCursor = positionEvent->GetPointerPositionOnScreen(); // Get main axes of rotation plane and store it for rotation step m_RotationPlaneNormal = clickedGeometry->GetNormal(); ScalarType xVector[] = { 1.0, 0.0, 0.0 }; ScalarType yVector[] = { 0.0, 1.0, 0.0 }; clickedGeometry->BaseGeometry::IndexToWorld(Vector3D(xVector), m_RotationPlaneXVector); clickedGeometry->BaseGeometry::IndexToWorld(Vector3D(yVector), m_RotationPlaneYVector); m_RotationPlaneNormal.Normalize(); m_RotationPlaneXVector.Normalize(); m_RotationPlaneYVector.Normalize(); m_PreviousRotationAxis.Fill(0.0); m_PreviousRotationAxis[2] = 1.0; m_PreviousRotationAngle = 0.0; return true; } } else { return false; } return false; } void mitk::DisplayActionEventBroadcast::Init(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } m_LastDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); m_CurrentDisplayCoordinate = m_LastDisplayCoordinate; positionEvent->GetSender()->DisplayToPlane(m_LastDisplayCoordinate, m_StartCoordinateInMM); m_LastCoordinateInMM = m_StartCoordinateInMM; } void mitk::DisplayActionEventBroadcast::Move(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } BaseRenderer* sender = interactionEvent->GetSender(); Vector2D moveVector = m_LastDisplayCoordinate - positionEvent->GetPointerPositionOnScreen(); if (m_InvertMoveDirection) { moveVector *= -1.0; } moveVector *= sender->GetScaleFactorMMPerDisplayUnit(); // #TODO: put here? // store new display coordinate m_LastDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); // propagate move event with computed geometry values InvokeEvent(DisplayMoveEvent(interactionEvent, moveVector)); } void mitk::DisplayActionEventBroadcast::SetCrosshair(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } Point3D position = positionEvent->GetPositionInWorld(); // propagate set crosshair event with computed geometry values InvokeEvent(DisplaySetCrosshairEvent(interactionEvent, position)); } void mitk::DisplayActionEventBroadcast::Zoom(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } float factor = 1.0; float distance = 0; if (m_ZoomDirection == "updown") { distance = m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1]; } else { distance = m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0]; } if (m_InvertZoomDirection) { distance *= -1.0; } // set zooming speed if (distance < 0.0) { factor = 1.0 / m_ZoomFactor; } else if (distance > 0.0) { factor = 1.0 * m_ZoomFactor; } // store new display coordinates m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); // propagate zoom event with computed geometry values InvokeEvent(DisplayZoomEvent(interactionEvent, factor, m_StartCoordinateInMM)); } void mitk::DisplayActionEventBroadcast::Scroll(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } int sliceDelta = 0; // scroll direction if (m_ScrollDirection == "updown") { sliceDelta = static_cast(m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1]); } else { sliceDelta = static_cast(m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0]); } if (m_InvertScrollDirection) { sliceDelta *= -1; } // set how many pixels the mouse has to be moved to scroll one slice // if the mouse has been moved less than 'm_IndexToSliceModifier', pixels slice ONE slice only if (sliceDelta > 0 && sliceDelta < m_IndexToSliceModifier) { sliceDelta = m_IndexToSliceModifier; } else if (sliceDelta < 0 && sliceDelta > -m_IndexToSliceModifier) { sliceDelta = -m_IndexToSliceModifier; } sliceDelta /= m_IndexToSliceModifier; // store new display coordinates m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); // propagate scroll event with computed geometry values InvokeEvent(DisplayScrollEvent(interactionEvent, sliceDelta)); } void mitk::DisplayActionEventBroadcast::ScrollOneUp(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { int sliceDelta = 1; if (m_InvertScrollDirection) { sliceDelta = -1; } // propagate scroll event with a single slice delta (increase) InvokeEvent(DisplayScrollEvent(interactionEvent, sliceDelta)); } void mitk::DisplayActionEventBroadcast::ScrollOneDown(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { int sliceDelta = -1; if (m_InvertScrollDirection) { sliceDelta = 1; } // propagate scroll event with a single slice delta (decrease) InvokeEvent(DisplayScrollEvent(interactionEvent, sliceDelta)); } void mitk::DisplayActionEventBroadcast::AdjustLevelWindow(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } - mitk::ScalarType level; - mitk::ScalarType window; + ScalarType level; + ScalarType window; if (m_LevelDirection == "leftright") { level = m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0]; window = m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1]; } else { level = m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1]; window = m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0]; } if (m_InvertLevelWindowDirection) { level *= -1; window *= -1; } level *= static_cast(2); window *= static_cast(2); // store new display coordinates m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); // propagate set level window event with the level and window delta InvokeEvent(DisplaySetLevelWindowEvent(interactionEvent, level, window)); } void mitk::DisplayActionEventBroadcast::StartRotation(StateMachineAction* /*stateMachineAction*/, InteractionEvent* /*interactionEvent*/) { // nothing here; no event sent } void mitk::DisplayActionEventBroadcast::EndRotation(StateMachineAction* /*stateMachineAction*/, InteractionEvent* /*interactionEvent*/) { // nothing here; no event sent } void mitk::DisplayActionEventBroadcast::Rotate(StateMachineAction* /*stateMachineAction*/, InteractionEvent* /*interactionEvent*/) { // nothing here; no event sent } void mitk::DisplayActionEventBroadcast::Swivel(StateMachineAction* /*stateMachineAction*/, InteractionEvent* /*interactionEvent*/) { // nothing here; no event sent } void mitk::DisplayActionEventBroadcast::UpdateStatusbar(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } - mitk::BaseRenderer::Pointer renderer = positionEvent->GetSender(); + BaseRenderer::Pointer renderer = positionEvent->GetSender(); - TNodePredicateDataType::Pointer isImageData = TNodePredicateDataType::New(); - mitk::DataStorage::SetOfObjects::ConstPointer nodes = renderer->GetDataStorage()->GetSubset(isImageData).GetPointer(); + TNodePredicateDataType::Pointer isImageData = TNodePredicateDataType::New(); + DataStorage::SetOfObjects::ConstPointer nodes = renderer->GetDataStorage()->GetSubset(isImageData).GetPointer(); if (nodes.IsNull()) { return; } Point3D worldposition; renderer->DisplayToWorld(positionEvent->GetPointerPositionOnScreen(), worldposition); - mitk::Image::Pointer image3D; - mitk::DataNode::Pointer node; - mitk::DataNode::Pointer topSourceNode; + Image::Pointer image3D; + DataNode::Pointer node; + DataNode::Pointer topSourceNode; int component = 0; node = renderer->GetDataStorage()->GetTopLayerNode(nodes, worldposition, renderer); if (node.IsNull()) { return; } bool isBinary(false); node->GetBoolProperty("binary", isBinary); if (isBinary) { - mitk::DataStorage::SetOfObjects::ConstPointer sourcenodes = renderer->GetDataStorage()->GetSources(node, nullptr, true); + DataStorage::SetOfObjects::ConstPointer sourcenodes = renderer->GetDataStorage()->GetSources(node, nullptr, true); if (!sourcenodes->empty()) { topSourceNode = renderer->GetDataStorage()->GetTopLayerNode(sourcenodes, worldposition, renderer); } if (topSourceNode.IsNotNull()) { - image3D = dynamic_cast(topSourceNode->GetData()); + image3D = dynamic_cast(topSourceNode->GetData()); topSourceNode->GetIntProperty("Image.Displayed Component", component); } else { - image3D = dynamic_cast(node->GetData()); + image3D = dynamic_cast(node->GetData()); node->GetIntProperty("Image.Displayed Component", component); } } else { - image3D = dynamic_cast(node->GetData()); + image3D = dynamic_cast(node->GetData()); node->GetIntProperty("Image.Displayed Component", component); } // get the position and pixel value from the image and build up status bar text - auto statusBar = mitk::StatusBar::GetInstance(); + auto statusBar = StatusBar::GetInstance(); if (image3D.IsNotNull() && statusBar != nullptr) { itk::Index<3> p; image3D->GetGeometry()->WorldToIndex(worldposition, p); auto pixelType = image3D->GetChannelDescriptor().GetPixelType().GetPixelType(); if (pixelType == itk::ImageIOBase::RGB || pixelType == itk::ImageIOBase::RGBA) { std::string pixelValue = "Pixel RGB(A) value: "; pixelValue.append(ConvertCompositePixelValueToString(image3D, p)); statusBar->DisplayImageInfo(worldposition, p, renderer->GetTime(), pixelValue.c_str()); } else if (pixelType == itk::ImageIOBase::DIFFUSIONTENSOR3D || pixelType == itk::ImageIOBase::SYMMETRICSECONDRANKTENSOR) { std::string pixelValue = "See ODF Details view. "; statusBar->DisplayImageInfo(worldposition, p, renderer->GetTime(), pixelValue.c_str()); } else { - mitk::ScalarType pixelValue; + ScalarType pixelValue; mitkPixelTypeMultiplex5( - mitk::FastSinglePixelAccess, + FastSinglePixelAccess, image3D->GetChannelDescriptor().GetPixelType(), image3D, image3D->GetVolumeData(renderer->GetTimeStep()), p, pixelValue, component); statusBar->DisplayImageInfo(worldposition, p, renderer->GetTime(), pixelValue); } } else { statusBar->DisplayImageInfoInvalid(); } } -bool mitk::DisplayActionEventBroadcast::GetBoolProperty(mitk::PropertyList::Pointer propertyList, const char* propertyName, bool defaultValue) +bool mitk::DisplayActionEventBroadcast::GetBoolProperty(PropertyList::Pointer propertyList, const char* propertyName, bool defaultValue) { std::string valueAsString; if (!propertyList->GetStringProperty(propertyName, valueAsString)) { return defaultValue; } else { if (valueAsString == "true") { return true; } else { return false; } } } diff --git a/Modules/Core/src/Interactions/mitkDisplayActionEventHandler.cpp b/Modules/Core/src/Interactions/mitkDisplayActionEventHandler.cpp index 084f995cd7..f28c3c6a99 100644 --- a/Modules/Core/src/Interactions/mitkDisplayActionEventHandler.cpp +++ b/Modules/Core/src/Interactions/mitkDisplayActionEventHandler.cpp @@ -1,75 +1,75 @@ /*=================================================================== 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 "mitkDisplayActionEventHandler.h" -void mitk::DisplayActionEventHandler::SetObservableBroadcast(mitk::DisplayActionEventBroadcast* observableBroadcast) +void mitk::DisplayActionEventHandler::SetObservableBroadcast(DisplayActionEventBroadcast* observableBroadcast) { if (m_ObservableBroadcast == observableBroadcast) { // no need to update the broadcast class return; } if (!m_ObservableBroadcast.IsExpired()) { auto observableBroadcastPtr = m_ObservableBroadcast.Lock(); // remove current observer for (const auto& tag : m_ObserverTags) { observableBroadcastPtr->RemoveObserver(tag); } m_ObserverTags.clear(); } // set new broadcast class m_ObservableBroadcast = observableBroadcast; } -mitk::DisplayActionEventHandler::OberserverTagType mitk::DisplayActionEventHandler::ConnectDisplayActionEvent(const mitk::DisplayActionEvent& displayActionEvent, - const mitk::StdFunctionCommand::ActionFunction& actionFunction, - const mitk::StdFunctionCommand::FilterFunction& filterFunction) +mitk::DisplayActionEventHandler::OberserverTagType mitk::DisplayActionEventHandler::ConnectDisplayActionEvent(const DisplayActionEvent& displayActionEvent, + const StdFunctionCommand::ActionFunction& actionFunction, + const StdFunctionCommand::FilterFunction& filterFunction) { if (m_ObservableBroadcast.IsExpired()) { mitkThrow() << "No display action event broadcast class set to observe. Use 'SetObservableBroadcast' before connecting events."; } auto observableBroadcast = m_ObservableBroadcast.Lock(); - auto command = mitk::StdFunctionCommand::New(); + auto command = StdFunctionCommand::New(); command->SetCommandAction(actionFunction); command->SetCommandFilter(filterFunction); OberserverTagType tag = observableBroadcast->AddObserver(displayActionEvent, command); m_ObserverTags.push_back(tag); return tag; } void mitk::DisplayActionEventHandler::DisconnectObserver(OberserverTagType observerTag) { if (m_ObservableBroadcast.IsExpired()) { mitkThrow() << "No display action event broadcast class set to observe. Use 'SetObservableBroadcast' before disconnecting observer."; } auto observableBroadcast = m_ObservableBroadcast.Lock(); std::vector::iterator observerTagPosition = std::find(m_ObserverTags.begin(), m_ObserverTags.end(), observerTag); if (observerTagPosition != m_ObserverTags.end()) { observableBroadcast->RemoveObserver(observerTag); m_ObserverTags.erase(observerTagPosition); } }