diff --git a/Modules/Core/include/mitkBaseRenderer.h b/Modules/Core/include/mitkBaseRenderer.h index c6c9477966..a9ffd4eb49 100644 --- a/Modules/Core/include/mitkBaseRenderer.h +++ b/Modules/Core/include/mitkBaseRenderer.h @@ -1,674 +1,676 @@ /*=================================================================== 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 BASERENDERER_H_HEADER_INCLUDED_C1CCA0F4 #define BASERENDERER_H_HEADER_INCLUDED_C1CCA0F4 #include "mitkDataStorage.h" #include "mitkPlaneGeometry.h" #include "mitkTimeGeometry.h" #include "mitkDisplayGeometry.h" #include "mitkPlaneGeometryData.h" #include "mitkCameraController.h" #include "mitkDisplayPositionEvent.h" #include "mitkWheelEvent.h" //#include "mitkMapper.h" #include "mitkSliceNavigationController.h" #include "mitkCameraController.h" #include "mitkCameraRotationController.h" #include "mitkBindDispatcherInteractor.h" #include "mitkDispatcher.h" #include #include #include #include // DEPRECATED #include namespace mitk { class NavigationController; class SliceNavigationController; class CameraRotationController; class CameraController; class DataStorage; class Mapper; class BaseLocalStorageHandler; class OverlayManager; //##Documentation //## @brief Organizes the rendering process //## //## Organizes the rendering process. A Renderer contains a reference to a //## DataStorage and asks the mappers of the data objects to render //## the data into the renderwindow it is associated to. //## //## \#Render() checks if rendering is currently allowed by calling //## RenderWindow::PrepareRendering(). Initialization of a rendering context //## can also be performed in this method. //## //## The actual rendering code has been moved to \#Repaint() //## Both \#Repaint() and \#Update() are declared protected now. //## //## Note: Separation of the Repaint and Update processes (rendering vs //## creating a vtk prop tree) still needs to be worked on. The whole //## rendering process also should be reworked to use VTK based classes for //## both 2D and 3D rendering. //## @ingroup Renderer class MITKCORE_EXPORT BaseRenderer: public itk::Object { public: /** \brief This rendering mode enumeration is specified at various constructors * of the Renderer and RenderWindow classes, which autoconfigures the * respective VTK objects. This has to be done at construction time because later * configuring turns out to be not working on most platforms. */ struct RenderingMode { enum Type { Standard = 0, // no multi-sampling, no depth-peeling MultiSampling, // multi-sampling (antialiasing), no depth-peeling DepthPeeling // no multi-sampling, depth-peeling is on (order-independant transparency) }; }; typedef std::map BaseRendererMapType; static BaseRendererMapType baseRendererMap; static BaseRenderer* GetInstance(vtkRenderWindow * renWin); static void AddInstance(vtkRenderWindow* renWin, BaseRenderer* baseRenderer); static void RemoveInstance(vtkRenderWindow* renWin); static BaseRenderer* GetByName(const std::string& name); static vtkRenderWindow* GetRenderWindowByName(const std::string& name); #pragma GCC visibility push(default) itkEventMacro( RendererResetEvent, itk::AnyEvent ); #pragma GCC visibility pop /** Standard class typedefs. */ mitkClassMacro(BaseRenderer, itk::Object); BaseRenderer(const char* name = NULL, vtkRenderWindow * renWin = NULL, mitk::RenderingManager* rm = NULL,RenderingMode::Type mode = RenderingMode::Standard); //##Documentation //## @brief MapperSlotId defines which kind of mapper (e.g., 2D or 3D) shoud be used. typedef int MapperSlotId; enum StandardMapperSlot { Standard2D = 1, Standard3D = 2 }; virtual void SetDataStorage(DataStorage* storage); ///< set the datastorage that will be used for rendering //##Documentation //## return the DataStorage that is used for rendering virtual DataStorage::Pointer GetDataStorage() const { return m_DataStorage.GetPointer(); } //##Documentation //## @brief Access the RenderWindow into which this renderer renders. vtkRenderWindow* GetRenderWindow() const { return m_RenderWindow; } vtkRenderer* GetVtkRenderer() const { return m_VtkRenderer; } //##Documentation //## @brief Returns the Dispatcher which handles Events for this BaseRenderer Dispatcher::Pointer GetDispatcher() const; //##Documentation //## @brief Default mapper id to use. static const MapperSlotId defaultMapper; //##Documentation //## @brief Do the rendering and flush the result. virtual void Paint(); //##Documentation //## @brief Initialize the RenderWindow. Should only be called from RenderWindow. virtual void Initialize(); //##Documentation //## @brief Called to inform the renderer that the RenderWindow has been resized. virtual void Resize(int w, int h); //##Documentation //## @brief Initialize the renderer with a RenderWindow (@a renderwindow). virtual void InitRenderer(vtkRenderWindow* renderwindow); //##Documentation //## @brief Set the initial size. Called by RenderWindow after it has become //## visible for the first time. virtual void InitSize(int w, int h); //##Documentation //## @brief Draws a point on the widget. //## Should be used during conferences to show the position of the remote mouse virtual void DrawOverlayMouse(Point2D& p2d); //##Documentation //## @brief Set/Get the WorldGeometry (m_WorldGeometry) for 3D and 2D rendering, that describing the //## (maximal) area to be rendered. //## //## Depending of the type of the passed BaseGeometry more or less information can be extracted: //## \li if it is a PlaneGeometry (which is a sub-class of BaseGeometry), m_CurrentWorldPlaneGeometry is //## also set to point to it. m_WorldTimeGeometry is set to NULL. //## \li if it is a TimeGeometry, m_WorldTimeGeometry is also set to point to it. //## If m_WorldTimeGeometry contains instances of SlicedGeometry3D, m_CurrentWorldPlaneGeometry is set to //## one of geometries stored in the SlicedGeometry3D according to the value of m_Slice; otherwise //## a PlaneGeometry describing the top of the bounding-box of the BaseGeometry is set as the //## m_CurrentWorldPlaneGeometry. //## \li otherwise a PlaneGeometry describing the top of the bounding-box of the BaseGeometry //## is set as the m_CurrentWorldPlaneGeometry. m_WorldTimeGeometry is set to NULL. //## @todo add calculation of PlaneGeometry describing the top of the bounding-box of the BaseGeometry //## when the passed BaseGeometry is not sliced. //## \sa m_WorldGeometry //## \sa m_WorldTimeGeometry //## \sa m_CurrentWorldPlaneGeometry virtual void SetWorldGeometry3D(BaseGeometry* geometry); virtual void SetWorldTimeGeometry(mitk::TimeGeometry* 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(void SetWorldGeometry3D(TimeSlicedGeometry* geometry)); itkGetConstObjectMacro(WorldGeometry, BaseGeometry) itkGetObjectMacro(WorldGeometry, BaseGeometry) itkGetConstObjectMacro(WorldTimeGeometry, TimeGeometry) itkGetObjectMacro(WorldTimeGeometry, TimeGeometry) //##Documentation //## @brief Get the current 3D-worldgeometry (m_CurrentWorldGeometry) used for 3D-rendering itkGetConstObjectMacro(CurrentWorldGeometry, BaseGeometry) //##Documentation //## @brief Get the current 2D-worldgeometry (m_CurrentWorldPlaneGeometry) used for 2D-rendering itkGetConstObjectMacro(CurrentWorldPlaneGeometry, PlaneGeometry) /** * \deprecatedSince{2014_10} Please use GetCurrentWorldPlaneGeometry */ DEPRECATED(const PlaneGeometry* GetCurrentWorldGeometry2D()){return GetCurrentWorldPlaneGeometry();}; //##Documentation //## Calculates the bounds of the DataStorage (if it contains any valid data), //## creates a geometry from these bounds and sets it as world geometry of the renderer. //## //## Call this method to re-initialize the renderer to the current DataStorage //## (e.g. after loading an additional dataset), to ensure that the view is //## aligned correctly. //## \warn This is not implemented yet. virtual bool SetWorldGeometryToDataStorageBounds() { return false; } //##Documentation //## @brief Set/Get the DisplayGeometry (for 2D rendering) //## //## The DisplayGeometry describes which part of the PlaneGeometry m_CurrentWorldPlaneGeometry //## is displayed. virtual void SetDisplayGeometry(DisplayGeometry* geometry2d); itkGetConstObjectMacro(DisplayGeometry, DisplayGeometry) itkGetObjectMacro(DisplayGeometry, DisplayGeometry) //##Documentation //## @brief Set/Get m_Slice which defines together with m_TimeStep the 2D geometry //## stored in m_WorldTimeGeometry used as m_CurrentWorldPlaneGeometry //## //## \sa m_Slice virtual void SetSlice(unsigned int slice); //##Documentation //## @brief Sets an OverlayManager which is used to add various Overlays to this //## renderer. If an OverlayManager was already set it will be overwritten. void SetOverlayManager(itk::SmartPointer overlayManager); //##Documentation //## @brief Get the OverlayManager registered with this renderer //## if none was set, it will be created at this point. itk::SmartPointer GetOverlayManager(); itkGetConstMacro(Slice, unsigned int) //##Documentation //## @brief Set/Get m_TimeStep which defines together with m_Slice the 2D geometry //## stored in m_WorldTimeGeometry used as m_CurrentWorldPlaneGeometry //## //## \sa m_TimeStep virtual void SetTimeStep(unsigned int timeStep); itkGetConstMacro(TimeStep, unsigned int) //##Documentation //## @brief Get the time-step of a BaseData object which //## exists at the time of the currently displayed content //## //## Returns -1 or mitk::BaseData::m_TimeSteps if there //## is no data at the current time. //## \sa GetTimeStep, m_TimeStep int GetTimeStep(const BaseData* data) const; //##Documentation //## @brief Get the time in ms of the currently displayed content //## //## \sa GetTimeStep, m_TimeStep ScalarType GetTime() const; //##Documentation //## @brief SetWorldGeometry is called according to the geometrySliceEvent, //## which is supposed to be a SliceNavigationController::GeometrySendEvent virtual void SetGeometry(const itk::EventObject & geometrySliceEvent); //##Documentation //## @brief UpdateWorldGeometry is called to re-read the 2D geometry from the //## slice navigation controller virtual void UpdateGeometry(const itk::EventObject & geometrySliceEvent); //##Documentation //## @brief SetSlice is called according to the geometrySliceEvent, //## which is supposed to be a SliceNavigationController::GeometrySliceEvent virtual void SetGeometrySlice(const itk::EventObject & geometrySliceEvent); //##Documentation //## @brief SetTimeStep is called according to the geometrySliceEvent, //## which is supposed to be a SliceNavigationController::GeometryTimeEvent virtual void SetGeometryTime(const itk::EventObject & geometryTimeEvent); //##Documentation //## @brief Get a data object containing the DisplayGeometry (for 2D rendering) itkGetObjectMacro(DisplayGeometryData, PlaneGeometryData) //##Documentation //## @brief Get a data object containing the WorldGeometry (for 2D rendering) itkGetObjectMacro(WorldGeometryData, PlaneGeometryData) //##Documentation //## @brief Get a DataNode pointing to a data object containing the WorldGeometry (3D and 2D rendering) itkGetObjectMacro(WorldGeometryNode, DataNode) //##Documentation //## @brief Get a DataNode pointing to a data object containing the DisplayGeometry (for 2D rendering) itkGetObjectMacro(DisplayGeometryNode, DataNode) //##Documentation //## @brief Get a DataNode pointing to a data object containing the current 2D-worldgeometry m_CurrentWorldPlaneGeometry (for 2D rendering) itkGetObjectMacro(CurrentWorldPlaneGeometryNode, DataNode) /** * \deprecatedSince{2014_10} Please use GetCurrentWorldPlaneGeometryNode */ DEPRECATED(DataNode* GetCurrentWorldGeometry2DNode()){return GetCurrentWorldPlaneGeometryNode();}; //##Documentation //## @brief Sets timestamp of CurrentWorldPlaneGeometry and DisplayGeometry and forces so reslicing in that renderwindow void SendUpdateSlice(); //##Documentation //## @brief Get timestamp of last call of SetCurrentWorldPlaneGeometry unsigned long GetCurrentWorldPlaneGeometryUpdateTime() { return m_CurrentWorldPlaneGeometryUpdateTime; } /** * \deprecatedSince{2014_10} Please use GetCurrentWorldPlaneGeometryUpdateTime */ DEPRECATED(unsigned long GetCurrentWorldGeometry2DUpdateTime()){return GetCurrentWorldPlaneGeometryUpdateTime();}; //##Documentation //## @brief Get timestamp of last call of SetDisplayGeometry unsigned long GetDisplayGeometryUpdateTime() { return m_CurrentWorldPlaneGeometryUpdateTime; } //##Documentation //## @brief Get timestamp of last change of current TimeStep unsigned long GetTimeStepUpdateTime() { return m_TimeStepUpdateTime; } //##Documentation //## @brief Perform a picking: find the x,y,z world coordinate of a //## display x,y coordinate. //## @warning Has to be overwritten in subclasses for the 3D-case. //## //## Implemented here only for 2D-rendering by using //## m_DisplayGeometry virtual void PickWorldPoint(const Point2D& diplayPosition, Point3D& worldPosition) const; /** \brief Determines the object (mitk::DataNode) closest to the current * position by means of picking * * \warning Implementation currently empty for 2D rendering; intended to be * implemented for 3D renderers */ virtual DataNode* PickObject(const Point2D& /*displayPosition*/, Point3D& /*worldPosition*/) const { return NULL; } //##Documentation //## @brief Get the MapperSlotId to use. itkGetMacro(MapperID, MapperSlotId) itkGetConstMacro(MapperID, MapperSlotId) //##Documentation //## @brief Set the MapperSlotId to use. itkSetMacro(MapperID, MapperSlotId) //##Documentation //## @brief Has the renderer the focus? itkGetMacro(Focused, bool) //##Documentation //## @brief Tell the renderer that it is focused. The caller is responsible for focus management, //## not the renderer itself. itkSetMacro(Focused, bool) itkGetMacro(Size, int*) void SetSliceNavigationController(SliceNavigationController* SlicenavigationController); void SetCameraController(CameraController* cameraController); itkGetObjectMacro(CameraController, CameraController) itkGetObjectMacro(SliceNavigationController, SliceNavigationController) itkGetObjectMacro(CameraRotationController, CameraRotationController) itkGetMacro(EmptyWorldGeometry, bool) //##Documentation //## @brief Tells if the displayed region is shifted and rescaled if the render window is resized. itkGetMacro(KeepDisplayedRegion, bool) //##Documentation //## @brief Tells if the displayed region should be shifted and rescaled if the render window is resized. itkSetMacro(KeepDisplayedRegion, bool) //##Documentation //## @brief Mouse event dispatchers //## @note for internal use only. preliminary. virtual void MousePressEvent(MouseEvent*); //##Documentation //## @brief Mouse event dispatchers //## @note for internal use only. preliminary. virtual void MouseReleaseEvent(MouseEvent*); //##Documentation //## @brief Mouse event dispatchers //## @note for internal use only. preliminary. virtual void MouseMoveEvent(MouseEvent*); //##Documentation //## @brief Wheel event dispatcher //## @note for internal use only. preliminary. virtual void WheelEvent(mitk::WheelEvent* we); //##Documentation //## @brief Key event dispatcher //## @note for internal use only. preliminary. virtual void KeyPressEvent(KeyEvent*); //##Documentation //## @brief get the name of the Renderer //## @note const char * GetName() const { return m_Name.c_str(); } //##Documentation //## @brief get the x_size of the RendererWindow //## @note int GetSizeX() const { return m_Size[0]; } //##Documentation //## @brief get the y_size of the RendererWindow //## @note int GetSizeY() const { return m_Size[1]; } const double* GetBounds() const; void RequestUpdate(); void ForceImmediateUpdate(); /** Returns number of mappers which are visible and have level-of-detail * rendering enabled */ unsigned int GetNumberOfVisibleLODEnabledMappers() const; ///** //* \brief Setter for the RenderingManager that handles this instance of BaseRenderer //*/ //void SetRenderingManager( mitk::RenderingManager* ); /** * \brief Getter for the RenderingManager that handles this instance of BaseRenderer */ virtual mitk::RenderingManager* GetRenderingManager() const; /** * \brief Provides (1) world coordinates for a given mouse position and (2) * translates mousePosition to Display coordinates */ virtual Point3D Map2DRendererPositionTo3DWorldPosition(const Point2D& mousePosition) const; /** * \deprecatedSince{2014_03} Please use Map2DRendererPositionTo3DWorldPosition(const Point2D& mousePosition) const */ DEPRECATED(Point3D Map2DRendererPositionTo3DWorldPosition(Point2D* mousePosition) const); protected: virtual ~BaseRenderer(); //##Documentation //## @brief Call update of all mappers. To be implemented in subclasses. virtual void Update() = 0; vtkRenderWindow* m_RenderWindow; vtkRenderer* m_VtkRenderer; //##Documentation //## @brief MapperSlotId to use. Defines which kind of mapper (e.g., 2D or 3D) shoud be used. MapperSlotId m_MapperID; //##Documentation //## @brief The DataStorage that is used for rendering. DataStorage::Pointer m_DataStorage; //##Documentation //## @brief The RenderingManager that manages this instance RenderingManager::Pointer m_RenderingManager; //##Documentation //## @brief Timestamp of last call of Update(). unsigned long m_LastUpdateTime; //##Documentation //## @brief CameraController for 3D rendering //## @note preliminary. CameraController::Pointer m_CameraController; SliceNavigationController::Pointer m_SliceNavigationController; CameraRotationController::Pointer m_CameraRotationController; //##Documentation //## @brief Size of the RenderWindow. int m_Size[2]; //##Documentation //## @brief Contains whether the renderer that it is focused. The caller of //## SetFocused is responsible for focus management, not the renderer itself. //## is doubled because of mitk::FocusManager in GlobalInteraction!!! (ingmar) bool m_Focused; //##Documentation //## @brief Sets m_CurrentWorldPlaneGeometry virtual void SetCurrentWorldPlaneGeometry(PlaneGeometry* geometry2d); /** * \deprecatedSince{2014_10} Please use SetCurrentWorldPlaneGeometry */ DEPRECATED(void SetCurrentWorldGeometry2D(PlaneGeometry* geometry2d)){SetCurrentWorldPlaneGeometry(geometry2d);}; //##Documentation //## @brief Sets m_CurrentWorldGeometry virtual void SetCurrentWorldGeometry(BaseGeometry* geometry); //##Documentation //## @brief This method is called during the rendering process to update or render the Overlays //## which are stored in the OverlayManager void UpdateOverlays(); private: + //TODO 18735: Warum gibt es drei weltgeometrien + welt plane? Warum sollte sie laut Kommentar const sein?! //##Documentation //## Pointer to the worldgeometry, describing the maximal area to be rendered //## (3D as well as 2D). //## It is const, since we are not allowed to change it (it may be taken //## directly from the geometry of an image-slice and thus it would be //## very strange when suddenly the image-slice changes its geometry). //## \sa SetWorldGeometry + //TODO 18735: Kann gelöscht werden, weil er nie verwendet wird (außer QmtikSlicesInterpolator (falsch verwendet, code kann nie erreicht werden, bug?)) BaseGeometry::Pointer m_WorldGeometry; itk::SmartPointer m_OverlayManager; //##Documentation //## m_WorldTimeGeometry is set by SetWorldGeometry if the passed BaseGeometry is a //## TimeGeometry (or a sub-class of it). If it contains instances of SlicedGeometry3D, //## m_Slice and m_TimeStep (set via SetSlice and SetTimeStep, respectively) define //## which 2D geometry stored in m_WorldTimeGeometry (if available) //## is used as m_CurrentWorldPlaneGeometry. //## \sa m_CurrentWorldPlaneGeometry TimeGeometry::Pointer m_WorldTimeGeometry; //##Documentation //## Pointer to the current 3D-worldgeometry. BaseGeometry::Pointer m_CurrentWorldGeometry; //##Documentation //## Pointer to the current 2D-worldgeometry. The 2D-worldgeometry //## describes the maximal area (2D manifold) to be rendered in case we //## are doing 2D-rendering. More precisely, a subpart of this according //## to m_DisplayGeometry is displayed. //## It is const, since we are not allowed to change it (it may be taken //## directly from the geometry of an image-slice and thus it would be //## very strange when suddenly the image-slice changes its geometry). PlaneGeometry::Pointer m_CurrentWorldPlaneGeometry; //##Documentation //## Pointer to the displaygeometry. The displaygeometry describes the //## geometry of the \em visible area in the window controlled by the renderer //## in case we are doing 2D-rendering. //## It is const, since we are not allowed to change it. DisplayGeometry::Pointer m_DisplayGeometry; //##Documentation //## Defines together with m_Slice which 2D geometry stored in m_WorldTimeGeometry //## is used as m_CurrentWorldPlaneGeometry: m_WorldTimeGeometry->GetPlaneGeometry(m_Slice, m_TimeStep). //## \sa m_WorldTimeGeometry unsigned int m_Slice; //##Documentation //## Defines together with m_TimeStep which 2D geometry stored in m_WorldTimeGeometry //## is used as m_CurrentWorldPlaneGeometry: m_WorldTimeGeometry->GetPlaneGeometry(m_Slice, m_TimeStep). //## \sa m_WorldTimeGeometry unsigned int m_TimeStep; //##Documentation //## @brief timestamp of last call of SetWorldGeometry itk::TimeStamp m_CurrentWorldPlaneGeometryUpdateTime; //##Documentation //## @brief timestamp of last call of SetDisplayGeometry itk::TimeStamp m_DisplayGeometryUpdateTime; //##Documentation //## @brief timestamp of last change of the current time step itk::TimeStamp m_TimeStepUpdateTime; //##Documentation //## @brief Helper class which establishes connection between Interactors and Dispatcher via a common DataStorage. BindDispatcherInteractor* m_BindDispatcherInteractor; //##Documentation //## @brief Tells if the displayed region should be shifted or rescaled if the render window is resized. bool m_KeepDisplayedRegion; protected: virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; //##Documentation //## Data object containing the m_WorldGeometry defined above. PlaneGeometryData::Pointer m_WorldGeometryData; //##Documentation //## Data object containing the m_DisplayGeometry defined above. PlaneGeometryData::Pointer m_DisplayGeometryData; //##Documentation //## Data object containing the m_CurrentWorldPlaneGeometry defined above. PlaneGeometryData::Pointer m_CurrentWorldPlaneGeometryData; //##Documentation //## DataNode objects containing the m_WorldGeometryData defined above. DataNode::Pointer m_WorldGeometryNode; //##Documentation //## DataNode objects containing the m_DisplayGeometryData defined above. DataNode::Pointer m_DisplayGeometryNode; //##Documentation //## DataNode objects containing the m_CurrentWorldPlaneGeometryData defined above. DataNode::Pointer m_CurrentWorldPlaneGeometryNode; //##Documentation //## @brief test only unsigned long m_DisplayGeometryTransformTime; //##Documentation //## @brief test only unsigned long m_CurrentWorldPlaneGeometryTransformTime; std::string m_Name; double m_Bounds[6]; bool m_EmptyWorldGeometry; typedef std::set LODEnabledMappersType; /** Number of mappers which are visible and have level-of-detail * rendering enabled */ unsigned int m_NumberOfVisibleLODEnabledMappers; // Local Storage Handling for mappers protected: std::list m_RegisteredLocalStorageHandlers; public: void RemoveAllLocalStorages(); void RegisterLocalStorageHandler(mitk::BaseLocalStorageHandler *lsh); void UnregisterLocalStorageHandler(mitk::BaseLocalStorageHandler *lsh); }; } // namespace mitk #endif /* BASERENDERER_H_HEADER_INCLUDED_C1CCA0F4 */ diff --git a/Modules/Core/src/DataManagement/mitkDisplayGeometry.cpp b/Modules/Core/src/DataManagement/mitkDisplayGeometry.cpp index ccf4cb3eff..41fa7dc5ed 100644 --- a/Modules/Core/src/DataManagement/mitkDisplayGeometry.cpp +++ b/Modules/Core/src/DataManagement/mitkDisplayGeometry.cpp @@ -1,618 +1,623 @@ /*=================================================================== 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 "mitkDisplayGeometry.h" itk::LightObject::Pointer mitk::DisplayGeometry::InternalClone() const { // itkExceptionMacro(<<"calling mitk::DisplayGeometry::Clone does not make much sense."); DisplayGeometry* returnValue = const_cast(this); return returnValue; } bool mitk::DisplayGeometry::IsValid() const { return m_WorldGeometry.IsNotNull() && m_WorldGeometry->IsValid(); } unsigned long mitk::DisplayGeometry::GetMTime() const { if((m_WorldGeometry.IsNotNull()) && (PlaneGeometry::GetMTime() < m_WorldGeometry->GetMTime())) { Modified(); } return PlaneGeometry::GetMTime(); } //const mitk::TimeBounds& mitk::DisplayGeometry::GetTimeBounds() const //{ // if(m_WorldGeometry.IsNull()) // { // return m_TimeBounds; // } // // return m_WorldGeometry->GetTimeBounds(); //} // size definition methods void mitk::DisplayGeometry::SetWorldGeometry(const PlaneGeometry* aWorldGeometry) { m_WorldGeometry = aWorldGeometry; Modified(); } bool mitk::DisplayGeometry::SetOriginInMM(const Vector2D& origin_mm) { m_OriginInMM = origin_mm; WorldToDisplay(m_OriginInMM, m_OriginInDisplayUnits); Modified(); return !this->RefitVisibleRect(); } mitk::Vector2D mitk::DisplayGeometry::GetOriginInMM() const { return m_OriginInMM; } mitk::Vector2D mitk::DisplayGeometry::GetOriginInDisplayUnits() const { return m_OriginInDisplayUnits; } void mitk::DisplayGeometry::SetSizeInDisplayUnits(unsigned int width, unsigned int height, bool keepDisplayedRegion) { Vector2D oldSizeInMM( m_SizeInMM ); Point2D oldCenterInMM; if(keepDisplayedRegion) { Point2D centerInDisplayUnits; centerInDisplayUnits[0] = m_SizeInDisplayUnits[0]*0.5; centerInDisplayUnits[1] = m_SizeInDisplayUnits[1]*0.5; DisplayToWorld(centerInDisplayUnits, oldCenterInMM); } m_SizeInDisplayUnits[0]=width; m_SizeInDisplayUnits[1]=height; if(m_SizeInDisplayUnits[0] <= 0) m_SizeInDisplayUnits[0] = 1; if(m_SizeInDisplayUnits[1] <= 0) m_SizeInDisplayUnits[1] = 1; DisplayToWorld(m_SizeInDisplayUnits, m_SizeInMM); if(keepDisplayedRegion) { Point2D positionOfOldCenterInCurrentDisplayUnits; WorldToDisplay(oldCenterInMM, positionOfOldCenterInCurrentDisplayUnits); Point2D currentNewCenterInDisplayUnits; currentNewCenterInDisplayUnits[0] = m_SizeInDisplayUnits[0]*0.5; currentNewCenterInDisplayUnits[1] = m_SizeInDisplayUnits[1]*0.5; Vector2D shift; shift=positionOfOldCenterInCurrentDisplayUnits-currentNewCenterInDisplayUnits; MoveBy(shift); Zoom(m_SizeInMM.GetNorm()/oldSizeInMM.GetNorm(), currentNewCenterInDisplayUnits); } Modified(); } mitk::Vector2D mitk::DisplayGeometry::GetSizeInDisplayUnits() const { return m_SizeInDisplayUnits; } mitk::Vector2D mitk::DisplayGeometry::GetSizeInMM() const { return m_SizeInMM; } unsigned int mitk::DisplayGeometry::GetDisplayWidth() const { assert(m_SizeInDisplayUnits[0] >= 0); return (unsigned int)m_SizeInDisplayUnits[0]; } unsigned int mitk::DisplayGeometry::GetDisplayHeight() const { assert(m_SizeInDisplayUnits[1] >= 0); return (unsigned int)m_SizeInDisplayUnits[1]; } // zooming, panning, restriction of both void mitk::DisplayGeometry::SetConstrainZoomingAndPanning(bool constrain) { m_ConstrainZoomingAndPanning = constrain; if (m_ConstrainZoomingAndPanning) { this->RefitVisibleRect(); } } bool mitk::DisplayGeometry::GetConstrainZommingAndPanning() const { return m_ConstrainZoomingAndPanning; } bool mitk::DisplayGeometry::SetScaleFactor(ScalarType mmPerDisplayUnit) { if(mmPerDisplayUnit<0.0001) { mmPerDisplayUnit=0.0001; } m_ScaleFactorMMPerDisplayUnit = mmPerDisplayUnit; assert(m_ScaleFactorMMPerDisplayUnit < itk::NumericTraits::infinity()); DisplayToWorld(m_SizeInDisplayUnits, m_SizeInMM); return !this->RefitVisibleRect(); } mitk::ScalarType mitk::DisplayGeometry::GetScaleFactorMMPerDisplayUnit() const { return m_ScaleFactorMMPerDisplayUnit; } // Zooms with a factor (1.0=identity) around the specified center in display units bool mitk::DisplayGeometry::Zoom(ScalarType factor, const Point2D& centerInDisplayUnits) { assert(factor > 0); if ( SetScaleFactor(m_ScaleFactorMMPerDisplayUnit/factor) ) { return SetOriginInMM(m_OriginInMM-centerInDisplayUnits.GetVectorFromOrigin()*(1-factor)*m_ScaleFactorMMPerDisplayUnit); } else { return false; } } // Zooms with a factor (1.0=identity) around the specified center, but tries (if its within view contraints) to match the center in display units with the center in world coordinates. bool mitk::DisplayGeometry::ZoomWithFixedWorldCoordinates(ScalarType factor, const Point2D& focusDisplayUnits, const Point2D& focusUnitsInMM ) { assert(factor > 0); if (factor != 1.0) { SetScaleFactor(m_ScaleFactorMMPerDisplayUnit/factor); SetOriginInMM(focusUnitsInMM.GetVectorFromOrigin()-focusDisplayUnits.GetVectorFromOrigin()*m_ScaleFactorMMPerDisplayUnit); } return true; } bool mitk::DisplayGeometry::MoveBy(const Vector2D& shiftInDisplayUnits) { SetOriginInMM(m_OriginInMM+shiftInDisplayUnits*m_ScaleFactorMMPerDisplayUnit); Modified(); return !this->RefitVisibleRect(); } void mitk::DisplayGeometry::Fit() { if((m_WorldGeometry.IsNull()) || (m_WorldGeometry->IsValid() == false)) return; /// \FIXME: try to remove all the casts int width=(int)m_SizeInDisplayUnits[0]; int height=(int)m_SizeInDisplayUnits[1]; ScalarType w = width; ScalarType h = height; const ScalarType& widthInMM = m_WorldGeometry->GetExtentInMM(0); const ScalarType& heightInMM = m_WorldGeometry->GetExtentInMM(1); ScalarType aspRatio=((ScalarType)widthInMM)/heightInMM; ScalarType x = (ScalarType)w/widthInMM; ScalarType y = (ScalarType)h/heightInMM; if (x > y) { w = (int) (aspRatio*h); } else { h = (int) (w/aspRatio); } if(w>0) { SetScaleFactor(widthInMM/w); } Vector2D origin_display; origin_display[0]=-(width-w)/2.0; origin_display[1]=-(height-h)/2.0; SetOriginInMM(origin_display*m_ScaleFactorMMPerDisplayUnit); this->RefitVisibleRect(); Modified(); } // conversion methods void mitk::DisplayGeometry::DisplayToWorld(const Point2D &pt_display, Point2D &pt_mm) const { + //pt_display is in pixel units. It is scaled by the zooming factor and moved by the origin of the image (world geometry). pt_mm[0]=m_ScaleFactorMMPerDisplayUnit*pt_display[0]+m_OriginInMM[0]; pt_mm[1]=m_ScaleFactorMMPerDisplayUnit*pt_display[1]+m_OriginInMM[1]; + MITK_INFO <<"m_originInMM aus DisplayGeo: "<< m_OriginInMM; + //the result is a 2D vector from the origin of the world geometry to the projection of the requested point onto the first slice. } void mitk::DisplayGeometry::WorldToDisplay(const Point2D &pt_mm, Point2D &pt_display) const { pt_display[0]=(pt_mm[0]-m_OriginInMM[0])*(1.0/m_ScaleFactorMMPerDisplayUnit); pt_display[1]=(pt_mm[1]-m_OriginInMM[1])*(1.0/m_ScaleFactorMMPerDisplayUnit); } void mitk::DisplayGeometry::DisplayToWorld(const Vector2D &vec_display, Vector2D &vec_mm) const { vec_mm=vec_display*m_ScaleFactorMMPerDisplayUnit; } void mitk::DisplayGeometry::WorldToDisplay(const Vector2D &vec_mm, Vector2D &vec_display) const { vec_display=vec_mm*(1.0/m_ScaleFactorMMPerDisplayUnit); } void mitk::DisplayGeometry::ULDisplayToMM(const Point2D &pt_ULdisplay, Point2D &pt_mm) const { ULDisplayToDisplay(pt_ULdisplay, pt_mm); DisplayToWorld(pt_mm, pt_mm); } void mitk::DisplayGeometry::MMToULDisplay(const Point2D &pt_mm, Point2D &pt_ULdisplay) const { WorldToDisplay(pt_mm, pt_ULdisplay); DisplayToULDisplay(pt_ULdisplay, pt_ULdisplay); } void mitk::DisplayGeometry::ULDisplayToMM(const Vector2D &vec_ULdisplay, Vector2D &vec_mm) const { ULDisplayToDisplay(vec_ULdisplay, vec_mm); DisplayToWorld(vec_mm, vec_mm); } void mitk::DisplayGeometry::MMToULDisplay(const Vector2D &vec_mm, Vector2D &vec_ULdisplay) const { WorldToDisplay(vec_mm, vec_ULdisplay); DisplayToULDisplay(vec_ULdisplay, vec_ULdisplay); } +//TODO 18735 remove this functions... not needed... can be done directly. Or delete this class... void mitk::DisplayGeometry::ULDisplayToDisplay(const Point2D &pt_ULdisplay, Point2D &pt_display) const { pt_display[0]=pt_ULdisplay[0]; pt_display[1]=GetDisplayHeight()-pt_ULdisplay[1]; } +//TODO 18735 remove this functions... not needed... can be done directly. Or delete this class... void mitk::DisplayGeometry::DisplayToULDisplay(const Point2D &pt_display, Point2D &pt_ULdisplay) const { ULDisplayToDisplay(pt_display, pt_ULdisplay); } void mitk::DisplayGeometry::ULDisplayToDisplay(const Vector2D &vec_ULdisplay, Vector2D &vec_display) const { vec_display[0]= vec_ULdisplay[0]; vec_display[1]=-vec_ULdisplay[1]; } void mitk::DisplayGeometry::DisplayToULDisplay(const Vector2D &vec_display, Vector2D &vec_ULdisplay) const { ULDisplayToDisplay(vec_display, vec_ULdisplay); } bool mitk::DisplayGeometry::Project(const Point3D &pt3d_mm, Point3D &projectedPt3d_mm) const { if(m_WorldGeometry.IsNotNull()) { return m_WorldGeometry->Project(pt3d_mm, projectedPt3d_mm); } else { return false; } } bool mitk::DisplayGeometry::Project(const Point3D & atPt3d_mm, const Vector3D &vec3d_mm, Vector3D &projectedVec3d_mm) const { if(m_WorldGeometry.IsNotNull()) { return m_WorldGeometry->Project(atPt3d_mm, vec3d_mm, projectedVec3d_mm); } else { return false; } } bool mitk::DisplayGeometry::Project(const Vector3D &vec3d_mm, Vector3D &projectedVec3d_mm) const { if(m_WorldGeometry.IsNotNull()) { return m_WorldGeometry->Project(vec3d_mm, projectedVec3d_mm); } else { return false; } } bool mitk::DisplayGeometry::Map(const Point3D &pt3d_mm, Point2D &pt2d_mm) const { if(m_WorldGeometry.IsNotNull()) { return m_WorldGeometry->Map(pt3d_mm, pt2d_mm); } else { return false; } } void mitk::DisplayGeometry::Map(const Point2D &pt2d_mm, Point3D &pt3d_mm) const { if(m_WorldGeometry.IsNull()) return; m_WorldGeometry->Map(pt2d_mm, pt3d_mm); } bool mitk::DisplayGeometry::Map(const Point3D & atPt3d_mm, const Vector3D &vec3d_mm, Vector2D &vec2d_mm) const { if(m_WorldGeometry.IsNotNull()) { return m_WorldGeometry->Map(atPt3d_mm, vec3d_mm, vec2d_mm); } else { return false; } } void mitk::DisplayGeometry::Map(const Point2D & atPt2d_mm, const Vector2D &vec2d_mm, Vector3D &vec3d_mm) const { if(m_WorldGeometry.IsNull()) return; m_WorldGeometry->Map(atPt2d_mm, vec2d_mm, vec3d_mm); } // protected methods mitk::DisplayGeometry::DisplayGeometry() : PlaneGeometry() ,m_ScaleFactorMMPerDisplayUnit(1.0) ,m_WorldGeometry(NULL) ,m_ConstrainZoomingAndPanning(true) ,m_MaxWorldViewPercentage(1.0) ,m_MinWorldViewPercentage(0.1) { m_OriginInMM.Fill(0.0); m_OriginInDisplayUnits.Fill(0.0); m_SizeInMM.Fill(1.0); m_SizeInDisplayUnits.Fill(10.0); } mitk::DisplayGeometry::~DisplayGeometry() { } bool mitk::DisplayGeometry::RefitVisibleRect() { // do nothing if not asked to if (!m_ConstrainZoomingAndPanning) return false; // don't allow recursion (need to be fixed, singleton) static bool inRecalculate = false; if (inRecalculate) return false; inRecalculate = true; // rename some basic measures of the current viewport and world geometry (MM = milimeters Px = Pixels = display units) float displayXMM = m_OriginInMM[0]; float displayYMM = m_OriginInMM[1]; float displayWidthPx = m_SizeInDisplayUnits[0]; float displayHeightPx = m_SizeInDisplayUnits[1]; float displayWidthMM = m_SizeInDisplayUnits[0] * m_ScaleFactorMMPerDisplayUnit; float displayHeightMM = m_SizeInDisplayUnits[1] * m_ScaleFactorMMPerDisplayUnit; float worldWidthMM = m_WorldGeometry->GetExtentInMM(0); float worldHeightMM = m_WorldGeometry->GetExtentInMM(1); // reserve variables for the correction logic to save a corrected origin and zoom factor Vector2D newOrigin = m_OriginInMM; bool correctPanning = false; float newScaleFactor = m_ScaleFactorMMPerDisplayUnit; bool correctZooming = false; // start of the correction logic // zoom to big means: // at a given percentage of the world's width/height should be visible. Otherwise // the whole screen could show only one pixel // // zoom to small means: // zooming out should be limited at the point where the smaller of the world's sides is completely visible bool zoomXtooSmall = displayWidthPx * m_ScaleFactorMMPerDisplayUnit > m_MaxWorldViewPercentage * worldWidthMM; bool zoomXtooBig = displayWidthPx * m_ScaleFactorMMPerDisplayUnit < m_MinWorldViewPercentage * worldWidthMM; bool zoomYtooSmall = displayHeightPx * m_ScaleFactorMMPerDisplayUnit > m_MaxWorldViewPercentage * worldHeightMM; bool zoomYtooBig = displayHeightPx * m_ScaleFactorMMPerDisplayUnit < m_MinWorldViewPercentage * worldHeightMM; // constrain zooming in both direction if ( zoomXtooBig && zoomYtooBig) { double fx = worldWidthMM * m_MinWorldViewPercentage / displayWidthPx; double fy = worldHeightMM * m_MinWorldViewPercentage / displayHeightPx; newScaleFactor = fx < fy ? fx : fy; correctZooming = true; } // constrain zooming in x direction else if ( zoomXtooBig ) { newScaleFactor = worldWidthMM * m_MinWorldViewPercentage / displayWidthPx; correctZooming = true; } // constrain zooming in y direction else if ( zoomYtooBig ) { newScaleFactor = worldHeightMM * m_MinWorldViewPercentage / displayHeightPx; correctZooming = true; } // constrain zooming out // we stop zooming out at these situations: // // *** display // --- image // // ********************** // * * x side maxed out // * * // *--------------------* // *| |* // *| |* // *--------------------* // * * // * * // * * // ********************** // // ********************** // * |------| * y side maxed out // * | | * // * | | * // * | | * // * | | * // * | | * // * | | * // * | | * // * |------| * // ********************** // // In both situations we center the not-maxed out direction // if ( zoomXtooSmall && zoomYtooSmall ) { // determine and set the bigger scale factor float fx = worldWidthMM * m_MaxWorldViewPercentage / displayWidthPx; float fy = worldHeightMM * m_MaxWorldViewPercentage / displayHeightPx; newScaleFactor = fx > fy ? fx : fy; correctZooming = true; } // actually execute correction if (correctZooming) { SetScaleFactor(newScaleFactor); } displayWidthMM = m_SizeInDisplayUnits[0] * m_ScaleFactorMMPerDisplayUnit; displayHeightMM = m_SizeInDisplayUnits[1] * m_ScaleFactorMMPerDisplayUnit; // constrain panning if(worldWidthMM center x newOrigin[0] = (worldWidthMM - displayWidthMM) / 2.0; correctPanning = true; } else { // make sure left display border inside our world if (displayXMM < 0) { newOrigin[0] = 0; correctPanning = true; } // make sure right display border inside our world else if (displayXMM + displayWidthMM > worldWidthMM) { newOrigin[0] = worldWidthMM - displayWidthMM; correctPanning = true; } } if (worldHeightMM center y newOrigin[1] = (worldHeightMM - displayHeightMM) / 2.0; correctPanning = true; } else { // make sure top display border inside our world if (displayYMM + displayHeightMM > worldHeightMM) { newOrigin[1] = worldHeightMM - displayHeightMM; correctPanning = true; } // make sure bottom display border inside our world else if (displayYMM < 0) { newOrigin[1] = 0; correctPanning = true; } } if (correctPanning) { SetOriginInMM( newOrigin ); } inRecalculate = false; if ( correctPanning || correctZooming ) { Modified(); } // return true if any correction has been made return correctPanning || correctZooming; } void mitk::DisplayGeometry::PrintSelf(std::ostream& os, itk::Indent indent) const { if(m_WorldGeometry.IsNull()) { os << indent << " WorldGeometry: " << "NULL" << std::endl; } else { m_WorldGeometry->Print(os, indent); os << indent << " OriginInMM: " << m_OriginInMM << std::endl; os << indent << " OriginInDisplayUnits: " << m_OriginInDisplayUnits << std::endl; os << indent << " SizeInMM: " << m_SizeInMM << std::endl; os << indent << " SizeInDisplayUnits: " << m_SizeInDisplayUnits << std::endl; os << indent << " ScaleFactorMMPerDisplayUni: " << m_ScaleFactorMMPerDisplayUnit << std::endl; } Superclass::PrintSelf(os,indent); } diff --git a/Modules/Core/src/DataManagement/mitkPlaneGeometry.cpp b/Modules/Core/src/DataManagement/mitkPlaneGeometry.cpp index ccc0aac060..e8707a8257 100644 --- a/Modules/Core/src/DataManagement/mitkPlaneGeometry.cpp +++ b/Modules/Core/src/DataManagement/mitkPlaneGeometry.cpp @@ -1,916 +1,922 @@ /*=================================================================== 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 "mitkPlaneGeometry.h" #include "mitkPlaneOperation.h" #include "mitkInteractionConst.h" #include "mitkLine.h" #include #include namespace mitk { PlaneGeometry::PlaneGeometry() : Superclass(), m_ScaleFactorMMPerUnitX( 1.0 ), m_ScaleFactorMMPerUnitY( 1.0 ), m_ReferenceGeometry( NULL ) { Initialize(); } PlaneGeometry::~PlaneGeometry() { } PlaneGeometry::PlaneGeometry(const PlaneGeometry& other) : Superclass(other), m_ScaleFactorMMPerUnitX( other.m_ScaleFactorMMPerUnitX), m_ScaleFactorMMPerUnitY( other.m_ScaleFactorMMPerUnitY), m_ReferenceGeometry( other.m_ReferenceGeometry ) { } void PlaneGeometry::EnsurePerpendicularNormal(mitk::AffineTransform3D *transform) { //ensure row(2) of transform to be perpendicular to plane, keep length. VnlVector normal = vnl_cross_3d( transform->GetMatrix().GetVnlMatrix().get_column(0), transform->GetMatrix().GetVnlMatrix().get_column(1) ); normal.normalize(); ScalarType len = transform->GetMatrix() .GetVnlMatrix().get_column(2).two_norm(); if (len==0) len = 1; normal*=len; Matrix3D matrix = transform->GetMatrix(); matrix.GetVnlMatrix().set_column(2, normal); transform->SetMatrix(matrix); } void PlaneGeometry::PreSetIndexToWorldTransform(mitk::AffineTransform3D *transform) { EnsurePerpendicularNormal(transform); } void PlaneGeometry::PreSetBounds(const BoundingBox::BoundsArrayType &bounds) { // error: unused parameter 'bounds' // this happens in release mode, where the assert macro is defined empty // hence we "use" the parameter: (void)bounds; //currently the unit rectangle must be starting at the origin [0,0] assert(bounds[0]==0); assert(bounds[2]==0); //the unit rectangle must be two-dimensional assert(bounds[1]>0); assert(bounds[3]>0); } void PlaneGeometry::IndexToWorld( const Point2D &pt_units, Point2D &pt_mm ) const { pt_mm[0]=m_ScaleFactorMMPerUnitX*pt_units[0]; pt_mm[1]=m_ScaleFactorMMPerUnitY*pt_units[1]; } void PlaneGeometry::WorldToIndex( const Point2D &pt_mm, Point2D &pt_units ) const { pt_units[0]=pt_mm[0]*(1.0/m_ScaleFactorMMPerUnitX); pt_units[1]=pt_mm[1]*(1.0/m_ScaleFactorMMPerUnitY); } void PlaneGeometry::IndexToWorld( const Point2D & /*atPt2d_units*/, const Vector2D &vec_units, Vector2D &vec_mm) const { MITK_WARN<<"Warning! Call of the deprecated function PlaneGeometry::IndexToWorld(point, vec, vec). Use PlaneGeometry::IndexToWorld(vec, vec) instead!"; this->IndexToWorld(vec_units, vec_mm); } void PlaneGeometry::IndexToWorld(const Vector2D &vec_units, Vector2D &vec_mm) const { vec_mm[0] = m_ScaleFactorMMPerUnitX * vec_units[0]; vec_mm[1] = m_ScaleFactorMMPerUnitY * vec_units[1]; } void PlaneGeometry::WorldToIndex( const Point2D & /*atPt2d_mm*/, const Vector2D &vec_mm, Vector2D &vec_units) const { MITK_WARN<<"Warning! Call of the deprecated function PlaneGeometry::WorldToIndex(point, vec, vec). Use PlaneGeometry::WorldToIndex(vec, vec) instead!"; this->WorldToIndex(vec_mm, vec_units); } void PlaneGeometry::WorldToIndex( const Vector2D &vec_mm, Vector2D &vec_units) const { vec_units[0] = vec_mm[0] * ( 1.0 / m_ScaleFactorMMPerUnitX ); vec_units[1] = vec_mm[1] * ( 1.0 / m_ScaleFactorMMPerUnitY ); } void PlaneGeometry::InitializeStandardPlane( mitk::ScalarType width, ScalarType height, const Vector3D & spacing, PlaneGeometry::PlaneOrientation planeorientation, ScalarType zPosition, bool frontside, bool rotated ) { AffineTransform3D::Pointer transform; transform = AffineTransform3D::New(); AffineTransform3D::MatrixType matrix; AffineTransform3D::MatrixType::InternalMatrixType &vnlmatrix = matrix.GetVnlMatrix(); vnlmatrix.set_identity(); vnlmatrix(0,0) = spacing[0]; vnlmatrix(1,1) = spacing[1]; vnlmatrix(2,2) = spacing[2]; transform->SetIdentity(); transform->SetMatrix(matrix); InitializeStandardPlane(width, height, transform.GetPointer(), planeorientation, zPosition, frontside, rotated); } void PlaneGeometry::InitializeStandardPlane( mitk::ScalarType width, ScalarType height, const AffineTransform3D* transform, PlaneGeometry::PlaneOrientation planeorientation, ScalarType zPosition, bool frontside, bool rotated ) { Superclass::Initialize(); //construct standard view Point3D origin; VnlVector rightDV(3), bottomDV(3); origin.Fill(0); int normalDirection; switch(planeorientation) { case Axial: if(frontside) { if(rotated==false) { FillVector3D(origin, 0, 0, zPosition); FillVector3D(rightDV, 1, 0, 0); FillVector3D(bottomDV, 0, 1, 0); } else { FillVector3D(origin, width, height, zPosition); FillVector3D(rightDV, -1, 0, 0); FillVector3D(bottomDV, 0, -1, 0); } } else { if(rotated==false) { FillVector3D(origin, width, 0, zPosition); FillVector3D(rightDV, -1, 0, 0); FillVector3D(bottomDV, 0, 1, 0); } else { FillVector3D(origin, 0, height, zPosition); FillVector3D(rightDV, 1, 0, 0); FillVector3D(bottomDV, 0, -1, 0); } } normalDirection = 2; break; case Frontal: if(frontside) { if(rotated==false) { FillVector3D(origin, 0, zPosition, 0); FillVector3D(rightDV, 1, 0, 0); FillVector3D(bottomDV, 0, 0, 1); } else { FillVector3D(origin, width, zPosition, height); FillVector3D(rightDV, -1, 0, 0); FillVector3D(bottomDV, 0, 0, -1); } } else { if(rotated==false) { FillVector3D(origin, width, zPosition, 0); FillVector3D(rightDV, -1, 0, 0); FillVector3D(bottomDV, 0, 0, 1); } else { FillVector3D(origin, 0, zPosition, height); FillVector3D(rightDV, 1, 0, 0); FillVector3D(bottomDV, 0, 0, -1); } } normalDirection = 1; break; case Sagittal: if(frontside) { if(rotated==false) { FillVector3D(origin, zPosition, 0, 0); FillVector3D(rightDV, 0, 1, 0); FillVector3D(bottomDV, 0, 0, 1); } else { FillVector3D(origin, zPosition, width, height); FillVector3D(rightDV, 0, -1, 0); FillVector3D(bottomDV, 0, 0, -1); } } else { if(rotated==false) { FillVector3D(origin, zPosition, width, 0); FillVector3D(rightDV, 0, -1, 0); FillVector3D(bottomDV, 0, 0, 1); } else { FillVector3D(origin, zPosition, 0, height); FillVector3D(rightDV, 0, 1, 0); FillVector3D(bottomDV, 0, 0, -1); } } normalDirection = 0; break; default: itkExceptionMacro("unknown PlaneOrientation"); } if ( transform != NULL ) { origin = transform->TransformPoint( origin ); rightDV = transform->TransformVector( rightDV ); bottomDV = transform->TransformVector( bottomDV ); } ScalarType bounds[6]= { 0, width, 0, height, 0, 1 }; this->SetBounds( bounds ); if ( transform == NULL ) { this->SetMatrixByVectors( rightDV, bottomDV ); } else { this->SetMatrixByVectors( rightDV, bottomDV, transform->GetMatrix().GetVnlMatrix() .get_column(normalDirection).magnitude() ); } this->SetOrigin(origin); } void PlaneGeometry::InitializeStandardPlane( const BaseGeometry *geometry3D, PlaneOrientation planeorientation, ScalarType zPosition, bool frontside, bool rotated ) { this->SetReferenceGeometry( const_cast< BaseGeometry * >( geometry3D ) ); ScalarType width, height; const BoundingBox::BoundsArrayType& boundsarray = geometry3D->GetBoundingBox()->GetBounds(); Vector3D originVector; FillVector3D(originVector, boundsarray[0], boundsarray[2], boundsarray[4]); if(geometry3D->GetImageGeometry()) { FillVector3D( originVector, originVector[0] - 0.5, originVector[1] - 0.5, originVector[2] - 0.5 ); } switch(planeorientation) { case Axial: width = geometry3D->GetExtent(0); height = geometry3D->GetExtent(1); break; case Frontal: width = geometry3D->GetExtent(0); height = geometry3D->GetExtent(2); break; case Sagittal: width = geometry3D->GetExtent(1); height = geometry3D->GetExtent(2); break; default: itkExceptionMacro("unknown PlaneOrientation"); } InitializeStandardPlane( width, height, geometry3D->GetIndexToWorldTransform(), planeorientation, zPosition, frontside, rotated ); ScalarType bounds[6]= { 0, width, 0, height, 0, 1 }; this->SetBounds( bounds ); Point3D origin; originVector = geometry3D->GetIndexToWorldTransform() ->TransformVector( originVector ); origin = GetOrigin() + originVector; SetOrigin(origin); } void PlaneGeometry::InitializeStandardPlane( const BaseGeometry *geometry3D, bool top, PlaneOrientation planeorientation, bool frontside, bool rotated ) { ScalarType zPosition; switch(planeorientation) { case Axial: zPosition = (top ? 0.5 : geometry3D->GetExtent(2)-1+0.5); break; case Frontal: zPosition = (top ? 0.5 : geometry3D->GetExtent(1)-1+0.5); break; case Sagittal: zPosition = (top ? 0.5 : geometry3D->GetExtent(0)-1+0.5); break; default: itkExceptionMacro("unknown PlaneOrientation"); } InitializeStandardPlane( geometry3D, planeorientation, zPosition, frontside, rotated ); } void PlaneGeometry::InitializeStandardPlane( const Vector3D &rightVector, const Vector3D &downVector, const Vector3D *spacing ) { InitializeStandardPlane( rightVector.GetVnlVector(), downVector.GetVnlVector(), spacing ); } void PlaneGeometry::InitializeStandardPlane( const VnlVector& rightVector, const VnlVector &downVector, const Vector3D *spacing ) { ScalarType width = rightVector.magnitude(); ScalarType height = downVector.magnitude(); InitializeStandardPlane( width, height, rightVector, downVector, spacing ); } void PlaneGeometry::InitializeStandardPlane( mitk::ScalarType width, ScalarType height, const Vector3D &rightVector, const Vector3D &downVector, const Vector3D *spacing ) { InitializeStandardPlane( width, height, rightVector.GetVnlVector(), downVector.GetVnlVector(), spacing ); } void PlaneGeometry::InitializeStandardPlane( mitk::ScalarType width, ScalarType height, const VnlVector &rightVector, const VnlVector &downVector, const Vector3D *spacing ) { assert(width > 0); assert(height > 0); VnlVector rightDV = rightVector; rightDV.normalize(); VnlVector downDV = downVector; downDV.normalize(); VnlVector normal = vnl_cross_3d(rightVector, downVector); normal.normalize(); if(spacing!=NULL) { rightDV *= (*spacing)[0]; downDV *= (*spacing)[1]; normal *= (*spacing)[2]; } AffineTransform3D::Pointer transform = AffineTransform3D::New(); Matrix3D matrix; matrix.GetVnlMatrix().set_column(0, rightDV); matrix.GetVnlMatrix().set_column(1, downDV); matrix.GetVnlMatrix().set_column(2, normal); transform->SetMatrix(matrix); transform->SetOffset(this->GetIndexToWorldTransform()->GetOffset()); ScalarType bounds[6] = { 0, width, 0, height, 0, 1 }; this->SetBounds( bounds ); this->SetIndexToWorldTransform( transform ); } void PlaneGeometry::InitializePlane( const Point3D &origin, const Vector3D &normal ) { VnlVector rightVectorVnl(3), downVectorVnl; if( Equal( normal[1], 0.0f ) == false ) { FillVector3D( rightVectorVnl, 1.0f, -normal[0]/normal[1], 0.0f ); rightVectorVnl.normalize(); } else { FillVector3D( rightVectorVnl, 0.0f, 1.0f, 0.0f ); } downVectorVnl = vnl_cross_3d( normal.GetVnlVector(), rightVectorVnl ); downVectorVnl.normalize(); InitializeStandardPlane( rightVectorVnl, downVectorVnl ); SetOrigin(origin); } void PlaneGeometry::SetMatrixByVectors( const VnlVector &rightVector, const VnlVector &downVector, ScalarType thickness ) { VnlVector normal = vnl_cross_3d(rightVector, downVector); normal.normalize(); normal *= thickness; AffineTransform3D::Pointer transform = AffineTransform3D::New(); Matrix3D matrix; matrix.GetVnlMatrix().set_column(0, rightVector); matrix.GetVnlMatrix().set_column(1, downVector); matrix.GetVnlMatrix().set_column(2, normal); transform->SetMatrix(matrix); transform->SetOffset(this->GetIndexToWorldTransform()->GetOffset()); SetIndexToWorldTransform(transform); } Vector3D PlaneGeometry::GetNormal() const { Vector3D frontToBack; frontToBack.SetVnlVector( this->GetIndexToWorldTransform() ->GetMatrix().GetVnlMatrix().get_column(2) ); return frontToBack; } VnlVector PlaneGeometry::GetNormalVnl() const { return this->GetIndexToWorldTransform() ->GetMatrix().GetVnlMatrix().get_column(2); } ScalarType PlaneGeometry::DistanceFromPlane( const Point3D &pt3d_mm ) const { return fabs(SignedDistance( pt3d_mm )); } ScalarType PlaneGeometry::SignedDistance( const Point3D &pt3d_mm ) const { return SignedDistanceFromPlane(pt3d_mm); } //Function from Geometry2D // mitk::ScalarType // PlaneGeometry::SignedDistance(const mitk::Point3D& pt3d_mm) const //{ // Point3D projectedPoint; // Project(pt3d_mm, projectedPoint); // Vector3D direction = pt3d_mm-projectedPoint; // ScalarType distance = direction.GetNorm(); // if(IsAbove(pt3d_mm) == false) // distance*=-1.0; // return distance; //} bool PlaneGeometry::IsAbove( const Point3D &pt3d_mm , bool considerBoundingBox) const { if(considerBoundingBox) { Point3D pt3d_units; BaseGeometry::WorldToIndex(pt3d_mm, pt3d_units); return (pt3d_units[2] > this->GetBoundingBox()->GetBounds()[4]); } else return SignedDistanceFromPlane(pt3d_mm) > 0; } bool PlaneGeometry::IntersectionLine( const PlaneGeometry* plane, Line3D& crossline ) const { Vector3D normal = this->GetNormal(); normal.Normalize(); Vector3D planeNormal = plane->GetNormal(); planeNormal.Normalize(); Vector3D direction = itk::CrossProduct( normal, planeNormal ); if ( direction.GetSquaredNorm() < eps ) return false; crossline.SetDirection( direction ); double N1dN2 = normal * planeNormal; double determinant = 1.0 - N1dN2 * N1dN2; Vector3D origin = this->GetOrigin().GetVectorFromOrigin(); Vector3D planeOrigin = plane->GetOrigin().GetVectorFromOrigin(); double d1 = normal * origin; double d2 = planeNormal * planeOrigin; double c1 = ( d1 - d2 * N1dN2 ) / determinant; double c2 = ( d2 - d1 * N1dN2 ) / determinant; Vector3D p = normal * c1 + planeNormal * c2; crossline.GetPoint().GetVnlVector() = p.GetVnlVector(); return true; } unsigned int PlaneGeometry::IntersectWithPlane2D( const PlaneGeometry* plane, Point2D& lineFrom, Point2D &lineTo ) const { Line3D crossline; if ( this->IntersectionLine( plane, crossline ) == false ) return 0; Point2D point2; Vector2D direction2; this->Map( crossline.GetPoint(), point2 ); this->Map( crossline.GetPoint(), crossline.GetDirection(), direction2 ); return Line3D::RectangleLineIntersection( 0, 0, GetExtentInMM(0), GetExtentInMM(1), point2, direction2, lineFrom, lineTo ); } double PlaneGeometry::Angle( const PlaneGeometry *plane ) const { return angle(plane->GetMatrixColumn(2), GetMatrixColumn(2)); } double PlaneGeometry::Angle( const Line3D &line ) const { return vnl_math::pi_over_2 - angle( line.GetDirection().GetVnlVector(), GetMatrixColumn(2) ); } bool PlaneGeometry::IntersectionPoint( const Line3D &line, Point3D &intersectionPoint ) const { Vector3D planeNormal = this->GetNormal(); planeNormal.Normalize(); Vector3D lineDirection = line.GetDirection(); lineDirection.Normalize(); double t = planeNormal * lineDirection; if ( fabs( t ) < eps ) { return false; } Vector3D diff; diff = this->GetOrigin() - line.GetPoint(); t = ( planeNormal * diff ) / t; intersectionPoint = line.GetPoint() + lineDirection * t; return true; } bool PlaneGeometry::IntersectionPointParam( const Line3D &line, double &t ) const { Vector3D planeNormal = this->GetNormal(); Vector3D lineDirection = line.GetDirection(); t = planeNormal * lineDirection; if ( fabs( t ) < eps ) { return false; } Vector3D diff; diff = this->GetOrigin() - line.GetPoint(); t = ( planeNormal * diff ) / t; return true; } bool PlaneGeometry::IsParallel( const PlaneGeometry *plane ) const { return ( (Angle(plane) < 10.0 * mitk::sqrteps ) || ( Angle(plane) > ( vnl_math::pi - 10.0 * sqrteps ) ) ) ; } bool PlaneGeometry::IsOnPlane( const Point3D &point ) const { return Distance(point) < eps; } bool PlaneGeometry::IsOnPlane( const Line3D &line ) const { return ( (Distance( line.GetPoint() ) < eps) && (Distance( line.GetPoint2() ) < eps) ); } bool PlaneGeometry::IsOnPlane( const PlaneGeometry *plane ) const { return ( IsParallel( plane ) && (Distance( plane->GetOrigin() ) < eps) ); } Point3D PlaneGeometry::ProjectPointOntoPlane( const Point3D& pt ) const { ScalarType len = this->GetNormalVnl().two_norm(); return pt - this->GetNormal() * this->SignedDistanceFromPlane( pt ) / len; } itk::LightObject::Pointer PlaneGeometry::InternalClone() const { Self::Pointer newGeometry = new PlaneGeometry(*this); newGeometry->UnRegister(); return newGeometry.GetPointer(); } void PlaneGeometry::ExecuteOperation( Operation *operation ) { vtkTransform *transform = vtkTransform::New(); transform->SetMatrix( this->GetVtkMatrix()); switch ( operation->GetOperationType() ) { case OpORIENT: { mitk::PlaneOperation *planeOp = dynamic_cast< mitk::PlaneOperation * >( operation ); if ( planeOp == NULL ) { return; } Point3D center = planeOp->GetPoint(); Vector3D orientationVector = planeOp->GetNormal(); Vector3D defaultVector; FillVector3D( defaultVector, 0.0, 0.0, 1.0 ); Vector3D rotationAxis = itk::CrossProduct( orientationVector, defaultVector ); //double rotationAngle = acos( orientationVector[2] / orientationVector.GetNorm() ); double rotationAngle = atan2( (double) rotationAxis.GetNorm(), (double) (orientationVector * defaultVector) ); rotationAngle *= 180.0 / vnl_math::pi; transform->PostMultiply(); transform->Identity(); transform->Translate( center[0], center[1], center[2] ); transform->RotateWXYZ( rotationAngle, rotationAxis[0], rotationAxis[1], rotationAxis[2] ); transform->Translate( -center[0], -center[1], -center[2] ); break; } case OpRESTOREPLANEPOSITION: { RestorePlanePositionOperation *op = dynamic_cast< mitk::RestorePlanePositionOperation* >(operation); if(op == NULL) { return; } AffineTransform3D::Pointer transform2 = AffineTransform3D::New(); Matrix3D matrix; matrix.GetVnlMatrix().set_column(0, op->GetTransform()->GetMatrix().GetVnlMatrix().get_column(0)); matrix.GetVnlMatrix().set_column(1, op->GetTransform()->GetMatrix().GetVnlMatrix().get_column(1)); matrix.GetVnlMatrix().set_column(2, op->GetTransform()->GetMatrix().GetVnlMatrix().get_column(2)); transform2->SetMatrix(matrix); Vector3D offset = op->GetTransform()->GetOffset(); transform2->SetOffset(offset); this->SetIndexToWorldTransform(transform2); ScalarType bounds[6] = {0, op->GetWidth(), 0, op->GetHeight(), 0 ,1 }; this->SetBounds(bounds); this->Modified(); transform->Delete(); return; } default: Superclass::ExecuteOperation( operation ); transform->Delete(); return; } this->SetVtkMatrixDeepCopy(transform); this->Modified(); transform->Delete(); } void PlaneGeometry::PrintSelf( std::ostream& os, itk::Indent indent ) const { Superclass::PrintSelf(os,indent); os << indent << " ScaleFactorMMPerUnitX: " << m_ScaleFactorMMPerUnitX << std::endl; os << indent << " ScaleFactorMMPerUnitY: " << m_ScaleFactorMMPerUnitY << std::endl; os << indent << " Normal: " << GetNormal() << std::endl; } void PlaneGeometry::PostSetIndexToWorldTransform( mitk::AffineTransform3D* /*transform*/) { m_ScaleFactorMMPerUnitX=GetExtentInMM(0)/GetExtent(0); m_ScaleFactorMMPerUnitY=GetExtentInMM(1)/GetExtent(1); assert(m_ScaleFactorMMPerUnitX::infinity()); assert(m_ScaleFactorMMPerUnitY::infinity()); } void PlaneGeometry::PostSetExtentInMM(int /*direction*/, ScalarType /*extentInMM*/) { m_ScaleFactorMMPerUnitX=GetExtentInMM(0)/GetExtent(0); m_ScaleFactorMMPerUnitY=GetExtentInMM(1)/GetExtent(1); assert(m_ScaleFactorMMPerUnitX::infinity()); assert(m_ScaleFactorMMPerUnitY::infinity()); } bool PlaneGeometry::Map(const mitk::Point3D &pt3d_mm, mitk::Point2D &pt2d_mm) const { assert(this->IsBoundingBoxNull()==false); Point3D pt3d_units; BackTransform(pt3d_mm, pt3d_units); pt2d_mm[0]=pt3d_units[0]*m_ScaleFactorMMPerUnitX; pt2d_mm[1]=pt3d_units[1]*m_ScaleFactorMMPerUnitY; pt3d_units[2]=0; return const_cast(this->GetBoundingBox())->IsInside(pt3d_units); } void PlaneGeometry::Map(const mitk::Point2D &pt2d_mm, mitk::Point3D &pt3d_mm) const { + //pt2d_mm is measured from the origin of the world geometry (at leats it called form BaseRendere::Mouse...Event) Point3D pt3d_units; pt3d_units[0]=pt2d_mm[0]/m_ScaleFactorMMPerUnitX; pt3d_units[1]=pt2d_mm[1]/m_ScaleFactorMMPerUnitY; pt3d_units[2]=0; + //pt3d_units is a continuos index. We divided it with the Scale Factor (= spacing in x and y) to convert it from mm to index units. + // pt3d_mm = GetIndexToWorldTransform()->TransformPoint(pt3d_units); + MITK_INFO << "ITWT der PlaneGeometry: "; + GetIndexToWorldTransform()->Print(std::cout); + //now we convert the 3d index to a 3D world point in mm. We could have used IndexToWorld as well as GetITW->Transform... } void PlaneGeometry::SetSizeInUnits(mitk::ScalarType width, mitk::ScalarType height) { ScalarType bounds[6]={0, width, 0, height, 0, 1}; ScalarType extent, newextentInMM; if(GetExtent(0)>0) { extent = GetExtent(0); if(width>extent) newextentInMM = GetExtentInMM(0)/width*extent; else newextentInMM = GetExtentInMM(0)*extent/width; SetExtentInMM(0, newextentInMM); } if(GetExtent(1)>0) { extent = GetExtent(1); if(width>extent) newextentInMM = GetExtentInMM(1)/height*extent; else newextentInMM = GetExtentInMM(1)*extent/height; SetExtentInMM(1, newextentInMM); } SetBounds(bounds); } bool PlaneGeometry::Project( const mitk::Point3D &pt3d_mm, mitk::Point3D &projectedPt3d_mm) const { assert(this->IsBoundingBoxNull()==false); Point3D pt3d_units; BackTransform(pt3d_mm, pt3d_units); pt3d_units[2] = 0; projectedPt3d_mm = GetIndexToWorldTransform()->TransformPoint(pt3d_units); return const_cast(this->GetBoundingBox())->IsInside(pt3d_units); } bool PlaneGeometry::Project(const mitk::Vector3D &vec3d_mm, mitk::Vector3D &projectedVec3d_mm) const { assert(this->IsBoundingBoxNull()==false); Vector3D vec3d_units; BackTransform(vec3d_mm, vec3d_units); vec3d_units[2] = 0; projectedVec3d_mm = GetIndexToWorldTransform()->TransformVector(vec3d_units); return true; } bool PlaneGeometry::Project(const mitk::Point3D & atPt3d_mm, const mitk::Vector3D &vec3d_mm, mitk::Vector3D &projectedVec3d_mm) const { MITK_WARN << "Deprecated function! Call Project(vec3D,vec3D) instead."; assert(this->IsBoundingBoxNull()==false); Vector3D vec3d_units; BackTransform(atPt3d_mm, vec3d_mm, vec3d_units); vec3d_units[2] = 0; projectedVec3d_mm = GetIndexToWorldTransform()->TransformVector(vec3d_units); Point3D pt3d_units; BackTransform(atPt3d_mm, pt3d_units); return const_cast(this->GetBoundingBox())->IsInside(pt3d_units); } bool PlaneGeometry::Map(const mitk::Point3D & atPt3d_mm, const mitk::Vector3D &vec3d_mm, mitk::Vector2D &vec2d_mm) const { Point2D pt2d_mm_start, pt2d_mm_end; Point3D pt3d_mm_end; bool inside=Map(atPt3d_mm, pt2d_mm_start); pt3d_mm_end = atPt3d_mm+vec3d_mm; inside&=Map(pt3d_mm_end, pt2d_mm_end); vec2d_mm=pt2d_mm_end-pt2d_mm_start; return inside; } void PlaneGeometry::Map(const mitk::Point2D &/*atPt2d_mm*/, const mitk::Vector2D &/*vec2d_mm*/, mitk::Vector3D &/*vec3d_mm*/) const { //@todo implement parallel to the other Map method! assert(false); } void PlaneGeometry::SetReferenceGeometry( mitk::BaseGeometry *geometry ) { m_ReferenceGeometry = geometry; } mitk::BaseGeometry * PlaneGeometry::GetReferenceGeometry() const { return m_ReferenceGeometry; } bool PlaneGeometry::HasReferenceGeometry() const { return ( m_ReferenceGeometry != NULL ); } } // namespace diff --git a/Modules/Core/src/Rendering/mitkBaseRenderer.cpp b/Modules/Core/src/Rendering/mitkBaseRenderer.cpp index ab4e59ff0a..f7b7fe7c40 100644 --- a/Modules/Core/src/Rendering/mitkBaseRenderer.cpp +++ b/Modules/Core/src/Rendering/mitkBaseRenderer.cpp @@ -1,904 +1,910 @@ /*=================================================================== 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 "mitkBaseRenderer.h" #include "mitkMapper.h" #include "mitkResliceMethodProperty.h" #include "mitkKeyEvent.h" // Geometries #include "mitkPlaneGeometry.h" #include "mitkSlicedGeometry3D.h" // Controllers #include "mitkCameraController.h" #include "mitkSliceNavigationController.h" #include "mitkCameraRotationController.h" #include "mitkVtkInteractorCameraController.h" #ifdef MITK_USE_TD_MOUSE #include "mitkTDMouseVtkCameraController.h" #else #include "mitkCameraController.h" #endif #include "mitkVtkLayerController.h" // Events // TODO: INTERACTION_LEGACY #include "mitkEventMapper.h" #include "mitkGlobalInteraction.h" #include "mitkPositionEvent.h" #include "mitkDisplayPositionEvent.h" #include "mitkProperties.h" #include "mitkWeakPointerProperty.h" #include "mitkInteractionConst.h" #include "mitkOverlayManager.h" // VTK #include #include #include #include #include #include #include mitk::BaseRenderer::BaseRendererMapType mitk::BaseRenderer::baseRendererMap; mitk::BaseRenderer* mitk::BaseRenderer::GetInstance(vtkRenderWindow * renWin) { for (BaseRendererMapType::iterator mapit = baseRendererMap.begin(); mapit != baseRendererMap.end(); mapit++) { if ((*mapit).first == renWin) return (*mapit).second; } return NULL; } void mitk::BaseRenderer::AddInstance(vtkRenderWindow* renWin, BaseRenderer* baseRenderer) { if (renWin == NULL || baseRenderer == NULL) return; // ensure that no BaseRenderer is managed twice mitk::BaseRenderer::RemoveInstance(renWin); baseRendererMap.insert(BaseRendererMapType::value_type(renWin, baseRenderer)); } void mitk::BaseRenderer::RemoveInstance(vtkRenderWindow* renWin) { BaseRendererMapType::iterator mapit = baseRendererMap.find(renWin); if (mapit != baseRendererMap.end()) baseRendererMap.erase(mapit); } mitk::BaseRenderer* mitk::BaseRenderer::GetByName(const std::string& name) { for (BaseRendererMapType::iterator mapit = baseRendererMap.begin(); mapit != baseRendererMap.end(); mapit++) { if ((*mapit).second->m_Name == name) return (*mapit).second; } return NULL; } vtkRenderWindow* mitk::BaseRenderer::GetRenderWindowByName(const std::string& name) { for (BaseRendererMapType::iterator mapit = baseRendererMap.begin(); mapit != baseRendererMap.end(); mapit++) { if ((*mapit).second->m_Name == name) return (*mapit).first; } return NULL; } mitk::BaseRenderer::BaseRenderer(const char* name, vtkRenderWindow * renWin, mitk::RenderingManager* rm,RenderingMode::Type renderingMode) : m_RenderWindow(NULL) , m_VtkRenderer(NULL) , m_MapperID(defaultMapper) , m_DataStorage(NULL) , m_RenderingManager(rm) , m_LastUpdateTime(0) , m_CameraController(NULL) , m_SliceNavigationController(NULL) , m_CameraRotationController(NULL) /*, m_Size()*/ , m_Focused(false) , m_WorldGeometry(NULL) , m_WorldTimeGeometry(NULL) , m_CurrentWorldGeometry(NULL) , m_CurrentWorldPlaneGeometry(NULL) , m_DisplayGeometry(NULL) , m_Slice(0) , m_TimeStep() , m_CurrentWorldPlaneGeometryUpdateTime() , m_DisplayGeometryUpdateTime() , m_TimeStepUpdateTime() , m_KeepDisplayedRegion(true) , m_WorldGeometryData(NULL) , m_DisplayGeometryData(NULL) , m_CurrentWorldPlaneGeometryData(NULL) , m_WorldGeometryNode(NULL) , m_DisplayGeometryNode(NULL) , m_CurrentWorldPlaneGeometryNode(NULL) , m_DisplayGeometryTransformTime(0) , m_CurrentWorldPlaneGeometryTransformTime(0) , m_Name(name) /*, m_Bounds()*/ , m_EmptyWorldGeometry(true) , m_NumberOfVisibleLODEnabledMappers(0) { m_Bounds[0] = 0; m_Bounds[1] = 0; m_Bounds[2] = 0; m_Bounds[3] = 0; m_Bounds[4] = 0; m_Bounds[5] = 0; if (name != NULL) { m_Name = name; } else { m_Name = "unnamed renderer"; itkWarningMacro(<< "Created unnamed renderer. Bad for serialization. Please choose a name."); } if (renWin != NULL) { m_RenderWindow = renWin; m_RenderWindow->Register(NULL); } else { itkWarningMacro(<< "Created mitkBaseRenderer without vtkRenderWindow present."); } m_Size[0] = 0; m_Size[1] = 0; //instances.insert( this ); //adding this BaseRenderer to the List of all BaseRenderer // TODO: INTERACTION_LEGACY m_RenderingManager->GetGlobalInteraction()->AddFocusElement(this); m_BindDispatcherInteractor = new mitk::BindDispatcherInteractor( GetName() ); WeakPointerProperty::Pointer rendererProp = WeakPointerProperty::New((itk::Object*) this); m_CurrentWorldPlaneGeometry = mitk::PlaneGeometry::New(); m_CurrentWorldPlaneGeometryData = mitk::PlaneGeometryData::New(); m_CurrentWorldPlaneGeometryData->SetPlaneGeometry(m_CurrentWorldPlaneGeometry); m_CurrentWorldPlaneGeometryNode = mitk::DataNode::New(); m_CurrentWorldPlaneGeometryNode->SetData(m_CurrentWorldPlaneGeometryData); m_CurrentWorldPlaneGeometryNode->GetPropertyList()->SetProperty("renderer", rendererProp); m_CurrentWorldPlaneGeometryNode->GetPropertyList()->SetProperty("layer", IntProperty::New(1000)); m_CurrentWorldPlaneGeometryNode->SetProperty("reslice.thickslices", mitk::ResliceMethodProperty::New()); m_CurrentWorldPlaneGeometryNode->SetProperty("reslice.thickslices.num", mitk::IntProperty::New(1)); m_CurrentWorldPlaneGeometryTransformTime = m_CurrentWorldPlaneGeometryNode->GetVtkTransform()->GetMTime(); m_DisplayGeometry = mitk::DisplayGeometry::New(); m_DisplayGeometry->SetWorldGeometry(m_CurrentWorldPlaneGeometry); m_DisplayGeometryData = mitk::PlaneGeometryData::New(); m_DisplayGeometryData->SetPlaneGeometry(m_DisplayGeometry); m_DisplayGeometryNode = mitk::DataNode::New(); m_DisplayGeometryNode->SetData(m_DisplayGeometryData); m_DisplayGeometryNode->GetPropertyList()->SetProperty("renderer", rendererProp); m_DisplayGeometryTransformTime = m_DisplayGeometryNode->GetVtkTransform()->GetMTime(); mitk::SliceNavigationController::Pointer sliceNavigationController = mitk::SliceNavigationController::New("navigation"); sliceNavigationController->SetRenderer(this); sliceNavigationController->ConnectGeometrySliceEvent(this); sliceNavigationController->ConnectGeometryUpdateEvent(this); sliceNavigationController->ConnectGeometryTimeEvent(this, false); m_SliceNavigationController = sliceNavigationController; m_CameraRotationController = mitk::CameraRotationController::New(); m_CameraRotationController->SetRenderWindow(m_RenderWindow); m_CameraRotationController->AcquireCamera(); //if TD Mouse Interaction is activated, then call TDMouseVtkCameraController instead of VtkInteractorCameraController #ifdef MITK_USE_TD_MOUSE m_CameraController = mitk::TDMouseVtkCameraController::New(); #else m_CameraController = mitk::CameraController::New(NULL); #endif m_VtkRenderer = vtkRenderer::New(); if( renderingMode == RenderingMode::DepthPeeling ) { m_VtkRenderer->SetUseDepthPeeling(1); m_VtkRenderer->SetMaximumNumberOfPeels(8); m_VtkRenderer->SetOcclusionRatio(0.0); } if (mitk::VtkLayerController::GetInstance(m_RenderWindow) == NULL) { mitk::VtkLayerController::AddInstance(m_RenderWindow, m_VtkRenderer); } mitk::VtkLayerController::GetInstance(m_RenderWindow)->InsertSceneRenderer(m_VtkRenderer); } mitk::BaseRenderer::~BaseRenderer() { if (m_OverlayManager.IsNotNull()) { m_OverlayManager->RemoveBaseRenderer(this); } if (m_VtkRenderer != NULL) { m_VtkRenderer->Delete(); m_VtkRenderer = NULL; } if (m_CameraController.IsNotNull()) m_CameraController->SetRenderer(NULL); m_RenderingManager->GetGlobalInteraction()->RemoveFocusElement(this); mitk::VtkLayerController::RemoveInstance(m_RenderWindow); RemoveAllLocalStorages(); m_DataStorage = NULL; if (m_BindDispatcherInteractor != NULL) { delete m_BindDispatcherInteractor; } if (m_RenderWindow != NULL) { m_RenderWindow->Delete(); m_RenderWindow = NULL; } } void mitk::BaseRenderer::RemoveAllLocalStorages() { this->InvokeEvent(mitk::BaseRenderer::RendererResetEvent()); std::list::iterator it; for (it = m_RegisteredLocalStorageHandlers.begin(); it != m_RegisteredLocalStorageHandlers.end(); it++) (*it)->ClearLocalStorage(this, false); m_RegisteredLocalStorageHandlers.clear(); } void mitk::BaseRenderer::RegisterLocalStorageHandler(mitk::BaseLocalStorageHandler *lsh) { m_RegisteredLocalStorageHandlers.push_back(lsh); } mitk::Dispatcher::Pointer mitk::BaseRenderer::GetDispatcher() const { return m_BindDispatcherInteractor->GetDispatcher(); } mitk::Point3D mitk::BaseRenderer::Map2DRendererPositionTo3DWorldPosition(const Point2D& mousePosition) const { Point2D p_mm; Point3D position; if (m_MapperID == 1) { + ////the p_mm is a 2D vector from the origin of the plane geometry to the projection of the requested point onto the first slice. GetDisplayGeometry()->DisplayToWorld(mousePosition, p_mm); GetDisplayGeometry()->Map(p_mm, position); + //position is the 3D vector from the origin of the world to the requested point. } else if (m_MapperID == 2) { - PickWorldPoint(mousePosition, position); + PickWorldPoint(mousePosition, position); //Seems to be the same code as above, but subclasses may contain different implementations. } return position; } void mitk::BaseRenderer::UnregisterLocalStorageHandler(mitk::BaseLocalStorageHandler *lsh) { m_RegisteredLocalStorageHandlers.remove(lsh); } void mitk::BaseRenderer::SetDataStorage(DataStorage* storage) { if (storage != NULL) { m_DataStorage = storage; m_BindDispatcherInteractor->SetDataStorage(m_DataStorage); this->Modified(); } } const mitk::BaseRenderer::MapperSlotId mitk::BaseRenderer::defaultMapper = 1; void mitk::BaseRenderer::Paint() { } void mitk::BaseRenderer::Initialize() { } void mitk::BaseRenderer::Resize(int w, int h) { m_Size[0] = w; m_Size[1] = h; if (m_CameraController) m_CameraController->Resize(w, h); //(formerly problematic on windows: vtkSizeBug) GetDisplayGeometry()->SetSizeInDisplayUnits(w, h, m_KeepDisplayedRegion); } void mitk::BaseRenderer::InitRenderer(vtkRenderWindow* renderwindow) { if (m_RenderWindow != renderwindow) { if (m_RenderWindow != NULL) { m_RenderWindow->Delete(); } m_RenderWindow = renderwindow; if (m_RenderWindow != NULL) { m_RenderWindow->Register(NULL); } } RemoveAllLocalStorages(); if (m_CameraController.IsNotNull()) { m_CameraController->SetRenderer(this); } } void mitk::BaseRenderer::InitSize(int w, int h) { m_Size[0] = w; m_Size[1] = h; GetDisplayGeometry()->SetSizeInDisplayUnits(w, h, false); GetDisplayGeometry()->Fit(); } void mitk::BaseRenderer::SetSlice(unsigned int slice) { if (m_Slice != slice) { m_Slice = slice; if (m_WorldTimeGeometry.IsNotNull()) { + // get world geometry which may be rotated, for the current time step SlicedGeometry3D* slicedWorldGeometry = dynamic_cast(m_WorldTimeGeometry->GetGeometryForTimeStep(m_TimeStep).GetPointer()); if (slicedWorldGeometry != NULL) { + // if slice position is part of the world geometry... if (m_Slice >= slicedWorldGeometry->GetSlices()) + // set the current worldplanegeomety as the selected 2D slice of the world geometry m_Slice = slicedWorldGeometry->GetSlices() - 1; SetCurrentWorldPlaneGeometry(slicedWorldGeometry->GetPlaneGeometry(m_Slice)); SetCurrentWorldGeometry(slicedWorldGeometry); } } else Modified(); } } void mitk::BaseRenderer::SetOverlayManager(itk::SmartPointer overlayManager) { if(overlayManager.IsNull()) return; if(this->m_OverlayManager.IsNotNull()) { if(this->m_OverlayManager.GetPointer() == overlayManager.GetPointer()) { return; } else { this->m_OverlayManager->RemoveBaseRenderer(this); } } this->m_OverlayManager = overlayManager; this->m_OverlayManager->AddBaseRenderer(this); //TODO } itk::SmartPointer mitk::BaseRenderer::GetOverlayManager() { if(this->m_OverlayManager.IsNull()) { m_OverlayManager = mitk::OverlayManager::New(); m_OverlayManager->AddBaseRenderer(this); } return this->m_OverlayManager; } void mitk::BaseRenderer::SetTimeStep(unsigned int timeStep) { if (m_TimeStep != timeStep) { m_TimeStep = timeStep; m_TimeStepUpdateTime.Modified(); if (m_WorldTimeGeometry.IsNotNull()) { if (m_TimeStep >= m_WorldTimeGeometry->CountTimeSteps()) m_TimeStep = m_WorldTimeGeometry->CountTimeSteps() - 1; SlicedGeometry3D* slicedWorldGeometry = dynamic_cast(m_WorldTimeGeometry->GetGeometryForTimeStep(m_TimeStep).GetPointer()); if (slicedWorldGeometry != NULL) { SetCurrentWorldPlaneGeometry(slicedWorldGeometry->GetPlaneGeometry(m_Slice)); SetCurrentWorldGeometry(slicedWorldGeometry); } } else Modified(); } } int mitk::BaseRenderer::GetTimeStep(const mitk::BaseData* data) const { if ((data == NULL) || (data->IsInitialized() == false)) { return -1; } return data->GetTimeGeometry()->TimePointToTimeStep(GetTime()); } mitk::ScalarType mitk::BaseRenderer::GetTime() const { if (m_WorldTimeGeometry.IsNull()) { return 0; } else { ScalarType timeInMS = m_WorldTimeGeometry->TimeStepToTimePoint(GetTimeStep()); if (timeInMS == itk::NumericTraits::NonpositiveMin()) return 0; else return timeInMS; } } void mitk::BaseRenderer::SetWorldTimeGeometry(mitk::TimeGeometry* geometry) { assert(geometry != NULL); itkDebugMacro("setting WorldTimeGeometry to " << geometry); if (m_WorldTimeGeometry != geometry) { if (geometry->GetBoundingBoxInWorld()->GetDiagonalLength2() == 0) return; m_WorldTimeGeometry = geometry; itkDebugMacro("setting WorldTimeGeometry to " << m_WorldTimeGeometry); if (m_TimeStep >= m_WorldTimeGeometry->CountTimeSteps()) m_TimeStep = m_WorldTimeGeometry->CountTimeSteps() - 1; BaseGeometry* geometry3d; geometry3d = m_WorldTimeGeometry->GetGeometryForTimeStep(m_TimeStep); SetWorldGeometry3D(geometry3d); } } void mitk::BaseRenderer::SetWorldGeometry3D(mitk::BaseGeometry* geometry) { itkDebugMacro("setting WorldGeometry3D to " << geometry); if (m_WorldGeometry != geometry) { if (geometry->GetBoundingBox()->GetDiagonalLength2() == 0) return; m_WorldGeometry = geometry; SlicedGeometry3D* slicedWorldGeometry; slicedWorldGeometry = dynamic_cast(geometry); PlaneGeometry::Pointer geometry2d; if (slicedWorldGeometry != NULL) { if (m_Slice >= slicedWorldGeometry->GetSlices() && (m_Slice != 0)) m_Slice = slicedWorldGeometry->GetSlices() - 1; geometry2d = slicedWorldGeometry->GetPlaneGeometry(m_Slice); if (geometry2d.IsNull()) { PlaneGeometry::Pointer plane = mitk::PlaneGeometry::New(); plane->InitializeStandardPlane(slicedWorldGeometry); geometry2d = plane; } SetCurrentWorldGeometry(slicedWorldGeometry); } else { geometry2d = dynamic_cast(geometry); if (geometry2d.IsNull()) { PlaneGeometry::Pointer plane = PlaneGeometry::New(); plane->InitializeStandardPlane(geometry); geometry2d = plane; } SetCurrentWorldGeometry(geometry); } SetCurrentWorldPlaneGeometry(geometry2d); // calls Modified() } if (m_CurrentWorldPlaneGeometry.IsNull()) itkWarningMacro("m_CurrentWorldPlaneGeometry is NULL"); } +//TODO 18735: Diese Funktion wird nie verwendet. Löschen!!!! Und dumm ist sie auch. Display Geometry sollte nie geändert werden... void mitk::BaseRenderer::SetDisplayGeometry(mitk::DisplayGeometry* geometry2d) { itkDebugMacro("setting DisplayGeometry to " << geometry2d); if (m_DisplayGeometry != geometry2d) { m_DisplayGeometry = geometry2d; m_DisplayGeometryData->SetPlaneGeometry(m_DisplayGeometry); m_DisplayGeometryUpdateTime.Modified(); Modified(); } } void mitk::BaseRenderer::SetCurrentWorldPlaneGeometry(mitk::PlaneGeometry* geometry2d) { if (m_CurrentWorldPlaneGeometry != geometry2d) { m_CurrentWorldPlaneGeometry = geometry2d; m_CurrentWorldPlaneGeometryData->SetPlaneGeometry(m_CurrentWorldPlaneGeometry); m_DisplayGeometry->SetWorldGeometry(m_CurrentWorldPlaneGeometry); m_CurrentWorldPlaneGeometryUpdateTime.Modified(); Modified(); } } void mitk::BaseRenderer::SendUpdateSlice() { m_DisplayGeometryUpdateTime.Modified(); m_CurrentWorldPlaneGeometryUpdateTime.Modified(); } void mitk::BaseRenderer::SetCurrentWorldGeometry(mitk::BaseGeometry* geometry) { m_CurrentWorldGeometry = geometry; if (geometry == NULL) { m_Bounds[0] = 0; m_Bounds[1] = 0; m_Bounds[2] = 0; m_Bounds[3] = 0; m_Bounds[4] = 0; m_Bounds[5] = 0; m_EmptyWorldGeometry = true; return; } BoundingBox::Pointer boundingBox = m_CurrentWorldGeometry->CalculateBoundingBoxRelativeToTransform(NULL); const BoundingBox::BoundsArrayType& worldBounds = boundingBox->GetBounds(); m_Bounds[0] = worldBounds[0]; m_Bounds[1] = worldBounds[1]; m_Bounds[2] = worldBounds[2]; m_Bounds[3] = worldBounds[3]; m_Bounds[4] = worldBounds[4]; m_Bounds[5] = worldBounds[5]; if (boundingBox->GetDiagonalLength2() <= mitk::eps) m_EmptyWorldGeometry = true; else m_EmptyWorldGeometry = false; } void mitk::BaseRenderer::UpdateOverlays() { if(m_OverlayManager.IsNotNull()) { m_OverlayManager->UpdateOverlays(this); } } void mitk::BaseRenderer::SetGeometry(const itk::EventObject & geometrySendEvent) { const SliceNavigationController::GeometrySendEvent* sendEvent = dynamic_cast(&geometrySendEvent); assert(sendEvent!=NULL); SetWorldTimeGeometry(sendEvent->GetTimeGeometry()); } void mitk::BaseRenderer::UpdateGeometry(const itk::EventObject & geometryUpdateEvent) { const SliceNavigationController::GeometryUpdateEvent* updateEvent = dynamic_cast(&geometryUpdateEvent); if (updateEvent == NULL) return; if (m_CurrentWorldGeometry.IsNotNull()) { SlicedGeometry3D* slicedWorldGeometry = dynamic_cast(m_CurrentWorldGeometry.GetPointer()); if (slicedWorldGeometry) { PlaneGeometry* geometry2D = slicedWorldGeometry->GetPlaneGeometry(m_Slice); SetCurrentWorldPlaneGeometry(geometry2D); // calls Modified() } } } void mitk::BaseRenderer::SetGeometrySlice(const itk::EventObject & geometrySliceEvent) { const SliceNavigationController::GeometrySliceEvent* sliceEvent = dynamic_cast(&geometrySliceEvent); assert(sliceEvent!=NULL); SetSlice(sliceEvent->GetPos()); } void mitk::BaseRenderer::SetGeometryTime(const itk::EventObject & geometryTimeEvent) { const SliceNavigationController::GeometryTimeEvent * timeEvent = dynamic_cast(&geometryTimeEvent); assert(timeEvent!=NULL); SetTimeStep(timeEvent->GetPos()); } const double* mitk::BaseRenderer::GetBounds() const { return m_Bounds; } void mitk::BaseRenderer::MousePressEvent(mitk::MouseEvent *me) { //set the Focus on the renderer /*bool success =*/m_RenderingManager->GetGlobalInteraction()->SetFocus(this); /* if (! success) mitk::StatusBar::GetInstance()->DisplayText("Warning! from mitkBaseRenderer.cpp: Couldn't focus this BaseRenderer!"); */ //if (m_CameraController) //{ // if(me->GetButtonState()!=512) // provisorisch: Ctrl nicht durchlassen. Bald wird aus m_CameraController eine StateMachine // m_CameraController->MousePressEvent(me); //} if (m_MapperID == 1) { Point2D p(me->GetDisplayPosition()); Point2D p_mm; Point3D position; GetDisplayGeometry()->ULDisplayToDisplay(p, p); GetDisplayGeometry()->DisplayToWorld(p, p_mm); GetDisplayGeometry()->Map(p_mm, position); mitk::PositionEvent event(this, me->GetType(), me->GetButton(), me->GetButtonState(), mitk::Key_unknown, p, position); mitk::EventMapper::MapEvent(&event, m_RenderingManager->GetGlobalInteraction()); } else if (m_MapperID > 1) //==2 for 3D and ==5 for stencil { Point2D p(me->GetDisplayPosition()); GetDisplayGeometry()->ULDisplayToDisplay(p, p); me->SetDisplayPosition(p); mitk::EventMapper::MapEvent(me, m_RenderingManager->GetGlobalInteraction()); } } void mitk::BaseRenderer::MouseReleaseEvent(mitk::MouseEvent *me) { //if (m_CameraController) //{ // if(me->GetButtonState()!=512) // provisorisch: Ctrl nicht durchlassen. Bald wird aus m_CameraController eine StateMachine // m_CameraController->MouseReleaseEvent(me); //} if (m_MapperID == 1) { Point2D p(me->GetDisplayPosition()); Point2D p_mm; Point3D position; GetDisplayGeometry()->ULDisplayToDisplay(p, p); GetDisplayGeometry()->DisplayToWorld(p, p_mm); GetDisplayGeometry()->Map(p_mm, position); mitk::PositionEvent event(this, me->GetType(), me->GetButton(), me->GetButtonState(), mitk::Key_unknown, p, position); mitk::EventMapper::MapEvent(&event, m_RenderingManager->GetGlobalInteraction()); } else if (m_MapperID == 2) { Point2D p(me->GetDisplayPosition()); GetDisplayGeometry()->ULDisplayToDisplay(p, p); me->SetDisplayPosition(p); mitk::EventMapper::MapEvent(me, m_RenderingManager->GetGlobalInteraction()); } } void mitk::BaseRenderer::MouseMoveEvent(mitk::MouseEvent *me) { //if (m_CameraController) //{ // if((me->GetButtonState()<=512) || (me->GetButtonState()>=516))// provisorisch: Ctrl nicht durchlassen. Bald wird aus m_CameraController eine StateMachine // m_CameraController->MouseMoveEvent(me); //} if (m_MapperID == 1) { Point2D p(me->GetDisplayPosition()); Point2D p_mm; Point3D position; GetDisplayGeometry()->ULDisplayToDisplay(p, p); GetDisplayGeometry()->DisplayToWorld(p, p_mm); GetDisplayGeometry()->Map(p_mm, position); mitk::PositionEvent event(this, me->GetType(), me->GetButton(), me->GetButtonState(), mitk::Key_unknown, p, position); mitk::EventMapper::MapEvent(&event, m_RenderingManager->GetGlobalInteraction()); } else if (m_MapperID == 2) { Point2D p(me->GetDisplayPosition()); GetDisplayGeometry()->ULDisplayToDisplay(p, p); me->SetDisplayPosition(p); mitk::EventMapper::MapEvent(me, m_RenderingManager->GetGlobalInteraction()); } } void mitk::BaseRenderer::PickWorldPoint(const mitk::Point2D& displayPoint, mitk::Point3D& worldPoint) const { mitk::Point2D worldPoint2D; GetDisplayGeometry()->DisplayToWorld(displayPoint, worldPoint2D); GetDisplayGeometry()->Map(worldPoint2D, worldPoint); } void mitk::BaseRenderer::WheelEvent(mitk::WheelEvent * we) { if (m_MapperID == 1) { Point2D p(we->GetDisplayPosition()); Point2D p_mm; Point3D position; GetDisplayGeometry()->ULDisplayToDisplay(p, p); GetDisplayGeometry()->DisplayToWorld(p, p_mm); GetDisplayGeometry()->Map(p_mm, position); mitk::PositionEvent event(this, we->GetType(), we->GetButton(), we->GetButtonState(), mitk::Key_unknown, p, position); mitk::EventMapper::MapEvent(we, m_RenderingManager->GetGlobalInteraction()); mitk::EventMapper::MapEvent(&event, m_RenderingManager->GetGlobalInteraction()); } else if (m_MapperID == 2) { Point2D p(we->GetDisplayPosition()); GetDisplayGeometry()->ULDisplayToDisplay(p, p); we->SetDisplayPosition(p); mitk::EventMapper::MapEvent(we, m_RenderingManager->GetGlobalInteraction()); } } void mitk::BaseRenderer::KeyPressEvent(mitk::KeyEvent *ke) { if (m_MapperID == 1) { Point2D p(ke->GetDisplayPosition()); Point2D p_mm; Point3D position; GetDisplayGeometry()->ULDisplayToDisplay(p, p); GetDisplayGeometry()->DisplayToWorld(p, p_mm); GetDisplayGeometry()->Map(p_mm, position); mitk::KeyEvent event(this, ke->GetType(), ke->GetButton(), ke->GetButtonState(), ke->GetKey(), ke->GetText(), p); mitk::EventMapper::MapEvent(&event, m_RenderingManager->GetGlobalInteraction()); } else if (m_MapperID == 2) { Point2D p(ke->GetDisplayPosition()); GetDisplayGeometry()->ULDisplayToDisplay(p, p); ke->SetDisplayPosition(p); mitk::EventMapper::MapEvent(ke, m_RenderingManager->GetGlobalInteraction()); } } void mitk::BaseRenderer::DrawOverlayMouse(mitk::Point2D& itkNotUsed(p2d)) { MITK_INFO<<"BaseRenderer::DrawOverlayMouse()- should be inconcret implementation OpenGLRenderer."<RequestUpdate(this->m_RenderWindow); } void mitk::BaseRenderer::ForceImmediateUpdate() { m_RenderingManager->ForceImmediateUpdate(this->m_RenderWindow); } unsigned int mitk::BaseRenderer::GetNumberOfVisibleLODEnabledMappers() const { return m_NumberOfVisibleLODEnabledMappers; } mitk::RenderingManager* mitk::BaseRenderer::GetRenderingManager() const { return m_RenderingManager.GetPointer(); } /*! Sets the new Navigation controller */ void mitk::BaseRenderer::SetSliceNavigationController(mitk::SliceNavigationController *SlicenavigationController) { if (SlicenavigationController == NULL) return; //disconnect old from globalinteraction m_RenderingManager->GetGlobalInteraction()->RemoveListener(SlicenavigationController); //copy worldgeometry SlicenavigationController->SetInputWorldTimeGeometry(SlicenavigationController->GetCreatedWorldGeometry()); SlicenavigationController->Update(); //set new m_SliceNavigationController = SlicenavigationController; m_SliceNavigationController->SetRenderer(this); if (m_SliceNavigationController.IsNotNull()) { m_SliceNavigationController->ConnectGeometrySliceEvent(this); m_SliceNavigationController->ConnectGeometryUpdateEvent(this); m_SliceNavigationController->ConnectGeometryTimeEvent(this, false); } } /*! Sets the new camera controller and deletes the vtkRenderWindowInteractor in case of the VTKInteractorCameraController */ void mitk::BaseRenderer::SetCameraController(CameraController* cameraController) { mitk::VtkInteractorCameraController::Pointer vtkInteractorCameraController = dynamic_cast(cameraController); if (vtkInteractorCameraController.IsNotNull()) MITK_INFO<<"!!!WARNING!!!: RenderWindow interaction events are no longer handled via CameraController (See Bug #954)."<SetRenderer(NULL); m_CameraController = NULL; m_CameraController = cameraController; m_CameraController->SetRenderer(this); } void mitk::BaseRenderer::PrintSelf(std::ostream& os, itk::Indent indent) const { os << indent << " MapperID: " << m_MapperID << std::endl; os << indent << " Slice: " << m_Slice << std::endl; os << indent << " TimeStep: " << m_TimeStep << std::endl; os << indent << " WorldGeometry: "; if (m_WorldGeometry.IsNull()) os << "NULL" << std::endl; else m_WorldGeometry->Print(os, indent); os << indent << " CurrentWorldPlaneGeometry: "; if (m_CurrentWorldPlaneGeometry.IsNull()) os << "NULL" << std::endl; else m_CurrentWorldPlaneGeometry->Print(os, indent); os << indent << " CurrentWorldPlaneGeometryUpdateTime: " << m_CurrentWorldPlaneGeometryUpdateTime << std::endl; os << indent << " CurrentWorldPlaneGeometryTransformTime: " << m_CurrentWorldPlaneGeometryTransformTime << std::endl; os << indent << " DisplayGeometry: "; if (m_DisplayGeometry.IsNull()) os << "NULL" << std::endl; else m_DisplayGeometry->Print(os, indent); os << indent << " DisplayGeometryTransformTime: " << m_DisplayGeometryTransformTime << std::endl; Superclass::PrintSelf(os, indent); } diff --git a/Modules/QtWidgets/src/QmitkRenderWindow.cpp b/Modules/QtWidgets/src/QmitkRenderWindow.cpp index 12261ec271..4af26262f4 100644 --- a/Modules/QtWidgets/src/QmitkRenderWindow.cpp +++ b/Modules/QtWidgets/src/QmitkRenderWindow.cpp @@ -1,548 +1,552 @@ /*=================================================================== 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 "QmitkRenderWindow.h" #include #include #include #include #include #include #include #include #include "QmitkEventAdapter.h" // TODO: INTERACTION_LEGACY #include "mitkMousePressEvent.h" #include "mitkMouseMoveEvent.h" #include "mitkMouseDoubleClickEvent.h" #include "mitkMouseReleaseEvent.h" #include "mitkInteractionKeyEvent.h" #include "mitkMouseWheelEvent.h" #include "mitkInternalEvent.h" #include "QmitkRenderWindowMenu.h" #include "QmitkMimeTypes.h" QmitkRenderWindow::QmitkRenderWindow(QWidget *parent, QString name, mitk::VtkPropRenderer* /*renderer*/, mitk::RenderingManager* renderingManager,mitk::BaseRenderer::RenderingMode::Type renderingMode) : QVTKWidget(parent), m_ResendQtEvents(true), m_MenuWidget(NULL), m_MenuWidgetActivated(false), m_LayoutIndex(0) { // Needed if QVTKWidget2 is used instead of QVTKWidget //this will be fixed in VTK source if change 18864 is accepted /*QGLFormat newform = this->format(); newform.setSamples(8); this->setFormat(newform);*/ if(renderingMode == mitk::BaseRenderer::RenderingMode::DepthPeeling) { GetRenderWindow()->SetMultiSamples(0); GetRenderWindow()->SetAlphaBitPlanes(1); } else if(renderingMode == mitk::BaseRenderer::RenderingMode::MultiSampling) { GetRenderWindow()->SetMultiSamples(8); } else if(renderingMode == mitk::BaseRenderer::RenderingMode::Standard) { GetRenderWindow()->SetMultiSamples(0); } Initialize(renderingManager, name.toStdString().c_str(),renderingMode); // Initialize mitkRenderWindowBase setFocusPolicy(Qt::StrongFocus); setMouseTracking(true); } QmitkRenderWindow::~QmitkRenderWindow() { Destroy(); // Destroy mitkRenderWindowBase } void QmitkRenderWindow::SetResendQtEvents(bool resend) { m_ResendQtEvents = resend; } void QmitkRenderWindow::SetLayoutIndex(unsigned int layoutIndex) { m_LayoutIndex = layoutIndex; if (m_MenuWidget) m_MenuWidget->SetLayoutIndex(layoutIndex); } unsigned int QmitkRenderWindow::GetLayoutIndex() { if (m_MenuWidget) return m_MenuWidget->GetLayoutIndex(); else return 0; } void QmitkRenderWindow::LayoutDesignListChanged(int layoutDesignIndex) { if (m_MenuWidget) m_MenuWidget->UpdateLayoutDesignList(layoutDesignIndex); } void QmitkRenderWindow::mousePressEvent(QMouseEvent *me) { + //Get mouse position in vtk display coordinate system. me contains qt display infos... mitk::Point2D displayPos = GetMousePosition(me); + //Transform 2D coordinates in 3D world position. Used transform comes from TODO 18735 + //TODO 10735: ersetze Methode mit disp... mitk::Point3D worldPos = m_Renderer->Map2DRendererPositionTo3DWorldPosition(GetMousePosition(me)); + //worldPos is the 3D vector from the origin of the world to the requested point. mitk::MousePressEvent::Pointer mPressEvent = mitk::MousePressEvent::New(m_Renderer, displayPos, worldPos, GetButtonState(me), GetModifiers(me), GetEventButton(me)); if (!this->HandleEvent(mPressEvent.GetPointer())) { // TODO: INTERACTION_LEGACY mitk::MouseEvent myevent(QmitkEventAdapter::AdaptMouseEvent(m_Renderer, me)); this->mousePressMitkEvent(&myevent); QVTKWidget::mousePressEvent(me); } if (m_ResendQtEvents) me->ignore(); } void QmitkRenderWindow::mouseDoubleClickEvent( QMouseEvent *me ) { mitk::Point2D displayPos = GetMousePosition(me); mitk::Point3D worldPos = m_Renderer->Map2DRendererPositionTo3DWorldPosition(GetMousePosition(me)); mitk::MouseDoubleClickEvent::Pointer mPressEvent = mitk::MouseDoubleClickEvent::New(m_Renderer,displayPos, worldPos, GetButtonState(me), GetModifiers(me), GetEventButton(me)); if (!this->HandleEvent(mPressEvent.GetPointer())) { // TODO: INTERACTION_LEGACY mitk::MouseEvent myevent(QmitkEventAdapter::AdaptMouseEvent(m_Renderer, me)); this->mousePressMitkEvent(&myevent); QVTKWidget::mousePressEvent(me); } if (m_ResendQtEvents) me->ignore(); } void QmitkRenderWindow::mouseReleaseEvent(QMouseEvent *me) { mitk::Point2D displayPos = GetMousePosition(me); mitk::Point3D worldPos = m_Renderer->Map2DRendererPositionTo3DWorldPosition(GetMousePosition(me)); mitk::MouseReleaseEvent::Pointer mReleaseEvent = mitk::MouseReleaseEvent::New(m_Renderer, displayPos,worldPos, GetButtonState(me), GetModifiers(me), GetEventButton(me)); if (!this->HandleEvent(mReleaseEvent.GetPointer())) { // TODO: INTERACTION_LEGACY mitk::MouseEvent myevent(QmitkEventAdapter::AdaptMouseEvent(m_Renderer, me)); this->mouseReleaseMitkEvent(&myevent); QVTKWidget::mouseReleaseEvent(me); } if (m_ResendQtEvents) me->ignore(); } void QmitkRenderWindow::mouseMoveEvent(QMouseEvent *me) { mitk::Point2D displayPos = GetMousePosition(me); mitk::Point3D worldPos = m_Renderer->Map2DRendererPositionTo3DWorldPosition(GetMousePosition(me)); this->AdjustRenderWindowMenuVisibility(me->pos()); mitk::MouseMoveEvent::Pointer mMoveEvent = mitk::MouseMoveEvent::New(m_Renderer, displayPos, worldPos, GetButtonState(me), GetModifiers(me)); if (!this->HandleEvent(mMoveEvent.GetPointer())) { // TODO: INTERACTION_LEGACY mitk::MouseEvent myevent(QmitkEventAdapter::AdaptMouseEvent(m_Renderer, me)); this->mouseMoveMitkEvent(&myevent); QVTKWidget::mouseMoveEvent(me); } } void QmitkRenderWindow::wheelEvent(QWheelEvent *we) { mitk::Point2D displayPos = GetMousePosition(we); mitk::Point3D worldPos = m_Renderer->Map2DRendererPositionTo3DWorldPosition(GetMousePosition(we)); mitk::MouseWheelEvent::Pointer mWheelEvent = mitk::MouseWheelEvent::New(m_Renderer, displayPos,worldPos, GetButtonState(we), GetModifiers(we), GetDelta(we)); if (!this->HandleEvent(mWheelEvent.GetPointer())) { // TODO: INTERACTION_LEGACY mitk::WheelEvent myevent(QmitkEventAdapter::AdaptWheelEvent(m_Renderer, we)); this->wheelMitkEvent(&myevent); QVTKWidget::wheelEvent(we); } if (m_ResendQtEvents) we->ignore(); } void QmitkRenderWindow::keyPressEvent(QKeyEvent *ke) { mitk::InteractionEvent::ModifierKeys modifiers = GetModifiers(ke); std::string key = GetKeyLetter(ke); mitk::InteractionKeyEvent::Pointer keyEvent = mitk::InteractionKeyEvent::New(m_Renderer, key, modifiers); if (!this->HandleEvent(keyEvent.GetPointer())) { // TODO: INTERACTION_LEGACY QPoint cp = mapFromGlobal(QCursor::pos()); mitk::KeyEvent mke(QmitkEventAdapter::AdaptKeyEvent(m_Renderer, ke, cp)); this->keyPressMitkEvent(&mke); ke->accept(); QVTKWidget::keyPressEvent(ke); } if (m_ResendQtEvents) ke->ignore(); } void QmitkRenderWindow::enterEvent(QEvent *e) { // TODO implement new event QVTKWidget::enterEvent(e); } void QmitkRenderWindow::DeferredHideMenu() { MITK_DEBUG << "QmitkRenderWindow::DeferredHideMenu"; if (m_MenuWidget) m_MenuWidget->HideMenu(); } void QmitkRenderWindow::leaveEvent(QEvent *e) { mitk::InternalEvent::Pointer internalEvent = mitk::InternalEvent::New(this->m_Renderer, NULL, "LeaveRenderWindow"); if (!this->HandleEvent(internalEvent.GetPointer())) if (m_MenuWidget) m_MenuWidget->smoothHide(); QVTKWidget::leaveEvent(e); } void QmitkRenderWindow::paintEvent(QPaintEvent* /*event*/) { //We are using our own interaction and thus have to call the rendering manually. this->GetRenderer()->GetRenderingManager()->RequestUpdate(GetRenderWindow()); } void QmitkRenderWindow::resizeEvent(QResizeEvent* event) { this->resizeMitkEvent(event->size().width(), event->size().height()); QVTKWidget::resizeEvent(event); emit resized(); } void QmitkRenderWindow::moveEvent(QMoveEvent* event) { QVTKWidget::moveEvent(event); // after a move the overlays need to be positioned emit moved(); } void QmitkRenderWindow::showEvent(QShowEvent* event) { QVTKWidget::showEvent(event); // this singleshot is necessary to have the overlays positioned correctly after initial show // simple call of moved() is no use here!! QTimer::singleShot(0, this, SIGNAL( moved() )); } void QmitkRenderWindow::ActivateMenuWidget(bool state, QmitkStdMultiWidget* stdMultiWidget) { m_MenuWidgetActivated = state; if (!m_MenuWidgetActivated && m_MenuWidget) { //disconnect Signal/Slot Connection disconnect(m_MenuWidget, SIGNAL( SignalChangeLayoutDesign(int) ), this, SLOT(OnChangeLayoutDesign(int))); disconnect(m_MenuWidget, SIGNAL( ResetView() ), this, SIGNAL( ResetView())); disconnect(m_MenuWidget, SIGNAL( ChangeCrosshairRotationMode(int) ), this, SIGNAL( ChangeCrosshairRotationMode(int))); delete m_MenuWidget; m_MenuWidget = 0; } else if (m_MenuWidgetActivated && !m_MenuWidget) { //create render window MenuBar for split, close Window or set new setting. m_MenuWidget = new QmitkRenderWindowMenu(this, 0, m_Renderer, stdMultiWidget); m_MenuWidget->SetLayoutIndex(m_LayoutIndex); //create Signal/Slot Connection connect(m_MenuWidget, SIGNAL( SignalChangeLayoutDesign(int) ), this, SLOT(OnChangeLayoutDesign(int))); connect(m_MenuWidget, SIGNAL( ResetView() ), this, SIGNAL( ResetView())); connect(m_MenuWidget, SIGNAL( ChangeCrosshairRotationMode(int) ), this, SIGNAL( ChangeCrosshairRotationMode(int))); } } void QmitkRenderWindow::AdjustRenderWindowMenuVisibility(const QPoint& /*pos*/) { if (m_MenuWidget) { m_MenuWidget->ShowMenu(); m_MenuWidget->MoveWidgetToCorrectPos(1.0f); } } void QmitkRenderWindow::HideRenderWindowMenu() { // DEPRECATED METHOD } void QmitkRenderWindow::OnChangeLayoutDesign(int layoutDesignIndex) { emit SignalLayoutDesignChanged(layoutDesignIndex); } void QmitkRenderWindow::OnWidgetPlaneModeChanged(int mode) { if (m_MenuWidget) m_MenuWidget->NotifyNewWidgetPlanesMode(mode); } void QmitkRenderWindow::FullScreenMode(bool state) { if (m_MenuWidget) m_MenuWidget->ChangeFullScreenMode(state); } void QmitkRenderWindow::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasFormat("application/x-mitk-datanodes")) { event->accept(); } } void QmitkRenderWindow::dropEvent(QDropEvent * event) { QList dataNodeList = QmitkMimeTypes::ToDataNodePtrList(event->mimeData()); if (!dataNodeList.empty()) { emit NodesDropped(this, dataNodeList.toVector().toStdVector()); } } mitk::Point2D QmitkRenderWindow::GetMousePosition(QMouseEvent* me) const { mitk::Point2D point; point[0] = me->x(); point[1] = me->y(); m_Renderer->GetDisplayGeometry()->ULDisplayToDisplay(point, point); return point; } mitk::Point2D QmitkRenderWindow::GetMousePosition(QWheelEvent* we) const { mitk::Point2D point; point[0] = we->x(); point[1] = we->y(); m_Renderer->GetDisplayGeometry()->ULDisplayToDisplay(point, point); return point; } mitk::InteractionEvent::MouseButtons QmitkRenderWindow::GetEventButton(QMouseEvent* me) const { mitk::InteractionEvent::MouseButtons eventButton; switch (me->button()) { case Qt::LeftButton: eventButton = mitk::InteractionEvent::LeftMouseButton; break; case Qt::RightButton: eventButton = mitk::InteractionEvent::RightMouseButton; break; case Qt::MidButton: eventButton = mitk::InteractionEvent::MiddleMouseButton; break; default: eventButton = mitk::InteractionEvent::NoButton; break; } return eventButton; } mitk::InteractionEvent::MouseButtons QmitkRenderWindow::GetButtonState(QMouseEvent* me) const { mitk::InteractionEvent::MouseButtons buttonState = mitk::InteractionEvent::NoButton; if (me->buttons() & Qt::LeftButton) { buttonState = buttonState | mitk::InteractionEvent::LeftMouseButton; } if (me->buttons() & Qt::RightButton) { buttonState = buttonState | mitk::InteractionEvent::RightMouseButton; } if (me->buttons() & Qt::MidButton) { buttonState = buttonState | mitk::InteractionEvent::MiddleMouseButton; } return buttonState; } mitk::InteractionEvent::ModifierKeys QmitkRenderWindow::GetModifiers(QInputEvent* me) const { mitk::InteractionEvent::ModifierKeys modifiers = mitk::InteractionEvent::NoKey; if (me->modifiers() & Qt::ALT) { modifiers = modifiers | mitk::InteractionEvent::AltKey; } if (me->modifiers() & Qt::CTRL) { modifiers = modifiers | mitk::InteractionEvent::ControlKey; } if (me->modifiers() & Qt::SHIFT) { modifiers = modifiers | mitk::InteractionEvent::ShiftKey; } return modifiers; } mitk::InteractionEvent::MouseButtons QmitkRenderWindow::GetButtonState(QWheelEvent* we) const { mitk::InteractionEvent::MouseButtons buttonState = mitk::InteractionEvent::NoButton; if (we->buttons() & Qt::LeftButton) { buttonState = buttonState | mitk::InteractionEvent::LeftMouseButton; } if (we->buttons() & Qt::RightButton) { buttonState = buttonState | mitk::InteractionEvent::RightMouseButton; } if (we->buttons() & Qt::MidButton) { buttonState = buttonState | mitk::InteractionEvent::MiddleMouseButton; } return buttonState; } std::string QmitkRenderWindow::GetKeyLetter(QKeyEvent *ke) const { // Converting Qt Key Event to string element. std::string key = ""; int tkey = ke->key(); if (tkey < 128) { //standard ascii letter key = (char) toupper(tkey); } else { // special keys switch (tkey) { case Qt::Key_Return: key = mitk::InteractionEvent::KeyReturn; break; case Qt::Key_Enter: key = mitk::InteractionEvent::KeyEnter; break; case Qt::Key_Escape: key = mitk::InteractionEvent::KeyEnter; break; case Qt::Key_Delete: key = mitk::InteractionEvent::KeyDelete; break; case Qt::Key_Up: key = mitk::InteractionEvent::KeyArrowUp; break; case Qt::Key_Down: key = mitk::InteractionEvent::KeyArrowDown; break; case Qt::Key_Left: key = mitk::InteractionEvent::KeyArrowLeft; break; case Qt::Key_Right: key = mitk::InteractionEvent::KeyArrowRight; break; case Qt::Key_F1: key = mitk::InteractionEvent::KeyF1; break; case Qt::Key_F2: key = mitk::InteractionEvent::KeyF2; break; case Qt::Key_F3: key = mitk::InteractionEvent::KeyF3; break; case Qt::Key_F4: key = mitk::InteractionEvent::KeyF4; break; case Qt::Key_F5: key = mitk::InteractionEvent::KeyF5; break; case Qt::Key_F6: key = mitk::InteractionEvent::KeyF6; break; case Qt::Key_F7: key = mitk::InteractionEvent::KeyF7; break; case Qt::Key_F8: key = mitk::InteractionEvent::KeyF8; break; case Qt::Key_F9: key = mitk::InteractionEvent::KeyF9; break; case Qt::Key_F10: key = mitk::InteractionEvent::KeyF10; break; case Qt::Key_F11: key = mitk::InteractionEvent::KeyF11; break; case Qt::Key_F12: key = mitk::InteractionEvent::KeyF12; break; case Qt::Key_End: key = mitk::InteractionEvent::KeyEnd; break; case Qt::Key_Home: key = mitk::InteractionEvent::KeyPos1; break; case Qt::Key_Insert: key = mitk::InteractionEvent::KeyInsert; break; case Qt::Key_PageDown: key = mitk::InteractionEvent::KeyPageDown; break; case Qt::Key_PageUp: key = mitk::InteractionEvent::KeyPageUp; break; case Qt::Key_Space: key = mitk::InteractionEvent::KeySpace; break; } } return key; } int QmitkRenderWindow::GetDelta(QWheelEvent* we) const { return we->delta(); } diff --git a/Modules/SegmentationUI/Qmitk/QmitkSlicesInterpolator.cpp b/Modules/SegmentationUI/Qmitk/QmitkSlicesInterpolator.cpp index 7d2448eef5..88a946fd3b 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkSlicesInterpolator.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkSlicesInterpolator.cpp @@ -1,1162 +1,1163 @@ /*=================================================================== 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 "QmitkSlicesInterpolator.h" #include "QmitkStdMultiWidget.h" #include "QmitkSelectableGLWidget.h" #include "mitkToolManager.h" #include "mitkLevelWindowProperty.h" #include "mitkColorProperty.h" #include "mitkProperties.h" #include "mitkRenderingManager.h" #include "mitkOverwriteSliceImageFilter.h" #include "mitkProgressBar.h" #include "mitkGlobalInteraction.h" #include "mitkOperationEvent.h" #include "mitkUndoController.h" #include "mitkInteractionConst.h" #include "mitkApplyDiffImageOperation.h" #include "mitkDiffImageApplier.h" #include "mitkSegTool2D.h" #include "mitkCoreObjectFactory.h" #include "mitkSurfaceToImageFilter.h" #include "mitkSliceNavigationController.h" #include #include #include #include #include #include #include #include #include #include #include //#define ROUND(a) ((a)>0 ? (int)((a)+0.5) : -(int)(0.5-(a))) float SURFACE_COLOR_RGB [3] = {0.49f, 1.0f, 0.16f}; const std::map QmitkSlicesInterpolator::createActionToSliceDimension() { std::map actionToSliceDimension; foreach(mitk::SliceNavigationController* slicer, m_ControllerToDeleteObserverTag.keys()) { actionToSliceDimension[new QAction(QString::fromStdString(slicer->GetViewDirectionAsString()),0)] = slicer; } return actionToSliceDimension; } QmitkSlicesInterpolator::QmitkSlicesInterpolator(QWidget* parent, const char* /*name*/) :QWidget(parent), // ACTION_TO_SLICEDIMENSION( createActionToSliceDimension() ), m_Interpolator( mitk::SegmentationInterpolationController::New() ), m_SurfaceInterpolator(mitk::SurfaceInterpolationController::GetInstance()), m_ToolManager(NULL), m_Initialized(false), m_LastSNC(0), m_LastSliceIndex(0), m_2DInterpolationEnabled(false), m_3DInterpolationEnabled(false) { m_GroupBoxEnableExclusiveInterpolationMode = new QGroupBox("Interpolation", this); QVBoxLayout* vboxLayout = new QVBoxLayout(m_GroupBoxEnableExclusiveInterpolationMode); m_CmbInterpolation = new QComboBox(m_GroupBoxEnableExclusiveInterpolationMode); m_CmbInterpolation->addItem("Disabled"); m_CmbInterpolation->addItem("2-Dimensional"); m_CmbInterpolation->addItem("3-Dimensional"); vboxLayout->addWidget(m_CmbInterpolation); m_BtnApply2D = new QPushButton("Confirm for single slice", m_GroupBoxEnableExclusiveInterpolationMode); vboxLayout->addWidget(m_BtnApply2D); m_BtnApplyForAllSlices2D = new QPushButton("Confirm for all slices", m_GroupBoxEnableExclusiveInterpolationMode); vboxLayout->addWidget(m_BtnApplyForAllSlices2D); m_BtnApply3D = new QPushButton("Confirm", m_GroupBoxEnableExclusiveInterpolationMode); vboxLayout->addWidget(m_BtnApply3D); m_BtnReinit3DInterpolation = new QPushButton("Reinit Interpolation", m_GroupBoxEnableExclusiveInterpolationMode); vboxLayout->addWidget(m_BtnReinit3DInterpolation); m_ChkShowPositionNodes = new QCheckBox("Show Position Nodes", m_GroupBoxEnableExclusiveInterpolationMode); vboxLayout->addWidget(m_ChkShowPositionNodes); this->HideAllInterpolationControls(); connect(m_CmbInterpolation, SIGNAL(currentIndexChanged(int)), this, SLOT(OnInterpolationMethodChanged(int))); connect(m_BtnApply2D, SIGNAL(clicked()), this, SLOT(OnAcceptInterpolationClicked())); connect(m_BtnApplyForAllSlices2D, SIGNAL(clicked()), this, SLOT(OnAcceptAllInterpolationsClicked())); connect(m_BtnApply3D, SIGNAL(clicked()), this, SLOT(OnAccept3DInterpolationClicked())); connect(m_BtnReinit3DInterpolation, SIGNAL(clicked()), this, SLOT(OnReinit3DInterpolation())); connect(m_ChkShowPositionNodes, SIGNAL(toggled(bool)), this, SLOT(OnShowMarkers(bool))); connect(m_ChkShowPositionNodes, SIGNAL(toggled(bool)), this, SIGNAL(SignalShowMarkerNodes(bool))); QHBoxLayout* layout = new QHBoxLayout(this); layout->addWidget(m_GroupBoxEnableExclusiveInterpolationMode); this->setLayout(layout); itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction( this, &QmitkSlicesInterpolator::OnInterpolationInfoChanged ); InterpolationInfoChangedObserverTag = m_Interpolator->AddObserver( itk::ModifiedEvent(), command ); itk::ReceptorMemberCommand::Pointer command2 = itk::ReceptorMemberCommand::New(); command2->SetCallbackFunction( this, &QmitkSlicesInterpolator::OnSurfaceInterpolationInfoChanged ); SurfaceInterpolationInfoChangedObserverTag = m_SurfaceInterpolator->AddObserver( itk::ModifiedEvent(), command2 ); // feedback node and its visualization properties m_FeedbackNode = mitk::DataNode::New(); mitk::CoreObjectFactory::GetInstance()->SetDefaultProperties( m_FeedbackNode ); m_FeedbackNode->SetProperty( "binary", mitk::BoolProperty::New(true) ); m_FeedbackNode->SetProperty( "outline binary", mitk::BoolProperty::New(true) ); m_FeedbackNode->SetProperty( "color", mitk::ColorProperty::New(255.0, 255.0, 0.0) ); m_FeedbackNode->SetProperty( "texture interpolation", mitk::BoolProperty::New(false) ); m_FeedbackNode->SetProperty( "layer", mitk::IntProperty::New( 20 ) ); m_FeedbackNode->SetProperty( "levelwindow", mitk::LevelWindowProperty::New( mitk::LevelWindow(0, 1) ) ); m_FeedbackNode->SetProperty( "name", mitk::StringProperty::New("Interpolation feedback") ); m_FeedbackNode->SetProperty( "opacity", mitk::FloatProperty::New(0.8) ); m_FeedbackNode->SetProperty( "helper object", mitk::BoolProperty::New(true) ); m_InterpolatedSurfaceNode = mitk::DataNode::New(); m_InterpolatedSurfaceNode->SetProperty( "color", mitk::ColorProperty::New(SURFACE_COLOR_RGB) ); m_InterpolatedSurfaceNode->SetProperty( "name", mitk::StringProperty::New("Surface Interpolation feedback") ); m_InterpolatedSurfaceNode->SetProperty( "opacity", mitk::FloatProperty::New(0.5) ); m_InterpolatedSurfaceNode->SetProperty( "line width", mitk::IntProperty::New(4) ); m_InterpolatedSurfaceNode->SetProperty( "includeInBoundingBox", mitk::BoolProperty::New(false)); m_InterpolatedSurfaceNode->SetProperty( "helper object", mitk::BoolProperty::New(true) ); m_InterpolatedSurfaceNode->SetVisibility(false); m_3DContourNode = mitk::DataNode::New(); m_3DContourNode->SetProperty( "color", mitk::ColorProperty::New(0.0, 0.0, 0.0) ); m_3DContourNode->SetProperty("hidden object", mitk::BoolProperty::New(true)); m_3DContourNode->SetProperty( "name", mitk::StringProperty::New("Drawn Contours") ); m_3DContourNode->SetProperty("material.representation", mitk::VtkRepresentationProperty::New(VTK_WIREFRAME)); m_3DContourNode->SetProperty("material.wireframeLineWidth", mitk::FloatProperty::New(2.0f)); m_3DContourNode->SetProperty("3DContourContainer", mitk::BoolProperty::New(true)); m_3DContourNode->SetProperty( "includeInBoundingBox", mitk::BoolProperty::New(false)); m_3DContourNode->SetVisibility(false, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1"))); m_3DContourNode->SetVisibility(false, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget2"))); m_3DContourNode->SetVisibility(false, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3"))); m_3DContourNode->SetVisibility(false, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); QWidget::setContentsMargins(0, 0, 0, 0); if ( QWidget::layout() != NULL ) { QWidget::layout()->setContentsMargins(0, 0, 0, 0); } //For running 3D Interpolation in background // create a QFuture and a QFutureWatcher connect(&m_Watcher, SIGNAL(started()), this, SLOT(StartUpdateInterpolationTimer())); connect(&m_Watcher, SIGNAL(finished()), this, SLOT(OnSurfaceInterpolationFinished())); connect(&m_Watcher, SIGNAL(finished()), this, SLOT(StopUpdateInterpolationTimer())); m_Timer = new QTimer(this); connect(m_Timer, SIGNAL(timeout()), this, SLOT(ChangeSurfaceColor())); } void QmitkSlicesInterpolator::SetDataStorage( mitk::DataStorage::Pointer storage ) { m_DataStorage = storage; m_SurfaceInterpolator->SetDataStorage(storage); } mitk::DataStorage* QmitkSlicesInterpolator::GetDataStorage() { if ( m_DataStorage.IsNotNull() ) { return m_DataStorage; } else { return NULL; } } void QmitkSlicesInterpolator::Initialize(mitk::ToolManager* toolManager, const QList &controllers) { Q_ASSERT(!controllers.empty()); if (m_Initialized) { // remove old observers Uninitialize(); } m_ToolManager = toolManager; if (m_ToolManager) { // set enabled only if a segmentation is selected mitk::DataNode* node = m_ToolManager->GetWorkingData(0); QWidget::setEnabled( node != NULL ); // react whenever the set of selected segmentation changes m_ToolManager->WorkingDataChanged += mitk::MessageDelegate( this, &QmitkSlicesInterpolator::OnToolManagerWorkingDataModified ); m_ToolManager->ReferenceDataChanged += mitk::MessageDelegate( this, &QmitkSlicesInterpolator::OnToolManagerReferenceDataModified ); // connect to the slice navigation controller. after each change, call the interpolator foreach(mitk::SliceNavigationController* slicer, controllers) { //Has to be initialized m_LastSNC = slicer; m_TimeStep.insert(slicer, slicer->GetTime()->GetPos()); itk::MemberCommand::Pointer deleteCommand = itk::MemberCommand::New(); deleteCommand->SetCallbackFunction( this, &QmitkSlicesInterpolator::OnSliceNavigationControllerDeleted); m_ControllerToDeleteObserverTag.insert(slicer, slicer->AddObserver(itk::DeleteEvent(), deleteCommand)); itk::MemberCommand::Pointer timeChangedCommand = itk::MemberCommand::New(); timeChangedCommand->SetCallbackFunction( this, &QmitkSlicesInterpolator::OnTimeChanged); m_ControllerToTimeObserverTag.insert(slicer, slicer->AddObserver(mitk::SliceNavigationController::TimeGeometryEvent(NULL,0), timeChangedCommand)); itk::MemberCommand::Pointer sliceChangedCommand = itk::MemberCommand::New(); sliceChangedCommand->SetCallbackFunction( this, &QmitkSlicesInterpolator::OnSliceChanged); m_ControllerToSliceObserverTag.insert(slicer, slicer->AddObserver(mitk::SliceNavigationController::GeometrySliceEvent(NULL,0), sliceChangedCommand)); } ACTION_TO_SLICEDIMENSION = createActionToSliceDimension(); } m_Initialized = true; } void QmitkSlicesInterpolator::Uninitialize() { if (m_ToolManager.IsNotNull()) { m_ToolManager->WorkingDataChanged -= mitk::MessageDelegate(this, &QmitkSlicesInterpolator::OnToolManagerWorkingDataModified); m_ToolManager->ReferenceDataChanged -= mitk::MessageDelegate(this, &QmitkSlicesInterpolator::OnToolManagerReferenceDataModified); } foreach(mitk::SliceNavigationController* slicer, m_ControllerToSliceObserverTag.keys()) { slicer->RemoveObserver(m_ControllerToDeleteObserverTag.take(slicer)); slicer->RemoveObserver(m_ControllerToTimeObserverTag.take(slicer)); slicer->RemoveObserver(m_ControllerToSliceObserverTag.take(slicer)); } ACTION_TO_SLICEDIMENSION.clear(); m_ToolManager = NULL; m_Initialized = false; } QmitkSlicesInterpolator::~QmitkSlicesInterpolator() { if (m_Initialized) { // remove old observers Uninitialize(); } if(m_DataStorage->Exists(m_3DContourNode)) m_DataStorage->Remove(m_3DContourNode); if(m_DataStorage->Exists(m_InterpolatedSurfaceNode)) m_DataStorage->Remove(m_InterpolatedSurfaceNode); // remove observer m_Interpolator->RemoveObserver( InterpolationInfoChangedObserverTag ); m_SurfaceInterpolator->RemoveObserver( SurfaceInterpolationInfoChangedObserverTag ); delete m_Timer; } /** External enableization... */ void QmitkSlicesInterpolator::setEnabled( bool enable ) { QWidget::setEnabled(enable); //Set the gui elements of the different interpolation modi enabled if (enable) { if (m_2DInterpolationEnabled) { this->Show2DInterpolationControls(true); m_Interpolator->Activate2DInterpolation(true); } else if (m_3DInterpolationEnabled) { this->Show3DInterpolationControls(true); this->Show3DInterpolationResult(true); } } //Set all gui elements of the interpolation disabled else { this->HideAllInterpolationControls(); this->Show3DInterpolationResult(false); } } void QmitkSlicesInterpolator::On2DInterpolationEnabled(bool status) { OnInterpolationActivated(status); m_Interpolator->Activate2DInterpolation(status); } void QmitkSlicesInterpolator::On3DInterpolationEnabled(bool status) { On3DInterpolationActivated(status); } void QmitkSlicesInterpolator::OnInterpolationDisabled(bool status) { if (status) { OnInterpolationActivated(!status); On3DInterpolationActivated(!status); this->Show3DInterpolationResult(false); } } void QmitkSlicesInterpolator::HideAllInterpolationControls() { this->Show2DInterpolationControls(false); this->Show3DInterpolationControls(false); } void QmitkSlicesInterpolator::Show2DInterpolationControls(bool show) { m_BtnApply2D->setVisible(show); m_BtnApplyForAllSlices2D->setVisible(show); } void QmitkSlicesInterpolator::Show3DInterpolationControls(bool show) { m_BtnApply3D->setVisible(show); m_ChkShowPositionNodes->setVisible(show); m_BtnReinit3DInterpolation->setVisible(show); } void QmitkSlicesInterpolator::OnInterpolationMethodChanged(int index) { switch(index) { case 0: // Disabled m_GroupBoxEnableExclusiveInterpolationMode->setTitle("Interpolation"); this->HideAllInterpolationControls(); this->OnInterpolationActivated(false); this->On3DInterpolationActivated(false); this->Show3DInterpolationResult(false); m_Interpolator->Activate2DInterpolation(false); break; case 1: // 2D m_GroupBoxEnableExclusiveInterpolationMode->setTitle("Interpolation (Enabled)"); this->HideAllInterpolationControls(); this->Show2DInterpolationControls(true); this->OnInterpolationActivated(true); this->On3DInterpolationActivated(false); m_Interpolator->Activate2DInterpolation(true); break; case 2: // 3D m_GroupBoxEnableExclusiveInterpolationMode->setTitle("Interpolation (Enabled)"); this->HideAllInterpolationControls(); this->Show3DInterpolationControls(true); this->OnInterpolationActivated(false); this->On3DInterpolationActivated(true); m_Interpolator->Activate2DInterpolation(false); break; default: MITK_ERROR << "Unknown interpolation method!"; m_CmbInterpolation->setCurrentIndex(0); break; } } void QmitkSlicesInterpolator::OnShowMarkers(bool state) { mitk::DataStorage::SetOfObjects::ConstPointer allContourMarkers = m_DataStorage->GetSubset(mitk::NodePredicateProperty::New("isContourMarker" , mitk::BoolProperty::New(true))); for (mitk::DataStorage::SetOfObjects::ConstIterator it = allContourMarkers->Begin(); it != allContourMarkers->End(); ++it) { it->Value()->SetProperty("helper object", mitk::BoolProperty::New(!state)); } } void QmitkSlicesInterpolator::OnToolManagerWorkingDataModified() { if (m_ToolManager->GetWorkingData(0) != 0) { m_Segmentation = dynamic_cast(m_ToolManager->GetWorkingData(0)->GetData()); m_BtnReinit3DInterpolation->setEnabled(true); } else { //If no workingdata is set, remove the interpolation feedback this->GetDataStorage()->Remove(m_FeedbackNode); m_FeedbackNode->SetData(NULL); this->GetDataStorage()->Remove(m_3DContourNode); m_3DContourNode->SetData(NULL); this->GetDataStorage()->Remove(m_InterpolatedSurfaceNode); m_InterpolatedSurfaceNode->SetData(NULL); m_BtnReinit3DInterpolation->setEnabled(false); return; } //Updating the current selected segmentation for the 3D interpolation SetCurrentContourListID(); if (m_2DInterpolationEnabled) { OnInterpolationActivated( true ); // re-initialize if needed } this->CheckSupportedImageDimension(); } void QmitkSlicesInterpolator::OnToolManagerReferenceDataModified() { } void QmitkSlicesInterpolator::OnTimeChanged(itk::Object* sender, const itk::EventObject& e) { //Check if we really have a GeometryTimeEvent if (!dynamic_cast(&e)) return; mitk::SliceNavigationController* slicer = dynamic_cast(sender); Q_ASSERT(slicer); m_TimeStep[slicer]; if (m_LastSNC == slicer) { slicer->SendSlice();//will trigger a new interpolation } } void QmitkSlicesInterpolator::OnSliceChanged(itk::Object *sender, const itk::EventObject &e) { //Check whether we really have a GeometrySliceEvent if (!dynamic_cast(&e)) return; mitk::SliceNavigationController* slicer = dynamic_cast(sender); if (TranslateAndInterpolateChangedSlice(e, slicer)) { slicer->GetRenderer()->RequestUpdate(); } } bool QmitkSlicesInterpolator::TranslateAndInterpolateChangedSlice(const itk::EventObject& e, mitk::SliceNavigationController* slicer) { if (!m_2DInterpolationEnabled) return false; try { const mitk::SliceNavigationController::GeometrySliceEvent& event = dynamic_cast(e); mitk::TimeGeometry* tsg = event.GetTimeGeometry(); if (tsg && m_TimeStep.contains(slicer)) { mitk::SlicedGeometry3D* slicedGeometry = dynamic_cast(tsg->GetGeometryForTimeStep(m_TimeStep[slicer]).GetPointer()); if (slicedGeometry) { m_LastSNC = slicer; mitk::PlaneGeometry* plane = dynamic_cast(slicedGeometry->GetPlaneGeometry( event.GetPos() )); if (plane) Interpolate( plane, m_TimeStep[slicer], slicer ); return true; } } } catch(std::bad_cast) { return false; // so what } return false; } void QmitkSlicesInterpolator::Interpolate( mitk::PlaneGeometry* plane, unsigned int timeStep, mitk::SliceNavigationController* slicer ) { if (m_ToolManager) { mitk::DataNode* node = m_ToolManager->GetWorkingData(0); if (node) { m_Segmentation = dynamic_cast(node->GetData()); if (m_Segmentation) { int clickedSliceDimension(-1); int clickedSliceIndex(-1); // calculate real slice position, i.e. slice of the image and not slice of the TimeSlicedGeometry mitk::SegTool2D::DetermineAffectedImageSlice( m_Segmentation, plane, clickedSliceDimension, clickedSliceIndex ); mitk::Image::Pointer interpolation = m_Interpolator->Interpolate( clickedSliceDimension, clickedSliceIndex, plane, timeStep ); m_FeedbackNode->SetData( interpolation ); m_LastSNC = slicer; m_LastSliceIndex = clickedSliceIndex; } } } } void QmitkSlicesInterpolator::OnSurfaceInterpolationFinished() { mitk::Surface::Pointer interpolatedSurface = m_SurfaceInterpolator->GetInterpolationResult(); mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); if(interpolatedSurface.IsNotNull() && workingNode && workingNode->IsVisible(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3")))) { m_BtnApply3D->setEnabled(true); m_InterpolatedSurfaceNode->SetData(interpolatedSurface); m_3DContourNode->SetData(m_SurfaceInterpolator->GetContoursAsSurface()); this->Show3DInterpolationResult(true); if( !m_DataStorage->Exists(m_InterpolatedSurfaceNode) ) { m_DataStorage->Add(m_InterpolatedSurfaceNode); } if (!m_DataStorage->Exists(m_3DContourNode)) { m_DataStorage->Add(m_3DContourNode, workingNode); } } else if (interpolatedSurface.IsNull()) { m_BtnApply3D->setEnabled(false); if (m_DataStorage->Exists(m_InterpolatedSurfaceNode)) { this->Show3DInterpolationResult(false); } } m_BtnReinit3DInterpolation->setEnabled(true); foreach (mitk::SliceNavigationController* slicer, m_ControllerToTimeObserverTag.keys()) { slicer->GetRenderer()->RequestUpdate(); } } void QmitkSlicesInterpolator::OnAcceptInterpolationClicked() { if (m_Segmentation && m_FeedbackNode->GetData()) { //making interpolation separately undoable mitk::UndoStackItem::IncCurrObjectEventId(); mitk::UndoStackItem::IncCurrGroupEventId(); mitk::UndoStackItem::ExecuteIncrement(); //Make sure that for reslicing and overwriting the same alogrithm is used. We can specify the mode of the vtk reslicer vtkSmartPointer reslice = vtkSmartPointer::New(); // Set slice as input mitk::Image::Pointer slice = dynamic_cast(m_FeedbackNode->GetData()); reslice->SetInputSlice(slice->GetSliceData()->GetVtkImageAccessor(slice)->GetVtkImageData()); //set overwrite mode to true to write back to the image volume reslice->SetOverwriteMode(true); reslice->Modified(); mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(reslice); extractor->SetInput( m_Segmentation ); unsigned int timestep = m_LastSNC->GetTime()->GetPos(); extractor->SetTimeStep( timestep ); extractor->SetWorldGeometry( m_LastSNC->GetCurrentPlaneGeometry() ); extractor->SetVtkOutputRequest(true); extractor->SetResliceTransformByGeometry( m_Segmentation->GetTimeGeometry()->GetGeometryForTimeStep( timestep ) ); extractor->Modified(); extractor->Update(); //the image was modified within the pipeline, but not marked so m_Segmentation->Modified(); m_Segmentation->GetVtkImageData()->Modified(); m_FeedbackNode->SetData(NULL); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkSlicesInterpolator::AcceptAllInterpolations(mitk::SliceNavigationController* slicer) { /* * What exactly is done here: * 1. We create an empty diff image for the current segmentation * 2. All interpolated slices are written into the diff image * 3. Then the diffimage is applied to the original segmentation */ if (m_Segmentation) { //making interpolation separately undoable mitk::UndoStackItem::IncCurrObjectEventId(); mitk::UndoStackItem::IncCurrGroupEventId(); mitk::UndoStackItem::ExecuteIncrement(); mitk::Image::Pointer image3D = m_Segmentation; unsigned int timeStep( slicer->GetTime()->GetPos() ); if (m_Segmentation->GetDimension() == 4) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput( m_Segmentation ); timeSelector->SetTimeNr( timeStep ); timeSelector->Update(); image3D = timeSelector->GetOutput(); } // create a empty diff image for the undo operation mitk::Image::Pointer diffImage = mitk::Image::New(); diffImage->Initialize( image3D ); // Create scope for ImageWriteAccessor so that the accessor is destroyed // after the image is initialized. Otherwise later image access will lead to an error { mitk::ImageWriteAccessor imAccess(diffImage); // Set all pixels to zero mitk::PixelType pixelType( mitk::MakeScalarPixelType() ); memset( imAccess.GetData(), 0, (pixelType.GetBpe() >> 3) * diffImage->GetDimension(0) * diffImage->GetDimension(1) * diffImage->GetDimension(2) ); } // Since we need to shift the plane it must be clone so that the original plane isn't altered mitk::PlaneGeometry::Pointer reslicePlane = slicer->GetCurrentPlaneGeometry()->Clone(); int sliceDimension(-1); int sliceIndex(-1); mitk::SegTool2D::DetermineAffectedImageSlice( m_Segmentation, reslicePlane, sliceDimension, sliceIndex ); unsigned int zslices = m_Segmentation->GetDimension( sliceDimension ); mitk::ProgressBar::GetInstance()->AddStepsToDo(zslices); mitk::Point3D origin = reslicePlane->GetOrigin(); unsigned int totalChangedSlices(0); for (unsigned int sliceIndex = 0; sliceIndex < zslices; ++sliceIndex) { // Transforming the current origin of the reslice plane // so that it matches the one of the next slice m_Segmentation->GetSlicedGeometry()->WorldToIndex(origin, origin); origin[sliceDimension] = sliceIndex; m_Segmentation->GetSlicedGeometry()->IndexToWorld(origin, origin); reslicePlane->SetOrigin(origin); //Set the slice as 'input' mitk::Image::Pointer interpolation = m_Interpolator->Interpolate( sliceDimension, sliceIndex, reslicePlane, timeStep ); if (interpolation.IsNotNull()) // we don't check if interpolation is necessary/sensible - but m_Interpolator does { //Setting up the reslicing pipeline which allows us to write the interpolation results back into //the image volume vtkSmartPointer reslice = vtkSmartPointer::New(); //set overwrite mode to true to write back to the image volume reslice->SetInputSlice(interpolation->GetSliceData()->GetVtkImageAccessor(interpolation)->GetVtkImageData()); reslice->SetOverwriteMode(true); reslice->Modified(); mitk::ExtractSliceFilter::Pointer diffslicewriter = mitk::ExtractSliceFilter::New(reslice); diffslicewriter->SetInput( diffImage ); diffslicewriter->SetTimeStep( timeStep ); diffslicewriter->SetWorldGeometry(reslicePlane); diffslicewriter->SetVtkOutputRequest(true); diffslicewriter->SetResliceTransformByGeometry( diffImage->GetTimeGeometry()->GetGeometryForTimeStep( timeStep ) ); diffslicewriter->Modified(); diffslicewriter->Update(); ++totalChangedSlices; } mitk::ProgressBar::GetInstance()->Progress(); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); if (totalChangedSlices > 0) { // store undo stack items if ( true ) { // create do/undo operations mitk::ApplyDiffImageOperation* doOp = new mitk::ApplyDiffImageOperation( mitk::OpTEST, m_Segmentation, diffImage, timeStep ); mitk::ApplyDiffImageOperation* undoOp = new mitk::ApplyDiffImageOperation( mitk::OpTEST, m_Segmentation, diffImage, timeStep ); undoOp->SetFactor( -1.0 ); std::stringstream comment; comment << "Confirm all interpolations (" << totalChangedSlices << ")"; mitk::OperationEvent* undoStackItem = new mitk::OperationEvent( mitk::DiffImageApplier::GetInstanceForUndo(), doOp, undoOp, comment.str() ); mitk::UndoController::GetCurrentUndoModel()->SetOperationEvent( undoStackItem ); // acutally apply the changes here to the original image mitk::DiffImageApplier::GetInstanceForUndo()->ExecuteOperation( doOp ); } } m_FeedbackNode->SetData(NULL); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkSlicesInterpolator::FinishInterpolation(mitk::SliceNavigationController* slicer) { //this redirect is for calling from outside if (slicer == NULL) OnAcceptAllInterpolationsClicked(); else AcceptAllInterpolations( slicer ); } void QmitkSlicesInterpolator::OnAcceptAllInterpolationsClicked() { QMenu orientationPopup(this); std::map::const_iterator it; for(it = ACTION_TO_SLICEDIMENSION.begin(); it != ACTION_TO_SLICEDIMENSION.end(); it++) orientationPopup.addAction(it->first); connect( &orientationPopup, SIGNAL(triggered(QAction*)), this, SLOT(OnAcceptAllPopupActivated(QAction*)) ); orientationPopup.exec( QCursor::pos() ); } void QmitkSlicesInterpolator::OnAccept3DInterpolationClicked() { if (m_InterpolatedSurfaceNode.IsNotNull() && m_InterpolatedSurfaceNode->GetData()) { mitk::SurfaceToImageFilter::Pointer s2iFilter = mitk::SurfaceToImageFilter::New(); s2iFilter->MakeOutputBinaryOn(); s2iFilter->SetInput(dynamic_cast(m_InterpolatedSurfaceNode->GetData())); // check if ToolManager holds valid ReferenceData if (m_ToolManager->GetReferenceData(0) == NULL || m_ToolManager->GetWorkingData(0) == NULL) { return; } s2iFilter->SetImage(dynamic_cast(m_ToolManager->GetReferenceData(0)->GetData())); s2iFilter->Update(); mitk::DataNode* segmentationNode = m_ToolManager->GetWorkingData(0); mitk::Image* oldSeg = dynamic_cast(segmentationNode->GetData()); mitk::Image::Pointer newSeg = s2iFilter->GetOutput(); if (oldSeg) m_SurfaceInterpolator->ReplaceInterpolationSession(oldSeg, newSeg); else return; segmentationNode->SetData(newSeg); m_CmbInterpolation->setCurrentIndex(0); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); mitk::DataNode::Pointer segSurface = mitk::DataNode::New(); float rgb[3]; segmentationNode->GetColor(rgb); segSurface->SetColor(rgb); segSurface->SetData(m_InterpolatedSurfaceNode->GetData()); std::stringstream stream; stream << segmentationNode->GetName(); stream << "_"; stream << "3D-interpolation"; segSurface->SetName(stream.str()); segSurface->SetProperty( "opacity", mitk::FloatProperty::New(0.7) ); segSurface->SetProperty( "includeInBoundingBox", mitk::BoolProperty::New(true)); segSurface->SetProperty( "3DInterpolationResult", mitk::BoolProperty::New(true)); m_DataStorage->Add(segSurface, segmentationNode); this->Show3DInterpolationResult(false); } } void QmitkSlicesInterpolator::OnReinit3DInterpolation() { mitk::NodePredicateProperty::Pointer pred = mitk::NodePredicateProperty::New("3DContourContainer", mitk::BoolProperty::New(true)); mitk::DataStorage::SetOfObjects::ConstPointer contourNodes = m_DataStorage->GetDerivations( m_ToolManager->GetWorkingData(0), pred); if (contourNodes->Size() != 0) { m_3DContourNode = contourNodes->at(0); } else { QMessageBox errorInfo; errorInfo.setWindowTitle("Reinitialize surface interpolation"); errorInfo.setIcon(QMessageBox::Information); errorInfo.setText("No contours available for the selected segmentation!"); errorInfo.exec(); } mitk::Surface::Pointer contours = dynamic_cast(m_3DContourNode->GetData()); if (contours) mitk::SurfaceInterpolationController::GetInstance()->ReinitializeInterpolation(contours); m_BtnReinit3DInterpolation->setEnabled(false); } void QmitkSlicesInterpolator::OnAcceptAllPopupActivated(QAction* action) { try { std::map::const_iterator iter = ACTION_TO_SLICEDIMENSION.find( action ); if (iter != ACTION_TO_SLICEDIMENSION.end()) { mitk::SliceNavigationController* slicer = iter->second; AcceptAllInterpolations( slicer ); } } catch(...) { /* Showing message box with possible memory error */ QMessageBox errorInfo; errorInfo.setWindowTitle("Interpolation Process"); errorInfo.setIcon(QMessageBox::Critical); errorInfo.setText("An error occurred during interpolation. Possible cause: Not enough memory!"); errorInfo.exec(); //additional error message on std::cerr std::cerr << "Ill construction in " __FILE__ " l. " << __LINE__ << std::endl; } } void QmitkSlicesInterpolator::OnInterpolationActivated(bool on) { m_2DInterpolationEnabled = on; try { if ( m_DataStorage.IsNotNull() ) { if (on && !m_DataStorage->Exists(m_FeedbackNode)) { m_DataStorage->Add( m_FeedbackNode ); } } } catch(...) { // don't care (double add/remove) } if (m_ToolManager) { mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); mitk::DataNode* referenceNode = m_ToolManager->GetReferenceData(0); QWidget::setEnabled( workingNode != NULL ); m_BtnApply2D->setEnabled( on ); m_FeedbackNode->SetVisibility( on ); if (!on) { mitk::RenderingManager::GetInstance()->RequestUpdateAll(); return; } if (workingNode) { mitk::Image* segmentation = dynamic_cast(workingNode->GetData()); if (segmentation) { m_Interpolator->SetSegmentationVolume( segmentation ); if (referenceNode) { mitk::Image* referenceImage = dynamic_cast(referenceNode->GetData()); m_Interpolator->SetReferenceVolume( referenceImage ); // may be NULL } } } } UpdateVisibleSuggestion(); } void QmitkSlicesInterpolator::Run3DInterpolation() { m_SurfaceInterpolator->Interpolate(); } void QmitkSlicesInterpolator::StartUpdateInterpolationTimer() { m_Timer->start(500); } void QmitkSlicesInterpolator::StopUpdateInterpolationTimer() { m_Timer->stop(); m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(SURFACE_COLOR_RGB)); mitk::RenderingManager::GetInstance()->RequestUpdate(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))->GetRenderWindow()); } void QmitkSlicesInterpolator::ChangeSurfaceColor() { float currentColor[3]; m_InterpolatedSurfaceNode->GetColor(currentColor); if( currentColor[2] == SURFACE_COLOR_RGB[2]) { m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(1.0f,1.0f,1.0f)); } else { m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(SURFACE_COLOR_RGB)); } m_InterpolatedSurfaceNode->Update(); mitk::RenderingManager::GetInstance()->RequestUpdate(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))->GetRenderWindow()); } void QmitkSlicesInterpolator::On3DInterpolationActivated(bool on) { m_3DInterpolationEnabled = on; this->CheckSupportedImageDimension(); try { if ( m_DataStorage.IsNotNull() && m_ToolManager && m_3DInterpolationEnabled) { mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); if (workingNode) { bool isInterpolationResult(false); workingNode->GetBoolProperty("3DInterpolationResult",isInterpolationResult); mitk::NodePredicateAnd::Pointer pred = mitk::NodePredicateAnd::New(mitk::NodePredicateProperty::New("3DInterpolationResult", mitk::BoolProperty::New(true)), mitk::NodePredicateDataType::New("Surface")); mitk::DataStorage::SetOfObjects::ConstPointer interpolationResults = m_DataStorage->GetDerivations(workingNode, pred); for (unsigned int i = 0; i < interpolationResults->Size(); ++i) { mitk::DataNode::Pointer currNode = interpolationResults->at(i); if (currNode.IsNotNull()) m_DataStorage->Remove(currNode); } if ((workingNode->IsVisible(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3")))) && !isInterpolationResult && m_3DInterpolationEnabled) { int ret = QMessageBox::Yes; if (m_SurfaceInterpolator->EstimatePortionOfNeededMemory() > 0.5) { QMessageBox msgBox; msgBox.setText("Due to short handed system memory the 3D interpolation may be very slow!"); msgBox.setInformativeText("Are you sure you want to activate the 3D interpolation?"); msgBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes); ret = msgBox.exec(); } if (m_Watcher.isRunning()) m_Watcher.waitForFinished(); if (ret == QMessageBox::Yes) { m_Future = QtConcurrent::run(this, &QmitkSlicesInterpolator::Run3DInterpolation); m_Watcher.setFuture(m_Future); } else { m_CmbInterpolation->setCurrentIndex(0); } } else if (!m_3DInterpolationEnabled) { this->Show3DInterpolationResult(false); m_BtnApply3D->setEnabled(m_3DInterpolationEnabled); } } else { QWidget::setEnabled( false ); m_ChkShowPositionNodes->setEnabled(m_3DInterpolationEnabled); } } if (!m_3DInterpolationEnabled) { this->Show3DInterpolationResult(false); m_BtnApply3D->setEnabled(m_3DInterpolationEnabled); } } catch(...) { MITK_ERROR<<"Error with 3D surface interpolation!"; } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSlicesInterpolator::EnableInterpolation(bool on) { // only to be called from the outside world // just a redirection to OnInterpolationActivated OnInterpolationActivated(on); } void QmitkSlicesInterpolator::Enable3DInterpolation(bool on) { // only to be called from the outside world // just a redirection to OnInterpolationActivated On3DInterpolationActivated(on); } void QmitkSlicesInterpolator::UpdateVisibleSuggestion() { if (m_2DInterpolationEnabled && m_LastSNC) { // determine which one is the current view, try to do an initial interpolation mitk::BaseRenderer* renderer = m_LastSNC->GetRenderer(); if (renderer && renderer->GetMapperID() == mitk::BaseRenderer::Standard2D) { + //TODO 18735: Hier wird immer null zurückgegeben, weil GetWorldGeometry ne BaseGeo zurück gibt?!?!?! const mitk::TimeGeometry* timeGeometry = dynamic_cast( renderer->GetWorldGeometry() ); if (timeGeometry) { mitk::SliceNavigationController::GeometrySliceEvent event( const_cast(timeGeometry), renderer->GetSlice() ); TranslateAndInterpolateChangedSlice(event, m_LastSNC); } } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSlicesInterpolator::OnInterpolationInfoChanged(const itk::EventObject& /*e*/) { // something (e.g. undo) changed the interpolation info, we should refresh our display UpdateVisibleSuggestion(); } void QmitkSlicesInterpolator::OnSurfaceInterpolationInfoChanged(const itk::EventObject& /*e*/) { if(m_3DInterpolationEnabled) { if (m_Watcher.isRunning()) m_Watcher.waitForFinished(); m_Future = QtConcurrent::run(this, &QmitkSlicesInterpolator::Run3DInterpolation); m_Watcher.setFuture(m_Future); } } void QmitkSlicesInterpolator:: SetCurrentContourListID() { // New ContourList = hide current interpolation Show3DInterpolationResult(false); if ( m_DataStorage.IsNotNull() && m_ToolManager && m_LastSNC ) { mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); if (workingNode) { bool isInterpolationResult(false); workingNode->GetBoolProperty("3DInterpolationResult",isInterpolationResult); if (!isInterpolationResult) { QWidget::setEnabled( true ); // In case the time is not valid use 0 to access the time geometry of the working node unsigned int time_position = 0; if( m_LastSNC->GetTime() != NULL ) time_position = m_LastSNC->GetTime()->GetPos(); mitk::Vector3D spacing = workingNode->GetData()->GetGeometry( time_position )->GetSpacing(); double minSpacing (100); double maxSpacing (0); for (int i =0; i < 3; i++) { if (spacing[i] < minSpacing) { minSpacing = spacing[i]; } else if (spacing[i] > maxSpacing) { maxSpacing = spacing[i]; } } m_SurfaceInterpolator->SetMaxSpacing(maxSpacing); m_SurfaceInterpolator->SetMinSpacing(minSpacing); m_SurfaceInterpolator->SetDistanceImageVolume(50000); mitk::Image* segmentationImage = dynamic_cast(workingNode->GetData()); if (segmentationImage->GetDimension() == 3) m_SurfaceInterpolator->SetCurrentInterpolationSession(segmentationImage); else MITK_INFO<<"3D Interpolation is only supported for 3D images at the moment!"; if (m_3DInterpolationEnabled) { if (m_Watcher.isRunning()) m_Watcher.waitForFinished(); m_Future = QtConcurrent::run(this, &QmitkSlicesInterpolator::Run3DInterpolation); m_Watcher.setFuture(m_Future); } } } else { QWidget::setEnabled(false); } } } void QmitkSlicesInterpolator::Show3DInterpolationResult(bool status) { if (m_InterpolatedSurfaceNode.IsNotNull()) m_InterpolatedSurfaceNode->SetVisibility(status); if (m_3DContourNode.IsNotNull()) m_3DContourNode->SetVisibility(status, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSlicesInterpolator::CheckSupportedImageDimension() { if (m_ToolManager->GetWorkingData(0)) m_Segmentation = dynamic_cast(m_ToolManager->GetWorkingData(0)->GetData()); if (m_3DInterpolationEnabled && m_Segmentation && m_Segmentation->GetDimension() != 3) { QMessageBox info; info.setWindowTitle("3D Interpolation Process"); info.setIcon(QMessageBox::Information); info.setText("3D Interpolation is only supported for 3D images at the moment!"); info.exec(); m_CmbInterpolation->setCurrentIndex(0); } } void QmitkSlicesInterpolator::OnSliceNavigationControllerDeleted(const itk::Object *sender, const itk::EventObject& /*e*/) { //Don't know how to avoid const_cast here?! mitk::SliceNavigationController* slicer = dynamic_cast(const_cast(sender)); if (slicer) { m_ControllerToTimeObserverTag.remove(slicer); m_ControllerToSliceObserverTag.remove(slicer); m_ControllerToDeleteObserverTag.remove(slicer); } }