Medical Imaging Interaction Toolkit  2018.4.99-b585543d
Medical Imaging Interaction Toolkit
QmitkIGTPlayerWidget.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
13 #include "QmitkIGTPlayerWidget.h"
14 
15 //mitk headers
16 #include "mitkTrackingTypes.h"
17 #include <mitkSurface.h>
23 #include <mitkIGTException.h>
24 #include <mitkIOUtil.h>
25 #include <QmitkIGTCommonHelper.h>
26 
27 //qt headers
28 #include <qfiledialog.h>
29 #include <qmessagebox.h>
30 #include <qtimer.h>
31 
32 QmitkIGTPlayerWidget::QmitkIGTPlayerWidget(QWidget* parent, Qt::WindowFlags f)
33  : QWidget(parent, f),
34  m_RealTimePlayer(mitk::NavigationDataPlayer::New()),
35  m_SequentialPlayer(mitk::NavigationDataSequentialPlayer::New()),
36  m_StartTime(-1.0),
37  m_CurrentSequentialPointNumber(0),
38  m_Controls(new Ui::QmitkIGTPlayerWidgetControls)
39 {
40  m_Controls->setupUi(this);
41  m_PlayingTimer = new QTimer(this); // initialize update timer
42 
44 
45  m_Controls->samplePositionHorizontalSlider->setVisible(false);
46 
47  this->ResetLCDNumbers(); // reset lcd numbers at start
48 }
49 
51 {
52  m_PlayingTimer->stop();
53 
54  delete m_Controls;
55 }
56 
58 {
59  connect( (QObject*)(m_Controls->playPushButton), SIGNAL(clicked(bool)), this, SLOT(OnPlayButtonClicked(bool)) ); // play button
60  connect( (QObject*)(m_PlayingTimer), SIGNAL(timeout()), this, SLOT(OnPlaying()) ); // update timer
61  connect( (QObject*) (m_Controls->beginPushButton), SIGNAL(clicked()), this, SLOT(OnGoToBegin()) ); // reset player and go to begin
62  connect( (QObject*) (m_Controls->stopPushButton), SIGNAL(clicked()), this, SLOT(OnGoToEnd()) ); // reset player
63  // pass this widgets protected combobox signal to public signal
64  connect( (QObject*) (m_Controls->trajectorySelectComboBox), SIGNAL(currentIndexChanged(int)), this, SIGNAL(SignalCurrentTrajectoryChanged(int)) );
65  // pass this widgets protected checkbox signal to public signal
66  connect( m_Controls->splineModeCheckBox, SIGNAL(toggled(bool)), this, SIGNAL(SignalSplineModeToggled(bool)) );
67  //connect( m_Controls->sequencialModeCheckBox, SIGNAL(toggled(bool)), this, SLOT(OnSequencialModeToggled(bool)) );
68 
69  connect( m_Controls->samplePositionHorizontalSlider, SIGNAL(sliderPressed()), this, SLOT(OnSliderPressed()) );
70  connect( m_Controls->samplePositionHorizontalSlider, SIGNAL(sliderReleased()), this, SLOT(OnSliderReleased()) );
71 
72  connect( m_Controls->m_OpenFileButton, SIGNAL(clicked()), this, SLOT(OnOpenFileButtonPressed()) );
73 }
74 
76 {
77  return m_Controls->splineModeCheckBox->isChecked();
78 }
79 
81 {
82  QFile file(m_CmpFilename);
83 
84  // check if file exists
85  if(!file.exists())
86  {
87  QMessageBox::warning(nullptr, "IGTPlayer: Error", "No valid input file was loaded. Please load input file first!");
88  return false;
89  }
90 
91  return true;
92 }
93 
95 {
96  unsigned int result = 0;
97 
99  {
100  if(m_RealTimePlayer.IsNotNull())
101  result = m_RealTimePlayer->GetNumberOfOutputs();
102  }
103 
104  else if(this->GetCurrentPlaybackMode() == SequentialMode)
105  {
106  if(m_SequentialPlayer.IsNotNull())
107  result = m_SequentialPlayer->GetNumberOfOutputs();
108  }
109 
110  // at the moment this works only if player is initialized
111  return result;
112 }
113 
114 void QmitkIGTPlayerWidget::SetUpdateRate(unsigned int msecs)
115 {
116  m_PlayingTimer->setInterval((int) msecs); // set update timer update rate
117 }
118 
120 {
121  if ( ! checked )
122  {
123  if ( this->GetCurrentPlaybackMode() == RealTimeMode )
124  {
125  m_RealTimePlayer->StopPlaying();
126  }
127  else if ( this->GetCurrentPlaybackMode() == SequentialMode )
128  {
129  // m_SequentialPlayer->
130  }
131  }
132 
133  if(CheckInputFileValid()) // no playing possible without valid input file
134  {
135  switch ( this->GetCurrentPlaybackMode() )
136  {
137  case RealTimeMode:
138  {
139  break;
140  }
141  case SequentialMode:
142  {
143  break;
144  }
145  }
146 
147  PlaybackMode currentMode = this->GetCurrentPlaybackMode();
148  bool isRealTimeMode = currentMode == RealTimeMode;
149  bool isSequentialMode = currentMode == SequentialMode;
150 
151  if(checked) // play
152  {
153  if( (isRealTimeMode && m_RealTimePlayer.IsNull()) || (isSequentialMode && m_SequentialPlayer.IsNull())) // start play
154  {
155  mitk::NavigationDataSet::Pointer navigationDataSet;
156  try
157  {
158  navigationDataSet = dynamic_cast<mitk::NavigationDataSet*> (mitk::IOUtil::Load(m_CmpFilename.toStdString())[0].GetPointer());
159  }
160  catch(const mitk::IGTException&)
161  {
162  std::string errormessage = "Error during start playing. Invalid or wrong file?";
163  QMessageBox::warning(nullptr, "IGTPlayer: Error", errormessage.c_str());
164  m_Controls->playPushButton->setChecked(false);
165  m_RealTimePlayer = nullptr;
166  return;
167  }
168 
169  if(isRealTimeMode)
170  {
172  m_RealTimePlayer->SetNavigationDataSet(navigationDataSet);
173  try
174  {
175  m_RealTimePlayer->StartPlaying();
176  }
177  catch(const mitk::IGTException&)
178  {
179  std::string errormessage = "Error during start playing. Invalid or wrong file?";
180  QMessageBox::warning(nullptr, "IGTPlayer: Error", errormessage.c_str());
181  m_Controls->playPushButton->setChecked(false);
182  m_RealTimePlayer = nullptr;
183  return;
184  }
185  }
186  else if(isSequentialMode)
187  {
189  try
190  {
191  m_SequentialPlayer->SetNavigationDataSet(navigationDataSet);
192  }
193  catch(const mitk::IGTException&)
194  {
195  std::string errormessage = "Error during start playing. Invalid or wrong file type?";
196  QMessageBox::warning(nullptr, "IGTPlayer: Error", errormessage.c_str());
197  m_Controls->playPushButton->setChecked(false);
198  m_RealTimePlayer = nullptr;
199  return;
200  }
201 
202  m_Controls->samplePositionHorizontalSlider->setMinimum(0);
203 
204  m_Controls->samplePositionHorizontalSlider->setMaximum(m_SequentialPlayer->GetNumberOfSnapshots());
205 
206  m_Controls->samplePositionHorizontalSlider->setEnabled(true);
207  }
208 
209  m_PlayingTimer->start(100);
210 
211  emit SignalPlayingStarted();
212  }
213  else // resume play
214  {
215  if(isRealTimeMode)
216  m_RealTimePlayer->Resume();
217 
218  m_PlayingTimer->start(100);
219  emit SignalPlayingResumed();
220  }
221  }
222 
223  else // pause
224  {
225  if(isRealTimeMode)
226  m_RealTimePlayer->Pause();
227 
228  m_PlayingTimer->stop();
229  emit SignalPlayingPaused();
230  }
231  }
232 
233  else
234  {
235  m_Controls->playPushButton->setChecked(false); // uncheck play button if file unvalid
236  }
237 }
238 
240 {
241  /*if(m_Controls->sequencialModeCheckBox->isChecked())
242  return SequentialMode;
243  else*/
244  return RealTimeMode;
245 }
246 
248 {
249  return m_PlayingTimer;
250 }
251 
253 {
254  this->StopPlaying();
255 }
256 
258 {
259  m_PlayingTimer->stop();
260  emit SignalPlayingStopped();
261 
262  if(m_RealTimePlayer.IsNotNull())
263  m_RealTimePlayer->StopPlaying();
264 
265  m_StartTime = -1; // set starttime back
267  m_Controls->samplePositionHorizontalSlider->setSliderPosition(m_CurrentSequentialPointNumber);
268  m_Controls->sampleLCDNumber->display(static_cast<int>(m_CurrentSequentialPointNumber));
269 
270  this->ResetLCDNumbers();
271  m_Controls->playPushButton->setChecked(false); // set play button unchecked
272 }
273 
275 {
276  switch ( this->GetCurrentPlaybackMode() )
277  {
278  case RealTimeMode:
279  {
280  if ( m_RealTimePlayer.IsNull() ) { return; }
281 
282  if ( m_StartTime < 0 )
283  {
284  // get playback start time
285  m_StartTime = m_RealTimePlayer->GetOutput()->GetTimeStamp();
286  }
287 
288  if( ! m_RealTimePlayer->IsAtEnd() )
289  {
290  m_RealTimePlayer->Update(); // update player
291 
292  int msc = (int) (m_RealTimePlayer->GetOutput()->GetTimeStamp() - m_StartTime);
293 
294  // calculation for playing time display
295  int ms = msc % 1000;
296  msc = (msc - ms) / 1000;
297  int s = msc % 60;
298  int min = (msc-s) / 60;
299 
300  // set lcd numbers
301  m_Controls->msecLCDNumber->display(ms);
302  m_Controls->secLCDNumber->display(s);
303  m_Controls->minLCDNumber->display(min);
304 
305  emit SignalPlayerUpdated(); // player successfully updated
306  }
307  else
308  {
309  this->StopPlaying(); // if player is at EOF
310  }
311 
312  break;
313  }
314  case SequentialMode:
315  {
316  if ( m_SequentialPlayer.IsNull() ) { return; }
317 
318  if ( m_CurrentSequentialPointNumber < m_SequentialPlayer->GetNumberOfSnapshots() )
319  {
320  m_SequentialPlayer->Update(); // update sequential player
321 
322  m_Controls->samplePositionHorizontalSlider->setSliderPosition(m_CurrentSequentialPointNumber++); // refresh slider position
323  m_Controls->sampleLCDNumber->display(static_cast<int>(m_CurrentSequentialPointNumber));
324 
325  //for debugging purposes
326  //std::cout << "Sample: " << m_CurrentSequentialPointNumber << " X: " << m_SequentialPlayer->GetOutput()->GetPosition()[0] << " Y: " << m_SequentialPlayer->GetOutput()->GetPosition()[1] << " Y: " << m_SequentialPlayer->GetOutput()->GetPosition()[2] << std::endl;
327 
328  emit SignalPlayerUpdated(); // player successfully updated
329  }
330  else
331  {
332  this->StopPlaying(); // if player is at EOF
333  }
334 
335  break;
336  }
337  }
338 }
339 
340 const std::vector<mitk::NavigationData::Pointer> QmitkIGTPlayerWidget::GetNavigationDatas()
341 {
342  std::vector<mitk::NavigationData::Pointer> navDatas;
343 
344  if(this->GetCurrentPlaybackMode() == RealTimeMode && m_RealTimePlayer.IsNotNull())
345  {
346  for(unsigned int i=0; i < m_RealTimePlayer->GetNumberOfOutputs(); ++i)
347  {
348  navDatas.push_back(m_RealTimePlayer->GetOutput(i)); // push back current navigation data for each tool
349  }
350  }
351 
352  else if(this->GetCurrentPlaybackMode() == SequentialMode && m_SequentialPlayer.IsNotNull())
353  {
354  for(unsigned int i=0; i < m_SequentialPlayer->GetNumberOfOutputs(); ++i)
355  {
356  navDatas.push_back(m_SequentialPlayer->GetOutput(i)); // push back current navigation data for each tool
357  }
358  }
359 
360  return navDatas;
361 }
362 
364 {
366 
367  mitk::PointSet::PointType pointType;
368 
369  PlaybackMode currentMode = this->GetCurrentPlaybackMode();
370  bool isRealTimeMode = currentMode == RealTimeMode;
371  bool isSequentialMode = currentMode == SequentialMode;
372 
373  if( (isRealTimeMode && m_RealTimePlayer.IsNotNull()) || (isSequentialMode && m_SequentialPlayer.IsNotNull()))
374  {
375  for(unsigned int i=0; i < m_RealTimePlayer->GetNumberOfOutputs(); ++i)
376  {
378 
379  if(isRealTimeMode)
380  position = m_RealTimePlayer->GetOutput(i)->GetPosition();
381  else if(isSequentialMode)
382  position = m_SequentialPlayer->GetOutput(i)->GetPosition();
383 
384  pointType[0] = position[0];
385  pointType[1] = position[1];
386  pointType[2] = position[2];
387 
388  result->InsertPoint(i,pointType); // insert current ND as Pointtype in PointSet for return
389  }
390  }
391 
392  return result;
393 }
394 
396 {
397  if( index > this->GetNumberOfTools() )
398  throw std::out_of_range("Tool Index out of range!");
399 
400  PlaybackMode currentMode = this->GetCurrentPlaybackMode();
401  bool isRealTimeMode = currentMode == RealTimeMode;
402  bool isSequentialMode = currentMode == SequentialMode;
403 
404  // create return PointType from current ND for tool index
406 
407  if( (isRealTimeMode && m_RealTimePlayer.IsNotNull()) || (isSequentialMode && m_SequentialPlayer.IsNotNull()))
408  {
410 
411  if(isRealTimeMode)
412  position = m_RealTimePlayer->GetOutput(index)->GetPosition();
413  else if(isSequentialMode)
414  position = m_SequentialPlayer->GetOutput(index)->GetPosition();
415 
416  result[0] = position[0];
417  result[1] = position[1];
418  result[2] = position[2];
419  }
420 
421  return result;
422 }
423 
424 /*void QmitkIGTPlayerWidget::SetRealTimePlayer( mitk::NavigationDataPlayer::Pointer player )
425 {
426 if(player.IsNotNull())
427 m_RealTimePlayer = player;
428 }
429 
430 void QmitkIGTPlayerWidget::SetSequentialPlayer( mitk::NavigationDataSequentialPlayer::Pointer player )
431 {
432 if(player.IsNotNull())
433 m_SequentialPlayer = player;
434 }*/
435 
437 {
438  QString filename = QFileDialog::getOpenFileName(this, "Load tracking data", QmitkIGTCommonHelper::GetLastFileLoadPath(),"XML files (*.xml)");
439  QFile file(filename);
440 
442  // if something went wrong or user pressed cancel in the save dialog
443  if ( filename.isEmpty() || ! file.exists() )
444  {
445  QMessageBox::warning(nullptr, "Warning", QString("Please enter valid path. Using previous path again."));
446  return;
447  }
448 
449  m_CmpFilename = filename;
450 
451  this->OnGoToEnd();
452 
453  m_Controls->m_ActiveFileLabel->setText(m_CmpFilename);
454 
455  emit SignalInputFileChanged();
456 
457  mitk::NavigationDataSet::Pointer navigationDataSet = dynamic_cast<mitk::NavigationDataSet*> (mitk::IOUtil::Load(m_CmpFilename.toStdString())[0].GetPointer());
458  m_RealTimePlayer->SetNavigationDataSet(navigationDataSet);
459  m_SequentialPlayer->SetNavigationDataSet(navigationDataSet);
460 
461  m_Controls->m_PlayerControlsGroupBox->setEnabled(true);
462 }
463 
465 {
466  this->StopPlaying();
467 
468  // reset lcd numbers
469  this->ResetLCDNumbers();
470 }
471 
473 {
474  // stop player manual so no PlayingStopped()
475  m_PlayingTimer->stop();
476 
477  if(this->GetCurrentPlaybackMode() == RealTimeMode && m_RealTimePlayer.IsNotNull())
478  {
479  m_RealTimePlayer->StopPlaying();
480  m_RealTimePlayer = nullptr; // set player to nullptr so it can be initialized again if playback is called afterwards
481  }
482 
483  m_StartTime = -1; // set starttime back
484 
485  //reset view elements
486  m_Controls->playPushButton->setChecked(false);
487  this->ResetLCDNumbers();
488 }
489 
491 {
492  m_Controls->minLCDNumber->display(QString("00"));
493  m_Controls->secLCDNumber->display(QString("00"));
494  m_Controls->msecLCDNumber->display(QString("000"));
495 }
496 
497 void QmitkIGTPlayerWidget::SetTrajectoryNames(const QStringList toolNames)
498 {
499  QComboBox* cBox = m_Controls->trajectorySelectComboBox;
500 
501  if(cBox->count() > 0)
503 
504  // before making changed to QComboBox it is recommended to disconnet it's SIGNALS and SLOTS
505  disconnect( (QObject*) (m_Controls->trajectorySelectComboBox), SIGNAL(currentIndexChanged(int)), this, SIGNAL(SignalCurrentTrajectoryChanged(int)) );
506 
507  if(!toolNames.isEmpty())
508  m_Controls->trajectorySelectComboBox->insertItems(0, toolNames); // adding current tool names to combobox
509 
510  // reconnect after performed changes
511  connect( (QObject*) (m_Controls->trajectorySelectComboBox), SIGNAL(currentIndexChanged(int)), this, SIGNAL(SignalCurrentTrajectoryChanged(int)) );
512 }
513 
515 {
516  return m_Controls->resolutionSpinBox->value(); // return currently selected trajectory resolution
517 }
518 
520 {
521  // before making changed to QComboBox it is recommended to disconnet it's SIGNALS and SLOTS
522  disconnect( (QObject*) (m_Controls->trajectorySelectComboBox), SIGNAL(currentIndexChanged(int)), this, SIGNAL(SignalCurrentTrajectoryChanged(int)) );
523 
524  m_Controls->trajectorySelectComboBox->clear();
525 
526  // reconnect after performed changes
527  connect( (QObject*) (m_Controls->trajectorySelectComboBox), SIGNAL(currentIndexChanged(int)), this, SIGNAL(SignalCurrentTrajectoryChanged(int)) );
528 }
529 
531 {
532  this->StopPlaying(); // stop playing when mode is changed
533 
534  if(toggled)
535  {
536  m_Controls->samplePositionHorizontalSlider->setEnabled(true); // enable slider if sequential mode
537  }
538  else if(!toggled)
539  {
540  m_Controls->samplePositionHorizontalSlider->setSliderPosition(0); // set back and disable slider
541  m_Controls->samplePositionHorizontalSlider->setDisabled(true);
542  }
543 }
544 
546 {
547  int currentSliderValue = m_Controls->samplePositionHorizontalSlider->value(); // current slider value selected through user movement
548 
549  if(currentSliderValue > static_cast<int>(m_CurrentSequentialPointNumber)) // at the moment only forward scrolling is possible
550  {
551  auto snapshotNumber = static_cast<unsigned int>(currentSliderValue);
552  m_SequentialPlayer->GoToSnapshot(snapshotNumber); // move player to selected snapshot
553  m_CurrentSequentialPointNumber = currentSliderValue;
554  m_Controls->sampleLCDNumber->display(currentSliderValue); // update lcdnumber in widget
555  }
556  else
557  m_Controls->samplePositionHorizontalSlider->setValue(m_CurrentSequentialPointNumber);
558 }
559 
561 {
562  if(m_Controls->playPushButton->isChecked()) // check if widget is playing
563  m_Controls->playPushButton->click(); // perform click to pause the play
564 }
bool CheckInputFileValid()
Checks if an imput file with the set filename exists.
mitk::NavigationData::TimeStampType m_StartTime
start time of playback needed for time display
void SetTrajectoryNames(const QStringList toolNames)
Sets the given tool names list to the trajectory select combobox.
static const QString GetLastFileLoadPath()
void SignalCurrentTrajectoryChanged(int index)
This signal is emitted if the index of the current selected trajectory select combobox item changes...
~QmitkIGTPlayerWidget() override
default deconstructor
void StopPlaying()
Stops the playback.
void OnStopPlaying()
Stops the playback.
void ClearTrajectorySelectCombobox()
Clears all items in the trajectory selection combobox.
void OnGoToEnd()
Stops the playback.
void SignalPlayingPaused()
This signal is emitted when the player is paused.
static void SetLastFileLoadPathByFileName(const QString &str)
static Pointer New()
void SignalInputFileChanged()
This signal is emitted if the input file for the replay was changed.
An object of this class represents an exception of the MITK-IGT module.
DataCollection - Class to facilitate loading/accessing structured data.
mitk::NavigationDataSequentialPlayer::Pointer m_SequentialPlayer
void SignalPlayerUpdated()
This signal is emitted every time the player updated the NavigationDatas.
bool IsTrajectoryInSplineMode()
Returns whether spline mode checkbox is selected.
mitk::NavigationDataPlayer::Pointer m_RealTimePlayer
plays NDs from a XML file
QString m_CmpFilename
filename of the input file
PlaybackMode GetCurrentPlaybackMode()
void OnOpenFileButtonPressed()
Opens file open dialog for searching the input file.
const std::vector< mitk::NavigationData::Pointer > GetNavigationDatas()
Returns the current playback NavigationDatas from the xml-file.
void OnSequencialModeToggled(bool toggled)
Switches widget between realtime and sequential mode.
void OnSliderPressed()
Pauses playback when slider is pressed by user.
void SignalPlayingStarted()
This signal is emitted when the player starts the playback.
const mitk::PointSet::Pointer GetNavigationDatasPointSet()
Returns a PointSet of the current NavigationDatas for all recorded tools.
unsigned int m_CurrentSequentialPointNumber
current point number
void OnPlayButtonClicked(bool toggled)
Starts or pauses the playback.
void ResetLCDNumbers()
Sets all LCD numbers to 0.
int GetResolution()
Returns the current resolution value from the resolution spinbox.
const mitk::PointSet::PointType GetNavigationDataPoint(unsigned int index)
Returns a PointType of the current NavigationData for a specific tool with the given index...
Data structure which stores streams of mitk::NavigationData for multiple tools.
QTimer * m_PlayingTimer
update timer
void SetUpdateRate(unsigned int msecs)
Sets the update rate of this widget&#39;s playing timer.
static T min(T x, T y)
Definition: svm.cpp:53
void SignalPlayingStopped()
This signal is emitted when the player stops.
unsigned int GetNumberOfTools()
Returns the number of different tools from the current playing stream.
void OnSliderReleased()
Moves player position to the position selected with the slider.
void OnGoToBegin()
Stops the playback and resets the player to the beginning.
QmitkIGTPlayerWidget(QWidget *parent=nullptr, Qt::WindowFlags f=nullptr)
default constructor
Ui::QmitkIGTPlayerWidgetControls * m_Controls
virtual void CreateConnections()
Creation of the connections.
void OnPlaying()
Updates the playback data.
void SignalSplineModeToggled(bool toggled)
This signal is emitted if the spline mode checkbox is toggled or untoggled.
void SignalPlayingResumed()
This signal is emitted when the player resumes after a pause.
static DataStorage::SetOfObjects::Pointer Load(const std::string &path, DataStorage &storage, const ReaderOptionsFunctorBase *optionsCallback=nullptr)
Load a file into the given DataStorage.
Definition: mitkIOUtil.cpp:489
QTimer * GetPlayingTimer()
Sets the real time player for this player widget.