ctkVTKThumbnailView.cpp 14 KB

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