UsTK : Ultrasound ToolKit  version 2.0.1 under development (2023-12-07)
us3DSceneWidget.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ustk software.
4  * Copyright (C) 2016 - 2017 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * ("GPL") version 2 as published by the Free Software Foundation.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ustk with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * This software was developed at:
17  * Inria Rennes - Bretagne Atlantique
18  * Campus Universitaire de Beaulieu
19  * 35042 Rennes Cedex
20  * France
21  *
22  * If you have questions regarding the use of this file, please contact
23  * Inria at ustk@inria.fr
24  *
25  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27  *
28  * Authors:
29  * Marc Pouliquen
30  *
31  *****************************************************************************/
32 
37 #include <visp3/core/vpException.h>
38 #include <visp3/core/vpRotationMatrix.h>
39 #include <visp3/ustk_gui/us3DSceneWidget.h>
40 
41 #ifdef USTK_HAVE_VTK_QT
42 
43 #include <visp3/ustk_gui/usVTKConverter.h>
44 
45 // VTK includes
46 #include <vtkArrowSource.h>
47 #include <vtkCellArray.h>
48 #include <vtkCylinderSource.h>
49 #include <vtkDistanceWidget.h>
50 #include <vtkImagePlaneWidget.h>
51 #include <vtkImageResliceMapper.h>
52 #include <vtkInteractorStyleTrackballCamera.h>
53 #include <vtkMatrix4x4.h>
54 #include <vtkPointData.h>
55 #include <vtkPolyLine.h>
56 #include <vtkProperty.h>
57 #include <vtkRenderWindowInteractor.h>
58 #include <vtkResliceImageViewer.h>
59 #include <vtkResliceImageViewerMeasurements.h>
60 #include <vtkSTLReader.h>
61 #include <vtkSTLWriter.h>
62 #include <vtkSmartPointer.h>
63 #include <vtkSphereSource.h>
64 
65 #include <QPaintEngine>
66 #include <QPainter>
67 
71 us3DSceneWidget::us3DSceneWidget(QWidget *parent, Qt::WindowFlags f) : usViewerWidget(parent, f)
72 {
73  imageResliceMapper1 = vtkImageResliceMapper::New();
74  imageResliceMapper2 = vtkImageResliceMapper::New();
75  imageResliceMapper3 = vtkImageResliceMapper::New();
76 
77  plane1 = NULL;
78  plane2 = NULL;
79  plane3 = NULL;
80 
81  imageSlice1 = vtkImageSlice::New();
82  imageSlice2 = vtkImageSlice::New();
83  imageSlice3 = vtkImageSlice::New();
84 
85  renderer = vtkRenderer::New();
86 }
87 
92 void us3DSceneWidget::paintEvent(QPaintEvent *event) { usViewerWidget::paintEvent(event); }
93 
98 vtkImageData *us3DSceneWidget::getImageData() { return this->imageData; }
99 
104 {
105  if (this->imageData == NULL)
106  throw(vpException(vpException::fatalError, "no vtk image provided"));
107 
108  // show the widget
109  imageResliceMapper1->SetInputData(this->imageData);
110  imageResliceMapper2->SetInputData(this->imageData);
111  imageResliceMapper3->SetInputData(this->imageData);
112 
113  this->imageData->SetOrigin(0, 0, 0);
114 
115  if (plane1 == NULL || plane2 == NULL || plane3 == NULL)
116  throw(vpException(vpException::fatalError, "no vtk planes provided"));
117 
118  // select plane
119  imageResliceMapper1->SetSlicePlane(plane1);
120  imageResliceMapper2->SetSlicePlane(plane2);
121  imageResliceMapper3->SetSlicePlane(plane3);
122 
123  imageSlice1->SetMapper(imageResliceMapper1);
124  imageSlice2->SetMapper(imageResliceMapper2);
125  imageSlice3->SetMapper(imageResliceMapper3);
126 
127  // Define image bounding box
128  double bounds[6];
129  imageData->GetBounds(bounds);
130  // Create a cube.
131  imageBoundsCube = vtkSmartPointer<vtkCubeSource>::New();
132  imageBoundsCube->SetBounds(bounds);
133 
134  // find intersections between planes and bounding box to draw colored lines to identify each plane
135  // Plane border 1
136  cutter1 = vtkSmartPointer<vtkCutter>::New();
137  cutter1->SetCutFunction(plane1);
138  cutter1->SetInputConnection(imageBoundsCube->GetOutputPort());
139  cutter1->Update();
140  vtkSmartPointer<vtkPolyDataMapper> cutterMapper1 = vtkSmartPointer<vtkPolyDataMapper>::New();
141  cutterMapper1->SetInputConnection(cutter1->GetOutputPort());
142  vtkSmartPointer<vtkActor> planeBorder1 = vtkSmartPointer<vtkActor>::New();
143  planeBorder1->GetProperty()->SetColor(1.0, 0, 0);
144  planeBorder1->GetProperty()->SetOpacity(1.0);
145  planeBorder1->GetProperty()->SetLighting(0);
146  planeBorder1->GetProperty()->SetLineWidth(1);
147  planeBorder1->SetMapper(cutterMapper1);
148 
149  // Plane border 2
150  cutter2 = vtkSmartPointer<vtkCutter>::New();
151  cutter2->SetCutFunction(plane2);
152  cutter2->SetInputConnection(imageBoundsCube->GetOutputPort());
153  cutter2->Update();
154  vtkSmartPointer<vtkPolyDataMapper> cutterMapper2 = vtkSmartPointer<vtkPolyDataMapper>::New();
155  cutterMapper2->SetInputConnection(cutter2->GetOutputPort());
156  vtkSmartPointer<vtkActor> planeBorder2 = vtkSmartPointer<vtkActor>::New();
157  planeBorder2->GetProperty()->SetColor(0, 1.0, 0);
158  planeBorder2->GetProperty()->SetOpacity(1.0);
159  planeBorder2->GetProperty()->SetLighting(0);
160  planeBorder2->GetProperty()->SetLineWidth(1);
161  planeBorder2->SetMapper(cutterMapper2);
162 
163  // Plane border 3
164  cutter3 = vtkSmartPointer<vtkCutter>::New();
165  cutter3->SetCutFunction(plane3);
166  cutter3->SetInputConnection(imageBoundsCube->GetOutputPort());
167  cutter3->Update();
168  vtkSmartPointer<vtkPolyDataMapper> cutterMapper3 = vtkSmartPointer<vtkPolyDataMapper>::New();
169  cutterMapper3->SetInputConnection(cutter3->GetOutputPort());
170  vtkSmartPointer<vtkActor> planeBorder3 = vtkSmartPointer<vtkActor>::New();
171  planeBorder3->GetProperty()->SetColor(0, 0, 1.0);
172  planeBorder3->GetProperty()->SetOpacity(1.0);
173  planeBorder3->GetProperty()->SetLighting(0);
174  planeBorder3->GetProperty()->SetLineWidth(1);
175  planeBorder3->SetMapper(cutterMapper3);
176 
177  // add axes in scene
178  m_axesActor = vtkSmartPointer<vtkAxesActor>::New();
179 
180  // arrows of 1cm
181  m_axesActor->SetXAxisLabelText("U");
182  m_axesActor->SetYAxisLabelText("V");
183  m_axesActor->SetZAxisLabelText("W");
184  m_axesActor->SetTotalLength(0.01, 0.01, 0.01);
185 
186  // Create a cylinder (polydata)
187  vtkSmartPointer<vtkCylinderSource> cylinderSource = vtkSmartPointer<vtkCylinderSource>::New();
188  cylinderSource->SetCenter(plane1->GetOrigin());
189  cylinderSource->SetRadius(0.005);
190  cylinderSource->SetHeight(0.01);
191  cylinderSource->SetResolution(100);
192  cylinderSource->Update();
193  meshPolyData = cylinderSource->GetOutput();
194 
195  // Create a mapper and actor for the polydata
196  vtkSmartPointer<vtkPolyDataMapper> meshMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
197  meshMapper->SetInputConnection(cylinderSource->GetOutputPort());
198  meshMapper->Update();
199  vtkSmartPointer<vtkActor> meshActor = vtkSmartPointer<vtkActor>::New();
200  meshActor->GetProperty()->SetColor(1.0, 1.0, 0);
201  meshActor->SetMapper(meshMapper);
202 
203  // polydata intersections with each reslice plane
204  cutterPolyDataPlane1 = vtkSmartPointer<vtkCutter>::New();
205  cutterPolyDataPlane1->SetCutFunction(plane1);
206  cutterPolyDataPlane1->SetInputConnection(cylinderSource->GetOutputPort());
207  cutterPolyDataPlane1->Update();
208 
209  vtkSmartPointer<vtkPolyDataMapper> cutterMeshMapper1 = vtkSmartPointer<vtkPolyDataMapper>::New();
210  cutterMeshMapper1->SetInputConnection(cutterPolyDataPlane1->GetOutputPort());
211  vtkSmartPointer<vtkActor> meshBorder1 = vtkSmartPointer<vtkActor>::New();
212  meshBorder1->GetProperty()->SetColor(1.0, 1.0, 0);
213  meshBorder1->GetProperty()->SetOpacity(1.0);
214  meshBorder1->GetProperty()->SetLighting(0);
215  meshBorder1->GetProperty()->SetLineWidth(1);
216  meshBorder1->SetMapper(cutterMeshMapper1);
217 
218  cutterPolyDataPlane2 = vtkSmartPointer<vtkCutter>::New();
219  cutterPolyDataPlane2->SetCutFunction(plane2);
220  cutterPolyDataPlane2->SetInputConnection(cylinderSource->GetOutputPort());
221  cutterPolyDataPlane2->Update();
222 
223  vtkSmartPointer<vtkPolyDataMapper> cutterMeshMapper2 = vtkSmartPointer<vtkPolyDataMapper>::New();
224  cutterMeshMapper2->SetInputConnection(cutterPolyDataPlane2->GetOutputPort());
225  vtkSmartPointer<vtkActor> meshBorder2 = vtkSmartPointer<vtkActor>::New();
226  meshBorder2->GetProperty()->SetColor(1.0, 1.0, 0);
227  meshBorder2->GetProperty()->SetOpacity(1.0);
228  meshBorder2->GetProperty()->SetLighting(0);
229  meshBorder2->GetProperty()->SetLineWidth(1);
230  meshBorder2->SetMapper(cutterMeshMapper2);
231 
232  cutterPolyDataPlane3 = vtkSmartPointer<vtkCutter>::New();
233  cutterPolyDataPlane3->SetCutFunction(plane3);
234  cutterPolyDataPlane3->SetInputConnection(cylinderSource->GetOutputPort());
235  cutterPolyDataPlane3->Update();
236 
237  vtkSmartPointer<vtkPolyDataMapper> cutterMeshMapper3 = vtkSmartPointer<vtkPolyDataMapper>::New();
238  cutterMeshMapper3->SetInputConnection(cutterPolyDataPlane3->GetOutputPort());
239  vtkSmartPointer<vtkActor> meshBorder3 = vtkSmartPointer<vtkActor>::New();
240  meshBorder3->GetProperty()->SetColor(1.0, 1.0, 0);
241  meshBorder3->GetProperty()->SetOpacity(1.0);
242  meshBorder3->GetProperty()->SetLighting(0);
243  meshBorder3->GetProperty()->SetLineWidth(1);
244  meshBorder3->SetMapper(cutterMeshMapper3);
245 
246  // Setup renderer
247  renderer = vtkRenderer::New();
248  renderer->AddActor(m_axesActor);
249  renderer->AddActor(imageSlice1);
250  renderer->AddActor(imageSlice2);
251  renderer->AddActor(imageSlice3);
252  renderer->AddActor(planeBorder1);
253  renderer->AddActor(planeBorder2);
254  renderer->AddActor(planeBorder3);
255  renderer->AddActor(meshActor);
256  renderer->AddActor(meshBorder1);
257  renderer->AddActor(meshBorder2);
258  renderer->AddActor(meshBorder3);
259  renderer->SetBackground(0.5, 0.5, 0.5);
260  renderer->ResetCamera();
261 
262  // Setup render window
263 #if USTK_HAVE_VTK_VERSION < 0x090000
264  vtkRenderWindow *renderWindow = this->GetRenderWindow();
265 #else
266  vtkRenderWindow *renderWindow = this->renderWindow();
267 #endif
268  renderWindow->AddRenderer(renderer);
269 
270  // Interaction style with the 3D image
271  vtkInteractorStyleTrackballCamera *style = vtkInteractorStyleTrackballCamera::New();
272 
273  renderWindow->GetInteractor()->SetInteractorStyle(style);
274 }
275 
280 void us3DSceneWidget::setImageData(vtkImageData *imageData)
281 {
282  this->imageData = imageData;
283 
284  this->imageData->Modified();
285 
286  imageResliceMapper1->SetInputData(imageData);
287  imageResliceMapper2->SetInputData(imageData);
288  imageResliceMapper3->SetInputData(imageData);
289 
290  // renderer->Render();
291 #if USTK_HAVE_VTK_VERSION < 0x090000
292  this->GetRenderWindow()->Render();
293 #else
294  this->renderWindow()->Render();
295 #endif
296 }
297 
302 void us3DSceneWidget::setPlane1(vtkPlane *plane) { this->plane1 = plane; }
303 
308 void us3DSceneWidget::setPlane2(vtkPlane *plane) { this->plane2 = plane; }
309 
314 void us3DSceneWidget::setPlane3(vtkPlane *plane) { this->plane3 = plane; }
319 vtkPlane *us3DSceneWidget::getPlane1() { return this->plane1; }
320 
325 vtkPlane *us3DSceneWidget::getPlane2() { return this->plane2; }
326 
331 vtkPlane *us3DSceneWidget::getPlane3() { return this->plane3; }
332 
337 vtkPolyData *us3DSceneWidget::getContour1() { return this->cutter1->GetOutput(); }
338 
343 vtkPolyData *us3DSceneWidget::getContour2() { return this->cutter2->GetOutput(); }
344 
349 vtkPolyData *us3DSceneWidget::getContour3() { return this->cutter3->GetOutput(); }
350 
355 vtkPolyData *us3DSceneWidget::getMeshInPlane1() { return this->cutterPolyDataPlane1->GetOutput(); }
356 
361 vtkPolyData *us3DSceneWidget::getMeshInPlane2() { return this->cutterPolyDataPlane2->GetOutput(); }
362 
367 vtkPolyData *us3DSceneWidget::getMeshInPlane3() { return this->cutterPolyDataPlane3->GetOutput(); }
368 
375 void us3DSceneWidget::setPlanes(vtkPlane *plane1, vtkPlane *plane2, vtkPlane *plane3)
376 {
377  this->plane1 = plane1;
378  this->plane2 = plane2;
379  this->plane3 = plane3;
380 }
381 
386 void us3DSceneWidget::updateImageData(vtkImageData *imageData)
387 {
388  // removing all actors taking the old image data as input to avoir render errors
389  renderer->RemoveActor(imageSlice1);
390  renderer->RemoveActor(imageSlice2);
391  renderer->RemoveActor(imageSlice3);
392 
393  // update image bounds actors (in case new image size is different from last)
394  imageBoundsCube->SetBounds(imageData->GetBounds());
395 
396  // updating imageData everywhere
397  this->imageData = imageData;
398  imageResliceMapper1->SetInputData(imageData);
399  imageResliceMapper2->SetInputData(imageData);
400  imageResliceMapper3->SetInputData(imageData);
401 
402  // adding back actors re-computed in the view
403  renderer->AddActor(imageSlice1);
404  renderer->AddActor(imageSlice2);
405  renderer->AddActor(imageSlice3);
406 
407 #if USTK_HAVE_VTK_VERSION < 0x090000
408  GetRenderWindow()->Render();
409 #else
410  renderWindow()->Render();
411 #endif
412 }
413 
418 void us3DSceneWidget::updateMatrix1(vtkMatrix4x4 *matrix)
419 {
420 
421  if (plane1 == NULL) {
422  plane1 = vtkPlane::New();
423  // rotation (valid only for init at X normal)
424  plane1->SetNormal(1, 0, 0);
425  }
426  // Translation
427  double origin[3];
428  origin[0] = matrix->Element[0][3];
429  origin[1] = matrix->Element[1][3];
430  origin[2] = matrix->Element[2][3];
431  plane1->SetOrigin(origin);
432 
433  // Rotation
434  vpRotationMatrix rMat;
435  vpHomogeneousMatrix hMat;
436  usVTKConverter::convert(matrix, hMat);
437  hMat.extract(rMat);
438 
439  vpColVector normal(3);
440  normal.data[0] = 0;
441  normal.data[1] = 0;
442  normal.data[2] = 1;
443 
444  normal = rMat * normal;
445 
446  plane1->SetNormal(normal.data[0], normal.data[1], normal.data[2]);
447 
448  this->update();
449  emit(plane1Changed());
450 }
451 
456 void us3DSceneWidget::updateMatrix2(vtkMatrix4x4 *matrix)
457 {
458 
459  if (plane2 == NULL) {
460  plane2 = vtkPlane::New();
461  // rotation (valid only for init at Y normal)
462  plane2->SetNormal(0, 1, 0);
463  }
464  // Translation
465  double origin[3];
466  origin[0] = matrix->Element[0][3];
467  origin[1] = matrix->Element[1][3];
468  origin[2] = matrix->Element[2][3];
469  plane2->SetOrigin(origin);
470 
471  // Rotation
472  vpRotationMatrix rMat;
473  vpHomogeneousMatrix hMat;
474  usVTKConverter::convert(matrix, hMat);
475  hMat.extract(rMat);
476 
477  vpColVector normal(3);
478  normal.data[0] = 0;
479  normal.data[1] = 0;
480  normal.data[2] = 1;
481 
482  normal = rMat * normal;
483 
484  plane2->SetNormal(normal.data[0], normal.data[1], normal.data[2]);
485 
486  this->update();
487  emit(plane2Changed());
488 }
489 
494 void us3DSceneWidget::updateMatrix3(vtkMatrix4x4 *matrix)
495 {
496 
497  if (plane3 == NULL) {
498  plane3 = vtkPlane::New();
499  // rotation (valid only for init at Z normal)
500  plane3->SetNormal(0, 0, 1);
501  }
502 
503  // Translation
504  double origin[3];
505  origin[0] = matrix->Element[0][3];
506  origin[1] = matrix->Element[1][3];
507  origin[2] = matrix->Element[2][3];
508  plane3->SetOrigin(origin);
509 
510  // Rotation
511  vpRotationMatrix rMat;
512  vpHomogeneousMatrix hMat;
513  usVTKConverter::convert(matrix, hMat);
514  hMat.extract(rMat);
515 
516  vpColVector normal(3);
517  normal.data[0] = 0;
518  normal.data[1] = 0;
519  normal.data[2] = 1;
520 
521  normal = rMat * normal;
522 
523  plane3->SetNormal(normal.data[0], normal.data[1], normal.data[2]);
524 
525  this->update();
526  emit(plane3Changed());
527 }
528 #endif
vtkPlane * getPlane1()
void updateImageData(vtkImageData *imageData)
vtkPolyData * getMeshInPlane2()
vtkPlane * getPlane3()
us3DSceneWidget(QWidget *parent=NULL, Qt::WindowFlags f=Qt::WindowFlags())
void updateMatrix2(vtkMatrix4x4 *matrix)
void paintEvent(QPaintEvent *event)
vtkPolyData * getContour3()
void setPlanes(vtkPlane *plane1, vtkPlane *plane2, vtkPlane *plane3)
void plane2Changed()
void setPlane2(vtkPlane *plane)
void plane3Changed()
vtkPolyData * getMeshInPlane3()
void updateMatrix3(vtkMatrix4x4 *matrix)
vtkPlane * getPlane2()
void plane1Changed()
vtkPolyData * getContour2()
void setImageData(vtkImageData *imageData)
vtkPolyData * getContour1()
void setPlane1(vtkPlane *plane)
vtkPolyData * getMeshInPlane1()
void setPlane3(vtkPlane *plane)
vtkImageData * getImageData()
void updateMatrix1(vtkMatrix4x4 *matrix)
static void convert(const usImagePostScan3D< unsigned char > &postScanImage, vtkSmartPointer< vtkImageData > &vtkPostScanImage, vtkSmartPointer< vtkImageImport > importer=NULL)
View used to render a vtk scene in a QWidget (based on QVTKWidget for Qt4, QVTKOpenGLWidget for Qt5)
void paintEvent(QPaintEvent *event)