1 /*=========================================================================
2
3 Library: CTK
4
5 Copyright (c) Kitware Inc.
6
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
10
11 http://www.apache.org/licenses/LICENSE-2.0.txt
12
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
18
19 =========================================================================*/
20
21 // Qt includes
22 #include <QTimer>
23 #include <QVBoxLayout>
24 #include <QDebug>
25
26 // CTK includes
27 #include "ctkVTKRenderView.h"
28 #include "ctkVTKRenderView_p.h"
29
30 // VTK includes
31 #include <vtkRendererCollection.h>
32 #include <vtkRenderWindowInteractor.h>
33 #include <vtkTextProperty.h>
34 #include <vtkCamera.h>
35
36 // --------------------------------------------------------------------------
37 // ctkVTKRenderViewPrivate methods
38
39 // --------------------------------------------------------------------------
ctkVTKRenderViewPrivate(ctkVTKRenderView & object)40 ctkVTKRenderViewPrivate::ctkVTKRenderViewPrivate(ctkVTKRenderView& object)
41 :ctkVTKAbstractViewPrivate(object)
42 {
43 qRegisterMetaType<ctkAxesWidget::Axis>("ctkAxesWidget::Axis");
44 this->Renderer = vtkSmartPointer<vtkRenderer>::New();
45 this->Axes = vtkSmartPointer<vtkAxesActor>::New();
46 this->Orientation = vtkSmartPointer<vtkOrientationMarkerWidget>::New();
47 this->ZoomFactor = 0.05;
48 this->PitchRollYawIncrement = 5;
49 this->PitchDirection = ctkVTKRenderView::PitchUp;
50 this->RollDirection = ctkVTKRenderView::RollRight;
51 this->YawDirection = ctkVTKRenderView::YawLeft;
52 this->SpinDirection = ctkVTKRenderView::YawRight;
53 this->SpinEnabled = false;
54 this->AnimationIntervalMs = 5;
55 this->SpinIncrement = 2;
56 this->RockEnabled = false;
57 this->RockIncrement = 0;
58 this->RockLength = 200;
59
60 this->Orientation->SetOrientationMarker(this->Axes);
61 }
62
63 // --------------------------------------------------------------------------
setupCornerAnnotation()64 void ctkVTKRenderViewPrivate::setupCornerAnnotation()
65 {
66 this->ctkVTKAbstractViewPrivate::setupCornerAnnotation();
67 if (!this->Renderer->HasViewProp(this->CornerAnnotation))
68 {
69 this->Renderer->AddViewProp(this->CornerAnnotation);
70 }
71 }
72
73 //---------------------------------------------------------------------------
setupRendering()74 void ctkVTKRenderViewPrivate::setupRendering()
75 {
76 // Add renderer
77 this->RenderWindow->AddRenderer(this->Renderer);
78 this->ctkVTKAbstractViewPrivate::setupRendering();
79 }
80
81 //----------------------------------------------------------------------------
zoom(double zoomFactor)82 void ctkVTKRenderViewPrivate::zoom(double zoomFactor)
83 {
84 Q_ASSERT(this->Renderer->IsActiveCameraCreated());
85 vtkCamera * camera = this->Renderer->GetActiveCamera();
86
87 if (camera->GetParallelProjection())
88 {
89 camera->SetParallelScale(camera->GetParallelScale() / (1 + zoomFactor));
90 }
91 else
92 {
93 camera->Dolly(1 + zoomFactor);
94 this->Renderer->ResetCameraClippingRange();
95 this->Renderer->UpdateLightsGeometryToFollowCamera();
96 }
97 }
98
99 //---------------------------------------------------------------------------
pitch(double rotateDegrees,ctkVTKRenderView::RotateDirection pitchDirection)100 void ctkVTKRenderViewPrivate::pitch(double rotateDegrees,
101 ctkVTKRenderView::RotateDirection pitchDirection)
102 {
103 Q_ASSERT(this->Renderer->IsActiveCameraCreated());
104 Q_ASSERT(rotateDegrees >= 0);
105 vtkCamera *cam = this->Renderer->GetActiveCamera();
106 cam->Elevation(pitchDirection == ctkVTKRenderView::PitchDown ? rotateDegrees : -rotateDegrees);
107 cam->OrthogonalizeViewUp();
108 this->Renderer->UpdateLightsGeometryToFollowCamera();
109 }
110
111 //---------------------------------------------------------------------------
roll(double rotateDegrees,ctkVTKRenderView::RotateDirection rollDirection)112 void ctkVTKRenderViewPrivate::roll(double rotateDegrees,
113 ctkVTKRenderView::RotateDirection rollDirection)
114 {
115 Q_ASSERT(this->Renderer->IsActiveCameraCreated());
116 Q_ASSERT(rotateDegrees >= 0);
117
118 vtkCamera *cam = this->Renderer->GetActiveCamera();
119 cam->Roll(rollDirection == ctkVTKRenderView::RollLeft ? rotateDegrees : -rotateDegrees);
120 cam->OrthogonalizeViewUp();
121 this->Renderer->UpdateLightsGeometryToFollowCamera();
122 }
123
124 //---------------------------------------------------------------------------
yaw(double rotateDegrees,ctkVTKRenderView::RotateDirection yawDirection)125 void ctkVTKRenderViewPrivate::yaw(double rotateDegrees,
126 ctkVTKRenderView::RotateDirection yawDirection)
127 {
128 Q_ASSERT(this->Renderer->IsActiveCameraCreated());
129 Q_ASSERT(rotateDegrees >= 0);
130 vtkCamera *cam = this->Renderer->GetActiveCamera();
131 cam->Azimuth(yawDirection == ctkVTKRenderView::YawLeft ? rotateDegrees : -rotateDegrees);
132 cam->OrthogonalizeViewUp();
133 this->Renderer->UpdateLightsGeometryToFollowCamera();
134 }
135
136 //---------------------------------------------------------------------------
doSpin()137 void ctkVTKRenderViewPrivate::doSpin()
138 {
139 Q_Q(ctkVTKRenderView);
140 if (!this->SpinEnabled)
141 {
142 return;
143 }
144
145 switch (this->SpinDirection)
146 {
147 case ctkVTKRenderView::PitchUp:
148 case ctkVTKRenderView::PitchDown:
149 this->pitch(this->SpinIncrement, this->SpinDirection);
150 break;
151 case ctkVTKRenderView::RollLeft:
152 case ctkVTKRenderView::RollRight:
153 this->roll(this->SpinIncrement, this->SpinDirection);
154 break;
155 case ctkVTKRenderView::YawLeft:
156 case ctkVTKRenderView::YawRight:
157 this->yaw(this->SpinIncrement, this->SpinDirection);
158 break;
159 }
160
161 q->forceRender();
162 QTimer::singleShot(this->AnimationIntervalMs, this, SLOT(doSpin()));
163 }
164
165 //---------------------------------------------------------------------------
doRock()166 void ctkVTKRenderViewPrivate::doRock()
167 {
168 Q_Q(ctkVTKRenderView);
169 Q_ASSERT(this->Renderer->IsActiveCameraCreated());
170
171 if (!this->RockEnabled)
172 {
173 return;
174 }
175
176 vtkCamera *camera = this->Renderer->GetActiveCamera();
177
178 double frac = static_cast<double>(this->RockIncrement) / static_cast<double>(this->RockLength);
179 double az = 1.5 * cos (2.0 * 3.1415926 * (frac - floor(frac)));
180 this->RockIncrement++;
181 this->RockIncrement = this->RockIncrement % this->RockLength;
182
183 // Move the camera
184 camera->Azimuth(az);
185 camera->OrthogonalizeViewUp();
186
187 //Make the lighting follow the camera to avoid illumination changes
188 this->Renderer->UpdateLightsGeometryToFollowCamera();
189
190 q->forceRender();
191 QTimer::singleShot(this->AnimationIntervalMs, this, SLOT(doRock()));
192 }
193
194 //---------------------------------------------------------------------------
195 // ctkVTKRenderView methods
196
197 // --------------------------------------------------------------------------
ctkVTKRenderView(QWidget * parentWidget)198 ctkVTKRenderView::ctkVTKRenderView(QWidget* parentWidget)
199 : Superclass(new ctkVTKRenderViewPrivate(*this), parentWidget)
200 {
201 Q_D(ctkVTKRenderView);
202 d->init();
203
204 // The interactor in RenderWindow exists after the renderwindow is set to
205 // the QVTKWidet
206 d->Orientation->SetInteractor(d->RenderWindow->GetInteractor());
207 d->Orientation->SetEnabled(1);
208 d->Orientation->InteractiveOff();
209 }
210
211 //----------------------------------------------------------------------------
~ctkVTKRenderView()212 ctkVTKRenderView::~ctkVTKRenderView()
213 {
214 }
215 //----------------------------------------------------------------------------
setInteractor(vtkRenderWindowInteractor * newInteractor)216 void ctkVTKRenderView::setInteractor(vtkRenderWindowInteractor* newInteractor)
217 {
218 Q_D(ctkVTKRenderView);
219 this->Superclass::setInteractor(newInteractor);
220 d->Orientation->SetInteractor(newInteractor);
221 }
222
223 //----------------------------------------------------------------------------
setOrientationWidgetVisible(bool visible)224 void ctkVTKRenderView::setOrientationWidgetVisible(bool visible)
225 {
226 Q_D(ctkVTKRenderView);
227 d->Orientation->SetEnabled(visible);
228 }
229
230 //----------------------------------------------------------------------------
orientationWidgetVisible()231 bool ctkVTKRenderView::orientationWidgetVisible()
232 {
233 Q_D(ctkVTKRenderView);
234 return d->Orientation->GetEnabled();
235 }
236
237 //----------------------------------------------------------------------------
activeCamera()238 vtkCamera* ctkVTKRenderView::activeCamera()
239 {
240 Q_D(ctkVTKRenderView);
241 if (d->Renderer->IsActiveCameraCreated())
242 {
243 return d->Renderer->GetActiveCamera();
244 }
245 else
246 {
247 return 0;
248 }
249 }
250
251 //----------------------------------------------------------------------------
resetCamera()252 void ctkVTKRenderView::resetCamera()
253 {
254 Q_D(ctkVTKRenderView);
255 d->Renderer->ResetCamera();
256 }
257
258 //----------------------------------------------------------------------------
259 CTK_GET_CPP(ctkVTKRenderView, vtkRenderer*, renderer, Renderer);
260
261 //----------------------------------------------------------------------------
262 CTK_GET_CPP(ctkVTKRenderView, double, pitchRollYawIncrement, PitchRollYawIncrement);
263
264 //----------------------------------------------------------------------------
setPitchRollYawIncrement(double newPitchRollYawIncrement)265 void ctkVTKRenderView::setPitchRollYawIncrement(double newPitchRollYawIncrement)
266 {
267 Q_D(ctkVTKRenderView);
268 d->PitchRollYawIncrement = qAbs(newPitchRollYawIncrement);
269 }
270
271 //----------------------------------------------------------------------------
272 CTK_GET_CPP(ctkVTKRenderView, ctkVTKRenderView::RotateDirection, pitchDirection, PitchDirection);
273
274 //----------------------------------------------------------------------------
setPitchDirection(ctkVTKRenderView::RotateDirection newPitchDirection)275 void ctkVTKRenderView::setPitchDirection(ctkVTKRenderView::RotateDirection newPitchDirection)
276 {
277 Q_D(ctkVTKRenderView);
278 if (newPitchDirection != ctkVTKRenderView::PitchUp &&
279 newPitchDirection != ctkVTKRenderView::PitchDown)
280 {
281 return;
282 }
283 d->PitchDirection = newPitchDirection;
284 }
285
286 //----------------------------------------------------------------------------
287 CTK_GET_CPP(ctkVTKRenderView, ctkVTKRenderView::RotateDirection, rollDirection, RollDirection);
288
289 //----------------------------------------------------------------------------
setRollDirection(ctkVTKRenderView::RotateDirection newRollDirection)290 void ctkVTKRenderView::setRollDirection(ctkVTKRenderView::RotateDirection newRollDirection)
291 {
292 Q_D(ctkVTKRenderView);
293 if (newRollDirection != ctkVTKRenderView::RollLeft &&
294 newRollDirection != ctkVTKRenderView::RollRight)
295 {
296 return;
297 }
298 d->RollDirection = newRollDirection;
299 }
300
301 //----------------------------------------------------------------------------
302 CTK_GET_CPP(ctkVTKRenderView, ctkVTKRenderView::RotateDirection, yawDirection, YawDirection);
303
304 //----------------------------------------------------------------------------
setYawDirection(ctkVTKRenderView::RotateDirection newYawDirection)305 void ctkVTKRenderView::setYawDirection(ctkVTKRenderView::RotateDirection newYawDirection)
306 {
307 Q_D(ctkVTKRenderView);
308 if (newYawDirection != ctkVTKRenderView::YawLeft &&
309 newYawDirection != ctkVTKRenderView::YawRight)
310 {
311 return;
312 }
313 d->YawDirection = newYawDirection;
314 }
315
316 //----------------------------------------------------------------------------
317 CTK_GET_CPP(ctkVTKRenderView, ctkVTKRenderView::RotateDirection, spinDirection, SpinDirection);
318 CTK_SET_CPP(ctkVTKRenderView, ctkVTKRenderView::RotateDirection, setSpinDirection, SpinDirection);
319
320 //----------------------------------------------------------------------------
pitch()321 void ctkVTKRenderView::pitch()
322 {
323 Q_D(ctkVTKRenderView);
324 if (!d->Renderer->IsActiveCameraCreated())
325 {
326 return;
327 }
328 d->pitch(d->PitchRollYawIncrement, d->PitchDirection);
329 }
330
331 //----------------------------------------------------------------------------
roll()332 void ctkVTKRenderView::roll()
333 {
334 Q_D(ctkVTKRenderView);
335 if (!d->Renderer->IsActiveCameraCreated())
336 {
337 return;
338 }
339 d->roll(d->PitchRollYawIncrement, d->RollDirection);
340 }
341
342 //----------------------------------------------------------------------------
yaw()343 void ctkVTKRenderView::yaw()
344 {
345 Q_D(ctkVTKRenderView);
346 if (!d->Renderer->IsActiveCameraCreated())
347 {
348 return;
349 }
350 d->yaw(d->PitchRollYawIncrement, d->YawDirection);
351 }
352
353 //----------------------------------------------------------------------------
setSpinEnabled(bool enabled)354 void ctkVTKRenderView::setSpinEnabled(bool enabled)
355 {
356 Q_D(ctkVTKRenderView);
357 if (enabled == d->SpinEnabled)
358 {
359 return;
360 }
361 d->SpinEnabled = enabled;
362 d->RockEnabled = false;
363
364 QTimer::singleShot(0, d, SLOT(doSpin()));
365 }
366
367 //----------------------------------------------------------------------------
368 CTK_GET_CPP(ctkVTKRenderView, bool, spinEnabled, SpinEnabled);
369
370 //----------------------------------------------------------------------------
setSpinIncrement(double newSpinIncrement)371 void ctkVTKRenderView::setSpinIncrement(double newSpinIncrement)
372 {
373 Q_D(ctkVTKRenderView);
374 d->SpinIncrement = qAbs(newSpinIncrement);
375 }
376
377 //----------------------------------------------------------------------------
378 CTK_GET_CPP(ctkVTKRenderView, double, spinIncrement, SpinIncrement);
379
380 //----------------------------------------------------------------------------
setAnimationIntervalMs(int newAnimationIntervalMs)381 void ctkVTKRenderView::setAnimationIntervalMs(int newAnimationIntervalMs)
382 {
383 Q_D(ctkVTKRenderView);
384 d->AnimationIntervalMs = qAbs(newAnimationIntervalMs);
385 }
386
387 //----------------------------------------------------------------------------
388 CTK_GET_CPP(ctkVTKRenderView, int, animationIntervalMs, AnimationIntervalMs);
389
390 //----------------------------------------------------------------------------
setRockEnabled(bool enabled)391 void ctkVTKRenderView::setRockEnabled(bool enabled)
392 {
393 Q_D(ctkVTKRenderView);
394 if (enabled == d->RockEnabled)
395 {
396 return;
397 }
398 d->RockEnabled = enabled;
399 d->SpinEnabled = false;
400
401 QTimer::singleShot(0, d, SLOT(doRock()));
402 }
403
404 //----------------------------------------------------------------------------
405 CTK_GET_CPP(ctkVTKRenderView, bool, rockEnabled, RockEnabled);
406
407 //----------------------------------------------------------------------------
setRockLength(int newRockLength)408 void ctkVTKRenderView::setRockLength(int newRockLength)
409 {
410 Q_D(ctkVTKRenderView);
411 d->RockLength = qAbs(newRockLength);
412 }
413
414 //----------------------------------------------------------------------------
415 CTK_GET_CPP(ctkVTKRenderView, int, rockLength, RockLength);
416
417 //----------------------------------------------------------------------------
setRockIncrement(int newRockIncrement)418 void ctkVTKRenderView::setRockIncrement(int newRockIncrement)
419 {
420 Q_D(ctkVTKRenderView);
421 d->RockIncrement = qAbs(newRockIncrement);
422 }
423
424 //----------------------------------------------------------------------------
425 CTK_GET_CPP(ctkVTKRenderView, int, rockIncrement, RockIncrement);
426
427 //----------------------------------------------------------------------------
setZoomFactor(double newZoomFactor)428 void ctkVTKRenderView::setZoomFactor(double newZoomFactor)
429 {
430 Q_D(ctkVTKRenderView);
431 d->ZoomFactor = qBound(0.0, qAbs(newZoomFactor), 1.0);
432 }
433
434 //----------------------------------------------------------------------------
435 CTK_GET_CPP(ctkVTKRenderView, double, zoomFactor, ZoomFactor);
436
437 //----------------------------------------------------------------------------
zoomIn()438 void ctkVTKRenderView::zoomIn()
439 {
440 Q_D(ctkVTKRenderView);
441 if (!d->Renderer->IsActiveCameraCreated())
442 {
443 return;
444 }
445 d->zoom(d->ZoomFactor);
446 }
447
448 //----------------------------------------------------------------------------
zoomOut()449 void ctkVTKRenderView::zoomOut()
450 {
451 Q_D(ctkVTKRenderView);
452 if (!d->Renderer->IsActiveCameraCreated())
453 {
454 return;
455 }
456 d->zoom(-d->ZoomFactor);
457 }
458
459 //----------------------------------------------------------------------------
setFocalPoint(double x,double y,double z)460 void ctkVTKRenderView::setFocalPoint(double x, double y, double z)
461 {
462 Q_D(ctkVTKRenderView);
463 if (!d->Renderer->IsActiveCameraCreated())
464 {
465 return;
466 }
467 vtkCamera * camera = d->Renderer->GetActiveCamera();
468 camera->SetFocalPoint(x, y, z);
469 camera->ComputeViewPlaneNormal();
470 camera->OrthogonalizeViewUp();
471 d->Renderer->UpdateLightsGeometryToFollowCamera();
472 }
473
474 //----------------------------------------------------------------------------
resetFocalPoint()475 void ctkVTKRenderView::resetFocalPoint()
476 {
477 Q_D(ctkVTKRenderView);
478 double bounds[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
479 d->Renderer->ComputeVisiblePropBounds(bounds);
480 double x_center = (bounds[1] + bounds[0]) / 2.0;
481 double y_center = (bounds[3] + bounds[2]) / 2.0;
482 double z_center = (bounds[5] + bounds[4]) / 2.0;
483 this->setFocalPoint(x_center, y_center, z_center);
484 }
485
486 //----------------------------------------------------------------------------
lookFromAxis(const ctkAxesWidget::Axis & axis,double fov)487 void ctkVTKRenderView::lookFromAxis(const ctkAxesWidget::Axis& axis, double fov)
488 {
489 Q_D(ctkVTKRenderView);
490 Q_ASSERT(d->Renderer);
491 if (!d->Renderer->IsActiveCameraCreated())
492 {
493 return;
494 }
495 vtkCamera * camera = d->Renderer->GetActiveCamera();
496 Q_ASSERT(camera);
497 double widefov = fov*3;
498 double* focalPoint = camera->GetFocalPoint();
499 switch (axis)
500 {
501 case ctkAxesWidget::Right:
502 camera->SetPosition(focalPoint[0]+widefov, focalPoint[1], focalPoint[2]);
503 camera->SetViewUp(0, 0, 1);
504 break;
505 case ctkAxesWidget::Left:
506 camera->SetPosition(focalPoint[0]-widefov, focalPoint[1], focalPoint[2]);
507 camera->SetViewUp(0, 0, 1);
508 break;
509 case ctkAxesWidget::Anterior:
510 camera->SetPosition(focalPoint[0], focalPoint[1]+widefov, focalPoint[2]);
511 camera->SetViewUp(0, 0, 1);
512 break;
513 case ctkAxesWidget::Posterior:
514 camera->SetPosition(focalPoint[0], focalPoint[1]-widefov, focalPoint[2]);
515 camera->SetViewUp(0, 0, 1);
516 break;
517 case ctkAxesWidget::Superior:
518 camera->SetPosition(focalPoint[0], focalPoint[1], focalPoint[2]+widefov);
519 camera->SetViewUp(0, 1, 0);
520 break;
521 case ctkAxesWidget::Inferior:
522 camera->SetPosition(focalPoint[0], focalPoint[1], focalPoint[2]-widefov);
523 camera->SetViewUp(0, 1, 0);
524 break;
525 case ctkAxesWidget::None:
526 default:
527 // do nothing
528 return;
529 break;
530 }
531 d->Renderer->ResetCameraClippingRange();
532 camera->ComputeViewPlaneNormal();
533 camera->OrthogonalizeViewUp();
534 d->Renderer->UpdateLightsGeometryToFollowCamera();
535 }
536