Medical Imaging Interaction Toolkit  2018.4.99-3e3f1a6e
Medical Imaging Interaction Toolkit
mitkCameraController.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
13 #include "mitkCameraController.h"
14 #include "mitkRenderingManager.h"
15 #include "mitkVtkPropRenderer.h"
16 #include "vtkCommand.h"
17 #include <vtkRenderWindowInteractor.h>
18 
19 #include "vtkCamera.h"
20 #include "vtkRenderer.h"
21 #include <vtkSmartPointer.h>
22 #include <vtkTransform.h>
23 
25 {
26 }
27 
29 {
30 }
31 
33 {
34  double widthInMM = this->GetRenderer()->GetCurrentWorldPlaneGeometry()->GetExtentInMM(0);
35  double heightInMM = this->GetRenderer()->GetCurrentWorldPlaneGeometry()->GetExtentInMM(1);
36 
37  double dispHeight = this->GetRenderer()->GetViewportSize()[1]; // in pixel!
38  double dispWidth = this->GetRenderer()->GetViewportSize()[0];
39 
40  // To get the right zooming factor, we need to set the (half) height to the vtk camera using SetParallelScale.
41  // However, it could be, that our picture is so wide or the display so small, that we cannot take the height of the
42  // picture.
43  // For a wide picture, we have to take the width and adapt the width so that our image fits to the screen.
44  // But we can only set the height. Therefore, if the width is the limiting factor, we need to get the ratio of scaling
45  // for the width and multiply it with the height, so that we have a modified height and set this one. Believe us, we
46  // figured it out...
47  if ((dispWidth / widthInMM) < (dispHeight / heightInMM))
48  {
49  heightInMM = widthInMM / dispWidth * dispHeight;
50  }
51 
52  return heightInMM * 0.5;
53 }
54 
55 void mitk::CameraController::AdjustConstrainedCameraPosition(mitk::Point2D &planePoint)
56 {
57  // TODO: GetExtentInMM is calculated wrong for rotated planes, e.g. crosshair rotation (bug 19105)
58  double widthInMM = this->GetRenderer()->GetCurrentWorldPlaneGeometry()->GetExtentInMM(0);
59  double heightInMM = this->GetRenderer()->GetCurrentWorldPlaneGeometry()->GetExtentInMM(1);
60 
61  mitk::Point2D dispSizeInMM = this->GetRenderer()->GetViewportSizeInMM();
62 
63  double xMin, xMax, yMin, yMax;
64 
65  // different calculation of min/max if display is lager/smaller than image.
66  // note, that the plane Position defines the middle of the display but is in image coordinates
67  //([0,0] is defined by the image, so planePosition can sometimes be negative).
68  if (dispSizeInMM[0] > widthInMM)
69  {
70  xMin = widthInMM - 0.5 * dispSizeInMM[0];
71  xMax = 0.5 * dispSizeInMM[0];
72  }
73  else
74  {
75  xMin = 0.5 * dispSizeInMM[0];
76  xMax = widthInMM - 0.5 * dispSizeInMM[0];
77  }
78 
79  if (dispSizeInMM[1] > heightInMM)
80  {
81  yMin = heightInMM - 0.5 * dispSizeInMM[1];
82  yMax = 0.5 * dispSizeInMM[1];
83  }
84  else
85  {
86  yMin = 0.5 * dispSizeInMM[1];
87  yMax = heightInMM - 0.5 * dispSizeInMM[1];
88  }
89 
90  if (planePoint[0] < xMin)
91  {
92  planePoint[0] = xMin;
93  }
94  if (planePoint[1] < yMin)
95  {
96  planePoint[1] = yMin;
97  }
98  if (planePoint[0] > xMax)
99  {
100  planePoint[0] = xMax;
101  }
102  if (planePoint[1] > yMax)
103  {
104  planePoint[1] = yMax;
105  }
106 }
107 
109 {
110  this->SetStandardView(ANTERIOR);
111 }
112 
114 {
115  this->SetStandardView(POSTERIOR);
116 }
117 
119 {
120  this->SetStandardView(SINISTER);
121 }
122 
124 {
125  this->SetStandardView(DEXTER);
126 }
127 
129 {
130  this->SetStandardView(CRANIAL);
131 }
132 
134 {
135  this->SetStandardView(CAUDAL);
136 }
137 
139 {
140  const auto *glRenderer = dynamic_cast<const mitk::VtkPropRenderer *>(m_Renderer);
141  if (glRenderer == nullptr)
142  return;
143  vtkRenderer *vtkRenderer = glRenderer->GetVtkRenderer();
144  assert(vtkRenderer);
145 
146  mitk::BoundingBox::Pointer bb;
148  if (ds != nullptr)
149  bb = ds->ComputeBoundingBox();
150  else
151  return;
152 
154  {
155  // set up the view for the 3D render window. The views for 2D are set up in the mitkVtkPropRenderer
156  mitk::Point3D middle = bb->GetCenter();
157  vtkRenderer->GetActiveCamera()->SetFocalPoint(middle[0], middle[1], middle[2]);
158  switch (view)
159  {
160  case ANTERIOR:
161  case POSTERIOR:
162  case SINISTER:
163  case DEXTER:
164  vtkRenderer->GetActiveCamera()->SetViewUp(0, 0, 1);
165  break;
166  case CRANIAL:
167  case CAUDAL:
168  vtkRenderer->GetActiveCamera()->SetViewUp(0, -1, 0);
169  break;
170  }
171  switch (view)
172  {
173  case ANTERIOR:
174  vtkRenderer->GetActiveCamera()->SetPosition(middle[0], -100000, middle[2]);
175  break;
176  case POSTERIOR:
177  vtkRenderer->GetActiveCamera()->SetPosition(middle[0], +100000, middle[2]);
178  break;
179  case SINISTER:
180  vtkRenderer->GetActiveCamera()->SetPosition(+100000, middle[1], middle[2]);
181  break;
182  case DEXTER:
183  vtkRenderer->GetActiveCamera()->SetPosition(-100000, middle[1], middle[2]);
184  break;
185  case CRANIAL:
186  vtkRenderer->GetActiveCamera()->SetPosition(middle[0], middle[1], 100000);
187  break;
188  case CAUDAL:
189  vtkRenderer->GetActiveCamera()->SetPosition(middle[0], middle[1], -100000);
190  break;
191  }
192  vtkRenderer->ResetCamera();
193 
194  vtkRenderer->ResetCameraClippingRange();
195  }
196 
198 }
199 
201 {
202  Point2D moveToPoint = planePoint;
203  AdjustCameraToPlane(moveToPoint);
204 
205  this->Modified();
206 }
207 
209 {
210  MoveCameraToPoint(GetCameraPositionOnPlane() + moveVectorInMM);
211 }
212 
213 void mitk::CameraController::Zoom(ScalarType factor, const Point2D &zoomPointInMM)
214 {
215  if (factor <= 0.0)
216  return;
217  if (this->GetRenderer()->GetMapperID() == BaseRenderer::Standard2D)
218  {
219  double parallelScale = this->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->GetParallelScale() / factor;
220  if (this->GetRenderer()->GetConstrainZoomingAndPanning() && factor < 1.0)
221  {
222  double maxParallelScale = ComputeMaxParallelScale();
223  if (maxParallelScale - parallelScale * factor <
224  mitk::eps) // this is not the famous 05-bug... Return if already near max zooming
225  return;
226 
227  if (parallelScale > maxParallelScale)
228  {
229  parallelScale = maxParallelScale;
230  }
231  }
232  this->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetParallelScale(parallelScale);
233  // Move camera in a way that the clicked point stays visible on the display where it was.
234  Point2D planePoint = GetCameraPositionOnPlane();
235  MoveCameraToPoint(planePoint + ((zoomPointInMM - planePoint) * (factor - 1)));
236  }
237 }
238 
240 {
241  Point2D CamPosOnPlane;
242  CamPosOnPlane[0] = this->GetRenderer()->GetVtkRenderer()->GetCenter()[0];
243  CamPosOnPlane[1] = this->GetRenderer()->GetVtkRenderer()->GetCenter()[1];
244  this->GetRenderer()->DisplayToPlane(CamPosOnPlane, CamPosOnPlane);
245  return CamPosOnPlane;
246 }
247 
249 {
250  if (this->GetRenderer()->GetMapperID() == BaseRenderer::Standard2D)
251  {
253  }
254 }
255 
257 {
258  if (this->GetRenderer()->GetMapperID() == BaseRenderer::Standard2D)
259  {
260  Point2D _planePoint = PlanePoint; // PlanePoint is const...
261  if (this->GetRenderer()->GetConstrainZoomingAndPanning())
262  {
263  double parallelScale = this->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->GetParallelScale();
264  double maxParallelScale = ComputeMaxParallelScale();
265  if (parallelScale > maxParallelScale)
266  {
267  this->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetParallelScale(maxParallelScale);
268  }
269  AdjustConstrainedCameraPosition(_planePoint);
270  }
271  const PlaneGeometry *planeGeometry = this->GetRenderer()->GetCurrentWorldPlaneGeometry();
272  if (planeGeometry != nullptr)
273  {
274  this->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetViewUp(0, 1, 0); // set the view-up for the camera
275  this->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetPosition(_planePoint[0], _planePoint[1], 900000);
276  this->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetFocalPoint(_planePoint[0], _planePoint[1], 0);
277  // Transform the camera to the current position (transversal, coronal and sagittal plane).
278  // This is necessary, because the SetUserTransform() method does not manipulate the vtkCamera.
279  //(Without not all three planes would be visible).
280  vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
281  vtkSmartPointer<vtkMatrix4x4> matrix = vtkSmartPointer<vtkMatrix4x4>::New();
282  Point3D origin;
283  Vector3D right, bottom, normal;
284 
285  origin = planeGeometry->GetOrigin();
286  right = planeGeometry->GetAxisVector(0); // right = Extent of Image in mm (worldspace)
287  bottom = planeGeometry->GetAxisVector(1);
288  normal = planeGeometry->GetNormal();
289 
290  right.Normalize();
291  bottom.Normalize();
292  normal.Normalize();
293 
294  matrix->SetElement(0, 0, right[0]);
295  matrix->SetElement(1, 0, right[1]);
296  matrix->SetElement(2, 0, right[2]);
297  matrix->SetElement(0, 1, bottom[0]);
298  matrix->SetElement(1, 1, bottom[1]);
299  matrix->SetElement(2, 1, bottom[2]);
300  matrix->SetElement(0, 2, normal[0]);
301  matrix->SetElement(1, 2, normal[1]);
302  matrix->SetElement(2, 2, normal[2]);
303  matrix->SetElement(0, 3, origin[0]);
304  matrix->SetElement(1, 3, origin[1]);
305  matrix->SetElement(2, 3, origin[2]);
306  matrix->SetElement(3, 0, 0.0);
307  matrix->SetElement(3, 1, 0.0);
308  matrix->SetElement(3, 2, 0.0);
309  matrix->SetElement(3, 3, 1.0);
310 
311  trans->SetMatrix(matrix);
312  // Transform the camera to the current position (transversal, coronal and sagittal plane).
313  this->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->ApplyTransform(trans);
314  }
315  }
316 }
317 
319 {
320  if (this->GetRenderer()->GetMapperID() == BaseRenderer::Standard2D)
321  {
322  this->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetParallelScale(ComputeMaxParallelScale());
323 
324  this->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetClippingRange(0.1, 1000000);
325  // Reason for huge range: VTK seems to calculate the clipping planes wrong for small values. See VTK bug (id #7823)
326  // in VTK bugtracker.
327 
328  Point2D planePoint;
329  planePoint[0] = this->GetRenderer()->GetCurrentWorldPlaneGeometry()->GetExtentInMM(0) * 0.5;
330  planePoint[1] = this->GetRenderer()->GetCurrentWorldPlaneGeometry()->GetExtentInMM(1) * 0.5;
331  MoveCameraToPoint(planePoint);
332  }
333 }
334 
336 {
337  if (this->GetRenderer()->GetMapperID() != BaseRenderer::Standard2D)
338  {
339  return;
340  }
341 
342  this->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetParallelScale(this->GetRenderer()->GetViewportSize()[1] *
343  scale * 0.5);
344 
345  this->Modified();
346 }
Data management class that handles &#39;was created by&#39; relations.
Vector3D GetAxisVector(unsigned int direction) const
Get vector along bounding-box in the specified direction in mm.
Baseclass for renderer slice-/camera-control.
vtkRenderer * GetVtkRenderer() const
CameraController()
Default Constructor.
double ScalarType
void Zoom(ScalarType factor, const Point2D &zoomPointInMM)
const BaseRenderer * m_Renderer
void DisplayToPlane(const Point2D &displayPoint, Point2D &planePointInMM) const
This method converts a display point to the 2D world index, mapped onto the display plane using the g...
virtual const PlaneGeometry * GetCurrentWorldPlaneGeometry()
Get the current 2D-worldgeometry (m_CurrentWorldPlaneGeometry) used for 2D-rendering.
void MoveBy(const Vector2D &moveVectorInMM)
~CameraController() override
Default Destructor.
ScalarType GetExtentInMM(int direction) const
Get the extent of the bounding-box in the specified direction in mm.
static RenderingManager * GetInstance()
virtual MapperSlotId GetMapperID()
Get the MapperSlotId to use.
void SetScaleFactorInMMPerDisplayUnit(ScalarType scale)
Set the desired zoom-level to the absolute value given.
virtual const BaseRenderer * GetRenderer() const
virtual int * GetViewportSize() const
const Point3D GetOrigin() const
Get the origin, e.g. the upper-left corner of the plane.
Vector3D GetNormal() const
Normal of the plane.
BoundingBox::Pointer ComputeBoundingBox(const char *boolPropertyKey=nullptr, const BaseRenderer *renderer=nullptr, const char *boolPropertyKey2=nullptr)
Compute the bounding box of data tree structure it -> an iterator to a data tree structure.
virtual void SetStandardView(StandardView view)
MITKCORE_EXPORT const ScalarType eps
Point2D GetViewportSizeInMM() const
Describes a two-dimensional, rectangular plane.
void MoveCameraToPoint(const Point2D &planePoint)
MoveCameraToPoint Move camera so that the point on the plane is in the view center.
void AdjustCameraToPlane()
AdjustCameraToPlane Moves the camera of a 2D Renderwindow without panning or zooming, eg. only rotate the camera.
void Fit()
Fit Adjust the camera, so that the world bounding box is fully visible.
virtual DataStorage::Pointer GetDataStorage() const
void RequestUpdateAll(RequestType type=REQUEST_UPDATE_ALL)