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