ctkVTKAbstractView.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) Kitware Inc.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0.txt
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. =========================================================================*/
  14. // Qt includes
  15. #include <QTimer>
  16. #include <QVBoxLayout>
  17. #include <QDebug>
  18. // CTK includes
  19. #include "ctkVTKAbstractView.h"
  20. #include "ctkVTKAbstractView_p.h"
  21. #include "ctkLogger.h"
  22. // VTK includes
  23. #include <vtkOpenGLRenderWindow.h>
  24. #include <vtkRendererCollection.h>
  25. #include <vtkRenderWindowInteractor.h>
  26. #include <vtkTextProperty.h>
  27. //--------------------------------------------------------------------------
  28. static ctkLogger logger("org.commontk.visualization.vtk.widgets.ctkVTKAbstractView");
  29. //--------------------------------------------------------------------------
  30. // --------------------------------------------------------------------------
  31. // ctkVTKAbstractViewPrivate methods
  32. // --------------------------------------------------------------------------
  33. ctkVTKAbstractViewPrivate::ctkVTKAbstractViewPrivate(ctkVTKAbstractView& object)
  34. : q_ptr(&object)
  35. {
  36. this->RenderWindow = vtkSmartPointer<vtkRenderWindow>::New();
  37. this->CornerAnnotation = vtkSmartPointer<vtkCornerAnnotation>::New();
  38. this->RequestTimer = 0;
  39. this->RenderEnabled = true;
  40. this->FPSVisible = false;
  41. this->FPSTimer = 0;
  42. this->FPS = 0;
  43. }
  44. // --------------------------------------------------------------------------
  45. void ctkVTKAbstractViewPrivate::init()
  46. {
  47. Q_Q(ctkVTKAbstractView);
  48. this->setParent(q);
  49. this->VTKWidget = new QVTKWidget;
  50. q->setLayout(new QVBoxLayout);
  51. q->layout()->setMargin(0);
  52. q->layout()->setSpacing(0);
  53. q->layout()->addWidget(this->VTKWidget);
  54. this->RequestTimer = new QTimer(q);
  55. this->RequestTimer->setSingleShot(true);
  56. QObject::connect(this->RequestTimer, SIGNAL(timeout()),
  57. q, SLOT(forceRender()));
  58. this->FPSTimer = new QTimer(q);
  59. this->FPSTimer->setInterval(1000);
  60. QObject::connect(this->FPSTimer, SIGNAL(timeout()),
  61. q, SLOT(updateFPS()));
  62. this->setupCornerAnnotation();
  63. this->setupRendering();
  64. // block renders and observe interactor to enforce framerate
  65. q->setInteractor(this->RenderWindow->GetInteractor());
  66. }
  67. // --------------------------------------------------------------------------
  68. void ctkVTKAbstractViewPrivate::setupCornerAnnotation()
  69. {
  70. this->CornerAnnotation->SetMaximumLineHeight(0.07);
  71. vtkTextProperty *tprop = this->CornerAnnotation->GetTextProperty();
  72. tprop->ShadowOn();
  73. this->CornerAnnotation->ClearAllTexts();
  74. }
  75. //---------------------------------------------------------------------------
  76. void ctkVTKAbstractViewPrivate::setupRendering()
  77. {
  78. Q_ASSERT(this->RenderWindow);
  79. this->RenderWindow->SetAlphaBitPlanes(1);
  80. this->RenderWindow->SetMultiSamples(0);
  81. this->RenderWindow->StereoCapableWindowOn();
  82. this->VTKWidget->SetRenderWindow(this->RenderWindow);
  83. }
  84. //---------------------------------------------------------------------------
  85. QList<vtkRenderer*> ctkVTKAbstractViewPrivate::renderers()const
  86. {
  87. QList<vtkRenderer*> rendererList;
  88. vtkRendererCollection* rendererCollection = this->RenderWindow->GetRenderers();
  89. vtkCollectionSimpleIterator rendererIterator;
  90. rendererCollection->InitTraversal(rendererIterator);
  91. vtkRenderer *renderer;
  92. while ( (renderer= rendererCollection->GetNextRenderer(rendererIterator)) )
  93. {
  94. rendererList << renderer;
  95. }
  96. return rendererList;
  97. }
  98. //---------------------------------------------------------------------------
  99. vtkRenderer* ctkVTKAbstractViewPrivate::firstRenderer()const
  100. {
  101. return static_cast<vtkRenderer*>(this->RenderWindow->GetRenderers()
  102. ->GetItemAsObject(0));
  103. }
  104. //---------------------------------------------------------------------------
  105. // ctkVTKAbstractView methods
  106. // --------------------------------------------------------------------------
  107. ctkVTKAbstractView::ctkVTKAbstractView(QWidget* parentWidget)
  108. : Superclass(parentWidget)
  109. , d_ptr(new ctkVTKAbstractViewPrivate(*this))
  110. {
  111. Q_D(ctkVTKAbstractView);
  112. d->init();
  113. }
  114. // --------------------------------------------------------------------------
  115. ctkVTKAbstractView::ctkVTKAbstractView(ctkVTKAbstractViewPrivate* pimpl, QWidget* parentWidget)
  116. : Superclass(parentWidget)
  117. , d_ptr(pimpl)
  118. {
  119. // derived classes must call init manually. Calling init() here may results in
  120. // actions on a derived public class not yet finished to be created
  121. }
  122. //----------------------------------------------------------------------------
  123. ctkVTKAbstractView::~ctkVTKAbstractView()
  124. {
  125. }
  126. //----------------------------------------------------------------------------
  127. void ctkVTKAbstractView::scheduleRender()
  128. {
  129. Q_D(ctkVTKAbstractView);
  130. //logger.trace(QString("scheduleRender - RenderEnabled: %1 - Request render elapsed: %2ms").
  131. // arg(d->RenderEnabled ? "true" : "false")
  132. // .arg(d->RequestTime.elapsed()));
  133. if (!d->RenderEnabled)
  134. {
  135. return;
  136. }
  137. double msecsBeforeRender = 100. / d->RenderWindow->GetDesiredUpdateRate();
  138. if(d->VTKWidget->testAttribute(Qt::WA_WState_InPaintEvent))
  139. {
  140. // If the request comes from the system (widget exposed, resized...), the
  141. // render must be done immediately.
  142. this->forceRender();
  143. }
  144. else if (!d->RequestTime.isValid())
  145. {
  146. // If the DesiredUpdateRate is in "still mode", the requested framerate
  147. // is fake, it is just a way to allocate as much time as possible for the
  148. // rendering, it doesn't really mean that rendering must occur only once
  149. // every couple seconds. It just means it should be done when there is
  150. // time to do it. A timer of 0, kind of mean a rendering is done next time
  151. // it is idle.
  152. if (msecsBeforeRender > 10000)
  153. {
  154. msecsBeforeRender = 0;
  155. }
  156. d->RequestTime.start();
  157. d->RequestTimer->start(static_cast<int>(msecsBeforeRender));
  158. }
  159. else if (d->RequestTime.elapsed() > msecsBeforeRender)
  160. {
  161. // The rendering hasn't still be done, but msecsBeforeRender milliseconds
  162. // have already been elapsed, it is likely that RequestTimer has already
  163. // timed out, but the event queue hasn't been processed yet, rendering is
  164. // done now to ensure the desired framerate is respected.
  165. this->forceRender();
  166. }
  167. }
  168. //----------------------------------------------------------------------------
  169. void ctkVTKAbstractView::forceRender()
  170. {
  171. Q_D(ctkVTKAbstractView);
  172. if (this->sender() == d->RequestTimer &&
  173. !d->RequestTime.isValid())
  174. {
  175. // The slot associated to the timeout signal is now called, however the
  176. // render has already been executed meanwhile. There is no need to do it
  177. // again.
  178. return;
  179. }
  180. // The timer can be stopped if it hasn't timed out yet.
  181. d->RequestTimer->stop();
  182. d->RequestTime = QTime();
  183. //logger.trace(QString("forceRender - RenderEnabled: %1")
  184. // .arg(d->RenderEnabled ? "true" : "false"));
  185. if (!d->RenderEnabled || !this->isVisible())
  186. {
  187. return;
  188. }
  189. d->RenderWindow->Render();
  190. }
  191. //----------------------------------------------------------------------------
  192. CTK_GET_CPP(ctkVTKAbstractView, vtkRenderWindow*, renderWindow, RenderWindow);
  193. //----------------------------------------------------------------------------
  194. void ctkVTKAbstractView::setInteractor(vtkRenderWindowInteractor* newInteractor)
  195. {
  196. Q_D(ctkVTKAbstractView);
  197. d->RenderWindow->SetInteractor(newInteractor);
  198. // Prevent the interactor to call Render() on the render window; only
  199. // scheduleRender() and forceRender() can Render() the window.
  200. // This is done to ensure the desired framerate is respected.
  201. newInteractor->SetEnableRender(false);
  202. qvtkReconnect(d->RenderWindow->GetInteractor(), newInteractor,
  203. vtkCommand::RenderEvent, this, SLOT(scheduleRender()));
  204. }
  205. //----------------------------------------------------------------------------
  206. vtkRenderWindowInteractor* ctkVTKAbstractView::interactor()const
  207. {
  208. Q_D(const ctkVTKAbstractView);
  209. return d->RenderWindow->GetInteractor();
  210. }
  211. //----------------------------------------------------------------------------
  212. vtkInteractorObserver* ctkVTKAbstractView::interactorStyle()const
  213. {
  214. return this->interactor() ?
  215. this->interactor()->GetInteractorStyle() : 0;
  216. }
  217. //----------------------------------------------------------------------------
  218. void ctkVTKAbstractView::setCornerAnnotationText(const QString& text)
  219. {
  220. Q_D(ctkVTKAbstractView);
  221. d->CornerAnnotation->ClearAllTexts();
  222. d->CornerAnnotation->SetText(2, text.toLatin1());
  223. }
  224. //----------------------------------------------------------------------------
  225. QString ctkVTKAbstractView::cornerAnnotationText() const
  226. {
  227. Q_D(const ctkVTKAbstractView);
  228. return QLatin1String(d->CornerAnnotation->GetText(2));
  229. }
  230. //----------------------------------------------------------------------------
  231. vtkCornerAnnotation* ctkVTKAbstractView::cornerAnnotation() const
  232. {
  233. Q_D(const ctkVTKAbstractView);
  234. return d->CornerAnnotation;
  235. }
  236. //----------------------------------------------------------------------------
  237. QVTKWidget * ctkVTKAbstractView::VTKWidget() const
  238. {
  239. Q_D(const ctkVTKAbstractView);
  240. return d->VTKWidget;
  241. }
  242. //----------------------------------------------------------------------------
  243. CTK_SET_CPP(ctkVTKAbstractView, bool, setRenderEnabled, RenderEnabled);
  244. CTK_GET_CPP(ctkVTKAbstractView, bool, renderEnabled, RenderEnabled);
  245. //----------------------------------------------------------------------------
  246. QSize ctkVTKAbstractView::minimumSizeHint()const
  247. {
  248. // Arbitrary size. 50x50 because smaller seems too small.
  249. return QSize(50, 50);
  250. }
  251. //----------------------------------------------------------------------------
  252. QSize ctkVTKAbstractView::sizeHint()const
  253. {
  254. // Arbitrary size. 300x300 is the default vtkRenderWindow size.
  255. return QSize(300, 300);
  256. }
  257. //----------------------------------------------------------------------------
  258. bool ctkVTKAbstractView::hasHeightForWidth()const
  259. {
  260. return true;
  261. }
  262. //----------------------------------------------------------------------------
  263. int ctkVTKAbstractView::heightForWidth(int width)const
  264. {
  265. // typically VTK render window tend to be square...
  266. return width;
  267. }
  268. //----------------------------------------------------------------------------
  269. void ctkVTKAbstractView::setBackgroundColor(const QColor& newBackgroundColor)
  270. {
  271. Q_D(ctkVTKAbstractView);
  272. double color[3];
  273. color[0] = newBackgroundColor.redF();
  274. color[1] = newBackgroundColor.greenF();
  275. color[2] = newBackgroundColor.blueF();
  276. foreach(vtkRenderer* renderer, d->renderers())
  277. {
  278. renderer->SetBackground(color);
  279. }
  280. }
  281. //----------------------------------------------------------------------------
  282. QColor ctkVTKAbstractView::backgroundColor()const
  283. {
  284. Q_D(const ctkVTKAbstractView);
  285. vtkRenderer* firstRenderer = d->firstRenderer();
  286. return firstRenderer ? QColor::fromRgbF(firstRenderer->GetBackground()[0],
  287. firstRenderer->GetBackground()[1],
  288. firstRenderer->GetBackground()[2])
  289. : QColor();
  290. }
  291. //----------------------------------------------------------------------------
  292. void ctkVTKAbstractView::setBackgroundColor2(const QColor& newBackgroundColor)
  293. {
  294. Q_D(ctkVTKAbstractView);
  295. double color[3];
  296. color[0] = newBackgroundColor.redF();
  297. color[1] = newBackgroundColor.greenF();
  298. color[2] = newBackgroundColor.blueF();
  299. foreach(vtkRenderer* renderer, d->renderers())
  300. {
  301. renderer->SetBackground2(color);
  302. }
  303. }
  304. //----------------------------------------------------------------------------
  305. QColor ctkVTKAbstractView::backgroundColor2()const
  306. {
  307. Q_D(const ctkVTKAbstractView);
  308. vtkRenderer* firstRenderer = d->firstRenderer();
  309. return firstRenderer ? QColor::fromRgbF(firstRenderer->GetBackground2()[0],
  310. firstRenderer->GetBackground2()[1],
  311. firstRenderer->GetBackground2()[2])
  312. : QColor();
  313. }
  314. //----------------------------------------------------------------------------
  315. void ctkVTKAbstractView::setGradientBackground(bool enable)
  316. {
  317. Q_D(ctkVTKAbstractView);
  318. foreach(vtkRenderer* renderer, d->renderers())
  319. {
  320. renderer->SetGradientBackground(enable);
  321. }
  322. }
  323. //----------------------------------------------------------------------------
  324. bool ctkVTKAbstractView::gradientBackground()const
  325. {
  326. Q_D(const ctkVTKAbstractView);
  327. vtkRenderer* firstRenderer = d->firstRenderer();
  328. return firstRenderer ? firstRenderer->GetGradientBackground() : false;
  329. }
  330. //----------------------------------------------------------------------------
  331. void ctkVTKAbstractView::setFPSVisible(bool show)
  332. {
  333. Q_D(ctkVTKAbstractView);
  334. if (d->FPSVisible == show)
  335. {
  336. return;
  337. }
  338. d->FPSVisible = show;
  339. vtkRenderer* renderer = d->firstRenderer();
  340. if (d->FPSVisible)
  341. {
  342. d->FPSTimer->start();
  343. qvtkConnect(renderer,
  344. vtkCommand::EndEvent, this, SLOT(onRender()));
  345. }
  346. else
  347. {
  348. d->FPSTimer->stop();
  349. qvtkDisconnect(renderer,
  350. vtkCommand::EndEvent, this, SLOT(onRender()));
  351. d->CornerAnnotation->SetText(1, "");
  352. }
  353. }
  354. //----------------------------------------------------------------------------
  355. bool ctkVTKAbstractView::isFPSVisible()const
  356. {
  357. Q_D(const ctkVTKAbstractView);
  358. return d->FPSVisible;
  359. }
  360. //----------------------------------------------------------------------------
  361. void ctkVTKAbstractView::onRender()
  362. {
  363. Q_D(ctkVTKAbstractView);
  364. ++d->FPS;
  365. }
  366. //----------------------------------------------------------------------------
  367. void ctkVTKAbstractView::updateFPS()
  368. {
  369. Q_D(ctkVTKAbstractView);
  370. vtkRenderer* renderer = d->firstRenderer();
  371. double lastRenderTime = renderer ? renderer->GetLastRenderTimeInSeconds() : 0.;
  372. QString fpsString = tr("FPS: %1(%2s)").arg(d->FPS).arg(lastRenderTime);
  373. d->FPS = 0;
  374. d->CornerAnnotation->SetText(1, fpsString.toLatin1());
  375. }
  376. //----------------------------------------------------------------------------
  377. bool ctkVTKAbstractView::useDepthPeeling()const
  378. {
  379. Q_D(const ctkVTKAbstractView);
  380. vtkRenderer* renderer = d->firstRenderer();
  381. return renderer ? static_cast<bool>(renderer->GetUseDepthPeeling()):0;
  382. }
  383. //----------------------------------------------------------------------------
  384. void ctkVTKAbstractView::setUseDepthPeeling(bool use)
  385. {
  386. Q_D(ctkVTKAbstractView);
  387. vtkRenderer* renderer = d->firstRenderer();
  388. if (!renderer)
  389. {
  390. return;
  391. }
  392. this->renderWindow()->SetAlphaBitPlanes( use ? 1 : 0);
  393. this->renderWindow()->SetMultiSamples(
  394. use ? 0 : vtkOpenGLRenderWindow::GetGlobalMaximumNumberOfMultiSamples());
  395. renderer->SetUseDepthPeeling(use ? 1 : 0);
  396. }