ctkVTKThumbnailView.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  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.commontk.org/LICENSE
  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 <QDebug>
  16. // CTK includes
  17. #include "ctkLogger.h"
  18. #include "ctkVTKThumbnailView.h"
  19. // VTK includes
  20. #include <vtkCamera.h>
  21. #include <vtkFollower.h>
  22. #include <vtkInteractorStyle.h>
  23. #include <vtkMath.h>
  24. #include <vtkOutlineSource.h>
  25. #include <vtkPolyDataMapper.h>
  26. #include <vtkProperty.h>
  27. #include <vtkRenderWindow.h>
  28. #include <vtkRenderWindowInteractor.h>
  29. #include <vtkRenderer.h>
  30. #include <vtkSmartPointer.h>
  31. #include <vtkWeakPointer.h>
  32. //--------------------------------------------------------------------------
  33. static ctkLogger logger("org.slicer.libs.qmrmlwidgets.ctkVTKThumbnailView");
  34. //--------------------------------------------------------------------------
  35. #define DEGREES2RADIANS 0.0174532925
  36. //-----------------------------------------------------------------------------
  37. class ctkVTKThumbnailViewPrivate
  38. {
  39. Q_DECLARE_PUBLIC(ctkVTKThumbnailView);
  40. protected:
  41. ctkVTKThumbnailView* const q_ptr;
  42. public:
  43. ctkVTKThumbnailViewPrivate(ctkVTKThumbnailView& object);
  44. ~ctkVTKThumbnailViewPrivate();
  45. void init();
  46. void initCamera();
  47. void updateBounds();
  48. void updateCamera();
  49. void resetCamera();
  50. vtkRenderer* Renderer;
  51. vtkWeakPointer<vtkRenderWindowInteractor> Interactor;
  52. vtkOutlineSource* FOVBox;
  53. vtkPolyDataMapper* FOVBoxMapper;
  54. vtkFollower* FOVBoxActor;
  55. };
  56. //--------------------------------------------------------------------------
  57. // ctkVTKThumbnailViewPrivate methods
  58. //---------------------------------------------------------------------------
  59. ctkVTKThumbnailViewPrivate::ctkVTKThumbnailViewPrivate(ctkVTKThumbnailView& object)
  60. : q_ptr(&object)
  61. {
  62. this->Renderer = 0;
  63. this->Interactor = 0;
  64. this->FOVBox = 0;
  65. this->FOVBoxMapper = 0;
  66. this->FOVBoxActor = 0;
  67. }
  68. //---------------------------------------------------------------------------
  69. ctkVTKThumbnailViewPrivate::~ctkVTKThumbnailViewPrivate()
  70. {
  71. this->FOVBox->Delete();
  72. this->FOVBoxMapper->Delete();
  73. this->FOVBoxActor->Delete();
  74. }
  75. //---------------------------------------------------------------------------
  76. void ctkVTKThumbnailViewPrivate::init()
  77. {
  78. Q_Q(ctkVTKThumbnailView);
  79. this->FOVBox = vtkOutlineSource::New();
  80. this->FOVBoxMapper = vtkPolyDataMapper::New();
  81. this->FOVBoxMapper->SetInput( this->FOVBox->GetOutput() );
  82. this->FOVBoxActor = vtkFollower::New();
  83. this->FOVBoxMapper->Update();
  84. this->FOVBoxActor->SetMapper( this->FOVBoxMapper );
  85. this->FOVBoxActor->SetPickable(0);
  86. this->FOVBoxActor->SetDragable(0);
  87. this->FOVBoxActor->SetVisibility(1);
  88. this->FOVBoxActor->SetScale(1.0, 1.0, 1.0);
  89. this->FOVBoxActor->GetProperty()->SetColor( 0.1, 0.45, 0.1 );
  90. this->FOVBoxActor->GetProperty()->SetLineWidth (2.0);
  91. q->renderWindow()->GetInteractor()->SetInteractorStyle(0);
  92. // not sure what's for...
  93. q->qvtkConnect(q->renderWindow(), vtkCommand::AbortCheckEvent,
  94. q, SLOT(checkAbort()));
  95. }
  96. //---------------------------------------------------------------------------
  97. void ctkVTKThumbnailViewPrivate::initCamera()
  98. {
  99. Q_Q(ctkVTKThumbnailView);
  100. vtkRenderer* ren = this->Renderer;
  101. if (!ren)
  102. {
  103. return;
  104. }
  105. vtkCamera *cam = ren->IsActiveCameraCreated() ? ren->GetActiveCamera() : NULL;
  106. if (!cam)
  107. {
  108. return;
  109. }
  110. vtkCamera *navcam = q->activeCamera();
  111. if (!navcam)
  112. {
  113. return;
  114. }
  115. navcam->SetPosition ( cam->GetPosition() );
  116. navcam->SetFocalPoint ( cam->GetFocalPoint() );
  117. navcam->ComputeViewPlaneNormal();
  118. navcam->SetViewUp( cam->GetViewUp() );
  119. this->FOVBoxActor->SetCamera (navcam);
  120. this->FOVBox->SetBoxTypeToOriented ( );
  121. }
  122. //---------------------------------------------------------------------------
  123. void ctkVTKThumbnailViewPrivate::updateBounds()
  124. {
  125. Q_Q(ctkVTKThumbnailView);
  126. vtkRenderer* ren = this->Renderer;
  127. vtkActorCollection *mainActors;
  128. vtkActor *mainActor;
  129. vtkActor *newActor;
  130. vtkPolyDataMapper *newMapper;
  131. // iterate thru the actor collection,
  132. // remove item, delete actor, delete mapper.
  133. vtkActorCollection *navActors = q->renderer()->GetActors();
  134. if (!navActors)
  135. {
  136. q->renderer()->RemoveAllViewProps();
  137. navActors->RemoveAllItems();
  138. }
  139. if (!ren)
  140. {
  141. return;
  142. }
  143. double bounds[6];
  144. double dimension;
  145. double x,y,z;
  146. double cutoff = 0.1;
  147. double cutoffDimension;
  148. ren->ComputeVisiblePropBounds( bounds );
  149. x = bounds[1] - bounds[0];
  150. y = bounds[3] - bounds[2];
  151. z = bounds[5] - bounds[4];
  152. dimension = x*x + y*y + z*z;
  153. cutoffDimension = cutoff * dimension;
  154. // Get actor collection from the main viewer's renderer
  155. mainActors = ren->GetActors();
  156. if (!mainActors)
  157. {
  158. return;
  159. }
  160. // add the little FOV box to NavigationWidget's actors
  161. q->renderer()->AddViewProp(this->FOVBoxActor);
  162. for(mainActors->InitTraversal(); (mainActor = mainActors->GetNextActor()); )
  163. {
  164. // get the bbox of this actor
  165. int vis = mainActor->GetVisibility();
  166. //if (vis)
  167. // {
  168. mainActor->GetBounds ( bounds );
  169. // check to see if it's big enough to include in the scene...
  170. x = bounds[1] - bounds[0];
  171. y = bounds[3] - bounds[2];
  172. z = bounds[5] - bounds[4];
  173. dimension = x*x + y*y + z*z;
  174. // }
  175. // add a copy of the actor to the renderer
  176. // only if it's big enough to count (don't bother with tiny
  177. // and don't bother with invisible stuff)
  178. if ( dimension > cutoffDimension && vis )
  179. {
  180. // ---new: create new actor, mapper, deep copy, add it.
  181. newMapper = vtkPolyDataMapper::New();
  182. newMapper->ShallowCopy (mainActor->GetMapper() );
  183. newMapper->SetInput ( vtkPolyData::SafeDownCast(mainActor->GetMapper()->GetInput()) );
  184. newActor = vtkActor::New();
  185. newActor->ShallowCopy (mainActor );
  186. newActor->SetMapper ( newMapper );
  187. newMapper->Delete();
  188. q->renderer()->AddActor( newActor );
  189. newActor->Delete();
  190. }
  191. }
  192. }
  193. //---------------------------------------------------------------------------
  194. void ctkVTKThumbnailViewPrivate::updateCamera()
  195. {
  196. Q_Q(ctkVTKThumbnailView);
  197. // Scale the FOVBox actor to show the
  198. // MainViewer's window on the scene.
  199. vtkRenderer *ren = this->Renderer;
  200. vtkCamera *cam = ren ? (ren->IsActiveCameraCreated() ? ren->GetActiveCamera() : NULL) : NULL;
  201. if (!cam)
  202. {
  203. return;
  204. }
  205. // 3DViewer's camera configuration
  206. double *focalPoint = cam->GetFocalPoint ( );
  207. double *camPos= cam->GetPosition ( );
  208. double *vpn = cam->GetViewPlaneNormal ();
  209. double thetaV = (cam->GetViewAngle()) / 2.0;
  210. // camera distance, and distance of FOVBox from focalPoint
  211. double camDist = cam->GetDistance ();
  212. double boxDist = camDist * 0.89;
  213. // configure navcam based on main renderer's camera
  214. vtkRenderer *navren = q->renderer();
  215. vtkCamera *navcam = q->activeCamera();
  216. if ( navcam == 0 )
  217. {
  218. return;
  219. }
  220. // give navcam the same parameters as MainViewer's ActiveCamera
  221. navcam->SetPosition ( camPos );
  222. navcam->SetFocalPoint ( focalPoint );
  223. navcam->SetViewUp( cam->GetViewUp() );
  224. navcam->ComputeViewPlaneNormal ( );
  225. // compute FOVBox height & width to correspond
  226. // to the main viewer's size and aspect ratio, in world-coordinates,
  227. // positioned just behind the near clipping plane, to make sure
  228. // nothing in the scene occludes it.
  229. double boxHalfHit;
  230. if ( cam->GetParallelProjection() )
  231. {
  232. boxHalfHit = cam->GetParallelScale();
  233. }
  234. else
  235. {
  236. boxHalfHit = (camDist) * tan ( thetaV * DEGREES2RADIANS);
  237. }
  238. // 3D MainViewer height and width for computing aspect
  239. int mainViewerWid = ren->GetRenderWindow()->GetSize()[0];
  240. int mainViewerHit = ren->GetRenderWindow()->GetSize()[1];
  241. // width of the FOVBox that represents MainViewer window.
  242. double boxHalfWid = boxHalfHit * static_cast<double>(mainViewerWid)
  243. / static_cast<double>(mainViewerHit);
  244. // configure and position the FOVBox
  245. double data [24];
  246. data[0] = -1.0;
  247. data[1] = -1.0;
  248. data[2] = 0.0;
  249. data[3] = 1.0;
  250. data[4] = -1.0;
  251. data[5] = 0.0;
  252. data[6] = -1.0;
  253. data[7] = 1.0;
  254. data[8] = 0.0;
  255. data[9] = 1.0;
  256. data[10] = 1.0;
  257. data[11] = 0.0;
  258. data[12] = -1.0;
  259. data[13] = -1.0;
  260. data[14] = 0.0;
  261. data[15] = 1.0;
  262. data[16] = -1.0;
  263. data[17] = 0.0;
  264. data[18] = -1.0;
  265. data[19] = 1.0;
  266. data[20] = 0.0;
  267. data[21] = 1.0;
  268. data[22] = 1.0;
  269. data[23] = 0.0;
  270. this->FOVBox->SetCorners ( data );
  271. // Position and scale FOVBox very close to camera,
  272. // to prevent things in the scene from occluding it.
  273. this->FOVBoxActor->SetScale ( boxHalfWid, boxHalfHit, 1.0);
  274. this->FOVBoxActor->SetPosition (focalPoint[0]+ (vpn[0]*boxDist),
  275. focalPoint[1] + (vpn[1]*boxDist),
  276. focalPoint[2] + (vpn[2]*boxDist));
  277. this->resetCamera();
  278. // put the focal point back into the center of
  279. // the scene without the FOVBox included,
  280. // since ResetNavigationCamera moved it.
  281. navcam->SetFocalPoint ( focalPoint );
  282. navren->ResetCameraClippingRange();
  283. navren->UpdateLightsGeometryToFollowCamera();
  284. }
  285. // ----------------------------------------------------------------------------
  286. void ctkVTKThumbnailViewPrivate::resetCamera()
  287. {
  288. Q_Q(ctkVTKThumbnailView);
  289. vtkRenderer *ren = q->renderer();
  290. vtkCamera *cam = q->activeCamera();
  291. if (!ren || !cam)
  292. {
  293. logger.error("Trying to reset non-existant camera");
  294. return;
  295. }
  296. double bounds[6];
  297. ren->ComputeVisiblePropBounds( bounds );
  298. if (!vtkMath::AreBoundsInitialized(bounds))
  299. {
  300. logger.error("Cannot reset camera!");
  301. return;
  302. }
  303. ren->InvokeEvent(vtkCommand::ResetCameraEvent, ren);
  304. double vn[3];
  305. cam->GetViewPlaneNormal(vn);
  306. double center[3];
  307. center[0] = (bounds[0] + bounds[1])/2.0;
  308. center[1] = (bounds[2] + bounds[3])/2.0;
  309. center[2] = (bounds[4] + bounds[5])/2.0;
  310. double w1 = bounds[1] - bounds[0];
  311. double w2 = bounds[3] - bounds[2];
  312. double w3 = bounds[5] - bounds[4];
  313. w1 *= w1;
  314. w2 *= w2;
  315. w3 *= w3;
  316. double radius = w1 + w2 + w3;
  317. // If we have just a single point, pick a radius of 1.0
  318. radius = (radius==0)?(1.0):(radius);
  319. // compute the radius of the enclosing sphere
  320. radius = sqrt(radius)*0.5;
  321. // default so that the bounding sphere fits within the view fustrum
  322. // compute the distance from the intersection of the view frustum with the
  323. // bounding sphere. Basically in 2D draw a circle representing the bounding
  324. // sphere in 2D then draw a horizontal line going out from the center of
  325. // the circle. That is the camera view. Then draw a line from the camera
  326. // position to the point where it intersects the circle. (it will be tangent
  327. // to the circle at this point, this is important, only go to the tangent
  328. // point, do not draw all the way to the view plane). Then draw the radius
  329. // from the tangent point to the center of the circle. You will note that
  330. // this forms a right triangle with one side being the radius, another being
  331. // the target distance for the camera, then just find the target dist using
  332. // a sin.
  333. double viewAngle = 20.0;
  334. double distance = radius/sin(viewAngle*vtkMath::Pi()/360.0);
  335. // check view-up vector against view plane normal
  336. double* vup = cam->GetViewUp();
  337. if ( fabs(vtkMath::Dot(vup,vn)) > 0.999 )
  338. {
  339. logger.warn("Resetting view-up since view plane normal is parallel");
  340. cam->SetViewUp(-vup[2], vup[0], vup[1]);
  341. }
  342. // update the camera
  343. cam->SetFocalPoint(center[0],center[1],center[2]);
  344. cam->SetPosition(center[0]+distance*vn[0],
  345. center[1]+distance*vn[1],
  346. center[2]+distance*vn[2]);
  347. ren->ResetCameraClippingRange( bounds );
  348. // setup default parallel scale
  349. cam->SetParallelScale(radius);
  350. }
  351. // --------------------------------------------------------------------------
  352. // ctkVTKThumbnailView methods
  353. // --------------------------------------------------------------------------
  354. ctkVTKThumbnailView::ctkVTKThumbnailView(QWidget* _parent) : Superclass(_parent)
  355. , d_ptr(new ctkVTKThumbnailViewPrivate(*this))
  356. {
  357. Q_D(ctkVTKThumbnailView);
  358. d->init();
  359. // Hide orientation widget
  360. this->setOrientationWidgetVisible(false);
  361. }
  362. // --------------------------------------------------------------------------
  363. ctkVTKThumbnailView::~ctkVTKThumbnailView()
  364. {
  365. }
  366. //------------------------------------------------------------------------------
  367. void ctkVTKThumbnailView::setRendererToListen(vtkRenderer* newRenderer)
  368. {
  369. Q_D(ctkVTKThumbnailView);
  370. d->Renderer = newRenderer;
  371. vtkRenderWindow* newRenderWindow = newRenderer ? newRenderer->GetRenderWindow() : 0;
  372. vtkRenderWindowInteractor* newInteractor = newRenderWindow ? newRenderWindow->GetInteractor() : 0;
  373. this->qvtkReconnect(d->Interactor, newInteractor,
  374. vtkCommand::EndInteractionEvent, this,SLOT(updateCamera()));
  375. d->Interactor = newInteractor;
  376. d->initCamera();
  377. d->updateBounds();
  378. d->updateCamera();
  379. }
  380. //---------------------------------------------------------------------------
  381. void ctkVTKThumbnailView::checkAbort()
  382. {
  383. if (this->renderWindow()->GetEventPending())
  384. {
  385. this->renderWindow()->SetAbortRender(1);
  386. }
  387. }
  388. //---------------------------------------------------------------------------
  389. void ctkVTKThumbnailView::updateCamera()
  390. {
  391. Q_D(ctkVTKThumbnailView);
  392. d->updateCamera();
  393. this->scheduleRender();
  394. }
  395. //---------------------------------------------------------------------------
  396. void ctkVTKThumbnailView::updateBounds()
  397. {
  398. Q_D(ctkVTKThumbnailView);
  399. d->updateBounds();
  400. this->scheduleRender();
  401. }