diff --git a/Modules/Core/include/mitkSliceNavigationController.h b/Modules/Core/include/mitkSliceNavigationController.h index 4b99ff8dfb..b0ce92b89f 100644 --- a/Modules/Core/include/mitkSliceNavigationController.h +++ b/Modules/Core/include/mitkSliceNavigationController.h @@ -1,558 +1,558 @@ /*=================================================================== 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 #include "mitkBaseController.h" #include "mitkRenderingManager.h" #include "mitkTimeGeometry.h" #include "mitkMessage.h" #pragma GCC visibility push(default) #include #pragma GCC visibility pop #include #include #include "mitkRestorePlanePositionOperation.h" #include "mitkDataStorage.h" //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 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 NULL, 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; /** * \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 NULL 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/mitkRenderingManager.cpp b/Modules/Core/src/Controllers/mitkRenderingManager.cpp index 198ec670bf..d885d15175 100644 --- a/Modules/Core/src/Controllers/mitkRenderingManager.cpp +++ b/Modules/Core/src/Controllers/mitkRenderingManager.cpp @@ -1,834 +1,834 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkRenderingManager.h" #include "mitkRenderingManagerFactory.h" #include "mitkBaseRenderer.h" #include "mitkNodePredicateNot.h" #include "mitkNodePredicateProperty.h" #include "mitkProportionalTimeGeometry.h" #include "mitkCameraController.h" #include #include #include "mitkNumericTypes.h" #include #include #include #include namespace mitk { RenderingManager::Pointer RenderingManager::s_Instance = 0; RenderingManagerFactory *RenderingManager::s_RenderingManagerFactory = 0; RenderingManager ::RenderingManager() : m_UpdatePending(false), m_MaxLOD(1), m_LODIncreaseBlocked(false), m_LODAbortMechanismEnabled(false), m_ClippingPlaneEnabled(false), m_TimeNavigationController(SliceNavigationController::New()), m_DataStorage(NULL), m_ConstrainedPanningZooming(true), m_FocusedRenderWindow(nullptr) { m_ShadingEnabled.assign(3, false); m_ShadingValues.assign(4, 0.0); InitializePropertyList(); } RenderingManager ::~RenderingManager() { // Decrease reference counts of all registered vtkRenderWindows for // proper destruction RenderWindowVector::iterator it; for (it = m_AllRenderWindows.begin(); it != m_AllRenderWindows.end(); ++it) { (*it)->UnRegister(NULL); RenderWindowCallbacksList::iterator callbacks_it = this->m_RenderWindowCallbacksList.find(*it); if (callbacks_it != this->m_RenderWindowCallbacksList.end()) { (*it)->RemoveObserver(callbacks_it->second.commands[0u]); (*it)->RemoveObserver(callbacks_it->second.commands[1u]); (*it)->RemoveObserver(callbacks_it->second.commands[2u]); } } } void RenderingManager ::SetFactory(RenderingManagerFactory *factory) { s_RenderingManagerFactory = factory; } const RenderingManagerFactory * RenderingManager ::GetFactory() { return s_RenderingManagerFactory; } bool RenderingManager ::HasFactory() { if (RenderingManager::s_RenderingManagerFactory) { return true; } else { return false; } } RenderingManager::Pointer RenderingManager ::New() { const RenderingManagerFactory* factory = GetFactory(); if (factory == NULL) return NULL; return factory->CreateRenderingManager(); } RenderingManager * RenderingManager ::GetInstance() { if (!RenderingManager::s_Instance) { if (s_RenderingManagerFactory) { s_Instance = s_RenderingManagerFactory->CreateRenderingManager(); } } return s_Instance; } bool RenderingManager ::IsInstantiated() { if (RenderingManager::s_Instance) return true; else return false; } void RenderingManager ::AddRenderWindow(vtkRenderWindow *renderWindow) { if (renderWindow && (m_RenderWindowList.find(renderWindow) == m_RenderWindowList.end())) { m_RenderWindowList[renderWindow] = RENDERING_INACTIVE; m_AllRenderWindows.push_back(renderWindow); if (m_DataStorage.IsNotNull()) mitk::BaseRenderer::GetInstance(renderWindow)->SetDataStorage(m_DataStorage.GetPointer()); // Register vtkRenderWindow instance renderWindow->Register(NULL); // Add callbacks for rendering abort mechanism //BaseRenderer *renderer = BaseRenderer::GetInstance( renderWindow ); vtkCallbackCommand *startCallbackCommand = vtkCallbackCommand::New(); startCallbackCommand->SetCallback( RenderingManager::RenderingStartCallback); renderWindow->AddObserver(vtkCommand::StartEvent, startCallbackCommand); vtkCallbackCommand *progressCallbackCommand = vtkCallbackCommand::New(); progressCallbackCommand->SetCallback( RenderingManager::RenderingProgressCallback); renderWindow->AddObserver(vtkCommand::AbortCheckEvent, progressCallbackCommand); vtkCallbackCommand *endCallbackCommand = vtkCallbackCommand::New(); endCallbackCommand->SetCallback( RenderingManager::RenderingEndCallback); renderWindow->AddObserver(vtkCommand::EndEvent, endCallbackCommand); RenderWindowCallbacks callbacks; callbacks.commands[0u] = startCallbackCommand; callbacks.commands[1u] = progressCallbackCommand; callbacks.commands[2u] = endCallbackCommand; this->m_RenderWindowCallbacksList[renderWindow] = callbacks; //Delete vtk variables correctly startCallbackCommand->Delete(); progressCallbackCommand->Delete(); endCallbackCommand->Delete(); } } void RenderingManager ::RemoveRenderWindow(vtkRenderWindow *renderWindow) { if (m_RenderWindowList.erase(renderWindow)) { - RenderWindowCallbacksList::iterator callbacks_it = this->m_RenderWindowCallbacksList.find(renderWindow); - if (callbacks_it != this->m_RenderWindowCallbacksList.end()) + RenderWindowCallbacksList::const_iterator callbacks_it = this->m_RenderWindowCallbacksList.find(renderWindow); + if (callbacks_it != this->m_RenderWindowCallbacksList.cend()) { renderWindow->RemoveObserver(callbacks_it->second.commands[0u]); renderWindow->RemoveObserver(callbacks_it->second.commands[1u]); renderWindow->RemoveObserver(callbacks_it->second.commands[2u]); this->m_RenderWindowCallbacksList.erase(callbacks_it); } - RenderWindowVector::iterator rw_it = std::find(m_AllRenderWindows.begin(), m_AllRenderWindows.end(), renderWindow); + RenderWindowVector::const_iterator rw_it = std::find(m_AllRenderWindows.cbegin(), m_AllRenderWindows.cend(), renderWindow); - if (rw_it != m_AllRenderWindows.end()) + if (rw_it != m_AllRenderWindows.cend()) { // Decrease reference count for proper destruction (*rw_it)->UnRegister(NULL); m_AllRenderWindows.erase(rw_it); } } } const RenderingManager::RenderWindowVector& RenderingManager ::GetAllRegisteredRenderWindows() { return m_AllRenderWindows; } void RenderingManager ::RequestUpdate(vtkRenderWindow *renderWindow) { // If the renderWindow is not valid, we do not want to inadvertantly create // an entry in the m_RenderWindowList map. It is possible if the user is // regularly calling AddRenderer and RemoveRenderer for a rendering update // to come into this method with a renderWindow pointer that is valid in the // sense that the window does exist within the application, but that // renderWindow has been temporarily removed from this RenderingManager for // performance reasons. - if (m_RenderWindowList.find(renderWindow) == m_RenderWindowList.end()) + if (m_RenderWindowList.find(renderWindow) == m_RenderWindowList.cend()) { return; } m_RenderWindowList[renderWindow] = RENDERING_REQUESTED; if (!m_UpdatePending) { m_UpdatePending = true; this->GenerateRenderingRequestEvent(); } } void RenderingManager ::ForceImmediateUpdate(vtkRenderWindow *renderWindow) { // If the renderWindow is not valid, we do not want to inadvertantly create // an entry in the m_RenderWindowList map. It is possible if the user is // regularly calling AddRenderer and RemoveRenderer for a rendering update // to come into this method with a renderWindow pointer that is valid in the // sense that the window does exist within the application, but that // renderWindow has been temporarily removed from this RenderingManager for // performance reasons. - if (m_RenderWindowList.find(renderWindow) == m_RenderWindowList.end()) + if (m_RenderWindowList.find(renderWindow) == m_RenderWindowList.cend()) { return; } // Erase potentially pending requests for this window m_RenderWindowList[renderWindow] = RENDERING_INACTIVE; m_UpdatePending = false; // Immediately repaint this window (implementation platform specific) - // If the size is 0 it crahses + // If the size is 0 it crashes int *size = renderWindow->GetSize(); if (0 != size[0] && 0 != size[1]) { //prepare the camera etc. before rendering //Note: this is a very important step which should be called before the VTK render! //If you modify the camera anywhere else or after the render call, the scene cannot be seen. mitk::VtkPropRenderer *vPR = dynamic_cast(mitk::BaseRenderer::GetInstance(renderWindow)); if (vPR) vPR->PrepareRender(); // Execute rendering renderWindow->Render(); } } void RenderingManager ::RequestUpdateAll(RequestType type) { - RenderWindowList::iterator it; - for (it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it) + RenderWindowList::const_iterator it; + for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { int id = BaseRenderer::GetInstance(it->first)->GetMapperID(); if ((type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2))) { this->RequestUpdate(it->first); } } } void RenderingManager ::ForceImmediateUpdateAll(RequestType type) { - RenderWindowList::iterator it; - for (it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it) + RenderWindowList::const_iterator it; + for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { int id = BaseRenderer::GetInstance(it->first)->GetMapperID(); if ((type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2))) { // Immediately repaint this window (implementation platform specific) // If the size is 0, it crashes this->ForceImmediateUpdate(it->first); } } } void RenderingManager::InitializeViewsByBoundingObjects(const DataStorage *ds) { if (!ds) return; // get all nodes that have not set "includeInBoundingBox" to false mitk::NodePredicateNot::Pointer pred = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("includeInBoundingBox" , mitk::BoolProperty::New(false))); mitk::DataStorage::SetOfObjects::ConstPointer rs = ds->GetSubset(pred); // calculate bounding geometry of these nodes mitk::TimeGeometry::Pointer bounds = ds->ComputeBoundingGeometry3D(rs, "visible"); // initialize the views to the bounding geometry this->InitializeViews(bounds); } //TODO_GOETZ // Remove old function, so only this one is working. bool RenderingManager ::InitializeViews(const BaseGeometry * dataGeometry, RequestType type, bool preserveRoughOrientationInWorldSpace) { ProportionalTimeGeometry::Pointer propTimeGeometry = ProportionalTimeGeometry::New(); propTimeGeometry->Initialize(dynamic_cast(dataGeometry->Clone().GetPointer()), 1); return InitializeViews(propTimeGeometry, type, preserveRoughOrientationInWorldSpace); } bool RenderingManager ::InitializeViews(const TimeGeometry * dataGeometry, RequestType type, bool /*preserveRoughOrientationInWorldSpace*/) { MITK_DEBUG << "initializing views"; bool boundingBoxInitialized = false; TimeGeometry::ConstPointer timeGeometry = dataGeometry; TimeGeometry::Pointer modifiedGeometry = NULL; if (dataGeometry != NULL) { modifiedGeometry = dataGeometry->Clone(); } int warningLevel = vtkObject::GetGlobalWarningDisplay(); vtkObject::GlobalWarningDisplayOff(); if ((timeGeometry.IsNotNull()) && (const_cast( timeGeometry->GetBoundingBoxInWorld())->GetDiagonalLength2() > mitk::eps)) { boundingBoxInitialized = true; } if (timeGeometry.IsNotNull()) {// make sure bounding box has an extent bigger than zero in any direction // clone the input geometry //Old Geometry3D::Pointer modifiedGeometry = dynamic_cast( dataGeometry->Clone().GetPointer() ); assert(modifiedGeometry.IsNotNull()); for (TimeStepType step = 0; step < modifiedGeometry->CountTimeSteps(); ++step) { BaseGeometry::BoundsArrayType newBounds = modifiedGeometry->GetGeometryForTimeStep(step)->GetBounds(); for (unsigned int dimension = 0; (2 * dimension) < newBounds.Size(); dimension++) { //check for equality but for an epsilon if (Equal(newBounds[2 * dimension], newBounds[2 * dimension + 1])) { newBounds[2 * dimension + 1] += 1; if( Equal( newBounds[ 2 * dimension ], newBounds[ 2 * dimension + 1 ] ) ) // newBounds will still be equal if values are beyond double precision { mitkThrow()<< "One dimension of object data has zero length, please make sure you're not using numbers beyond double precision as coordinates."; } } } modifiedGeometry->GetGeometryForTimeStep(step)->SetBounds(newBounds); } } timeGeometry = modifiedGeometry; - RenderWindowList::iterator it; - for (it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it) + RenderWindowList::const_iterator it; + for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance(it->first); baseRenderer->SetConstrainZoomingAndPanning(m_ConstrainedPanningZooming); int id = baseRenderer->GetMapperID(); if (((type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2))) ) { this->InternalViewInitialization(baseRenderer, timeGeometry, boundingBoxInitialized, id); } } if (boundingBoxInitialized) { m_TimeNavigationController->SetInputWorldTimeGeometry(timeGeometry); } m_TimeNavigationController->Update(); this->RequestUpdateAll(type); vtkObject::SetGlobalWarningDisplay(warningLevel); // Inform listeners that views have been initialized this->InvokeEvent(mitk::RenderingManagerViewsInitializedEvent()); return boundingBoxInitialized; } bool RenderingManager ::InitializeViews(RequestType type) { - RenderWindowList::iterator it; - for (it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it) + RenderWindowList::const_iterator it; + for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance(it->first); int id = baseRenderer->GetMapperID(); if ((type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2))) { mitk::SliceNavigationController *nc = baseRenderer->GetSliceNavigationController(); // Re-initialize view direction nc->SetViewDirectionToDefault(); // Update the SNC nc->Update(); } } this->RequestUpdateAll(type); return true; } bool RenderingManager::InitializeView(vtkRenderWindow * renderWindow, const BaseGeometry * geometry, bool initializeGlobalTimeSNC) { ProportionalTimeGeometry::Pointer propTimeGeometry = ProportionalTimeGeometry::New(); propTimeGeometry->Initialize(dynamic_cast(geometry->Clone().GetPointer()), 1); return InitializeView(renderWindow, propTimeGeometry, initializeGlobalTimeSNC); } bool RenderingManager::InitializeView(vtkRenderWindow * renderWindow, const TimeGeometry * geometry, bool initializeGlobalTimeSNC) { bool boundingBoxInitialized = false; int warningLevel = vtkObject::GetGlobalWarningDisplay(); vtkObject::GlobalWarningDisplayOff(); if ((geometry != NULL) && (const_cast( geometry->GetBoundingBoxInWorld())->GetDiagonalLength2() > mitk::eps)) { boundingBoxInitialized = true; } mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance(renderWindow); int id = baseRenderer->GetMapperID(); this->InternalViewInitialization(baseRenderer, geometry, boundingBoxInitialized, id); if (boundingBoxInitialized && initializeGlobalTimeSNC) { m_TimeNavigationController->SetInputWorldTimeGeometry(geometry); } m_TimeNavigationController->Update(); this->RequestUpdate(renderWindow); vtkObject::SetGlobalWarningDisplay(warningLevel); return boundingBoxInitialized; } bool RenderingManager::InitializeView(vtkRenderWindow * renderWindow) { mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance(renderWindow); mitk::SliceNavigationController *nc = baseRenderer->GetSliceNavigationController(); // Re-initialize view direction nc->SetViewDirectionToDefault(); // Update the SNC nc->Update(); this->RequestUpdate(renderWindow); return true; } void RenderingManager::InternalViewInitialization(mitk::BaseRenderer *baseRenderer, const mitk::TimeGeometry *geometry, bool boundingBoxInitialized, int mapperID) { mitk::SliceNavigationController *nc = baseRenderer->GetSliceNavigationController(); // Re-initialize view direction nc->SetViewDirectionToDefault(); if (boundingBoxInitialized) { // Set geometry for NC nc->SetInputWorldTimeGeometry(geometry); nc->Update(); if (mapperID == BaseRenderer::Standard2D) { // For 2D SNCs, steppers are set so that the cross is centered // in the image nc->GetSlice()->SetPos(nc->GetSlice()->GetSteps() / 2); } baseRenderer->GetCameraController()->SetViewToAnterior(); baseRenderer->GetCameraController()->Fit(); } else { nc->Update(); } } const SliceNavigationController* RenderingManager::GetTimeNavigationController() const { return m_TimeNavigationController.GetPointer(); } SliceNavigationController* RenderingManager::GetTimeNavigationController() { return m_TimeNavigationController.GetPointer(); } void RenderingManager::ExecutePendingRequests() { m_UpdatePending = false; // Satisfy all pending update requests - RenderWindowList::iterator it; + RenderWindowList::const_iterator it; int i = 0; - for (it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it, ++i) + for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it, ++i) { if (it->second == RENDERING_REQUESTED) { this->ForceImmediateUpdate(it->first); } } } void RenderingManager::RenderingStartCallback(vtkObject *caller, unsigned long, void *, void *) { vtkRenderWindow *renderWindow = dynamic_cast(caller); mitk::RenderingManager* renman = mitk::BaseRenderer::GetInstance(renderWindow)->GetRenderingManager(); RenderWindowList &renderWindowList = renman->m_RenderWindowList; if (renderWindow) { renderWindowList[renderWindow] = RENDERING_INPROGRESS; } renman->m_UpdatePending = false; } void RenderingManager ::RenderingProgressCallback(vtkObject *caller, unsigned long, void *, void *) { vtkRenderWindow *renderWindow = dynamic_cast(caller); mitk::RenderingManager* renman = mitk::BaseRenderer::GetInstance(renderWindow)->GetRenderingManager(); if (renman->m_LODAbortMechanismEnabled) { vtkRenderWindow *renderWindow = dynamic_cast(caller); if (renderWindow) { BaseRenderer *renderer = BaseRenderer::GetInstance(renderWindow); if (renderer && (renderer->GetNumberOfVisibleLODEnabledMappers() > 0)) { renman->DoMonitorRendering(); } } } } void RenderingManager ::RenderingEndCallback(vtkObject *caller, unsigned long, void *, void *) { vtkRenderWindow *renderWindow = dynamic_cast(caller); mitk::RenderingManager* renman = mitk::BaseRenderer::GetInstance(renderWindow)->GetRenderingManager(); RenderWindowList &renderWindowList = renman->m_RenderWindowList; RendererIntMap &nextLODMap = renman->m_NextLODMap; if (renderWindow) { BaseRenderer *renderer = BaseRenderer::GetInstance(renderWindow); if (renderer) { renderWindowList[renderer->GetRenderWindow()] = RENDERING_INACTIVE; // Level-of-Detail handling if (renderer->GetNumberOfVisibleLODEnabledMappers() > 0) { if (nextLODMap[renderer] == 0) renman->StartOrResetTimer(); else nextLODMap[renderer] = 0; } } } } bool RenderingManager ::IsRendering() const { RenderWindowList::const_iterator it; - for (it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it) + for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { if (it->second == RENDERING_INPROGRESS) { return true; } } return false; } void RenderingManager ::AbortRendering() { - RenderWindowList::iterator it; - for (it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it) + RenderWindowList::const_iterator it; + for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { if (it->second == RENDERING_INPROGRESS) { it->first->SetAbortRender(true); m_RenderingAbortedMap[BaseRenderer::GetInstance(it->first)] = true; } } } int RenderingManager ::GetNextLOD(BaseRenderer *renderer) { if (renderer != NULL) { return m_NextLODMap[renderer]; } else { return 0; } } void RenderingManager ::ExecutePendingHighResRenderingRequest() { - RenderWindowList::iterator it; - for (it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it) + RenderWindowList::const_iterator it; + for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { BaseRenderer *renderer = BaseRenderer::GetInstance(it->first); if (renderer->GetNumberOfVisibleLODEnabledMappers() > 0) { if (m_NextLODMap[renderer] == 0) { m_NextLODMap[renderer] = 1; RequestUpdate(it->first); } } } } void RenderingManager ::SetMaximumLOD(unsigned int max) { m_MaxLOD = max; } //enable/disable shading void RenderingManager ::SetShading(bool state, unsigned int lod) { if (lod > m_MaxLOD) { itkWarningMacro(<< "LOD out of range requested: " << lod << " maxLOD: " << m_MaxLOD); return; } m_ShadingEnabled[lod] = state; } bool RenderingManager ::GetShading(unsigned int lod) { if (lod > m_MaxLOD) { itkWarningMacro(<< "LOD out of range requested: " << lod << " maxLOD: " << m_MaxLOD); return false; } return m_ShadingEnabled[lod]; } //enable/disable the clipping plane void RenderingManager ::SetClippingPlaneStatus(bool status) { m_ClippingPlaneEnabled = status; } bool RenderingManager ::GetClippingPlaneStatus() { return m_ClippingPlaneEnabled; } void RenderingManager ::SetShadingValues(float ambient, float diffuse, float specular, float specpower) { m_ShadingValues[0] = ambient; m_ShadingValues[1] = diffuse; m_ShadingValues[2] = specular; m_ShadingValues[3] = specpower; } RenderingManager::FloatVector & RenderingManager ::GetShadingValues() { return m_ShadingValues; } void RenderingManager::InitializePropertyList() { if (m_PropertyList.IsNull()) { m_PropertyList = PropertyList::New(); } this->SetProperty("coupled-zoom", BoolProperty::New(false)); this->SetProperty("coupled-plane-rotation", BoolProperty::New(false)); this->SetProperty("MIP-slice-rendering", BoolProperty::New(false)); } PropertyList::Pointer RenderingManager::GetPropertyList() const { return m_PropertyList; } BaseProperty* RenderingManager::GetProperty(const char *propertyKey) const { return m_PropertyList->GetProperty(propertyKey); } void RenderingManager::SetProperty(const char *propertyKey, BaseProperty* propertyValue) { m_PropertyList->SetProperty(propertyKey, propertyValue); } void RenderingManager::SetDataStorage(DataStorage* storage) { if (storage != NULL) { m_DataStorage = storage; - RenderingManager::RenderWindowVector::iterator iter; - for (iter = m_AllRenderWindows.begin(); iter < m_AllRenderWindows.end(); iter++) + RenderingManager::RenderWindowVector::const_iterator iter; + for (iter = m_AllRenderWindows.cbegin(); iter < m_AllRenderWindows.cend(); iter++) { mitk::BaseRenderer::GetInstance((*iter))->SetDataStorage(m_DataStorage.GetPointer()); } } } mitk::DataStorage* RenderingManager::GetDataStorage() { return m_DataStorage; } void RenderingManager::SetRenderWindowFocus(vtkRenderWindow *focusWindow) { - if (!focusWindow || (m_RenderWindowList.find(focusWindow) != m_RenderWindowList.end())) + if (!focusWindow || (m_RenderWindowList.find(focusWindow) != m_RenderWindowList.cend())) { m_FocusedRenderWindow = focusWindow; return; } MITK_ERROR << "Tried to set a RenderWindow that does not exist."; } // Create and register generic RenderingManagerFactory. TestingRenderingManagerFactory renderingManagerFactory; } // namespace diff --git a/Modules/Core/src/Controllers/mitkSliceNavigationController.cpp b/Modules/Core/src/Controllers/mitkSliceNavigationController.cpp index 13a00e01e3..98ebcad7f0 100644 --- a/Modules/Core/src/Controllers/mitkSliceNavigationController.cpp +++ b/Modules/Core/src/Controllers/mitkSliceNavigationController.cpp @@ -1,699 +1,701 @@ /*=================================================================== 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 "mitkBaseRenderer.h" #include "mitkSlicedGeometry3D.h" #include "mitkPlaneGeometry.h" #include "mitkOperation.h" #include "mitkOperationActor.h" #include "mitkCrosshairPositionEvent.h" #include "mitkProportionalTimeGeometry.h" #include "mitkInteractionConst.h" #include "mitkAction.h" #include "mitkVtkPropRenderer.h" #include "mitkRenderingManager.h" #include "mitkInteractionConst.h" #include "mitkPointOperation.h" #include "mitkPlaneOperation.h" #include "mitkUndoController.h" #include "mitkOperationEvent.h" #include "mitkNodePredicateDataType.h" #include "mitkStatusBar.h" #include "mitkImage.h" #include "mitkPixelTypeMultiplex.h" #include "mitkImagePixelReadAccessor.h" #include "mitkApplyTransformMatrixOperation.h" #include "mitkMemoryUtilities.h" #include namespace mitk { SliceNavigationController::SliceNavigationController( ) : BaseController(), m_InputWorldGeometry3D( NULL ), m_InputWorldTimeGeometry( NULL ), m_CreatedWorldGeometry( NULL ), m_ViewDirection( Axial ), m_DefaultViewDirection( Axial ), m_RenderingManager( NULL ), m_Renderer( NULL ), m_Top( false ), m_FrontSide( false ), m_Rotated( false ), m_BlockUpdate( false ), m_SliceLocked( false ), m_SliceRotationLocked( false ), m_OldPos(0) { typedef itk::SimpleMemberCommand< SliceNavigationController > 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 != NULL ) { if ( const_cast< BoundingBox * >( geometry->GetBoundingBox()) ->GetDiagonalLength2() < eps ) { itkWarningMacro( "setting an empty bounding-box" ); geometry = NULL; } } if ( m_InputWorldGeometry3D != geometry ) { m_InputWorldGeometry3D = geometry; m_InputWorldTimeGeometry = NULL; this->Modified(); } } void SliceNavigationController::SetInputWorldTimeGeometry( const TimeGeometry *geometry ) { if ( geometry != NULL ) { if ( const_cast< BoundingBox * >( geometry->GetBoundingBoxInWorld()) ->GetDiagonalLength2() < eps ) { itkWarningMacro( "setting an empty bounding-box" ); geometry = NULL; } } if ( m_InputWorldTimeGeometry != geometry ) { m_InputWorldTimeGeometry = geometry; m_InputWorldGeometry3D = NULL; this->Modified(); } } RenderingManager * SliceNavigationController::GetRenderingManager() const { mitk::RenderingManager* renderingManager = m_RenderingManager.GetPointer(); if (renderingManager != NULL) return renderingManager; if ( m_Renderer != NULL ) { renderingManager = m_Renderer->GetRenderingManager(); if (renderingManager != NULL) return renderingManager; } return mitk::RenderingManager::GetInstance(); } void SliceNavigationController::SetViewDirectionToDefault() { m_ViewDirection = m_DefaultViewDirection; } -const char* SliceNavigationController::GetViewDirectionAsString() +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 == 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 = NULL; BaseGeometry::ConstPointer currentGeometry = NULL; 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 = NULL; switch ( viewDirection ) { case Original: if ( worldTimeGeometry.IsNotNull()) { m_CreatedWorldGeometry = worldTimeGeometry->Clone(); worldTimeGeometry = m_CreatedWorldGeometry.GetPointer(); slicedWorldGeometry = dynamic_cast< SlicedGeometry3D * >( m_CreatedWorldGeometry->GetGeometryForTimeStep( this->GetTime()->GetPos() ).GetPointer() ); if ( slicedWorldGeometry.IsNotNull() ) { break; } } else { const SlicedGeometry3D *worldSlicedGeometry = dynamic_cast< const SlicedGeometry3D * >( currentGeometry.GetPointer()); if ( worldSlicedGeometry != NULL ) { slicedWorldGeometry = static_cast< SlicedGeometry3D * >( 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 ( m_CreatedWorldGeometry.IsNull() ) { // initialize TimeGeometry m_CreatedWorldGeometry = ProportionalTimeGeometry::New(); } if ( worldTimeGeometry.IsNull()) { m_CreatedWorldGeometry = ProportionalTimeGeometry::New(); dynamic_cast(m_CreatedWorldGeometry.GetPointer())->Initialize(slicedWorldGeometry, 1); 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; assert( worldTimeGeometry->GetGeometryForTimeStep( this->GetTime()->GetPos() ).IsNotNull() ); TimePointType minimumTimePoint = worldTimeGeometry->TimeStepToTimePoint(this->GetTime()->GetPos()); TimePointType stepDuration = worldTimeGeometry->TimeStepToTimePoint(this->GetTime()->GetPos()+1)-worldTimeGeometry->TimeStepToTimePoint(this->GetTime()->GetPos()); //@todo implement for non-evenly-timed geometry! m_CreatedWorldGeometry = ProportionalTimeGeometry::New(); dynamic_cast(m_CreatedWorldGeometry.GetPointer())->Initialize(slicedWorldGeometry, worldTimeGeometry->CountTimeSteps()); dynamic_cast(m_CreatedWorldGeometry.GetPointer())->GetMinimumTimePoint(minimumTimePoint); dynamic_cast(m_CreatedWorldGeometry.GetPointer())->SetStepDuration(stepDuration); } } // 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(); // 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 SliceNavigationController::GeometryTimeEvent *timeEvent = dynamic_cast< const SliceNavigationController::GeometryTimeEvent * >( &geometryTimeEvent); assert( timeEvent != NULL ); TimeGeometry *timeGeometry = timeEvent->GetTimeGeometry(); assert( timeGeometry != NULL ); int 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 SliceNavigationController::GeometrySliceEvent* sliceEvent = dynamic_cast( &geometrySliceEvent); assert(sliceEvent!=NULL); 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< SlicedGeometry3D * >( 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 defualt 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 ); 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(); } } 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 NULL; } } const mitk::PlaneGeometry * SliceNavigationController::GetCurrentPlaneGeometry() { const mitk::SlicedGeometry3D *slicedGeometry = dynamic_cast< const mitk::SlicedGeometry3D * > ( this->GetCurrentGeometry3D() ); if ( slicedGeometry ) { const mitk::PlaneGeometry *planeGeometry = ( slicedGeometry->GetPlaneGeometry(this->GetSlice()->GetPos()) ); return planeGeometry; } else { return NULL; } } void SliceNavigationController::SetRenderer( BaseRenderer *renderer ) { m_Renderer = renderer; } BaseRenderer * SliceNavigationController::GetRenderer() const { return m_Renderer; } void SliceNavigationController::AdjustSliceStepperRange() { const mitk::SlicedGeometry3D *slicedGeometry = dynamic_cast< const mitk::SlicedGeometry3D * > ( 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 PointOperation *po = dynamic_cast< PointOperation * >( 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/mitkDispatcher.cpp b/Modules/Core/src/Interactions/mitkDispatcher.cpp index 39ee1754e1..b41f325e8d 100644 --- a/Modules/Core/src/Interactions/mitkDispatcher.cpp +++ b/Modules/Core/src/Interactions/mitkDispatcher.cpp @@ -1,253 +1,253 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDispatcher.h" #include "mitkInteractionEvent.h" #include "mitkInternalEvent.h" // MicroServices #include "usGetModuleContext.h" #include "mitkInteractionEventObserver.h" mitk::Dispatcher::Dispatcher( const std::string& rendererName ) : m_ProcessingMode(REGULAR) { // LDAP filter string to find all listeners specific for the renderer // corresponding to this dispatcher std::string specificRenderer = "(rendererName=" + rendererName +")"; // LDAP filter string to find all listeners that are not specific // to any renderer std::string anyRenderer = "(!(rendererName=*))"; // LDAP filter string to find only instances of InteractionEventObserver std::string classInteractionEventObserver = "(" + us::ServiceConstants::OBJECTCLASS() + "=" + us_service_interface_iid() + ")"; // Configure the LDAP filter to find all instances of InteractionEventObserver // that are specific to this dispatcher or unspecific to any dispatchers (real global listener) us::LDAPFilter filter( "(&(|"+ specificRenderer + anyRenderer + ")"+classInteractionEventObserver+")" ); // Give the filter to the ObserverTracker m_EventObserverTracker = new us::ServiceTracker(us::GetModuleContext(), filter); m_EventObserverTracker->Open(); } void mitk::Dispatcher::AddDataInteractor(const DataNode* dataNode) { RemoveDataInteractor(dataNode); RemoveOrphanedInteractors(); DataInteractor::Pointer dataInteractor = dataNode->GetDataInteractor(); if (dataInteractor.IsNotNull()) { m_Interactors.push_back(dataInteractor); } } /* * Note: One DataInteractor can only have one DataNode and vice versa, * BUT the m_Interactors list may contain another DataInteractor that is still connected to this DataNode, * in this case we have to remove >1 DataInteractor. (Some special case of switching DataNodes between DataInteractors and registering a * DataNode to a DataStorage after assigning it to an DataInteractor) */ void mitk::Dispatcher::RemoveDataInteractor(const DataNode* dataNode) { for (ListInteractorType::iterator it = m_Interactors.begin(); it != m_Interactors.end();) { if ((*it)->GetDataNode() == dataNode) { it = m_Interactors.erase(it); } else { ++it; } } } size_t mitk::Dispatcher::GetNumberOfInteractors() { return m_Interactors.size(); } mitk::Dispatcher::~Dispatcher() { m_EventObserverTracker->Close(); delete m_EventObserverTracker; m_Interactors.clear(); } bool mitk::Dispatcher::ProcessEvent(InteractionEvent* event) { InteractionEvent::Pointer p = event; bool eventIsHandled = false; /* Filter out and handle Internal Events separately */ InternalEvent* internalEvent = dynamic_cast(event); if (internalEvent != NULL) { eventIsHandled = HandleInternalEvent(internalEvent); // InternalEvents that are handled are not sent to the listeners if (eventIsHandled) { return true; } } switch (m_ProcessingMode) { case CONNECTEDMOUSEACTION: // finished connected mouse action if (std::strcmp(p->GetNameOfClass(), "MouseReleaseEvent") == 0) { m_ProcessingMode = REGULAR; eventIsHandled = m_SelectedInteractor->HandleEvent(event, m_SelectedInteractor->GetDataNode()); // delete reference to interactor as soon as connected action is finished m_SelectedInteractor = NULL; } // give event to selected interactor if (eventIsHandled == false && m_SelectedInteractor.IsNotNull()) { eventIsHandled = m_SelectedInteractor->HandleEvent(event, m_SelectedInteractor->GetDataNode()); } break; case GRABINPUT: eventIsHandled = m_SelectedInteractor->HandleEvent(event, m_SelectedInteractor->GetDataNode()); SetEventProcessingMode(m_SelectedInteractor); break; case PREFERINPUT: if (m_SelectedInteractor->HandleEvent(event, m_SelectedInteractor->GetDataNode()) == true) { SetEventProcessingMode(m_SelectedInteractor); eventIsHandled = true; } break; case REGULAR: break; } // Standard behavior. Is executed in STANDARD mode and PREFERINPUT mode, if preferred interactor rejects event. if (m_ProcessingMode == REGULAR || (m_ProcessingMode == PREFERINPUT && eventIsHandled == false)) { if (std::strcmp(p->GetNameOfClass(), "MousePressEvent") == 0) event->GetSender()->GetRenderingManager()->SetRenderWindowFocus(event->GetSender()->GetRenderWindow()); m_Interactors.sort(cmp()); // sorts interactors by layer (descending); // copy the list to prevent iterator invalidation as executing actions // in HandleEvent() can cause the m_Interactors list to be updated - std::list tmpInteractorList( m_Interactors ); - std::list::iterator it; - for ( it=tmpInteractorList.begin(); it!=tmpInteractorList.end(); ++it ) + const std::list tmpInteractorList( m_Interactors ); + std::list::const_iterator it; + for ( it=tmpInteractorList.cbegin(); it!=tmpInteractorList.cend(); ++it ) { DataInteractor::Pointer dataInteractor = *it; if ( (*it)->HandleEvent(event, dataInteractor->GetDataNode()) ) { // if an event is handled several properties are checked, in order to determine the processing mode of the dispatcher SetEventProcessingMode(dataInteractor); if (std::strcmp(p->GetNameOfClass(), "MousePressEvent") == 0 && m_ProcessingMode == REGULAR) { m_SelectedInteractor = dataInteractor; m_ProcessingMode = CONNECTEDMOUSEACTION; } eventIsHandled = true; break; } } } /* Notify InteractionEventObserver */ - std::vector > listEventObserver = + const std::vector > listEventObserver = m_EventObserverTracker->GetServiceReferences(); - for (std::vector >::iterator it = listEventObserver.begin(); - it != listEventObserver.end(); ++it) + for (std::vector >::const_iterator it = listEventObserver.cbegin(); + it != listEventObserver.cend(); ++it) { InteractionEventObserver* interactionEventObserver = m_EventObserverTracker->GetService(*it); if (interactionEventObserver != NULL) { if (interactionEventObserver->IsEnabled()) { interactionEventObserver->Notify(event, eventIsHandled); } } } // Process event queue if (!m_QueuedEvents.empty()) { InteractionEvent::Pointer e = m_QueuedEvents.front(); m_QueuedEvents.pop_front(); ProcessEvent(e); } return eventIsHandled; } /* * Checks if DataNodes associated with DataInteractors point back to them. * If not remove the DataInteractors. (This can happen when s.o. tries to set DataNodes to multiple DataInteractors) */ void mitk::Dispatcher::RemoveOrphanedInteractors() { for (ListInteractorType::iterator it = m_Interactors.begin(); it != m_Interactors.end();) { DataNode::Pointer dn = (*it)->GetDataNode(); if (dn.IsNull()) { it = m_Interactors.erase(it); } else { DataInteractor::Pointer interactor = dn->GetDataInteractor(); if (interactor != it->GetPointer()) { it = m_Interactors.erase(it); } else { ++it; } } } } void mitk::Dispatcher::QueueEvent(InteractionEvent* event) { m_QueuedEvents.push_back(event); } void mitk::Dispatcher::SetEventProcessingMode(DataInteractor::Pointer dataInteractor) { m_ProcessingMode = dataInteractor->GetMode(); if (dataInteractor->GetMode() != REGULAR) { m_SelectedInteractor = dataInteractor; } } bool mitk::Dispatcher::HandleInternalEvent(InternalEvent* internalEvent) { if (internalEvent->GetSignalName() == DataInteractor::IntDeactivateMe && internalEvent->GetTargetInteractor() != NULL) { internalEvent->GetTargetInteractor()->GetDataNode()->SetDataInteractor(NULL); internalEvent->GetTargetInteractor()->SetDataNode(NULL); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); return true; } return false; } diff --git a/Modules/Core/src/Interactions/mitkEventConfig.cpp b/Modules/Core/src/Interactions/mitkEventConfig.cpp index a006f78083..c9fd76f5e6 100755 --- a/Modules/Core/src/Interactions/mitkEventConfig.cpp +++ b/Modules/Core/src/Interactions/mitkEventConfig.cpp @@ -1,425 +1,425 @@ /*=================================================================== 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 "mitkEventConfig.h" #include "mitkEventFactory.h" #include "mitkInteractionEvent.h" #include "mitkInternalEvent.h" #include "mitkInteractionKeyEvent.h" #include "mitkInteractionEventConst.h" // VTK #include #include // us #include "usGetModuleContext.h" #include "usModule.h" #include "usModuleResource.h" #include "usModuleResourceStream.h" namespace mitk { class EventConfigXMLParser : public vtkXMLParser { public: EventConfigXMLParser(EventConfigPrivate* d); protected: /** * @brief Derived from XMLReader **/ void StartElement(const char* elementName, const char **atts) override; /** * @brief Derived from XMLReader **/ void EndElement(const char* elementName) override; std::string ReadXMLStringAttribute(const std::string& name, const char** atts); bool ReadXMLBooleanAttribute(const std::string& name, const char** atts); private: EventConfigPrivate* const d; }; struct EventConfigPrivate : public us::SharedData { EventConfigPrivate(); EventConfigPrivate(const EventConfigPrivate& other); struct EventMapping { std::string variantName; InteractionEvent::ConstPointer interactionEvent; }; typedef std::list EventListType; /** * Checks if mapping with the same parameters already exists, if so, it is replaced, * else the new mapping added */ void InsertMapping(const EventMapping& mapping); void CopyMapping( const EventListType ); /** * @brief List of all global properties of the config object. */ PropertyList::Pointer m_PropertyList; /** * @brief Temporal list of all prMousePressEventoperties of a Event. Used to parse an Input-Event and collect all parameters between the two * and tags. */ PropertyList::Pointer m_EventPropertyList; EventMapping m_CurrEventMapping; /** * Stores InteractionEvents and their corresponding VariantName */ EventListType m_EventList; bool m_Errors; // use member, because of inheritance from vtkXMLParser we can't return a success value for parsing the file. EventConfigXMLParser m_XmlParser; }; } mitk::EventConfigPrivate::EventConfigPrivate() : m_PropertyList(PropertyList::New()) , m_EventPropertyList( PropertyList::New() ) , m_Errors(false) , m_XmlParser(this) { // Avoid VTK warning: Trying to delete object with non-zero reference count. m_XmlParser.SetReferenceCount(0); } mitk::EventConfigPrivate::EventConfigPrivate(const EventConfigPrivate& other) : us::SharedData(other) , m_PropertyList(other.m_PropertyList->Clone()) , m_EventPropertyList(other.m_EventPropertyList->Clone()) , m_CurrEventMapping(other.m_CurrEventMapping) , m_EventList(other.m_EventList) , m_Errors(other.m_Errors) , m_XmlParser(this) { // Avoid VTK warning: Trying to delete object with non-zero reference count. m_XmlParser.SetReferenceCount(0); } void mitk::EventConfigPrivate::InsertMapping(const EventMapping& mapping) { for (EventListType::iterator it = m_EventList.begin(); it != m_EventList.end(); ++it) { if (*(it->interactionEvent) == *mapping.interactionEvent) { //MITK_INFO<< "Configuration overwritten:" << (*it).variantName; m_EventList.erase(it); break; } } m_EventList.push_back(mapping); } void mitk::EventConfigPrivate::CopyMapping( const EventListType eventList ) { EventListType::const_iterator iter; for( iter=eventList.begin(); iter!=eventList.end(); ++iter ) { InsertMapping( *(iter) ); } } mitk::EventConfigXMLParser::EventConfigXMLParser(EventConfigPrivate *d) : d(d) { } void mitk::EventConfigXMLParser::StartElement(const char* elementName, const char **atts) { std::string name(elementName); if (name == InteractionEventConst::xmlTagConfigRoot()) { // } else if (name == InteractionEventConst::xmlTagParam()) { - std::string name = ReadXMLStringAttribute(InteractionEventConst::xmlParameterName(), atts); - std::string value = ReadXMLStringAttribute(InteractionEventConst::xmlParameterValue(), atts); + const std::string name = ReadXMLStringAttribute(InteractionEventConst::xmlParameterName(), atts); + const std::string value = ReadXMLStringAttribute(InteractionEventConst::xmlParameterValue(), atts); d->m_PropertyList->SetStringProperty(name.c_str(), value.c_str()); } else if (name == InteractionEventConst::xmlTagEventVariant()) { - std::string eventClass = ReadXMLStringAttribute(InteractionEventConst::xmlParameterEventClass(), atts); - std::string eventVariant = ReadXMLStringAttribute(InteractionEventConst::xmlParameterName(), atts); + const std::string eventClass = ReadXMLStringAttribute(InteractionEventConst::xmlParameterEventClass(), atts); + const std::string eventVariant = ReadXMLStringAttribute(InteractionEventConst::xmlParameterName(), atts); // New list in which all parameters are stored that are given within the tag d->m_EventPropertyList = PropertyList::New(); d->m_EventPropertyList->SetStringProperty(InteractionEventConst::xmlParameterEventClass().c_str(), eventClass.c_str()); d->m_EventPropertyList->SetStringProperty(InteractionEventConst::xmlParameterEventVariant().c_str(), eventVariant.c_str()); d->m_CurrEventMapping.variantName = eventVariant; } else if (name == InteractionEventConst::xmlTagAttribute()) { // Attributes that describe an Input Event, such as which MouseButton triggered the event,or which modifier keys are pressed - std::string name = ReadXMLStringAttribute(InteractionEventConst::xmlParameterName(), atts); - std::string value = ReadXMLStringAttribute(InteractionEventConst::xmlParameterValue(), atts); + const std::string name = ReadXMLStringAttribute(InteractionEventConst::xmlParameterName(), atts); + const std::string value = ReadXMLStringAttribute(InteractionEventConst::xmlParameterValue(), atts); d->m_EventPropertyList->SetStringProperty(name.c_str(), value.c_str()); } } void mitk::EventConfigXMLParser::EndElement(const char* elementName) { - std::string name(elementName); + const std::string name(elementName); // At end of input section, all necessary infos are collected to created an interaction event. if (name == InteractionEventConst::xmlTagEventVariant()) { InteractionEvent::Pointer event = EventFactory::CreateEvent(d->m_EventPropertyList); if (event.IsNotNull()) { d->m_CurrEventMapping.interactionEvent = event; d->InsertMapping(d->m_CurrEventMapping); } else { MITK_WARN<< "EventConfig: Unknown Event-Type in config. Entry skipped: " << name; } } } std::string mitk::EventConfigXMLParser::ReadXMLStringAttribute(const std::string& name, const char** atts) { if (atts) { const char** attsIter = atts; while (*attsIter) { if (name == *attsIter) { attsIter++; return *attsIter; } attsIter += 2; } } return std::string(); } bool mitk::EventConfigXMLParser::ReadXMLBooleanAttribute(const std::string& name, const char** atts) { std::string s = ReadXMLStringAttribute(name, atts); std::transform(s.begin(), s.end(), s.begin(), ::toupper); return s == "TRUE"; } mitk::EventConfig::EventConfig() : d(new EventConfigPrivate) { } mitk::EventConfig::EventConfig(const EventConfig &other) : d(other.d) { } mitk::EventConfig::EventConfig(const std::string& filename, const us::Module* module) : d(new EventConfigPrivate) { if (module == NULL) { module = us::GetModuleContext()->GetModule(); } us::ModuleResource resource = module->GetResource("Interactions/" + filename); if (!resource.IsValid()) { MITK_ERROR << "Resource not valid. State machine pattern in module " << module->GetName() << " not found: /Interactions/" << filename; return; } EventConfig newConfig; us::ModuleResourceStream stream(resource); newConfig.d->m_XmlParser.SetStream(&stream); bool success = newConfig.d->m_XmlParser.Parse() && !newConfig.d->m_Errors; if (success) { *this = newConfig; } } mitk::EventConfig::EventConfig(std::istream &inputStream) : d(new EventConfigPrivate) { EventConfig newConfig; newConfig.d->m_XmlParser.SetStream(&inputStream); bool success = newConfig.d->m_XmlParser.Parse() && !newConfig.d->m_Errors; if (success) { *this = newConfig; } } mitk::EventConfig::EventConfig(const std::vector &configDescription) : d(new EventConfigPrivate) { std::vector::const_iterator it_end = configDescription.end(); for (std::vector::const_iterator it = configDescription.begin(); it != it_end; ++it) { std::string typeVariant; (*it)->GetStringProperty(InteractionEventConst::xmlTagEventVariant().c_str(), typeVariant); if ( typeVariant != "" ) { InteractionEvent::Pointer event = EventFactory::CreateEvent(*it); if (event.IsNotNull()) { d->m_CurrEventMapping.interactionEvent = event; std::string eventVariant; (*it)->GetStringProperty(InteractionEventConst::xmlTagEventVariant().c_str(), eventVariant); d->m_CurrEventMapping.variantName = eventVariant; d->InsertMapping(d->m_CurrEventMapping); } else { MITK_WARN<< "EventConfig: Unknown Event-Type in config. When constructing from PropertyList."; } } else { (*it)->GetStringProperty(InteractionEventConst::xmlTagParam().c_str(), typeVariant); if ( typeVariant != "" ) { std::string name, value; (*it)->GetStringProperty(InteractionEventConst::xmlParameterName().c_str(), name); (*it)->GetStringProperty(InteractionEventConst::xmlParameterValue().c_str(), value); d->m_PropertyList->SetStringProperty(name.c_str(), value.c_str()); } } } } mitk::EventConfig& mitk::EventConfig::operator =(const mitk::EventConfig& other) { d = other.d; return *this; } mitk::EventConfig::~EventConfig() { } bool mitk::EventConfig::IsValid() const { return !( d->m_EventList.empty() && d->m_PropertyList->IsEmpty() ); } bool mitk::EventConfig::AddConfig(const std::string& fileName, const us::Module* module) { if (module == NULL) { module = us::GetModuleContext()->GetModule(); } us::ModuleResource resource = module->GetResource("Interactions/" + fileName); if (!resource.IsValid()) { MITK_ERROR << "Resource not valid. State machine pattern in module " << module->GetName() << " not found: /Interactions/" << fileName; return false; } EventConfig newConfig(*this); us::ModuleResourceStream stream(resource); newConfig.d->m_XmlParser.SetStream(&stream); bool success = newConfig.d->m_XmlParser.Parse() && !newConfig.d->m_Errors; if (success) { *this = newConfig; } return success; } bool mitk::EventConfig::AddConfig(const EventConfig& config) { if (!config.IsValid()) return false; d->m_PropertyList->ConcatenatePropertyList(config.d->m_PropertyList->Clone(), true); d->m_EventPropertyList = config.d->m_EventPropertyList->Clone(); d->m_CurrEventMapping = config.d->m_CurrEventMapping; d->CopyMapping( config.d->m_EventList ); return true; } mitk::PropertyList::Pointer mitk::EventConfig::GetAttributes() const { return d->m_PropertyList; } std::string mitk::EventConfig::GetMappedEvent(const EventType& interactionEvent) const { // internal events are excluded from mapping if (std::strcmp(interactionEvent->GetNameOfClass(), "InternalEvent") == 0) { InternalEvent* internalEvent = dynamic_cast(interactionEvent.GetPointer()); return internalEvent->GetSignalName(); } for (EventConfigPrivate::EventListType::const_iterator it = d->m_EventList.begin(); it != d->m_EventList.end(); ++it) { if (*(it->interactionEvent) == *interactionEvent) { return (*it).variantName; } } // if this part is reached, no mapping has been found, // so here we handle key events and map a key event to the string "Std" + letter/code // so "A" will be returned as "StdA" if (std::strcmp(interactionEvent->GetNameOfClass(), "InteractionKeyEvent") == 0) { InteractionKeyEvent* keyEvent = dynamic_cast(interactionEvent.GetPointer()); return ("Std" + keyEvent->GetKey()); } return ""; } void mitk::EventConfig::ClearConfig() { d->m_PropertyList->Clear(); d->m_EventPropertyList->Clear(); d->m_CurrEventMapping.variantName.clear(); d->m_CurrEventMapping.interactionEvent = NULL; d->m_EventList.clear(); d->m_Errors = false; } diff --git a/Modules/Core/src/Interactions/mitkEventFactory.cpp b/Modules/Core/src/Interactions/mitkEventFactory.cpp index 6bb641aff1..b0f87b6114 100755 --- a/Modules/Core/src/Interactions/mitkEventFactory.cpp +++ b/Modules/Core/src/Interactions/mitkEventFactory.cpp @@ -1,571 +1,571 @@ /*=================================================================== 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 "mitkEventFactory.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace { std::vector &split(const std::string &s, char delim, std::vector &elems) { std::stringstream ss(s); std::string item; while (std::getline(ss, item, delim)) { elems.push_back(item); } return elems; } std::vector split(const std::string &s, char delim) { std::vector < std::string > elems; return split(s, delim, elems); } } /** * @brief GetEventButton Return EventButton as String * @param event * @return */ static std::string GetButtonState(mitk::InteractionEvent *event) { mitk::InteractionEvent::MouseButtons buttonState = mitk::InteractionEvent::NoButton; std::string eventClass = event->GetNameOfClass(); - std::transform(eventClass.begin(), eventClass.end(), eventClass.begin(), ::toupper); + std::transform(eventClass.cbegin(), eventClass.cend(), eventClass.begin(), ::toupper); std::string strButtonState = ""; if (eventClass == "MOUSEPRESSEVENT") { mitk::MousePressEvent* mme = dynamic_cast (event); buttonState = mme->GetButtonStates(); } if (eventClass == "MOUSERELEASEEVENT") { mitk::MouseReleaseEvent* mme = dynamic_cast (event); buttonState = mme->GetButtonStates(); } if (eventClass == "MOUSEDOUBLECLICKEVENT") { mitk::MouseDoubleClickEvent* mme = dynamic_cast (event); buttonState = mme->GetButtonStates(); } if (eventClass == "MOUSEMOVEEVENT") { mitk::MouseMoveEvent* mme = dynamic_cast (event); buttonState = mme->GetButtonStates(); } if (eventClass == "MOUSEWHEELEVENT") { mitk::MouseWheelEvent* mme = dynamic_cast (event); buttonState = mme->GetButtonStates(); } if (buttonState & mitk::InteractionEvent::LeftMouseButton ) { strButtonState = "LeftMouseButton"; } if (buttonState & mitk::InteractionEvent::RightMouseButton ) { if (strButtonState != "") strButtonState += ","; strButtonState += "RightMouseButton"; } if (buttonState & mitk::InteractionEvent::MiddleMouseButton ) { if (strButtonState != "") strButtonState += ","; strButtonState += "MiddleMouseButton"; } return strButtonState; } /** * @brief GetModifierState Return ModifierState as String * @param event * @return */ static std::string GetModifierState(mitk::InteractionEvent *event) { mitk::InteractionEvent::ModifierKeys modifierKeys = mitk::InteractionEvent::NoKey; std::string eventClass = event->GetNameOfClass(); - std::transform(eventClass.begin(), eventClass.end(), eventClass.begin(), ::toupper); + std::transform(eventClass.cbegin(), eventClass.cend(), eventClass.begin(), ::toupper); std::string strModKeys = ""; // TODO Add InteractionKey if (eventClass == "MOUSEPRESSEVENT") { mitk::MousePressEvent* mme = dynamic_cast (event); modifierKeys = mme->GetModifiers(); } if (eventClass == "MOUSERELEASEEVENT") { mitk::MouseReleaseEvent* mme = dynamic_cast (event); modifierKeys = mme->GetModifiers(); } if (eventClass == "MOUSEDOUBLECLICKEVENT") { mitk::MouseDoubleClickEvent* mme = dynamic_cast (event); modifierKeys = mme->GetModifiers(); } if (eventClass == "MOUSEMOVEEVENT") { mitk::MouseMoveEvent* mme = dynamic_cast (event); modifierKeys = mme->GetModifiers(); } if (eventClass == "MOUSEWHEELEVENT") { mitk::MouseWheelEvent* mme = dynamic_cast (event); modifierKeys = mme->GetModifiers(); } if (modifierKeys & mitk::InteractionEvent::ShiftKey ) { strModKeys = "SHIFT"; } if (modifierKeys & mitk::InteractionEvent::ControlKey ) { if (strModKeys != "") strModKeys += ","; strModKeys += "CTRL"; } if (modifierKeys & mitk::InteractionEvent::AltKey ) { if (strModKeys != "") strModKeys += ","; strModKeys += "ALT"; } return strModKeys; } /** * @brief GetEventButton Return EventButton as String * @param event * @return */ static std::string GetEventButton(mitk::InteractionEvent *event) { mitk::InteractionEvent::MouseButtons button = mitk::InteractionEvent::NoButton; std::string eventClass = event->GetNameOfClass(); - std::transform(eventClass.begin(), eventClass.end(), eventClass.begin(), ::toupper); + std::transform(eventClass.cbegin(), eventClass.cend(), eventClass.begin(), ::toupper); std::string stdButton = ""; // TODO Add InteractionKey if (eventClass == "MOUSEPRESSEVENT") { mitk::MousePressEvent* mme = dynamic_cast (event); button = mme->GetEventButton(); } if (eventClass == "MOUSERELEASEEVENT") { mitk::MouseReleaseEvent* mme = dynamic_cast (event); button = mme->GetEventButton(); } if (eventClass == "MOUSEDOUBLECLICKEVENT") { mitk::MouseDoubleClickEvent* mme = dynamic_cast (event); button = mme->GetEventButton(); } if (button & mitk::InteractionEvent::LeftMouseButton ) { stdButton = "LeftMouseButton"; } if (button & mitk::InteractionEvent::RightMouseButton ) { stdButton = "RightMouseButton"; } if (button & mitk::InteractionEvent::MiddleMouseButton ) { stdButton = "MiddleMouseButton"; } return stdButton; } /** * @brief GetPosition Return World Position as String * @param event * @return */ static std::string GetPositionInWorld(mitk::InteractionEvent *event) { std::stringstream ss; mitk::InteractionPositionEvent* pe = dynamic_cast (event); if (pe != NULL) { mitk::Point3D p = pe->GetPositionInWorld(); ss << p[0] << "," << p[1] << "," << p[2]; } return ss.str(); } /** * @brief GetPositionOnScreen Return PositionOnScreen as String * @param event * @return */ static std::string GetPositionOnScreen(mitk::InteractionEvent *event) { std::stringstream ss; mitk::InteractionPositionEvent* pe = dynamic_cast (event); if (pe != NULL) { mitk::Point2D p = pe->GetPointerPositionOnScreen(); ss << p[0] << "," << p[1]; } return ss.str(); } mitk::InteractionEvent::Pointer mitk::EventFactory::CreateEvent(PropertyList::Pointer list) { // std::string eventClass, eventVariant; list->GetStringProperty(InteractionEventConst::xmlParameterEventClass().c_str(), eventClass); list->GetStringProperty(InteractionEventConst::xmlParameterEventVariant().c_str(), eventVariant); // Query all possible attributes, if they are not present, set their default values. // Position Events & Key Events std::string strModifiers; InteractionEvent::ModifierKeys modifiers = InteractionEvent::NoKey; std::string strEventButton; InteractionEvent::MouseButtons eventButton = InteractionEvent::NoButton; std::string strButtonState; InteractionEvent::MouseButtons buttonState = InteractionEvent::NoButton; std::string strKey; std::string key; std::string strWheelDelta; int wheelDelta; std::string strSignalName = ""; Point2D pos; pos.Fill(0); std::string strPos; // Position on screen if( list->GetStringProperty(InteractionEventConst::xmlEventPropertyPositionOnScreen().c_str(), strPos)) { //split comma separated string int commaPos; commaPos = strPos.find_first_of(','); pos[0] = static_cast(std::atof(strPos.substr(0, commaPos).c_str())); pos[1] = static_cast(std::atof(strPos.substr(commaPos+1, strPos.length()).c_str())); } std::string strWorld; Point3D worldPos; worldPos.Fill(0); //Position in world coordinates if(list->GetStringProperty(InteractionEventConst::xmlEventPropertyPositionInWorld().c_str(), strWorld)) { - std::vector coords = split(strWorld, ','); + const std::vector coords = split(strWorld, ','); int i = 0; - for ( std::vector::iterator it = coords.begin(); it != coords.end(); ++it, ++i) + for ( std::vector::const_iterator it = coords.cbegin(); it != coords.cend(); ++it, ++i) { worldPos[i] = atof((*it).c_str()); } } // Parse modifier information if (list->GetStringProperty(InteractionEventConst::xmlEventPropertyModifier().c_str(), strModifiers)) { std::vector mods = split(strModifiers, ','); for (std::vector::iterator it = mods.begin(); it != mods.end(); ++it) { - std::transform((*it).begin(), (*it).end(), (*it).begin(), ::toupper); + std::transform((*it).cbegin(), (*it).cend(), (*it).begin(), ::toupper); if (*it == "CTRL") { modifiers = modifiers | InteractionEvent::ControlKey; } else if (*it == "ALT") { modifiers = modifiers | InteractionEvent::AltKey; } else if (*it == "SHIFT") { modifiers = modifiers | InteractionEvent::ShiftKey; } else { MITK_WARN<< "mitkEventFactory: Invalid event modifier in config file :" << (*it); } } } // Set EventButton if (list->GetStringProperty(InteractionEventConst::xmlEventPropertyEventButton().c_str(), strEventButton)) { - std::transform(strEventButton.begin(), strEventButton.end(), strEventButton.begin(), ::toupper); + std::transform(strEventButton.cbegin(), strEventButton.cend(), strEventButton.begin(), ::toupper); if (strEventButton == "MIDDLEMOUSEBUTTON") { eventButton = InteractionEvent::MiddleMouseButton; } else if (strEventButton == "LEFTMOUSEBUTTON") { eventButton = InteractionEvent::LeftMouseButton; } else if (strEventButton == "RIGHTMOUSEBUTTON") { eventButton = InteractionEvent::RightMouseButton; } else { MITK_WARN<< "mitkEventFactory: Invalid event button in config file: " << strEventButton; } } // Parse ButtonStates if (list->GetStringProperty(InteractionEventConst::xmlEventPropertyButtonState().c_str(), strButtonState)) { std::vector mods = split(strButtonState, ','); for (std::vector::iterator it = mods.begin(); it != mods.end(); ++it) { - std::transform((*it).begin(), (*it).end(), (*it).begin(), ::toupper); + std::transform((*it).cbegin(), (*it).cend(), (*it).begin(), ::toupper); if (*it == "MIDDLEMOUSEBUTTON") { buttonState = buttonState | InteractionEvent::MiddleMouseButton; } else if (*it == "LEFTMOUSEBUTTON") { buttonState = buttonState | InteractionEvent::LeftMouseButton; } else if (*it == "RIGHTMOUSEBUTTON") { buttonState = buttonState | InteractionEvent::RightMouseButton; } else { MITK_WARN<< "mitkEventFactory: Invalid event buttonstate in config file:" << (*it); } } } // Key if (!list->GetStringProperty(InteractionEventConst::xmlEventPropertyKey().c_str(), strKey)) { key = ""; } else { key = strKey; } // WheelDelta if (!list->GetStringProperty(InteractionEventConst::xmlEventPropertyScrollDirection().c_str(), strWheelDelta)) { wheelDelta = 0; } else { - std::transform(strWheelDelta.begin(), strWheelDelta.end(), strWheelDelta.begin(), ::toupper); + std::transform(strWheelDelta.cbegin(), strWheelDelta.cend(), strWheelDelta.begin(), ::toupper); if (strWheelDelta == "DOWN") { wheelDelta = -1; } else { wheelDelta = 1; } } // Internal Signals Name list->GetStringProperty(InteractionEventConst::xmlEventPropertySignalName().c_str(), strSignalName); // Get BaseRenderer by name mitk::BaseRenderer* renderer = NULL; std::string strRenderer; // only search for a renderer if there is at least one renderer registered if(mitk::BaseRenderer::baseRendererMap.size() > 0) { if(list->GetStringProperty(mitk::InteractionEventConst::xmlEventPropertyRendererName().c_str(), strRenderer)) { //look up for renderer registered with the name in xml file renderer = mitk::BaseRenderer::GetByName(strRenderer); } //if not found always use first registered renderer if(renderer == NULL) - renderer = (*(mitk::BaseRenderer::baseRendererMap.begin())).second; + renderer = (*(mitk::BaseRenderer::baseRendererMap.cbegin())).second; } /* * Here the objects are created */ mitk::InteractionEvent::Pointer event; - std::transform(eventClass.begin(), eventClass.end(), eventClass.begin(), ::toupper); + std::transform(eventClass.cbegin(), eventClass.cend(), eventClass.begin(), ::toupper); if (eventClass == "MOUSEPRESSEVENT") { // buttonstates incorporate the event button (as in Qt) buttonState = buttonState | eventButton; event = MousePressEvent::New(renderer, pos, buttonState, modifiers, eventButton); } else if (eventClass == "MOUSEDOUBLECLICKEVENT") { buttonState = buttonState | eventButton; event = MouseDoubleClickEvent::New(renderer, pos, buttonState, modifiers, eventButton); } else if (eventClass == "MOUSEMOVEEVENT") { event = MouseMoveEvent::New(renderer, pos, buttonState, modifiers); } else if (eventClass == "MOUSERELEASEEVENT") { event = MouseReleaseEvent::New(renderer, pos, buttonState, modifiers, eventButton); } else if (eventClass == "INTERACTIONKEYEVENT") { event = InteractionKeyEvent::New(renderer, key, modifiers); } else if (eventClass == "MOUSEWHEELEVENT") { event = MouseWheelEvent::New(renderer, pos, buttonState, modifiers, wheelDelta); } else if (eventClass == "INTERACTIONPOSITIONEVENT") { event = InteractionPositionEvent::New(renderer, pos); } else if (eventClass == "INTERNALEVENT") { event = InternalEvent::New(renderer, NULL, strSignalName); } else if (eventClass == "INTERACTIONEVENT") { event = InteractionEvent::New(renderer); } if (event.IsNull()) { MITK_WARN<< "Event couldn't be constructed. Please check your StateMachine patterns and config files\n for the following event class, which is not valid: " << eventClass; return NULL; } return event; } std::string mitk::EventFactory::EventToXML(mitk::InteractionEvent *event) { InternalEvent* ie = dynamic_cast (event); if (ie != NULL) return ""; std::string eventClass = event->GetNameOfClass(); std::string eventXML = "<" + InteractionEventConst::xmlTagEventVariant() + " " + InteractionEventConst::xmlParameterEventClass() + "=\""; - std::transform(eventClass.begin(), eventClass.end(), eventClass.begin(), ::toupper); + std::transform(eventClass.cbegin(), eventClass.cend(), eventClass.begin(), ::toupper); eventXML += eventClass + "\" >\n"; // here follow event specific attributes if (eventClass == "MOUSEPRESSEVENT" || eventClass == "MOUSERELEASEEVENT" || eventClass == "MOUSEDOUBLECLICKEVENT" || eventClass == "MOUSEMOVEEVENT" || eventClass == "MOUSEWHEELEVENT") { if (!(eventClass == "MOUSEMOVEEVENT") && !(eventClass == "MOUSEWHEELEVENT")) { // EventButton eventXML += " <" + InteractionEventConst::xmlTagAttribute() +" " + InteractionEventConst::xmlParameterName() + "=\"" + InteractionEventConst::xmlEventPropertyEventButton() + "\" "; eventXML += InteractionEventConst::xmlParameterValue() + "=\""; eventXML += GetEventButton(event); eventXML += "\"/>\n"; } // ButtonState if (GetButtonState(event) != "") { eventXML += " <" + InteractionEventConst::xmlTagAttribute() +" " + InteractionEventConst::xmlParameterName() + "=\"" + InteractionEventConst::xmlEventPropertyButtonState() + "\" "; eventXML += InteractionEventConst::xmlParameterValue() + "=\""; eventXML += GetButtonState(event); eventXML += "\"/>\n"; } // Modifiers if (GetModifierState(event) != "") { eventXML += " <" + InteractionEventConst::xmlTagAttribute() +" " + InteractionEventConst::xmlParameterName() + "=\"" + InteractionEventConst::xmlEventPropertyModifier() + "\" "; eventXML += InteractionEventConst::xmlParameterValue() + "=\""; eventXML += GetModifierState(event); eventXML += "\"/>\n"; } // Position on Screen eventXML += " <" + InteractionEventConst::xmlTagAttribute() +" " + InteractionEventConst::xmlParameterName() + "=\"" + InteractionEventConst::xmlEventPropertyPositionOnScreen() + "\" "; eventXML += InteractionEventConst::xmlParameterValue() + "=\""; eventXML += GetPositionOnScreen(event); eventXML += "\"/>\n"; // Position in World eventXML += " <" + InteractionEventConst::xmlTagAttribute() +" " + InteractionEventConst::xmlParameterName() + "=\"" + InteractionEventConst::xmlEventPropertyPositionInWorld() + "\" "; eventXML += InteractionEventConst::xmlParameterValue() + "=\""; eventXML += GetPositionInWorld(event); eventXML += "\"/>\n"; } else if (eventClass == "INTERACTIONKEYEVENT") { mitk::InteractionKeyEvent* ke = dynamic_cast(event); // key eventXML += " <" + InteractionEventConst::xmlTagAttribute() +" " + InteractionEventConst::xmlParameterName() + "=\"" + InteractionEventConst::xmlEventPropertyKey() + "\" "; eventXML += InteractionEventConst::xmlParameterValue() + "=\""; eventXML += ke->GetKey(); eventXML += "\"/>\n"; } else { MITK_WARN << "Event not recognized, discarding event of type " << event->GetNameOfClass(); } if (eventClass == "MOUSEWHEELEVENT") { MouseWheelEvent* we = dynamic_cast (event); int delta = we->GetWheelDelta(); std::stringstream ss; ss << delta; eventXML += " <" + InteractionEventConst::xmlTagAttribute() +" " + InteractionEventConst::xmlParameterName() + "=\"" + InteractionEventConst::xmlEventPropertyWheelDelta() + "\" "; eventXML += InteractionEventConst::xmlParameterValue() + "=\""; eventXML += ss.str(); eventXML += "\"/>\n"; eventXML += " <" + InteractionEventConst::xmlTagAttribute() +" " + InteractionEventConst::xmlParameterName() + "=\"" + InteractionEventConst::xmlEventPropertyScrollDirection() + "\" "; eventXML += InteractionEventConst::xmlParameterValue() + "=\""; eventXML += delta < 0 ? "DOWN" : "UP"; eventXML += "\"/>\n"; } // Renderer name eventXML += " <" + InteractionEventConst::xmlTagAttribute() +" " + InteractionEventConst::xmlParameterName() + "=\"" + InteractionEventConst::xmlEventPropertyRendererName() + "\" "; eventXML += InteractionEventConst::xmlParameterValue() + "=\""; eventXML += event->GetSender()->GetName(); eventXML += "\"/>\n"; // closing tag: eventXML += ""; return eventXML; } diff --git a/Modules/Core/src/Interactions/mitkEventStateMachine.cpp b/Modules/Core/src/Interactions/mitkEventStateMachine.cpp index debe4ac8a1..2b99689ca2 100644 --- a/Modules/Core/src/Interactions/mitkEventStateMachine.cpp +++ b/Modules/Core/src/Interactions/mitkEventStateMachine.cpp @@ -1,351 +1,351 @@ /*=================================================================== 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 "mitkEventStateMachine.h" #include "mitkStateMachineContainer.h" #include "mitkInteractionEvent.h" #include "mitkStateMachineAction.h" #include "mitkStateMachineCondition.h" #include "mitkStateMachineTransition.h" #include "mitkStateMachineState.h" #include "mitkUndoController.h" #include "mitkApplicationCursor.h" mitk::EventStateMachine::EventStateMachine() : m_IsActive(true), m_UndoController(NULL), m_StateMachineContainer(NULL), m_CurrentState(NULL), m_MouseCursorSet(false) { if (!m_UndoController) { m_UndoController = new UndoController(UndoController::VERBOSE_LIMITEDLINEARUNDO);//switch to LLU or add LLU /** * here the Undo mechanism is enabled / disabled for all interactors. **/ m_UndoEnabled = true; } } bool mitk::EventStateMachine::LoadStateMachine(const std::string& filename, const us::Module* module) { if (m_StateMachineContainer != NULL) { m_StateMachineContainer->Delete(); } m_StateMachineContainer = StateMachineContainer::New(); if (m_StateMachineContainer->LoadBehavior(filename, module)) { m_CurrentState = m_StateMachineContainer->GetStartState(); for(ConditionDelegatesMapType::iterator i = m_ConditionDelegatesMap.begin(); i != m_ConditionDelegatesMap.end(); ++i) { delete i->second; } m_ConditionDelegatesMap.clear(); // clear actions map ,and connect all actions as declared in sub-class for(std::map::iterator i = m_ActionFunctionsMap.begin(); i != m_ActionFunctionsMap.end(); ++i) { delete i->second; } m_ActionFunctionsMap.clear(); for(ActionDelegatesMapType::iterator i = m_ActionDelegatesMap.begin(); i != m_ActionDelegatesMap.end(); ++i) { delete i->second; } m_ActionDelegatesMap.clear(); ConnectActionsAndFunctions(); return true; } else { MITK_WARN<< "Unable to load StateMachine from file: " << filename; return false; } } mitk::EventStateMachine::~EventStateMachine() { if (m_StateMachineContainer != NULL) { m_StateMachineContainer->Delete(); } } void mitk::EventStateMachine::AddActionFunction(const std::string& action, mitk::TActionFunctor* functor) { if (!functor) return; // make sure double calls for same action won't cause memory leaks delete m_ActionFunctionsMap[action]; ActionDelegatesMapType::iterator i = m_ActionDelegatesMap.find(action); if (i != m_ActionDelegatesMap.end()) { delete i->second; m_ActionDelegatesMap.erase(i); } m_ActionFunctionsMap[action] = functor; } void mitk::EventStateMachine::AddActionFunction(const std::string& action, const ActionFunctionDelegate& delegate) { std::map::iterator i = m_ActionFunctionsMap.find(action); if (i != m_ActionFunctionsMap.end()) { delete i->second; m_ActionFunctionsMap.erase(i); } delete m_ActionDelegatesMap[action]; m_ActionDelegatesMap[action] = delegate.Clone(); } void mitk::EventStateMachine::AddConditionFunction(const std::string& condition, const ConditionFunctionDelegate& delegate) { m_ConditionDelegatesMap[condition] = delegate.Clone(); } bool mitk::EventStateMachine::HandleEvent(InteractionEvent* event, DataNode* dataNode) { if (!m_IsActive) return false; if (!FilterEvents(event, dataNode)) { return false; } // Get the transition that can be executed mitk::StateMachineTransition::Pointer transition = GetExecutableTransition( event ); // check if the current state holds a transition that works with the given event. if ( transition.IsNotNull() ) { // all conditions are fulfilled so we can continue with the actions m_CurrentState = transition->GetNextState(); // iterate over all actions in this transition and execute them - ActionVectorType actions = transition->GetActions(); - for (ActionVectorType::iterator it = actions.begin(); it != actions.end(); ++it) + const ActionVectorType actions = transition->GetActions(); + for (ActionVectorType::const_iterator it = actions.cbegin(); it != actions.cend(); ++it) { try { ExecuteAction(*it, event); } catch( const std::exception& e ) { MITK_ERROR << "Unhandled excaption caught in ExecuteAction(): " << e.what(); return false; } catch( ... ) { MITK_ERROR << "Unhandled excaption caught in ExecuteAction()"; return false; } } return true; } return false; } void mitk::EventStateMachine::ConnectActionsAndFunctions() { MITK_WARN<< "ConnectActionsAndFunctions in DataInteractor not implemented.\n DataInteractor will not be able to process any events."; } bool mitk::EventStateMachine::CheckCondition( const StateMachineCondition& condition, const InteractionEvent* event) { bool retVal = false; - ConditionDelegatesMapType::iterator delegateIter = m_ConditionDelegatesMap.find(condition.GetConditionName()); - if (delegateIter != m_ConditionDelegatesMap.end()) + ConditionDelegatesMapType::const_iterator delegateIter = m_ConditionDelegatesMap.find(condition.GetConditionName()); + if (delegateIter != m_ConditionDelegatesMap.cend()) { retVal = delegateIter->second->Execute(event); } else { MITK_WARN << "No implementation of condition '" << condition.GetConditionName() << "' has been found."; } return retVal; } void mitk::EventStateMachine::ExecuteAction(StateMachineAction* action, InteractionEvent* event) { if (action == NULL) { return; } // Maps Action-Name to Functor and executes the Functor. - ActionDelegatesMapType::iterator delegateIter = m_ActionDelegatesMap.find(action->GetActionName()); - if (delegateIter != m_ActionDelegatesMap.end()) + ActionDelegatesMapType::const_iterator delegateIter = m_ActionDelegatesMap.find(action->GetActionName()); + if (delegateIter != m_ActionDelegatesMap.cend()) { delegateIter->second->Execute(action, event); } else { // try the legacy system - std::map::iterator functionIter = m_ActionFunctionsMap.find(action->GetActionName()); - if (functionIter != m_ActionFunctionsMap.end()) + std::map::const_iterator functionIter = m_ActionFunctionsMap.find(action->GetActionName()); + if (functionIter != m_ActionFunctionsMap.cend()) { functionIter->second->DoAction(action, event); } else { MITK_WARN << "No implementation of action '" << action->GetActionName() << "' has been found."; } } } mitk::StateMachineState* mitk::EventStateMachine::GetCurrentState() const { return m_CurrentState.GetPointer(); } bool mitk::EventStateMachine::FilterEvents(InteractionEvent* interactionEvent, DataNode* dataNode) { if (dataNode == NULL) { MITK_WARN<< "EventStateMachine: Empty DataNode received along with this Event " << interactionEvent; return false; } bool visible = false; if (dataNode->GetPropertyList()->GetBoolProperty("visible", visible) == false) { //property doesn't exist return false; } return visible; } mitk::StateMachineTransition* mitk::EventStateMachine::GetExecutableTransition( mitk::InteractionEvent* event ) { // Map that will contain all conditions that are possibly used by the // transitions std::map conditionsMap; // Get a list of all transitions that match the given event - mitk::StateMachineState::TransitionVector transitionList = + const mitk::StateMachineState::TransitionVector transitionList = m_CurrentState->GetTransitionList( event->GetNameOfClass(), MapToEventVariant(event) ); // if there are not transitions, we can return NULL here. if ( transitionList.empty() ) { return NULL; } - StateMachineState::TransitionVector::iterator transitionIter; - ConditionVectorType::iterator conditionIter; - for( transitionIter=transitionList.begin(); transitionIter!=transitionList.end(); ++transitionIter ) + StateMachineState::TransitionVector::const_iterator transitionIter; + ConditionVectorType::const_iterator conditionIter; + for( transitionIter=transitionList.cbegin(); transitionIter!=transitionList.cend(); ++transitionIter ) { bool allConditionsFulfilled(true); // Get all conditions for the current transition - ConditionVectorType conditions = (*transitionIter)->GetConditions(); - for (conditionIter = conditions.begin(); conditionIter != conditions.end(); ++conditionIter) + const ConditionVectorType conditions = (*transitionIter)->GetConditions(); + for (conditionIter = conditions.cbegin(); conditionIter != conditions.cend(); ++conditionIter) { bool currentConditionFulfilled(false); // sequentially check all conditions that we have evaluated above - std::string conditionName = (*conditionIter).GetConditionName(); + const std::string conditionName = (*conditionIter).GetConditionName(); // Check if the condition has already been evaluated - if ( conditionsMap.find(conditionName) == conditionsMap.end() ) + if ( conditionsMap.find(conditionName) == conditionsMap.cend() ) { // if the condition has not been evaluated yet, do it now and store // the result in the map try { currentConditionFulfilled = CheckCondition( (*conditionIter), event ); conditionsMap.insert( std::pair(conditionName, currentConditionFulfilled) ); } catch (const std::exception& e) { MITK_ERROR << "Unhandled excaption caught in CheckCondition(): " << e.what(); currentConditionFulfilled = false; break; } catch (...) { MITK_ERROR << "Unhandled excaption caught in CheckCondition()"; currentConditionFulfilled = false; break; } } else { // if the condition has been evaluated before, use that result currentConditionFulfilled = conditionsMap[conditionName]; } // set 'allConditionsFulfilled' under consideration of a possible // inversion of the condition if ( currentConditionFulfilled == (*conditionIter).IsInverted() ) { allConditionsFulfilled = false; break; } } // If all conditions are fulfilled, we execute this transition if ( allConditionsFulfilled ) { return (*transitionIter); } } // We have found no transition that can be executed, return NULL return NULL; } void mitk::EventStateMachine::ResetToStartState() { m_CurrentState = m_StateMachineContainer->GetStartState(); } void mitk::EventStateMachine::SetMouseCursor(const char *xpm[], int hotspotX, int hotspotY) { // Remove previously set mouse cursor if ( m_MouseCursorSet ) { ApplicationCursor::GetInstance()->PopCursor(); } ApplicationCursor::GetInstance()->PushCursor( xpm, hotspotX, hotspotY ); m_MouseCursorSet = true; } void mitk::EventStateMachine::ResetMouseCursor() { if ( m_MouseCursorSet ) { ApplicationCursor::GetInstance()->PopCursor(); m_MouseCursorSet = false; } }