diff --git a/Modules/Core/include/mitkSliceNavigationController.h b/Modules/Core/include/mitkSliceNavigationController.h index 172cfea161..3e47fe2da4 100644 --- a/Modules/Core/include/mitkSliceNavigationController.h +++ b/Modules/Core/include/mitkSliceNavigationController.h @@ -1,459 +1,461 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITKSLICENAVIGATIONCONTROLLER_H #define MITKSLICENAVIGATIONCONTROLLER_H #include #include #include #include #include #include #pragma GCC visibility push(default) #include #pragma GCC visibility pop #include namespace mitk { #define mitkTimeGeometryEventMacro(classname, super) \ class MITKCORE_EXPORT classname : public super \ { \ public: \ typedef classname Self; \ typedef super Superclass; \ classname(TimeGeometry *aTimeGeometry, unsigned int aPos) : Superclass(aTimeGeometry, aPos) {} \ virtual ~classname() {} \ virtual const char *GetEventName() const { return #classname; } \ virtual bool CheckEvent(const ::itk::EventObject *e) const { return dynamic_cast(e); } \ virtual ::itk::EventObject *MakeObject() const { return new Self(GetTimeGeometry(), GetPos()); } \ private: \ void operator=(const Self &); \ } class PlaneGeometry; class BaseGeometry; class BaseRenderer; /** * \brief Controls the selection of the slice the associated BaseRenderer * will display * * A SliceNavigationController takes a BaseGeometry or a TimeGeometry as input world geometry * (TODO what are the exact requirements?) and generates a TimeGeometry * as output. The TimeGeometry holds a number of SlicedGeometry3Ds and * these in turn hold a series of PlaneGeometries. One of these PlaneGeometries is * selected as world geometry for the BaseRenderers associated to 2D views. * * The SliceNavigationController holds has Steppers (one for the slice, a * second for the time step), which control the selection of a single * PlaneGeometry from the TimeGeometry. SliceNavigationController generates * ITK events to tell observers, like a BaseRenderer, when the selected slice * or timestep changes. * * Example: * \code * // Initialization * sliceCtrl = mitk::SliceNavigationController::New(); * * // Tell the navigator the geometry to be sliced (with geometry a * // BaseGeometry::ConstPointer) * sliceCtrl->SetInputWorldTimeGeometry(geometry.GetPointer()); * * // Tell the navigator in which direction it shall slice the data * sliceCtrl->SetViewDirection(mitk::SliceNavigationController::Axial); * * // Connect one or more BaseRenderer to this navigator, i.e.: events sent * // by the navigator when stepping through the slices (e.g. by * // sliceCtrl->GetSlice()->Next()) will be received by the BaseRenderer * // (in this example only slice-changes, see also ConnectGeometryTimeEvent * // and ConnectGeometryEvents.) * sliceCtrl->ConnectGeometrySliceEvent(renderer.GetPointer()); * * //create a world geometry and send the information to the connected renderer(s) * sliceCtrl->Update(); * \endcode * * * You can connect visible navigators to a SliceNavigationController, e.g., a * QmitkSliderNavigator (for Qt): * * \code * // Create the visible navigator (a slider with a spin-box) * QmitkSliderNavigator* navigator = * new QmitkSliderNavigator(parent, "slidernavigator"); * * // Connect the navigator to the slice-stepper of the * // SliceNavigationController. For initialization (position, mininal and * // maximal values) the values of the SliceNavigationController are used. * // Thus, accessing methods of a navigator is normally not necessary, since * // everything can be set via the (Qt-independent) SliceNavigationController. * // The QmitkStepperAdapter converts the Qt-signals to Qt-independent * // itk-events. * new QmitkStepperAdapter(navigator, sliceCtrl->GetSlice(), "navigatoradaptor"); * \endcode * * If you do not want that all renderwindows are updated when a new slice is * selected, you can use a specific RenderingManager, which updates only those * renderwindows that should be updated. This is sometimes useful when a 3D view * does not need to be updated when the slices in some 2D views are changed. * QmitkSliderNavigator (for Qt): * * \code * // create a specific RenderingManager * mitk::RenderingManager::Pointer myManager = mitk::RenderingManager::New(); * * // tell the RenderingManager to update only renderwindow1 and renderwindow2 * myManager->AddRenderWindow(renderwindow1); * myManager->AddRenderWindow(renderwindow2); * * // tell the SliceNavigationController of renderwindow1 and renderwindow2 * // to use the specific RenderingManager instead of the global one * renderwindow1->GetSliceNavigationController()->SetRenderingManager(myManager); * renderwindow2->GetSliceNavigationController()->SetRenderingManager(myManager); * \endcode * * \todo implement for non-evenly-timed geometry! * \ingroup NavigationControl */ class MITKCORE_EXPORT SliceNavigationController : public BaseController { public: + mitkClassMacro(SliceNavigationController, BaseController); // itkFactorylessNewMacro(Self) // mitkNewMacro1Param(Self, const char *); itkNewMacro(Self); // itkCloneMacro(Self) /** * \brief Possible view directions, \a Original will use * the PlaneGeometry instances in a SlicedGeometry3D provided * as input world geometry (by SetInputWorldTimeGeometry). */ enum ViewDirection { Axial, Sagittal, Coronal, Original }; /** * \brief Set the input world geometry3D out of which the * geometries for slicing will be created. * * Any previous previous set input geometry (3D or Time) will * be ignored in future. */ - void SetInputWorldTimeGeometry(const TimeGeometry *geometry); + void SetInputWorldTimeGeometry(const TimeGeometry* geometry); itkGetConstObjectMacro(InputWorldTimeGeometry, TimeGeometry); /** * \brief Access the created geometry */ itkGetConstObjectMacro(CreatedWorldGeometry, TimeGeometry); itkGetObjectMacro(CreatedWorldGeometry, TimeGeometry); /** * \brief Set the desired view directions * * \sa ViewDirection * \sa Update(ViewDirection viewDirection, bool top = true, * bool frontside = true, bool rotated = false) */ itkSetEnumMacro(ViewDirection, ViewDirection); itkGetEnumMacro(ViewDirection, ViewDirection); /** * \brief Set the default view direction * * This is used to re-initialize the view direction of the SNC to the * default value with SetViewDirectionToDefault() * * \sa ViewDirection * \sa Update(ViewDirection viewDirection, bool top = true, * bool frontside = true, bool rotated = false) */ itkSetEnumMacro(DefaultViewDirection, ViewDirection); itkGetEnumMacro(DefaultViewDirection, ViewDirection); const char *GetViewDirectionAsString() const; virtual void SetViewDirectionToDefault(); /** * \brief Do the actual creation and send it to the connected * observers (renderers) * */ virtual void Update(); /** * \brief Extended version of Update, additionally allowing to * specify the direction/orientation of the created geometry. * */ virtual void Update(ViewDirection viewDirection, bool top = true, bool frontside = true, bool rotated = false); /** * \brief Send the created geometry to the connected * observers (renderers) * * Called by Update(). */ virtual void SendCreatedWorldGeometry(); /** * \brief Tell observers to re-read the currently selected 2D geometry * */ virtual void SendCreatedWorldGeometryUpdate(); /** * \brief Send the currently selected slice to the connected * observers (renderers) * * Called by Update(). */ virtual void SendSlice(); /** * \brief Send the currently selected time to the connected * observers (renderers) * * Called by Update(). */ virtual void SendTime(); class MITKCORE_EXPORT TimeGeometryEvent : public itk::AnyEvent { public: typedef TimeGeometryEvent Self; typedef itk::AnyEvent Superclass; - TimeGeometryEvent(TimeGeometry *aTimeGeometry, unsigned int aPos) : m_TimeGeometry(aTimeGeometry), m_Pos(aPos) {} + TimeGeometryEvent(TimeGeometry* aTimeGeometry, unsigned int aPos) : m_TimeGeometry(aTimeGeometry), m_Pos(aPos) {} ~TimeGeometryEvent() override {} - const char *GetEventName() const override { return "TimeGeometryEvent"; } - bool CheckEvent(const ::itk::EventObject *e) const override { return dynamic_cast(e); } - ::itk::EventObject *MakeObject() const override { return new Self(m_TimeGeometry, m_Pos); } - TimeGeometry *GetTimeGeometry() const { return m_TimeGeometry; } + const char* GetEventName() const override { return "TimeGeometryEvent"; } + bool CheckEvent(const ::itk::EventObject* e) const override { return dynamic_cast(e); } + ::itk::EventObject* MakeObject() const override { return new Self(m_TimeGeometry, m_Pos); } + TimeGeometry* GetTimeGeometry() const { return m_TimeGeometry; } unsigned int GetPos() const { return m_Pos; } + private: TimeGeometry::Pointer m_TimeGeometry; unsigned int m_Pos; // TimeGeometryEvent(const Self&); - void operator=(const Self &); // just hide + void operator=(const Self&); // just hide }; mitkTimeGeometryEventMacro(GeometrySendEvent, TimeGeometryEvent); mitkTimeGeometryEventMacro(GeometryUpdateEvent, TimeGeometryEvent); mitkTimeGeometryEventMacro(GeometryTimeEvent, TimeGeometryEvent); mitkTimeGeometryEventMacro(GeometrySliceEvent, TimeGeometryEvent); template - void ConnectGeometrySendEvent(T *receiver) + void ConnectGeometrySendEvent(T* receiver) { auto eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::SetGeometry); unsigned long tag = AddObserver(GeometrySendEvent(nullptr, 0), eventReceptorCommand); - m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); + m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); } template - void ConnectGeometryUpdateEvent(T *receiver) + void ConnectGeometryUpdateEvent(T* receiver) { auto eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::UpdateGeometry); unsigned long tag = AddObserver(GeometryUpdateEvent(nullptr, 0), eventReceptorCommand); - m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); + m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); } template - void ConnectGeometrySliceEvent(T *receiver) + void ConnectGeometrySliceEvent(T* receiver) { auto eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::SetGeometrySlice); unsigned long tag = AddObserver(GeometrySliceEvent(nullptr, 0), eventReceptorCommand); - m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); + m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); } template - void ConnectGeometryTimeEvent(T *receiver) + void ConnectGeometryTimeEvent(T* receiver) { auto eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::SetGeometryTime); unsigned long tag = AddObserver(GeometryTimeEvent(nullptr, 0), eventReceptorCommand); - m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); + m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); } template - void ConnectGeometryEvents(T *receiver) + void ConnectGeometryEvents(T* receiver) { // connect sendEvent only once ConnectGeometrySliceEvent(receiver, false); ConnectGeometryTimeEvent(receiver); } // use a templated method to get the right offset when casting to void* template - void Disconnect(T *receiver) + void Disconnect(T* receiver) { - auto i = m_ReceiverToObserverTagsMap.find(static_cast(receiver)); + auto i = m_ReceiverToObserverTagsMap.find(static_cast(receiver)); if (i == m_ReceiverToObserverTagsMap.end()) return; - const std::list &tags = i->second; + const std::list& tags = i->second; for (auto tagIter = tags.begin(); tagIter != tags.end(); ++tagIter) { RemoveObserver(*tagIter); } m_ReceiverToObserverTagsMap.erase(i); } Message1 SetCrosshairEvent; /** * \brief To connect multiple SliceNavigationController, we can * act as an observer ourselves: implemented interface * \warning not implemented */ - virtual void SetGeometry(const itk::EventObject &geometrySliceEvent); + virtual void SetGeometry(const itk::EventObject& geometrySliceEvent); /** * \brief To connect multiple SliceNavigationController, we can * act as an observer ourselves: implemented interface */ - virtual void SetGeometrySlice(const itk::EventObject &geometrySliceEvent); + virtual void SetGeometrySlice(const itk::EventObject& geometrySliceEvent); /** * \brief To connect multiple SliceNavigationController, we can * act as an observer ourselves: implemented interface */ - virtual void SetGeometryTime(const itk::EventObject &geometryTimeEvent); + virtual void SetGeometryTime(const itk::EventObject& geometryTimeEvent); /** \brief Positions the SNC according to the specified point */ - void SelectSliceByPoint(const Point3D &point); + void SelectSliceByPoint(const Point3D& point); /** \brief Returns the BaseGeometry of the currently selected time step. */ - const BaseGeometry *GetCurrentGeometry3D(); + const BaseGeometry* GetCurrentGeometry3D(); /** \brief Returns the currently selected Plane in the current * BaseGeometry (if existent). */ - const PlaneGeometry *GetCurrentPlaneGeometry(); + const PlaneGeometry* GetCurrentPlaneGeometry(); /** \brief Sets the BaseRenderer associated with this SNC (if any). While * the BaseRenderer is not directly used by SNC, this is a convenience * method to enable BaseRenderer access via the SNC. */ - void SetRenderer(BaseRenderer *renderer); + void SetRenderer(BaseRenderer* renderer); /** \brief Gets the BaseRenderer associated with this SNC (if any). While * the BaseRenderer is not directly used by SNC, this is a convenience * method to enable BaseRenderer access via the SNC. Returns nullptr if no * BaseRenderer has been specified*/ - BaseRenderer *GetRenderer() const; + BaseRenderer* GetRenderer() const; /** \brief Re-orients the slice stack. All slices will be oriented to the given normal vector. The given point (world coordinates) defines the selected slice. Careful: The resulting axis vectors are not clearly defined this way. If you want to define them clearly, use ReorientSlices (const Point3D &point, const Vector3D &axisVec0, const Vector3D &axisVec1). */ - void ReorientSlices(const Point3D &point, const Vector3D &normal); + void ReorientSlices(const Point3D& point, const Vector3D& normal); /** \brief Re-orients the slice stack so that all planes are oriented according to the - * given axis vectors. The given Point eventually defines selected slice. - */ - void ReorientSlices(const Point3D &point, const Vector3D &axisVec0, const Vector3D &axisVec1); + * given axis vectors. The given Point eventually defines selected slice. + */ + void ReorientSlices(const Point3D& point, const Vector3D& axisVec0, const Vector3D& axisVec1); - void ExecuteOperation(Operation *operation) override; + void ExecuteOperation(Operation* operation) override; /** * \brief Feature option to lock planes during mouse interaction. * This option flag disables the mouse event which causes the center * cross to move near by. */ itkSetMacro(SliceLocked, bool); itkGetMacro(SliceLocked, bool); itkBooleanMacro(SliceLocked); /** * \brief Feature option to lock slice rotation. * * This option flag disables separately the rotation of a slice which is * implemented in mitkSliceRotator. */ itkSetMacro(SliceRotationLocked, bool); itkGetMacro(SliceRotationLocked, bool); itkBooleanMacro(SliceRotationLocked); /** * \brief Adjusts the numerical range of the slice stepper according to * the current geometry orientation of this SNC's SlicedGeometry. */ void AdjustSliceStepperRange(); /** \brief Convenience method that returns the time step currently selected by the controller.*/ TimeStepType GetSelectedTimeStep() const; /** \brief Convenience method that returns the time point that corresponds to the selected * time step. The conversion is done using the time geometry of the SliceNavigationController. * If the time geometry is not yet set, this function will always return 0.0.*/ TimePointType GetSelectedTimePoint() const; protected: SliceNavigationController(); ~SliceNavigationController() override; TimeGeometry::ConstPointer m_InputWorldTimeGeometry; TimeGeometry::Pointer m_CreatedWorldGeometry; ViewDirection m_ViewDirection; ViewDirection m_DefaultViewDirection; RenderingManager::Pointer m_RenderingManager; - BaseRenderer *m_Renderer; + BaseRenderer* m_Renderer; itkSetMacro(Top, bool); itkGetMacro(Top, bool); itkBooleanMacro(Top); itkSetMacro(FrontSide, bool); itkGetMacro(FrontSide, bool); itkBooleanMacro(FrontSide); itkSetMacro(Rotated, bool); itkGetMacro(Rotated, bool); itkBooleanMacro(Rotated); bool m_Top; bool m_FrontSide; bool m_Rotated; bool m_BlockUpdate; bool m_SliceLocked; bool m_SliceRotationLocked; unsigned int m_OldPos; - typedef std::map> ObserverTagsMapType; + typedef std::map> ObserverTagsMapType; ObserverTagsMapType m_ReceiverToObserverTagsMap; }; } // namespace mitk #endif // MITKSLICENAVIGATIONCONTROLLER_H diff --git a/Modules/Core/src/Controllers/mitkSliceNavigationController.cpp b/Modules/Core/src/Controllers/mitkSliceNavigationController.cpp index 2d621717e2..1f37f53bcd 100644 --- a/Modules/Core/src/Controllers/mitkSliceNavigationController.cpp +++ b/Modules/Core/src/Controllers/mitkSliceNavigationController.cpp @@ -1,631 +1,624 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkSliceNavigationController.h" #include "mitkBaseRenderer.h" #include "mitkCrosshairPositionEvent.h" #include "mitkOperation.h" #include "mitkOperationActor.h" #include "mitkPlaneGeometry.h" #include "mitkProportionalTimeGeometry.h" #include "mitkArbitraryTimeGeometry.h" #include "mitkSlicedGeometry3D.h" #include "mitkVtkPropRenderer.h" #include "mitkImage.h" #include "mitkImagePixelReadAccessor.h" #include "mitkInteractionConst.h" #include "mitkNodePredicateDataType.h" #include "mitkOperationEvent.h" #include "mitkPixelTypeMultiplex.h" #include "mitkPlaneOperation.h" #include "mitkPointOperation.h" #include "mitkStatusBar.h" #include "mitkApplyTransformMatrixOperation.h" namespace mitk { SliceNavigationController::SliceNavigationController() : BaseController() , m_InputWorldTimeGeometry(TimeGeometry::ConstPointer()) , m_CreatedWorldGeometry(TimeGeometry::Pointer()) , m_ViewDirection(Axial) , m_DefaultViewDirection(Axial) , m_RenderingManager(RenderingManager::Pointer()) , m_Renderer(nullptr) , m_Top(false) , m_FrontSide(false) , m_Rotated(false) , m_BlockUpdate(false) , m_SliceLocked(false) , m_SliceRotationLocked(false) , m_OldPos(0) { typedef itk::SimpleMemberCommand SNCCommandType; SNCCommandType::Pointer sliceStepperChangedCommand, timeStepperChangedCommand; sliceStepperChangedCommand = SNCCommandType::New(); timeStepperChangedCommand = SNCCommandType::New(); sliceStepperChangedCommand->SetCallbackFunction(this, &SliceNavigationController::SendSlice); timeStepperChangedCommand->SetCallbackFunction(this, &SliceNavigationController::SendTime); m_Slice->AddObserver(itk::ModifiedEvent(), sliceStepperChangedCommand); m_Time->AddObserver(itk::ModifiedEvent(), timeStepperChangedCommand); m_Slice->SetUnitName("mm"); m_Time->SetUnitName("ms"); m_Top = false; m_FrontSide = false; m_Rotated = false; } SliceNavigationController::~SliceNavigationController() {} - void SliceNavigationController::SetInputWorldTimeGeometry(const TimeGeometry *geometry) + void SliceNavigationController::SetInputWorldTimeGeometry(const TimeGeometry* geometry) { - if ( geometry != nullptr ) + if (geometry != nullptr) { if (geometry->GetBoundingBoxInWorld()->GetDiagonalLength2() < eps) { itkWarningMacro("setting an empty bounding-box"); geometry = nullptr; } } if (m_InputWorldTimeGeometry != geometry) { m_InputWorldTimeGeometry = geometry; this->Modified(); } } void SliceNavigationController::SetViewDirectionToDefault() { m_ViewDirection = m_DefaultViewDirection; } - const char *SliceNavigationController::GetViewDirectionAsString() const + const char* SliceNavigationController::GetViewDirectionAsString() const { - const char *viewDirectionString; + const char* viewDirectionString; switch (m_ViewDirection) { case SliceNavigationController::Axial: viewDirectionString = "Axial"; break; case SliceNavigationController::Sagittal: viewDirectionString = "Sagittal"; break; case SliceNavigationController::Coronal: viewDirectionString = "Coronal"; break; case SliceNavigationController::Original: viewDirectionString = "Original"; break; default: viewDirectionString = "No View Direction Available"; break; } return viewDirectionString; } void SliceNavigationController::Update() { if (!m_BlockUpdate) { if (m_ViewDirection == Sagittal) { this->Update(Sagittal, true, true, false); } else if (m_ViewDirection == Coronal) { this->Update(Coronal, false, true, false); } else if (m_ViewDirection == Axial) { this->Update(Axial, false, false, true); } else { this->Update(m_ViewDirection); } } } void SliceNavigationController::Update(SliceNavigationController::ViewDirection viewDirection, bool top, bool frontside, bool rotated) { if (m_BlockUpdate) { return; } if (m_InputWorldTimeGeometry.IsNull()) { return; } if(0 == m_InputWorldTimeGeometry->CountTimeSteps()) { return; } m_BlockUpdate = true; if (m_LastUpdateTime < m_InputWorldTimeGeometry->GetMTime()) { Modified(); } TimeGeometry::ConstPointer worldTimeGeometry = m_InputWorldTimeGeometry; this->SetViewDirection(viewDirection); this->SetTop(top); this->SetFrontSide(frontside); this->SetRotated(rotated); if (m_LastUpdateTime < GetMTime()) { m_LastUpdateTime = GetMTime(); // initialize the viewplane SlicedGeometry3D::Pointer slicedWorldGeometry = SlicedGeometry3D::Pointer(); BaseGeometry::ConstPointer currentGeometry = BaseGeometry::ConstPointer(); if (m_InputWorldTimeGeometry->IsValidTimeStep(GetTime()->GetPos())) currentGeometry = m_InputWorldTimeGeometry->GetGeometryForTimeStep(GetTime()->GetPos()); else currentGeometry = m_InputWorldTimeGeometry->GetGeometryForTimeStep(0); m_CreatedWorldGeometry = TimeGeometry::Pointer(); switch (viewDirection) { case Original: if (worldTimeGeometry.IsNotNull()) { m_CreatedWorldGeometry = worldTimeGeometry->Clone(); worldTimeGeometry = m_CreatedWorldGeometry.GetPointer(); - slicedWorldGeometry = dynamic_cast( + slicedWorldGeometry = dynamic_cast( m_CreatedWorldGeometry->GetGeometryForTimeStep(this->GetTime()->GetPos()).GetPointer()); if (slicedWorldGeometry.IsNotNull()) { break; } } else { - const auto *worldSlicedGeometry = - dynamic_cast(currentGeometry.GetPointer()); + const auto* worldSlicedGeometry = dynamic_cast(currentGeometry.GetPointer()); - if ( worldSlicedGeometry != nullptr ) + if (worldSlicedGeometry != nullptr) { - slicedWorldGeometry = static_cast(currentGeometry->Clone().GetPointer()); + slicedWorldGeometry = static_cast(currentGeometry->Clone().GetPointer()); break; } } slicedWorldGeometry = SlicedGeometry3D::New(); slicedWorldGeometry->InitializePlanes(currentGeometry, PlaneGeometry::None, top, frontside, rotated); slicedWorldGeometry->SetSliceNavigationController(this); break; case Axial: slicedWorldGeometry = SlicedGeometry3D::New(); slicedWorldGeometry->InitializePlanes(currentGeometry, PlaneGeometry::Axial, top, frontside, rotated); slicedWorldGeometry->SetSliceNavigationController(this); break; case Coronal: slicedWorldGeometry = SlicedGeometry3D::New(); slicedWorldGeometry->InitializePlanes(currentGeometry, PlaneGeometry::Coronal, top, frontside, rotated); slicedWorldGeometry->SetSliceNavigationController(this); break; case Sagittal: slicedWorldGeometry = SlicedGeometry3D::New(); slicedWorldGeometry->InitializePlanes(currentGeometry, PlaneGeometry::Sagittal, top, frontside, rotated); slicedWorldGeometry->SetSliceNavigationController(this); break; default: itkExceptionMacro("unknown ViewDirection"); } m_Slice->SetPos(0); m_Slice->SetSteps((int)slicedWorldGeometry->GetSlices()); - if ( worldTimeGeometry.IsNull() ) + if (worldTimeGeometry.IsNull()) { auto createdTimeGeometry = ProportionalTimeGeometry::New(); - createdTimeGeometry->Initialize( slicedWorldGeometry, 1 ); + createdTimeGeometry->Initialize(slicedWorldGeometry, 1); m_CreatedWorldGeometry = createdTimeGeometry; m_Time->SetSteps(0); m_Time->SetPos(0); m_Time->InvalidateRange(); } else { m_BlockUpdate = true; m_Time->SetSteps(worldTimeGeometry->CountTimeSteps()); m_Time->SetPos(0); - const TimeBounds &timeBounds = worldTimeGeometry->GetTimeBounds(); + const TimeBounds& timeBounds = worldTimeGeometry->GetTimeBounds(); m_Time->SetRange(timeBounds[0], timeBounds[1]); m_BlockUpdate = false; const auto currentTemporalPosition = this->GetTime()->GetPos(); - assert( worldTimeGeometry->GetGeometryForTimeStep( currentTemporalPosition ).IsNotNull() ); + assert(worldTimeGeometry->GetGeometryForTimeStep(currentTemporalPosition).IsNotNull()); - if ( dynamic_cast( worldTimeGeometry.GetPointer() ) != nullptr ) - { - const TimePointType minimumTimePoint = - worldTimeGeometry->TimeStepToTimePoint( currentTemporalPosition ); - - const TimePointType stepDuration = - worldTimeGeometry->TimeStepToTimePoint( currentTemporalPosition + 1 ) - minimumTimePoint; + if (dynamic_cast(worldTimeGeometry.GetPointer()) != nullptr) + { + const TimePointType minimumTimePoint = worldTimeGeometry->TimeStepToTimePoint(currentTemporalPosition); - auto createdTimeGeometry = ProportionalTimeGeometry::New(); - createdTimeGeometry->Initialize( slicedWorldGeometry, worldTimeGeometry->CountTimeSteps() ); - createdTimeGeometry->SetFirstTimePoint( minimumTimePoint ); - createdTimeGeometry->SetStepDuration( stepDuration ); + const TimePointType stepDuration = + worldTimeGeometry->TimeStepToTimePoint(currentTemporalPosition + 1) - minimumTimePoint; - m_CreatedWorldGeometry = createdTimeGeometry; - } - else - { - auto createdTimeGeometry = ArbitraryTimeGeometry::New(); - const TimeStepType numberOfTimeSteps = worldTimeGeometry->CountTimeSteps(); - createdTimeGeometry->ReserveSpaceForGeometries( numberOfTimeSteps ); + auto createdTimeGeometry = ProportionalTimeGeometry::New(); + createdTimeGeometry->Initialize(slicedWorldGeometry, worldTimeGeometry->CountTimeSteps()); + createdTimeGeometry->SetFirstTimePoint(minimumTimePoint); + createdTimeGeometry->SetStepDuration(stepDuration); - for ( TimeStepType i = 0; i < numberOfTimeSteps; ++i ) - { - const BaseGeometry::Pointer clonedGeometry = slicedWorldGeometry->Clone().GetPointer(); - const auto bounds = worldTimeGeometry->GetTimeBounds( i ); - createdTimeGeometry->AppendNewTimeStep( clonedGeometry, - bounds[0], bounds[1]); + m_CreatedWorldGeometry = createdTimeGeometry; } - createdTimeGeometry->Update(); + else + { + auto createdTimeGeometry = ArbitraryTimeGeometry::New(); + const TimeStepType numberOfTimeSteps = worldTimeGeometry->CountTimeSteps(); + createdTimeGeometry->ReserveSpaceForGeometries(numberOfTimeSteps); - m_CreatedWorldGeometry = createdTimeGeometry; - } + for (TimeStepType i = 0; i < numberOfTimeSteps; ++i) + { + const BaseGeometry::Pointer clonedGeometry = slicedWorldGeometry->Clone().GetPointer(); + const auto bounds = worldTimeGeometry->GetTimeBounds(i); + createdTimeGeometry->AppendNewTimeStep(clonedGeometry, bounds[0], bounds[1]); + } + createdTimeGeometry->Update(); + + m_CreatedWorldGeometry = createdTimeGeometry; + } } } // unblock update; we may do this now, because if m_BlockUpdate was already // true before this method was entered, then we will never come here. m_BlockUpdate = false; // Send the geometry. Do this even if nothing was changed, because maybe // Update() was only called to re-send the old geometry and time/slice data. this->SendCreatedWorldGeometry(); this->SendSlice(); this->SendTime(); // Adjust the stepper range of slice stepper according to geometry this->AdjustSliceStepperRange(); } void SliceNavigationController::SendCreatedWorldGeometry() { // Send the geometry. Do this even if nothing was changed, because maybe // Update() was only called to re-send the old geometry. if (!m_BlockUpdate) { this->InvokeEvent(GeometrySendEvent(m_CreatedWorldGeometry, 0)); } } void SliceNavigationController::SendCreatedWorldGeometryUpdate() { if (!m_BlockUpdate) { this->InvokeEvent(GeometryUpdateEvent(m_CreatedWorldGeometry, m_Slice->GetPos())); } } void SliceNavigationController::SendSlice() { if (!m_BlockUpdate) { if (m_CreatedWorldGeometry.IsNotNull()) { this->InvokeEvent(GeometrySliceEvent(m_CreatedWorldGeometry, m_Slice->GetPos())); RenderingManager::GetInstance()->RequestUpdateAll(); } } } void SliceNavigationController::SendTime() { if (!m_BlockUpdate) { if (m_CreatedWorldGeometry.IsNotNull()) { this->InvokeEvent(GeometryTimeEvent(m_CreatedWorldGeometry, m_Time->GetPos())); RenderingManager::GetInstance()->RequestUpdateAll(); } } } - void SliceNavigationController::SetGeometry(const itk::EventObject &) {} - void SliceNavigationController::SetGeometryTime(const itk::EventObject &geometryTimeEvent) + void SliceNavigationController::SetGeometry(const itk::EventObject&) {} + void SliceNavigationController::SetGeometryTime(const itk::EventObject& geometryTimeEvent) { if (m_CreatedWorldGeometry.IsNull()) { return; } - const auto *timeEvent = - dynamic_cast< const SliceNavigationController::GeometryTimeEvent * >(&geometryTimeEvent); - assert( timeEvent != nullptr ); + const auto* timeEvent = dynamic_cast(&geometryTimeEvent); + assert(timeEvent != nullptr); - TimeGeometry *timeGeometry = timeEvent->GetTimeGeometry(); - assert( timeGeometry != nullptr ); + TimeGeometry* timeGeometry = timeEvent->GetTimeGeometry(); + assert(timeGeometry != nullptr); auto timeStep = (int)timeEvent->GetPos(); ScalarType timeInMS; timeInMS = timeGeometry->TimeStepToTimePoint(timeStep); timeStep = m_CreatedWorldGeometry->TimePointToTimeStep(timeInMS); this->GetTime()->SetPos(timeStep); } - void SliceNavigationController::SetGeometrySlice(const itk::EventObject &geometrySliceEvent) + void SliceNavigationController::SetGeometrySlice(const itk::EventObject& geometrySliceEvent) { - const auto *sliceEvent = - dynamic_cast(&geometrySliceEvent); - assert(sliceEvent!=nullptr); + const auto* sliceEvent = dynamic_cast(&geometrySliceEvent); + assert(sliceEvent != nullptr); this->GetSlice()->SetPos(sliceEvent->GetPos()); } - void SliceNavigationController::SelectSliceByPoint(const Point3D &point) + void SliceNavigationController::SelectSliceByPoint(const Point3D& point) { if (m_CreatedWorldGeometry.IsNull()) { return; } //@todo add time to PositionEvent and use here!! - SlicedGeometry3D *slicedWorldGeometry = dynamic_cast( + SlicedGeometry3D* slicedWorldGeometry = dynamic_cast( m_CreatedWorldGeometry->GetGeometryForTimeStep(this->GetTime()->GetPos()).GetPointer()); if (slicedWorldGeometry) { int bestSlice = -1; double bestDistance = itk::NumericTraits::max(); int s, slices; slices = slicedWorldGeometry->GetSlices(); if (slicedWorldGeometry->GetEvenlySpaced()) { - PlaneGeometry *plane = slicedWorldGeometry->GetPlaneGeometry(0); + PlaneGeometry* plane = slicedWorldGeometry->GetPlaneGeometry(0); - const Vector3D &direction = slicedWorldGeometry->GetDirectionVector(); + const Vector3D& direction = slicedWorldGeometry->GetDirectionVector(); Point3D projectedPoint; plane->Project(point, projectedPoint); // Check whether the point is somewhere within the slice stack volume; // otherwise, the default slice (0) will be selected if (direction[0] * (point[0] - projectedPoint[0]) + direction[1] * (point[1] - projectedPoint[1]) + direction[2] * (point[2] - projectedPoint[2]) >= 0) { bestSlice = (int)(plane->Distance(point) / slicedWorldGeometry->GetSpacing()[2] + 0.5); } } else { Point3D projectedPoint; for (s = 0; s < slices; ++s) { slicedWorldGeometry->GetPlaneGeometry(s)->Project(point, projectedPoint); const Vector3D distance = projectedPoint - point; ScalarType currentDistance = distance.GetSquaredNorm(); if (currentDistance < bestDistance) { bestDistance = currentDistance; bestSlice = s; } } } if (bestSlice >= 0) { this->GetSlice()->SetPos(bestSlice); } else { this->GetSlice()->SetPos(0); } this->SendCreatedWorldGeometryUpdate(); // send crosshair event SetCrosshairEvent.Send(point); } } - void SliceNavigationController::ReorientSlices(const Point3D &point, const Vector3D &normal) + void SliceNavigationController::ReorientSlices(const Point3D& point, const Vector3D& normal) { if (m_CreatedWorldGeometry.IsNull()) { return; } PlaneOperation op(OpORIENT, point, normal); m_CreatedWorldGeometry->ExecuteOperation(&op); this->SendCreatedWorldGeometryUpdate(); } - void SliceNavigationController::ReorientSlices(const Point3D &point, - const Vector3D &axisVec0, - const Vector3D &axisVec1) + void SliceNavigationController::ReorientSlices(const Point3D& point, + const Vector3D& axisVec0, + const Vector3D& axisVec1) { if (m_CreatedWorldGeometry) { PlaneOperation op(OpORIENT, point, axisVec0, axisVec1); m_CreatedWorldGeometry->ExecuteOperation(&op); this->SendCreatedWorldGeometryUpdate(); } } - const BaseGeometry *SliceNavigationController::GetCurrentGeometry3D() + const BaseGeometry* SliceNavigationController::GetCurrentGeometry3D() { if (m_CreatedWorldGeometry.IsNotNull()) { return m_CreatedWorldGeometry->GetGeometryForTimeStep(this->GetTime()->GetPos()); } else { return nullptr; } } - const PlaneGeometry *SliceNavigationController::GetCurrentPlaneGeometry() + const PlaneGeometry* SliceNavigationController::GetCurrentPlaneGeometry() { - const auto *slicedGeometry = - dynamic_cast(this->GetCurrentGeometry3D()); + const auto* slicedGeometry = dynamic_cast(this->GetCurrentGeometry3D()); if (slicedGeometry) { - const PlaneGeometry *planeGeometry = (slicedGeometry->GetPlaneGeometry(this->GetSlice()->GetPos())); + const PlaneGeometry* planeGeometry = (slicedGeometry->GetPlaneGeometry(this->GetSlice()->GetPos())); return planeGeometry; } else { return nullptr; } } - void SliceNavigationController::SetRenderer(BaseRenderer *renderer) { m_Renderer = renderer; } - BaseRenderer *SliceNavigationController::GetRenderer() const { return m_Renderer; } + void SliceNavigationController::SetRenderer(BaseRenderer* renderer) { m_Renderer = renderer; } + BaseRenderer* SliceNavigationController::GetRenderer() const { return m_Renderer; } void SliceNavigationController::AdjustSliceStepperRange() { - const auto *slicedGeometry = - dynamic_cast(this->GetCurrentGeometry3D()); + const auto* slicedGeometry = dynamic_cast(this->GetCurrentGeometry3D()); - const Vector3D &direction = slicedGeometry->GetDirectionVector(); + const Vector3D& direction = slicedGeometry->GetDirectionVector(); int c = 0; int i, k = 0; for (i = 0; i < 3; ++i) { if (fabs(direction[i]) < 0.000000001) { ++c; } else { k = i; } } if (c == 2) { ScalarType min = slicedGeometry->GetOrigin()[k]; ScalarType max = min + slicedGeometry->GetExtentInMM(k); m_Slice->SetRange(min, max); } else { m_Slice->InvalidateRange(); } } - void SliceNavigationController::ExecuteOperation(Operation *operation) + void SliceNavigationController::ExecuteOperation(Operation* operation) { // switch on type // - select best slice for a given point // - rotate created world geometry according to Operation->SomeInfo() if (!operation || m_CreatedWorldGeometry.IsNull()) { return; } switch (operation->GetOperationType()) { case OpMOVE: // should be a point operation { if (!m_SliceLocked) // do not move the cross position { // select a slice - auto *po = dynamic_cast(operation); + auto* po = dynamic_cast(operation); if (po && po->GetIndex() == -1) { this->SelectSliceByPoint(po->GetPoint()); } else if (po && po->GetIndex() != -1) // undo case because index != -1, index holds the old position of this slice { this->GetSlice()->SetPos(po->GetIndex()); } } break; } case OpRESTOREPLANEPOSITION: { m_CreatedWorldGeometry->ExecuteOperation(operation); this->SendCreatedWorldGeometryUpdate(); break; } case OpAPPLYTRANSFORMMATRIX: { m_CreatedWorldGeometry->ExecuteOperation(operation); this->SendCreatedWorldGeometryUpdate(); break; } default: { // do nothing break; } } } TimeStepType SliceNavigationController::GetSelectedTimeStep() const { return this->GetTime()->GetPos(); } TimePointType SliceNavigationController::GetSelectedTimePoint() const { auto timeStep = this->GetSelectedTimeStep(); if (m_CreatedWorldGeometry.IsNull()) { return 0.0; } if (!m_CreatedWorldGeometry->IsValidTimeStep(timeStep)) { mitkThrow() << "SliceNavigationController is in an invalid state. It has a time step" - << "selected that is not covered by its time geometry. Selected time step: " - << timeStep << "; TimeGeometry steps count: " << m_CreatedWorldGeometry->CountTimeSteps(); + << "selected that is not covered by its time geometry. Selected time step: " << timeStep + << "; TimeGeometry steps count: " << m_CreatedWorldGeometry->CountTimeSteps(); } return m_CreatedWorldGeometry->TimeStepToTimePoint(timeStep); } -} // namespace +} // namespace mitk