1616// STL includes
1717#include < array>
1818
19+ // / \brief Abstract class for the camera strategies.
20+ // / Implements only the reset camera clipping range logic for the layer cameras.
21+ // / Other methods are expected to be implemented by deriving classes.
1922class CameraSynchronizeStrategy
2023{
2124public:
22- explicit CameraSynchronizeStrategy (const vtkSmartPointer<vtkCamera>& camera)
25+ explicit CameraSynchronizeStrategy (const vtkSmartPointer<vtkCamera>& camera, std::function< void ()> invokeModifiedEvent )
2326 : m_camera(camera)
27+ , m_invokeModifiedEvent{ std::move (invokeModifiedEvent) }
2428 {
2529 }
2630 virtual ~CameraSynchronizeStrategy () = default ;
@@ -29,26 +33,25 @@ class CameraSynchronizeStrategy
2933protected:
3034 vtkSmartPointer<vtkCamera> m_camera;
3135 vtkNew<vtkMRMLLayerDMObjectEventObserver> m_eventObserver;
36+ std::function<void ()> m_invokeModifiedEvent;
3237};
3338
39+ // / Default camera synchronization consists in updating the camera when the first renderer active camera is updated.
3440class DefaultCameraSynchronizeStrategy : public CameraSynchronizeStrategy
3541{
3642public:
37- explicit DefaultCameraSynchronizeStrategy (const vtkSmartPointer<vtkCamera>& camera, vtkRenderer* renderer)
38- : CameraSynchronizeStrategy(camera)
43+ explicit DefaultCameraSynchronizeStrategy (const vtkSmartPointer<vtkCamera>& camera, vtkRenderer* renderer, std::function< void ()> invokeModifiedEvent )
44+ : CameraSynchronizeStrategy(camera, std::move(invokeModifiedEvent) )
3945 , m_renderer(renderer)
4046 {
4147 this ->m_eventObserver ->SetUpdateCallback (
4248 [this ](vtkObject* object)
4349 {
44- if (object == this ->m_observedCamera )
45- {
46- this ->UpdateCamera ();
47- }
4850 if (object == this ->m_renderer )
4951 {
5052 this ->ObserveActiveCamera ();
5153 }
54+ this ->UpdateCamera ();
5255 });
5356
5457 this ->m_eventObserver ->UpdateObserver (nullptr , this ->m_renderer , vtkCommand::ActiveCameraEvent);
@@ -57,11 +60,17 @@ class DefaultCameraSynchronizeStrategy : public CameraSynchronizeStrategy
5760
5861 void UpdateCamera () override
5962 {
60- if (this ->m_observedCamera )
63+ if (! this ->m_observedCamera )
6164 {
62- this ->m_camera ->DeepCopy (this ->m_observedCamera );
63- this ->m_camera ->Modified ();
65+ return ;
6466 }
67+
68+ // Update camera and preserve clipping range
69+ double clippingRange[2 ];
70+ this ->m_camera ->GetClippingRange (clippingRange);
71+ this ->m_camera ->DeepCopy (this ->m_observedCamera );
72+ this ->m_camera ->SetClippingRange (clippingRange);
73+ this ->m_invokeModifiedEvent ();
6574 }
6675
6776private:
@@ -76,18 +85,26 @@ class DefaultCameraSynchronizeStrategy : public CameraSynchronizeStrategy
7685
7786 this ->m_eventObserver ->UpdateObserver (this ->m_observedCamera , camera);
7887 this ->m_observedCamera = camera;
79- this ->UpdateCamera ();
8088 }
8189
8290 vtkWeakPointer<vtkRenderer> m_renderer;
8391 vtkWeakPointer<vtkCamera> m_observedCamera;
8492};
8593
94+ // / Synchronizes the default camera to the current slice node view configuration.
95+ // / The Slice renderer 0 camera is not configured nor modified during camera changes.
96+ // / All of its actors are set to render in 2D.
97+ // /
98+ // / To simplify adding new pipelines, the sync adjusts the default camera to render in parallel projection in the correct
99+ // / orientation with respect to the current node configuration.
100+ // /
101+ // / Clipping range is configured to show all actors attached to the default camera.
102+ // / If clipping is required, then it should be done inside the specific pipeline.
86103class SliceViewCameraSynchronizeStrategy : public CameraSynchronizeStrategy
87104{
88105public:
89- explicit SliceViewCameraSynchronizeStrategy (const vtkSmartPointer<vtkCamera>& camera, vtkMRMLSliceNode* sliceNode)
90- : CameraSynchronizeStrategy(camera)
106+ explicit SliceViewCameraSynchronizeStrategy (const vtkSmartPointer<vtkCamera>& camera, vtkMRMLSliceNode* sliceNode, std::function< void ()> invokeModifiedEvent )
107+ : CameraSynchronizeStrategy(camera, std::move(invokeModifiedEvent) )
91108 , m_sliceNode{ sliceNode }
92109 {
93110 this ->m_eventObserver ->SetUpdateCallback (
@@ -142,6 +159,7 @@ class SliceViewCameraSynchronizeStrategy : public CameraSynchronizeStrategy
142159 vtkMath::Cross (vRight.data (), vUp.data (), normal.data ());
143160 double position[3 ] = { viewCenterRAS[0 ] + normal[0 ] * d, viewCenterRAS[1 ] + normal[1 ] * d, viewCenterRAS[2 ] + normal[2 ] * d };
144161 this ->m_camera ->SetPosition (position);
162+ this ->m_invokeModifiedEvent ();
145163 }
146164
147165private:
@@ -199,13 +217,29 @@ void vtkMRMLLayerDMCameraSynchronizer::UpdateStrategy()
199217 return ;
200218 }
201219
220+ const auto invokeModifiedEvent = [this ]
221+ {
222+ if (this ->m_isBlocked )
223+ {
224+ return ;
225+ }
226+ this ->Modified ();
227+ };
228+
202229 if (auto sliceNode = vtkMRMLSliceNode::SafeDownCast (this ->m_viewNode ))
203230 {
204- this ->m_syncStrategy = std::make_unique<SliceViewCameraSynchronizeStrategy>(this ->m_defaultCamera , sliceNode);
231+ this ->m_syncStrategy = std::make_unique<SliceViewCameraSynchronizeStrategy>(this ->m_defaultCamera , sliceNode, invokeModifiedEvent );
205232 }
206233 else
207234 {
208- this ->m_syncStrategy = std::make_unique<DefaultCameraSynchronizeStrategy>(this ->m_defaultCamera , this ->m_renderer );
235+ this ->m_syncStrategy = std::make_unique<DefaultCameraSynchronizeStrategy>(this ->m_defaultCamera , this ->m_renderer , invokeModifiedEvent );
209236 }
210237 this ->m_syncStrategy ->UpdateCamera ();
211238}
239+
240+ bool vtkMRMLLayerDMCameraSynchronizer::BlockModified (bool isBlocked)
241+ {
242+ bool wasBlocked = this ->m_isBlocked ;
243+ m_isBlocked = isBlocked;
244+ return wasBlocked;
245+ }
0 commit comments