CustusX  2023.01.05-dev+develop.0da12
An IGT application
cxVBWidget.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) SINTEF Department of Medical Technology.
5 All rights reserved.
6 
7 CustusX is released under a BSD 3-Clause license.
8 
9 See Lisence.txt (https://github.com/SINTEFMedtek/CustusX/blob/master/License.txt) for details.
10 =========================================================================*/
11 
12 #include <QLabel>
13 #include <QHBoxLayout>
14 #include <QVBoxLayout>
15 #include <QGroupBox>
16 #include <QSlider>
17 #include <QSpinBox>
18 #include <QGridLayout>
19 #include <QLabel>
20 #include <QDial>
21 #include <QPushButton>
22 #include <QTimer>
23 
24 #include "cxVBWidget.h"
26 #include "cxViewServiceProxy.h"
27 #include "cxDataSelectWidget.h"
28 #include "cxTrackingServiceProxy.h"
29 #include "cxView.h"
31 #include "cxPatientStorage.h"
32 #include "cxVisServices.h"
33 #include "cxLogger.h"
34 #include "cxRouteToTarget.h"
35 #include "cxVLCRecorder.h"
36 
37 
38 
39 namespace cx
40 {
41 
42 VBWidget::VBWidget(VisServicesPtr services, QWidget *parent) :
43  QWidget(parent),
44  mServices(services),
45  mVerticalLayout(new QVBoxLayout(this)),
46  mControlsEnabled(false),
47  mAutomaticRotation(true),
48  mRecordVideo(false),
49  mStorage(new PatientStorage(services->session(), "VirtualBronchoscopy"))
50 {
51  this->setObjectName("virtual_bronchoscopy_widget");
52  this->setWindowTitle("Virtual Bronchoscopy");
53  this->setWhatsThis(this->defaultWhatsThis());
54 
55  this->setFocusPolicy(Qt::StrongFocus); // Widget needs focus to handle Key events
56 
57  mRouteToTarget = StringPropertySelectMesh::New(services->patient());
58  mRouteToTarget->setValueName("Route to target path: ");
59  mStorage->storeVariable("routeToTarget",
62 
63  // Selector for route to target
64  QVBoxLayout *inputVbox = new QVBoxLayout;
65  inputVbox->addWidget(new DataSelectWidget(services->view(), services->patient(), this,mRouteToTarget));
66  QGroupBox *inputBox = new QGroupBox(tr("Input"));
67  inputBox->setLayout(inputVbox);
68  mVerticalLayout->addWidget(inputBox);
69 
70  // play/pause button
71  mPlayButton = new QPushButton(QIcon(":/icons/open_icon_library/media-playback-start-3.png"),"");
72  mTimer = new QTimer;
73  connect(mTimer, SIGNAL(timeout()), this, SLOT(moveCameraSlot()));
74  mTimer->setInterval(20); // slot processing time is about 30 ms, thus about 50 ms in total.
75 
76  // Selectors for position along path and play/pause
77  QHBoxLayout *playbackHBox = new QHBoxLayout;
78  QGroupBox *playbackBox = new QGroupBox(tr("Playback"));
79  mPlaybackSlider = new QSlider(Qt::Horizontal);
80  QLabel *labelStart = new QLabel(tr("Start "));
81  QLabel *labelTarget = new QLabel(tr(" Target"));
82  playbackHBox->addWidget(mPlayButton);
83  playbackHBox->addWidget(labelStart);
84  playbackHBox->addWidget(mPlaybackSlider);
85  playbackHBox->addWidget(labelTarget);
86  playbackBox->setLayout(playbackHBox);
87  mVerticalLayout->addWidget(playbackBox);
88  mPlaybackSlider->setMinimum(0);
89  mPlaybackSlider->setMaximum(1000);
90 
91  // Selectors for virtual endoscope control
92  QGroupBox *endoscopeBox = new QGroupBox(tr("Bronchoscope"));
93  QGridLayout *endoscopeControlLayout = new QGridLayout;
94  QLabel *labelRot = new QLabel(tr("Rotate (360 deg)"));
95  QLabel *labelView = new QLabel(tr("Left/right (+/- 60 deg)"));
96  mRotateDial = new QDial;
97  mRotateDial->setMinimum(-180);
98  mRotateDial->setMaximum(180);
99  mViewDial = new QDial;
100  mViewDial->setMinimum(-60);
101  mViewDial->setMaximum(60);
102  mResetEndoscopeButton = new QPushButton("Reset");
103  mUseAutomaticRotationButton = new QPushButton("Automatic rotation");
105  mAutomaticRotationButtonBackgroundColor.setColor(QPalette::Button, Qt::green);
107 
108  endoscopeControlLayout->addWidget(labelRot,0,0,Qt::AlignHCenter);
109  endoscopeControlLayout->addWidget(labelView,0,2,Qt::AlignHCenter);
110  endoscopeControlLayout->addWidget(mRotateDial,1,0);
111  endoscopeControlLayout->addWidget(mViewDial,1,2);
112  endoscopeControlLayout->addWidget(mResetEndoscopeButton,2,0);
113  endoscopeControlLayout->addWidget(mUseAutomaticRotationButton,3,0);
114  endoscopeBox->setLayout(endoscopeControlLayout);
115  mVerticalLayout->addWidget(endoscopeBox);
116 
117  this->setLayout(mVerticalLayout);
118 
119 
120  this->enableControls(false);
121 
122  mCameraPath = new CXVBcameraPath(services->tracking(), services->patient(), services->view());
123 
125  this, &VBWidget::inputChangedSlot, Qt::UniqueConnection);
127  connect(mPlaybackSlider, &QSlider::valueChanged, mCameraPath, &CXVBcameraPath::cameraPathPositionSlot);
128  connect(mPlayButton, &QPushButton::clicked, this, &VBWidget::playButtonClickedSlot);
129  connect(mViewDial, &QSlider::valueChanged, mCameraPath, &CXVBcameraPath::cameraViewAngleSlot);
130  connect(mRotateDial, &QDial::valueChanged, mCameraPath, &CXVBcameraPath::cameraRotateAngleSlot);
131  connect(mResetEndoscopeButton, &QPushButton::clicked, this, &VBWidget::resetEndoscopeSlot);
132  connect(mUseAutomaticRotationButton, &QPushButton::clicked, this, &VBWidget::automaticRotationSlot);
133  connect(mCameraPath, &CXVBcameraPath::rotationChanged, this, &VBWidget::updateRotationDialSlot);
134 
135  mVerticalLayout->addStretch();
136 }
137 
139 {
140  delete mTimer;
141 }
142 
143 void VBWidget::setRouteToTarget(QString uid)
144 {
145  disconnect(mRouteToTarget.get(), &SelectDataStringPropertyBase::dataChanged, this, &VBWidget::inputChangedSlot);
146  mRouteToTarget->setValue("");
147  connect(mRouteToTarget.get(), &SelectDataStringPropertyBase::dataChanged, this, &VBWidget::inputChangedSlot, Qt::UniqueConnection);
148  mRouteToTarget->setValue(uid);
149 
150  disconnect(mPlaybackSlider, &QSlider::valueChanged, mCameraPath, &CXVBcameraPath::cameraPathPositionSlot);
151  mPlaybackSlider->setValue(1);
152  connect(mPlaybackSlider, &QSlider::valueChanged, mCameraPath, &CXVBcameraPath::cameraPathPositionSlot, Qt::UniqueConnection);
153  mPlaybackSlider->setValue(5);
154 }
155 
156 void VBWidget::setRoutePositions(std::vector< Eigen::Vector3d > routePositions)
157 {
158  mCameraPath->setRoutePositions(routePositions);
159 }
160 
161 void VBWidget::setCameraRotationAlongRoute(std::vector< double > cameraRotations)
162 {
163  mCameraPath->setCameraRotations(cameraRotations);
164 }
165 
166 void VBWidget::setBranchingIndexAlongRoute(std::vector< int > branchingIndex)
167 {
168  mCameraPath->setBranchingIndexAlongRoute(branchingIndex);
169 }
170 
171 void VBWidget::setRecordVideoOption(bool recordVideo)
172 {
173  mRecordVideo = recordVideo;
174 }
175 
177 {
178  QFileInfo fileInfo;
179  fileInfo.setFile(mServices->patient()->generateFilePath("Screenshots", "mp4"));
180  if(!vlc()->isRecording())
181  vlc()->startRecording(fileInfo.absoluteFilePath());
182  return fileInfo;
183 }
184 
186 {
187  if(vlc()->isRecording())
188  vlc()->stopRecording();
189  vlc()->waitForFinished();
190 }
191 
192 void VBWidget::enableControls(bool enable)
193 {
194  mPlaybackSlider->setEnabled(enable);
195  mRotateDial->setEnabled(enable);
196  mViewDial->setEnabled(enable);
197  mControlsEnabled = enable;
198 }
199 
200 void VBWidget::inputChangedSlot()
201 {
202  this->enableControls(true);
203  emit cameraPathChanged(mRouteToTarget->getMesh());
204 }
205 
206 void VBWidget::keyPressEvent(QKeyEvent* event)
207 {
208  if (event->key()==Qt::Key_Up || event->key()==Qt::Key_8)
209  {
210  if(mControlsEnabled) {
211  int currentPos = mPlaybackSlider->value();
212  mPlaybackSlider->setValue(currentPos+1);
213  return;
214  }
215  }
216 
217  if (event->key()==Qt::Key_Down || event->key()==Qt::Key_2)
218  {
219  if(mControlsEnabled) {
220  int currentPos = mPlaybackSlider->value();
221  mPlaybackSlider->setValue(currentPos-1);
222  return;
223  }
224  }
225 
226  if (event->key()==Qt::Key_Right || event->key()==Qt::Key_6)
227  {
228  if(mControlsEnabled) {
229  int currentPos = mViewDial->value();
230  mViewDial->setValue(currentPos+1);
231  return;
232  }
233  }
234 
235  if (event->key()==Qt::Key_Left || event->key()==Qt::Key_4)
236  {
237  if(mControlsEnabled) {
238  int currentPos = mViewDial->value();
239  mViewDial->setValue(currentPos-1);
240  return;
241  }
242  }
243 
244  if (event->key()==Qt::Key_PageUp || event->key()==Qt::Key_9)
245  {
246  if(mControlsEnabled) {
247  int currentPos = mRotateDial->value();
248  mRotateDial->setValue(currentPos+1);
249  return;
250  }
251  }
252 
253  if (event->key()==Qt::Key_PageDown || event->key()==Qt::Key_3)
254  {
255  if(mControlsEnabled) {
256  int currentPos = mRotateDial->value();
257  mRotateDial->setValue(currentPos-1);
258  return;
259  }
260  }
261 
262  if (event->key()==Qt::Key_5)
263  {
264  if(mControlsEnabled) {
265  this->resetEndoscopeSlot();
266  return;
267  }
268  }
269 
270  // Forward the keyPressevent if not processed
271  QWidget::keyPressEvent(event);
272 }
273 
275 {
276  if(mTimer->isActive())
277  {
278  mTimer->stop();
279  if(mRecordVideo)
280  {
281  this->stopRecordFullscreen();
283  }
284  mPlayButton->setIcon(QIcon(":/icons/open_icon_library/media-playback-start-3.png"));
285  }
286  else
287  {
288  mTimer->start();
289  if(mRecordVideo)
290  {
291  QFileInfo fileInfo = this->startRecordFullscreen();
292  mCameraPath->setWritePositionsFilePath(fileInfo.absolutePath() + "/" + fileInfo.baseName());
294  }
295  mPlayButton->setIcon(QIcon(":/icons/open_icon_library/media-playback-pause-3.png"));
296  }
297 }
298 
299 void VBWidget::moveCameraSlot()
300 {
301  int currentPos = mPlaybackSlider->value();
302  if(currentPos >= mPlaybackSlider->maximum())
303  {
304  this->playButtonClickedSlot();
305  emit cameraAtEndPosition();
306  return;
307  }
308  mPlaybackSlider->setValue(currentPos+1);
309 }
310 
311 void VBWidget::resetEndoscopeSlot()
312 {
313  mRotateDial->setValue(0);
314  mViewDial->setValue(0);
315 }
316 
317 void VBWidget::automaticRotationSlot()
318 {
322  {
323  mAutomaticRotationButtonBackgroundColor.setColor(QPalette::Button, Qt::green);
325  }
326  else
327  {
328  mAutomaticRotationButtonBackgroundColor.setColor(QPalette::Button, Qt::gray);
330  }
331 }
332 
333 void VBWidget::updateRotationDialSlot(int value)
334 {
335  mRotateDial->setValue(value);
336 }
337 
339 {
340 return "<html>"
341  "<h3>Virtual Bronchoscopy.</h3>"
342  "<p>GUI for visualizing a route-to-target path</p>"
343  "</html>";
344 }
345 
346 
347 
348 } /* namespace cx */
virtual ~VBWidget()
Definition: cxVBWidget.cpp:138
void setWritePositionsFilePath(QString path)
bool waitForFinished(int msecs=30000)
bool mRecordVideo
Definition: cxVBWidget.h:73
void cameraAtEndPosition()
void rotationChanged(int value)
VisServicesPtr mServices
Definition: cxVBWidget.h:58
void setAutomaticRotation(bool automaticRotation)
void cameraRawPointsSlot(MeshPtr mesh)
void cameraPathPositionSlot(int positionPermillage)
boost::shared_ptr< class VisServices > VisServicesPtr
Definition: cxMainWindow.h:40
Helper class for storing variables in the patient file.
VBWidget(VisServicesPtr services, QWidget *parent=0)
Definition: cxVBWidget.cpp:42
void setCameraRotations(std::vector< double > cameraRotations)
QDial * mViewDial
Definition: cxVBWidget.h:64
QPalette mAutomaticRotationButtonBackgroundColor
Definition: cxVBWidget.h:67
void stopRecordFullscreen()
Definition: cxVBWidget.cpp:185
void startRecording(QString saveFile)
PatientStoragePtr mStorage
Definition: cxVBWidget.h:79
void cameraRotateAngleSlot(int angle)
StringPropertySelectMeshPtr mRouteToTarget
Definition: cxVBWidget.h:69
virtual QString getValue() const
get the data value.
virtual void keyPressEvent(QKeyEvent *event)
Definition: cxVBWidget.cpp:206
QDial * mRotateDial
Definition: cxVBWidget.h:63
void setRecordVideoOption(bool recordVideo)
Definition: cxVBWidget.cpp:171
void setRouteToTarget(QString uid)
Definition: cxVBWidget.cpp:143
bool mControlsEnabled
Definition: cxVBWidget.h:71
QTimer * mTimer
Definition: cxVBWidget.h:62
void setCameraRotationAlongRoute(std::vector< double > cameraRotations)
Definition: cxVBWidget.cpp:161
void setBranchingIndexAlongRoute(std::vector< int > branchingIndex)
QSlider * mPlaybackSlider
Definition: cxVBWidget.h:60
void cameraViewAngleSlot(int angle)
QPushButton * mUseAutomaticRotationButton
Definition: cxVBWidget.h:66
QString defaultWhatsThis() const
Definition: cxVBWidget.cpp:338
QPushButton * mPlayButton
Definition: cxVBWidget.h:61
void setRoutePositions(std::vector< Eigen::Vector3d > routePositions)
QVBoxLayout * mVerticalLayout
Definition: cxVBWidget.h:59
void enableControls(bool enable)
Definition: cxVBWidget.cpp:192
CXVBcameraPath * mCameraPath
Definition: cxVBWidget.h:70
static StringPropertySelectMeshPtr New(PatientModelServicePtr patientModelService)
void setRoutePositions(std::vector< Eigen::Vector3d > routePositions)
Definition: cxVBWidget.cpp:156
QPushButton * mResetEndoscopeButton
Definition: cxVBWidget.h:65
virtual bool setValue(const QString &value)
set the data value.
QFileInfo startRecordFullscreen()
Definition: cxVBWidget.cpp:176
void cameraPathChanged(MeshPtr pathMesh)
void setWritePositionsToFile(bool write)
VLCRecorder * vlc()
Shortcut for accessing the vlc recorder.
bool mAutomaticRotation
Definition: cxVBWidget.h:72
void playButtonClickedSlot()
Definition: cxVBWidget.cpp:274
void setBranchingIndexAlongRoute(std::vector< int > branchingIndex)
Definition: cxVBWidget.cpp:166
Namespace for all CustusX production code.