MITK-IGT
IGT Extension of MITK
Loading...
Searching...
No Matches
mitkOpenIGTLinkTrackingDevice.cpp
Go to the documentation of this file.
1/*============================================================================
2
3The Medical Imaging Interaction Toolkit (MITK)
4
5Copyright (c) German Cancer Research Center (DKFZ)
6All rights reserved.
7
8Use of this source code is governed by a 3-clause BSD license that can be
9found in the LICENSE file.
10
11============================================================================*/
12
15#include "mitkIGTConfig.h"
16#include "mitkIGTTimeStamp.h"
17#include "mitkIGTHardwareException.h"
18#include "mitkTrackingTypes.h"
19#include <itksys/SystemTools.hxx>
20#include <iostream>
21#include <itkCommand.h>
23#include <vtkConeSource.h>
24
25//sleep headers
26#include <chrono>
27#include <thread>
28
30{
31 //set the type of this tracking device
33
34 m_OpenIGTLinkClient = mitk::IGTLClient::New(true);
35 m_OpenIGTLinkClient->SetName("OpenIGTLink Tracking Device");
36 m_OpenIGTLinkClient->EnableNoBufferingMode(false);
37
38 m_IGTLDeviceSource = mitk::IGTLTrackingDataDeviceSource::New();
40}
41
45
47{
48 return m_OpenIGTLinkClient->GetPortNumber();
49}
50
55
56mitk::NavigationToolStorage::Pointer mitk::OpenIGTLinkTrackingDevice::AutoDetectTools()
57{
58 mitk::NavigationToolStorage::Pointer returnValue = mitk::NavigationToolStorage::New();
59
60 if (m_OpenIGTLinkClient->GetPortNumber() == -1)
61 {
62 MITK_WARN << "Connection not initialized, aborting (invalid port number).";
63 return mitk::NavigationToolStorage::New();
64 }
65
66 //open connection
67 try
68 {
69 m_IGTLDeviceSource->Connect();
70 m_IGTLDeviceSource->StartCommunication();
71 }
72 catch (std::runtime_error &e)
73 {
74 MITK_WARN << "AutoDetection: Open IGT Link device retruned an error while trying to connect: " << e.what();
75 return mitk::NavigationToolStorage::New();
76 }
77
78 //get a message to find out type
79 m_IGTLDeviceSource->SettrackingDataType(mitk::IGTLTrackingDataDeviceSource::UNKNOWN);
80 mitk::IGTLMessage::Pointer receivedMessage = ReceiveMessage(100);
81
82 const char* msgType = receivedMessage->GetIGTLMessageType();
83
84 if (std::string(msgType).empty())
85 {
86 MITK_INFO << "Did not receive a message. Do you have to start the stream manually at the server?";
87 MITK_INFO << "Waiting for 10 seconds ...";
88 receivedMessage = ReceiveMessage(10000);
89 msgType = receivedMessage->GetIGTLMessageType();
90 }
91 MITK_INFO << "################# got message type: " << msgType;
92 mitk::OpenIGTLinkTrackingDevice::TrackingMessageType type = GetMessageTypeFromString(msgType);
93 switch (type)
94 {
95 case UNKNOWN:
96 m_IGTLDeviceSource->SettrackingDataType(mitk::IGTLTrackingDataDeviceSource::UNKNOWN);
97 break;
98 case TDATA:
99 m_IGTLDeviceSource->SettrackingDataType(mitk::IGTLTrackingDataDeviceSource::TDATA);
100 break;
101 case QTDATA:
102 m_IGTLDeviceSource->SettrackingDataType(mitk::IGTLTrackingDataDeviceSource::QTDATA);
103 break;
104 case TRANSFORM:
105 m_IGTLDeviceSource->SettrackingDataType(mitk::IGTLTrackingDataDeviceSource::TRANSFORM);
106 break;
107 }
108 returnValue = DiscoverToolsAndConvertToNavigationTools(type);
109
110 //close connection
111 try
112 {
113 m_IGTLDeviceSource->StopCommunication();
114 m_IGTLDeviceSource->Disconnect();
115 }
116 catch (std::runtime_error &e)
117 {
118 MITK_WARN << "AutoDetection: Open IGT Link device retruned an error while trying to disconnect: " << e.what();
119 return mitk::NavigationToolStorage::New();
120 }
121
122
123 return returnValue;
124}
125
126mitk::NavigationToolStorage::Pointer mitk::OpenIGTLinkTrackingDevice::DiscoverToolsAndConvertToNavigationTools(mitk::OpenIGTLinkTrackingDevice::TrackingMessageType type, int NumberOfMessagesToWait)
127{
128 MITK_INFO << "Start discovering tools by " << type << " messages";
129 mitk::NavigationToolStorage::Pointer returnValue = mitk::NavigationToolStorage::New();
130 std::map<std::string, int> toolNameMap;
131
132 for (int j = 0; j<NumberOfMessagesToWait; j++)
133 {
134 std::this_thread::sleep_for(std::chrono::milliseconds(20));
135 m_IGTLDeviceSource->Update();
136 switch (type)
137 {
138 case TRANSFORM:
139 {
140 igtl::TransformMessage::Pointer msg = dynamic_cast<igtl::TransformMessage*>(m_IGTLDeviceSource->GetOutput()->GetMessage().GetPointer());
141 if (msg == nullptr || msg.IsNull()) { MITK_INFO << "Received message is invalid / null. Skipping.."; continue; }
142 int count = toolNameMap[msg->GetDeviceName()];
143 if (count == 0) { toolNameMap[msg->GetDeviceName()] = 1; }
144 else { toolNameMap[msg->GetDeviceName()]++; }
145 }
146 break;
147 case TDATA:
148 {
149 igtl::TrackingDataMessage::Pointer msg = dynamic_cast<igtl::TrackingDataMessage*>(m_IGTLDeviceSource->GetOutput()->GetMessage().GetPointer());
150 if (msg == nullptr || msg.IsNull()) { MITK_INFO << "Received message is invalid / null. Skipping.."; continue; }
151 for (int k = 0; k < msg->GetNumberOfTrackingDataElements(); k++)
152 {
153 igtl::TrackingDataElement::Pointer tde;
154 msg->GetTrackingDataElement(k, tde);
155 if (tde.IsNotNull())
156 {
157 int count = toolNameMap[tde->GetName()];
158 if (count == 0) { toolNameMap[tde->GetName()] = 1; }
159 else { toolNameMap[tde->GetName()]++; }
160 }
161 }
162 }
163 break;
164 default:
165 MITK_WARN << "Only TRANSFORM and TDATA is currently supported, skipping!";
166 break;
167 }
168 }
169
170 int i = 0;
171 for (std::map<std::string, int>::iterator it = toolNameMap.begin(); it != toolNameMap.end(); ++it)
172 {
173 MITK_INFO << "Found tool: " << it->first;
174
175 std::stringstream name;
176 name << it->first;
177
178 std::stringstream identifier;
179 identifier << "AutoDetectedTool-" << i;
180 i++;
181
182 mitk::NavigationTool::Pointer newTool = ConstructDefaultOpenIGTLinkTool(name.str(), identifier.str());
183
184 returnValue->AddTool(newTool);
185 }
186
187 return returnValue;
188}
189
191{
192 return m_OpenIGTLinkClient->GetHostname();
193}
194
196{
197 m_OpenIGTLinkClient->SetPortNumber(portNumber);
198}
199
201{
202 m_OpenIGTLinkClient->SetHostname(hostname);
203}
204
209
211{
212 mitk::OpenIGTLinkTrackingTool::Pointer t;// = mitk::OpenIGTLinkTrackingTool::New();
213 //TODO: Implement
214 if (this->InternalAddTool(t) == false)
215 return nullptr;
216 return t.GetPointer();
217}
218
219bool mitk::OpenIGTLinkTrackingDevice::InternalAddTool(OpenIGTLinkTrackingTool::Pointer tool)
220{
221 m_AllTools.push_back(tool);
222 return true;
223}
224
226{
227 if (m_OpenIGTLinkClient->GetPortNumber() == -1)
228 {
229 MITK_WARN << "Connection not initialized, aborting (invalid port number).";
230 return false;
231 }
232
233 try
234 {
235 m_IGTLDeviceSource->Connect();
236 m_IGTLDeviceSource->StartCommunication();
237 }
238 catch (std::runtime_error &e)
239 {
240 MITK_WARN << "Open IGT Link device retruned an error while trying to connect: " << e.what();
241 return false;
242 }
243
244 mitk::IGTLMessage::Pointer receivedMessage = ReceiveMessage(waitingTime);
245
246 //check the tracking stream for the number and type of tools
247 //igtl::MessageBase::Pointer receivedMessage = m_OpenIGTLinkClient->GetNextMessage();
248 if (receivedMessage.IsNull())
249 {
250 MITK_WARN << "No message was received. Is there really a server?";
251 return false;
252 }
253 else if (!receivedMessage->IsDataValid())
254 {
255 MITK_WARN << "Received invalid message.";
256 return false;
257 }
258
259 const char* msgType = receivedMessage->GetIGTLMessageType();
260
261 mitk::OpenIGTLinkTrackingDevice::TrackingMessageType type = GetMessageTypeFromString(msgType);
262
263 mitk::NavigationToolStorage::Pointer foundTools = this->DiscoverToolsAndConvertToNavigationTools(type);
264 if (foundTools.IsNull() || (foundTools->GetToolCount() == 0)) { return false; }
265 for (unsigned int i = 0; i < foundTools->GetToolCount(); i++) { AddNewToolForName(foundTools->GetTool(i)->GetToolName(), i); }
266 MITK_INFO << "Found tools: " << foundTools->GetToolCount();
267 return true;
268}
269
270mitk::IGTLMessage::Pointer mitk::OpenIGTLinkTrackingDevice::ReceiveMessage(int waitingTime)
271{
272 mitk::IGTLMessage::Pointer receivedMessage;
273 //send a message to the server: start tracking stream
274 mitk::IGTLMessageFactory::Pointer msgFactory = m_OpenIGTLinkClient->GetMessageFactory();
275 std::string message[2] = {"STT_QTDATA","STT_TDATA"};
276
277 for (int i = 0; i < 2; i++)
278 {
279 igtl::MessageBase::Pointer sttMsg = msgFactory->CreateInstance(message[i]);
280 //TODO: Fix this to dynamically get this from GUI
281 ((igtl::StartTrackingDataMessage*)sttMsg.GetPointer())->SetResolution(m_UpdateRate);
282 m_OpenIGTLinkClient->SendMessage(mitk::IGTLMessage::New(sttMsg));
283 }
284
285 std::chrono::high_resolution_clock::time_point time = std::chrono::high_resolution_clock::now();
286 std::chrono::milliseconds d = std::chrono::milliseconds(waitingTime);
287
288 while (!(receivedMessage.IsNotNull() && receivedMessage->IsDataValid()))
289 {
290 m_IGTLDeviceSource->Update();
291 receivedMessage = m_IGTLDeviceSource->GetOutput();
292
293 if ((time + d) < std::chrono::high_resolution_clock::now())
294 break;
295
296 std::this_thread::sleep_for(std::chrono::milliseconds(100));
297 }
298 return receivedMessage;
299}
300
301void mitk::OpenIGTLinkTrackingDevice::AddNewToolForName(std::string name, int i)
302{
303 mitk::OpenIGTLinkTrackingTool::Pointer newTool = mitk::OpenIGTLinkTrackingTool::New();
304 if (name == "") //if no name was given create a default name
305 {
306 std::stringstream defaultName;
307 defaultName << "OpenIGTLinkTool#" << i;
308 name = defaultName.str();
309 }
310 MITK_INFO << "Added tool " << name << " to tracking device.";
311 newTool->SetToolName(name);
312 InternalAddTool(newTool);
313}
314
315mitk::NavigationTool::Pointer mitk::OpenIGTLinkTrackingDevice::ConstructDefaultOpenIGTLinkTool(std::string name, std::string identifier)
316{
317 mitk::NavigationTool::Pointer newTool = mitk::NavigationTool::New();
318 newTool->GetDataNode()->SetName(name);
319 newTool->SetIdentifier(identifier);
320
322
323 return newTool;
324
325}
326
328{
329 if (this->GetState() != Tracking)
330 {
331 MITK_ERROR << "Method was called in the wrong state, something went wrong!";
332 return;
333 }
334
335 m_IGTLMsgToNavDataFilter->Update();
336
337 for (std::size_t j = 0; j < m_IGTLMsgToNavDataFilter->GetNumberOfIndexedOutputs(); ++j)
338 {
339 mitk::NavigationData::Pointer currentNavData = m_IGTLMsgToNavDataFilter->GetOutput(j);
340 const char* name = currentNavData->GetName();
341 for (std::size_t i = 0; i < m_AllTools.size(); i++)
342 {
343 if (strcmp(m_AllTools.at(i)->GetToolName(), name) == 0)
344 {
345 m_AllTools.at(i)->SetDataValid(currentNavData->IsDataValid());
346 m_AllTools.at(i)->SetPosition(currentNavData->GetPosition());
347 m_AllTools.at(i)->SetOrientation(currentNavData->GetOrientation());
348 m_AllTools.at(i)->SetIGTTimeStamp(currentNavData->GetIGTTimeStamp());
349 }
350 }
351 }
352}
353
355{
356 //check tracking state
357 if (this->GetState() != Ready)
358 {
359 MITK_WARN << "Cannot start tracking, device is not ready!";
360 return false;
361 }
362
363 try
364 {
365 m_IGTLDeviceSource->StartCommunication();
366
367 //send a message to the server: start tracking stream
368 mitk::IGTLMessageFactory::Pointer msgFactory = m_OpenIGTLinkClient->GetMessageFactory();
369 std::string message = "STT_TDATA";
370 //m_OpenIGTLinkClient->SendMessage(msgFactory->CreateInstance(message));
371 }
372 catch (std::runtime_error &e)
373 {
374 MITK_WARN << "Open IGT Link device retruned an error while starting communication: " << e.what();
375 return false;
376 }
377
378 //create internal igtl pipeline
379 m_IGTLMsgToNavDataFilter = mitk::IGTLMessageToNavigationDataFilter::New();
380 m_IGTLMsgToNavDataFilter->SetNumberOfExpectedOutputs(this->GetToolCount());
381 m_IGTLMsgToNavDataFilter->ConnectTo(m_IGTLDeviceSource);
382
383 //connect itk events
384 typedef itk::SimpleMemberCommand< mitk::OpenIGTLinkTrackingDevice > CurCommandType;
385 CurCommandType::Pointer messageReceivedCommand = CurCommandType::New();
386 messageReceivedCommand->SetCallbackFunction(this, &mitk::OpenIGTLinkTrackingDevice::UpdateTools);
387 m_MessageReceivedObserverTag = m_OpenIGTLinkClient->AddObserver(mitk::MessageReceivedEvent(), messageReceivedCommand);
388
389 m_OpenIGTLinkClient->EnableNoBufferingMode(true);
390 this->SetState(Tracking);
391 return true;
392}
393
395{
396 //check tracking state
397 if (this->GetState() != Tracking)
398 {
399 MITK_WARN << "Cannot open connection, device is already connected!";
400 return false;
401 }
402
403 m_OpenIGTLinkClient->RemoveObserver(m_MessageReceivedObserverTag); //disconnect itk events
404
405 try
406 {
407 m_IGTLDeviceSource->StopCommunication();
408 }
409 catch (std::runtime_error &e)
410 {
411 MITK_WARN << "Open IGT Link device retruned an error while stopping communication: " << e.what();
412 return false;
413 }
414 m_OpenIGTLinkClient->EnableNoBufferingMode(false);
415 this->SetState(Ready);
416 return true;
417}
418
420{
421 return (unsigned int)this->m_AllTools.size();
422}
423
425{
426 if (toolNumber >= this->GetToolCount())
427 return nullptr;
428 else
429 return this->m_AllTools[toolNumber];
430}
431
433{
434 //check tracking state
435 if (this->GetState() != Setup)
436 {
437 MITK_WARN << "Cannot open connection, device is already connected!";
438 return false;
439 }
440
441 try
442 {
443 m_IGTLDeviceSource->Connect();
444 }
445 catch (std::runtime_error &e)
446 {
447 MITK_WARN << "Open IGT Link device retruned an error while trying to connect: " << e.what();
448 return false;
449 }
450 this->SetState(Ready);
451 return true;
452}
453
455{
456 //check tracking state
457 if (this->GetState() != Ready)
458 {
459 MITK_WARN << "Cannot close connection, device is in the wrong state!";
460 return false;
461 }
462
463 try
464 {
465 m_IGTLDeviceSource->Disconnect();
466 }
467 catch (std::runtime_error &e)
468 {
469 MITK_WARN << "Open IGT Link device retruned an error while trying to disconnect: " << e.what();
470 return false;
471 }
472
473 this->SetState(Setup);
474
475 return true;
476}
477
478std::vector<mitk::OpenIGTLinkTrackingTool::Pointer> mitk::OpenIGTLinkTrackingDevice::GetAllTools()
479{
480 return this->m_AllTools;
481}
482
483mitk::OpenIGTLinkTrackingDevice::TrackingMessageType mitk::OpenIGTLinkTrackingDevice::GetMessageTypeFromString(const char* messageTypeString)
484{
485 if (strcmp(messageTypeString, "TDATA") == 0)
486 {
487 return mitk::OpenIGTLinkTrackingDevice::TrackingMessageType::TDATA;
488 }
489 else if (strcmp(messageTypeString, "QTDATA") == 0)
490 {
491 return mitk::OpenIGTLinkTrackingDevice::TrackingMessageType::QTDATA;
492 }
493 else if (strcmp(messageTypeString, "TRANSFORM") == 0)
494 {
495 return mitk::OpenIGTLinkTrackingDevice::TrackingMessageType::TRANSFORM;
496 }
497 else
498 {
499 return mitk::OpenIGTLinkTrackingDevice::TrackingMessageType::UNKNOWN;
500 }
501}
bool StopTracking() override
Stops the tracking.
bool InternalAddTool(OpenIGTLinkTrackingTool::Pointer tool)
Adds a tool to the tracking device.
bool DiscoverTools(int WaitingTime=10000)
Discover the tools available from the connected OpenIGTLink device and adds these tools to this track...
bool StartTracking() override
Starts the tracking.
bool OpenConnection() override
Opens the connection to the device. This have to be done before the tracking is started.
mitk::IGTLTrackingDataDeviceSource::Pointer m_IGTLDeviceSource
bool CloseConnection() override
Closes the connection and clears all resources.
TrackingTool * GetTool(unsigned int toolNumber) const override
mitk::NavigationToolStorage::Pointer AutoDetectTools() override
mitk::TrackingTool * AddTool(const char *toolName, const char *fileName)
Create a new OpenIGTLink tool with toolName and fileName and add it to the list of tools.
mitk::IGTLMessage::Pointer ReceiveMessage(int waitingTime)
std::vector< OpenIGTLinkTrackingTool::Pointer > GetAllTools()
static TrackingDeviceData GetDeviceDataOpenIGTLinkTrackingDeviceConnection()
Interface for all Tracking Devices.
TrackingDeviceData m_Data
current device Data
Interface for all Tracking Tools.
IGT Exceptions.
int strcmp(const String &s1, const String &s2)
Definition relates.cpp:14