We already know the three views of the IGT tracking plugin from the first tutorial step (The IGT Tracking Plugin): The MITK-IGT Tracking Toolbox , The MITK-IGT Navigation Tool Manager and The NavigationData Player . While the first tutorial step only dealt with the usage of these views, we now want to have a deeper look at some parts of the code.
IGT Widgets
A lot of the IGT functionality is available as a widget. So if you need some part of it for your own plugin, you might just want to include the widget. This is for example done for the QmitkNavigationToolCreationWidget, which is used in the The MITK-IGT Tracking Toolbox view as well as in the The MITK-IGT Navigation Tool Manager view.
Data access
The fist important question is, how to get the tools you want to use for your application. The most simple way is using the The MITK-IGT Navigation Tool Manager to load, create or edit the tools and access it via the NavigationToolStorage. It's provided by a microservice and you can access it e.g. via the module context (make sure, your module depends on IGT):
us::ModuleContext* context = us::GetModuleContext();
std::vector<us::ServiceReference <mitk::NavigationToolStorage> > refs = context->GetServiceReferences<mitk::NavigationToolStorage>();
m_ToolStorage = context->GetService<mitk::NavigationToolStorage>(refs.front());
Then, simply access the tools by
m_ToolStorage->GetTool();
There are also many different functions available, e.g. providing the number of available tools or the name of the current tracking device. Just have a look at the documentation of the mitk::NavigationToolStorage if you are interested in it.
Autoload all parameters from last session
To increase the usability of the application, the tracking toolbox restores all parameters from the last session. Therefore, we will use the following code to save all parameters. It is also used in the specific tracking device widgets, but we will just have a look at one example, restoring some parameters like the Show-Tracking-Volume-Checkbox, the filename of the autosave path of the tool storage or the index of the tracking volume.
To store the settings, the following code is used:
void QmitkMITKIGTTrackingToolboxView::StoreUISettings()
{
QSettings settings;
settings.beginGroup(QString::fromStdString(VIEW_ID));
settings.setValue("ShowTrackingVolume", QVariant(m_Controls->m_ShowTrackingVolume->isChecked()));
settings.setValue("toolStorageFilename", QVariant(m_ToolStorageFilename));
settings.setValue("VolumeSelectionBox", QVariant(m_Controls->m_VolumeSelectionBox->currentIndex()));
settings.endGroup();
}
We will reload it with
void QmitkMITKIGTTrackingToolboxView::LoadUISettings()
{
QSettings settings;
settings.beginGroup(QString::fromStdString(VIEW_ID));
m_Controls->m_ShowTrackingVolume->setChecked(settings.value("ShowTrackingVolume", true).toBool());
m_Controls->m_VolumeSelectionBox->setCurrentIndex(settings.value("VolumeSelectionBox", 0).toInt());
m_ToolStorageFilename = settings.value("toolStorageFilename", QVariant("")).toString();
settings.endGroup();
Load Tool Storage
This code will load a previously stored or autosaved tool storage:
if (!m_ToolStorageFilename.isEmpty())
{
try
{
m_toolStorage->UnRegisterMicroservice();
m_toolStorage = myDeserializer->Deserialize(m_ToolStorageFilename.toStdString());
m_toolStorage->RegisterAsMicroservice("no tracking device");
UpdateToolStorageLabel(m_ToolStorageFilename);
m_Controls->m_TrackingToolsStatusWidget->RemoveStatusLabels();
m_Controls->m_TrackingToolsStatusWidget->PreShowTools(m_toolStorage);
}
{
MITK_WARN(
"QmitkMITKIGTTrackingToolBoxView") <<
"Error during restoring tools. Problems with file (" << m_ToolStorageFilename.toStdString() <<
"), please check the file?";
this->OnResetTools();
}
}
Threaded Tracking
Usually, the tracking is done in a separate thread in order to still allow parallel usage of the workbench. If we track the devices in the same thread, the workbench might freeze. That's why we use thread workers
m_WorkerThread = new QThread();
m_Worker = new QmitkMITKIGTTrackingToolboxViewWorker();
...which are connected to functions
connect(m_Worker, SIGNAL(AutoDetectToolsFinished(bool, QString)), this, SLOT(OnAutoDetectToolsFinished(bool, QString)));
connect(m_Worker, SIGNAL(ConnectDeviceFinished(bool, QString)), this, SLOT(OnConnectFinished(bool, QString)));
connect(m_Worker, SIGNAL(StartTrackingFinished(bool, QString)), this, SLOT(OnStartTrackingFinished(bool, QString)));
connect(m_Worker, SIGNAL(StopTrackingFinished(bool, QString)), this, SLOT(OnStopTrackingFinished(bool, QString)));
connect(m_Worker, SIGNAL(DisconnectDeviceFinished(bool, QString)), this, SLOT(OnDisconnectFinished(bool, QString)));
connect(m_WorkerThread, SIGNAL(started()), m_Worker, SLOT(ThreadFunc()));
m_Worker->moveToThread(m_WorkerThread);
The thread will be startet, if we connect a tracking device by pushing the connect button or start tracking etc:
m_Worker->SetWorkerMethod(QmitkMITKIGTTrackingToolboxViewWorker::eConnectDevice);
m_Worker->SetTrackingDevice(this->m_Controls->m_configurationWidget->GetTrackingDevice());
m_Worker->SetInverseMode(m_Controls->m_InverseMode->isChecked());
m_Worker->SetNavigationToolStorage(this->m_toolStorage);
m_Worker->SetTrackingDeviceData(data);
m_WorkerThread->start();
...and finished afterwards:
m_WorkerThread->quit();
m_WorkerThread->wait();
You can access the data from the worker thread if needed:
m_TrackingDeviceSource = m_Worker->GetTrackingDeviceSource();
m_TrackingDeviceData = m_Worker->GetTrackingDeviceData();
m_ToolVisualizationFilter = m_Worker->GetToolVisualizationFilter();
Which of the functions is finally executed will be chosen in the ThreadFunc:
void QmitkMITKIGTTrackingToolboxViewWorker::ThreadFunc()
{
switch (m_WorkerMethod)
{
case eAutoDetectTools:
this->AutoDetectTools();
break;
case eConnectDevice:
this->ConnectDevice();
break;
case eStartTracking:
this->StartTracking();
break;
case eStopTracking:
this->StopTracking();
break;
case eDisconnectDevice:
this->DisconnectDevice();
break;
default:
MITK_WARN <<
"Undefined worker method was set ... something went wrong!";
break;
}
}
To deconstruct the workers, we first terminate the threads and then delete them
m_WorkerThread->terminate();
m_WorkerThread->wait();
if (m_WorkerThread) { delete m_WorkerThread; }
if (m_Worker) { delete m_Worker; }
Return to the [IGT Tutorial Overview]