Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkOpenIGTLinkTrackingDevice.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,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
19 #include "mitkIGTConfig.h"
20 #include "mitkIGTTimeStamp.h"
21 #include "mitkIGTHardwareException.h"
22 #include "mitkTrackingTypes.h"
23 #include <itksys/SystemTools.hxx>
24 #include <iostream>
25 #include <itkMutexLockHolder.h>
26 #include <itkCommand.h>
28 
29 //sleep headers
30 #include <chrono>
31 #include <thread>
32 
34 
36 {
37  //set the type of this tracking device
39 
41  m_OpenIGTLinkClient->SetName("OpenIGTLink Tracking Device");
42 
45 }
46 
48 {
49 }
50 
52 {
53  return m_OpenIGTLinkClient->GetPortNumber();
54 }
55 
57 {
58  return m_OpenIGTLinkClient->GetHostname();
59 }
60 
62 {
63  m_OpenIGTLinkClient->SetPortNumber(portNumber);
64 }
65 
67 {
68  m_OpenIGTLinkClient->SetHostname(hostname);
69 }
70 
72 {
73  return true;
74 }
75 
76 mitk::TrackingTool* mitk::OpenIGTLinkTrackingDevice::AddTool(const char* toolName, const char* fileName)
77 {
78  mitk::OpenIGTLinkTrackingTool::Pointer t;// = mitk::OpenIGTLinkTrackingTool::New();
79  //TODO: Implement
80  if (this->InternalAddTool(t) == false)
81  return NULL;
82  return t.GetPointer();
83 }
84 
86 {
87  m_AllTools.push_back(tool);
88  return true;
89 }
90 
92 {
93  if (m_OpenIGTLinkClient->GetPortNumber() == -1)
94  {
95  MITK_WARN << "Connection not initialized, aborting (invalid port number).";
96  return false;
97  }
98 
99  try
100  {
101  m_IGTLDeviceSource->Connect();
102  m_IGTLDeviceSource->StartCommunication();
103  }
104  catch (std::runtime_error &e)
105  {
106  MITK_WARN << "Open IGT Link device retruned an error while trying to connect: " << e.what();
107  return false;
108  }
109 
110  //send a message to the server: start tracking stream
111  mitk::IGTLMessageFactory::Pointer msgFactory = m_OpenIGTLinkClient->GetMessageFactory();
112  std::string message = "STT_TDATA";
113  igtl::MessageBase::Pointer sttMsg = msgFactory->CreateInstance(message);
114  //TODO: Fix this to dynamically get this from GUI
115  ((igtl::StartTrackingDataMessage*)sttMsg.GetPointer())->SetResolution(m_UpdateRate);
116  m_OpenIGTLinkClient->SendMessage(sttMsg);
117 
118  mitk::IGTLMessage::Pointer receivedMessage;
119 
120  std::chrono::high_resolution_clock::time_point time = std::chrono::high_resolution_clock::now();
121  std::chrono::milliseconds d = std::chrono::milliseconds(waitingTime);
122 
123  while (!(receivedMessage.IsNotNull() && receivedMessage->IsDataValid()))
124  {
125  m_IGTLDeviceSource->Update();
126  receivedMessage = m_IGTLDeviceSource->GetOutput();
127 
128  if ((time + d) < std::chrono::high_resolution_clock::now())
129  break;
130 
131  std::this_thread::sleep_for(std::chrono::milliseconds(100));
132  }
133 
134  //check the tracking stream for the number and type of tools
135  //igtl::MessageBase::Pointer receivedMessage = m_OpenIGTLinkClient->GetNextMessage();
136  if (receivedMessage.IsNull())
137  {
138  MITK_WARN << "No message was received. Is there really a server?";
139  return false;
140  }
141  else if (!receivedMessage->IsDataValid())
142  {
143  MITK_WARN << "Received invalid message.";
144  return false;
145  }
146 
147  const char* msgType = receivedMessage->GetIGTLMessageType();
148 
149  mitk::OpenIGTLinkTrackingDevice::TrackingMessageType type = GetMessageTypeFromString(msgType);
150 
151  switch (type)
152  {
153  case TDATA:
154  return DiscoverToolsFromTData(dynamic_cast<igtl::TrackingDataMessage*>(receivedMessage->GetMessage().GetPointer()));
155  case QTDATA:
156  return DiscoverToolsFromQTData(dynamic_cast<igtl::QuaternionTrackingDataMessage*>(receivedMessage->GetMessage().GetPointer()));
157  case TRANSFORM:
158  return DiscoverToolsFromTransform();
159  default:
160  MITK_INFO << "Server does not send tracking data. Received data is not of a compatible type. Received type: " << msgType;
161  return false;
162  }
163 }
164 
165 bool mitk::OpenIGTLinkTrackingDevice::DiscoverToolsFromTData(igtl::TrackingDataMessage::Pointer tdMsg)
166 {
167  MITK_INFO << "Start discovering tools by TDATA messages";
168  if (tdMsg == nullptr)
169  {
170  MITK_WARN << "Message was not a TrackingDataMessage, aborting!";
171  return false;
172  }
173 
174  int numberOfTools = tdMsg->GetNumberOfTrackingDataElements();
175  MITK_INFO << "Found " << numberOfTools << " tools";
176  for (int i = 0; i < numberOfTools; i++)
177  {
178  igtl::TrackingDataElement::Pointer currentTrackingData;
179  tdMsg->GetTrackingDataElement(i, currentTrackingData);
180  std::string name = currentTrackingData->GetName();
181  AddNewToolForName(name, i);
182  }
183 
184  m_IGTLDeviceSource->StopCommunication();
185  SetState(Ready);
186  return true;
187 }
188 
189 bool mitk::OpenIGTLinkTrackingDevice::DiscoverToolsFromQTData(igtl::QuaternionTrackingDataMessage::Pointer msg)
190 {
191  MITK_INFO << "Start discovering tools by QTDATA messages";
192  if (msg == nullptr)
193  {
194  MITK_WARN << "Message was not a QuaternionTrackingDataMessage, aborting!";
195  return false;
196  }
197  int numberOfTools = msg->GetNumberOfQuaternionTrackingDataElements();
198  MITK_INFO << "Found " << numberOfTools << " tools";
199  for (int i = 0; i < numberOfTools; i++)
200  {
202  msg->GetQuaternionTrackingDataElement(i, currentTrackingData);
203  std::string name = currentTrackingData->GetName();
204  AddNewToolForName(name, i);
205  }
206  m_IGTLDeviceSource->StopCommunication();
207  SetState(Ready);
208  return true;
209 }
210 
211 void mitk::OpenIGTLinkTrackingDevice::AddNewToolForName(std::string name, int i)
212 {
214  if (name == "") //if no name was given create a default name
215  {
216  std::stringstream defaultName;
217  defaultName << "OpenIGTLinkTool#" << i;
218  name = defaultName.str();
219  }
220  MITK_INFO << "Added tool " << name << " to tracking device.";
221  newTool->SetToolName(name);
222  InternalAddTool(newTool);
223 }
224 
225 bool mitk::OpenIGTLinkTrackingDevice::DiscoverToolsFromTransform()
226 {
227  MITK_INFO << "Start discovering tools by TRANSFORM messages";
228  std::map<std::string, int> toolNameMap;
229  bool condition = false;
230  while (!condition)
231  {
232  //TODO: Fix this.. :/
233  std::this_thread::sleep_for(std::chrono::milliseconds(20));
234  m_IGTLDeviceSource->Update();
235  igtl::TransformMessage::Pointer msg = dynamic_cast<igtl::TransformMessage*>(m_IGTLDeviceSource->GetOutput()->GetMessage().GetPointer());
236  if (msg == nullptr || msg.IsNull())
237  {
238  MITK_INFO << "Received message could not be casted to TransformMessage. Skipping..";
239  continue;
240  }
241 
242  condition = true;
243  int count = toolNameMap[msg->GetDeviceName()];
244  if (count == 0)
245  {
246  MITK_WARN << "ADDED NEW TOOL TO TOOLCHAIN: " << msg->GetDeviceName() << " - 1";
247  toolNameMap[msg->GetDeviceName()] = 1;
248  }
249  else
250  {
251  toolNameMap[msg->GetDeviceName()]++;
252  MITK_WARN << "INCREMENTED TOOL COUNT IN TOOLCHAIN: " << msg->GetDeviceName() << " - " << toolNameMap[msg->GetDeviceName()];
253  }
254 
255  for (std::map<std::string, int>::iterator it = toolNameMap.begin(); it != toolNameMap.end(); ++it)
256  {
257  if (it->second < 5)
258  {
259  condition = false;
260  break;
261  }
262  }
263  }
264 
265  int i = 0;
266  for (std::map<std::string, int>::iterator it = toolNameMap.begin(); it != toolNameMap.end(); ++it)
267  {
268  AddNewToolForName(it->first, i++);
269  }
270  //TODO InternalAddTool for all tools
271 
272  return true;
273 }
274 
276 {
277  if (this->GetState() != Tracking)
278  {
279  MITK_ERROR << "Method was called in the wrong state, something went wrong!";
280  return;
281  }
282 
283  m_IGTLMsgToNavDataFilter->Update();
284 
285  mitk::NavigationData::Pointer currentNavData = m_IGTLMsgToNavDataFilter->GetOutput();
286  const char* name = currentNavData->GetName();
287  MITK_WARN << name;
288 
289  for (int i = 0; i < m_AllTools.size(); i++)
290  {
291  if (strcmp(m_AllTools.at(i)->GetToolName(), name) == 0)
292  {
293  m_AllTools.at(i)->SetDataValid(currentNavData->IsDataValid());
294  m_AllTools.at(i)->SetPosition(currentNavData->GetPosition());
295  m_AllTools.at(i)->SetOrientation(currentNavData->GetOrientation());
296  m_AllTools.at(i)->SetIGTTimeStamp(currentNavData->GetIGTTimeStamp());
297  }
298  }
299 }
300 
302 {
303  //check tracking state
304  if (this->GetState() != Ready)
305  {
306  MITK_WARN << "Cannot start tracking, device is not ready!";
307  return false;
308  }
309 
310  try
311  {
312  m_IGTLDeviceSource->StartCommunication();
313 
314  //send a message to the server: start tracking stream
315  mitk::IGTLMessageFactory::Pointer msgFactory = m_OpenIGTLinkClient->GetMessageFactory();
316  std::string message = "STT_TDATA";
317  //m_OpenIGTLinkClient->SendMessage(msgFactory->CreateInstance(message));
318  }
319  catch (std::runtime_error &e)
320  {
321  MITK_WARN << "Open IGT Link device retruned an error while starting communication: " << e.what();
322  return false;
323  }
324 
325  //create internal igtl pipeline
326  m_IGTLMsgToNavDataFilter = mitk::IGTLMessageToNavigationDataFilter::New();
327  m_IGTLMsgToNavDataFilter->SetNumberOfExpectedOutputs(this->GetToolCount());
328  m_IGTLMsgToNavDataFilter->ConnectTo(m_IGTLDeviceSource);
329 
330  //connect itk events
331  typedef itk::SimpleMemberCommand< mitk::OpenIGTLinkTrackingDevice > CurCommandType;
332  CurCommandType::Pointer messageReceivedCommand = CurCommandType::New();
333  messageReceivedCommand->SetCallbackFunction(this, &mitk::OpenIGTLinkTrackingDevice::UpdateTools);
334  m_MessageReceivedObserverTag = m_OpenIGTLinkClient->AddObserver(mitk::MessageReceivedEvent(), messageReceivedCommand);
335 
336  this->SetState(Tracking);
337  return true;
338 }
339 
341 {
342  //check tracking state
343  if (this->GetState() != Tracking)
344  {
345  MITK_WARN << "Cannot open connection, device is already connected!";
346  return false;
347  }
348 
349  m_OpenIGTLinkClient->RemoveObserver(m_MessageReceivedObserverTag); //disconnect itk events
350 
351  try
352  {
353  m_IGTLDeviceSource->StopCommunication();
354  }
355  catch (std::runtime_error &e)
356  {
357  MITK_WARN << "Open IGT Link device retruned an error while stopping communication: " << e.what();
358  return false;
359  }
360  this->SetState(Ready);
361  return true;
362 }
363 
365 {
366  return (unsigned int)this->m_AllTools.size();
367 }
368 
370 {
371  if (toolNumber >= this->GetToolCount())
372  return NULL;
373  else
374  return this->m_AllTools[toolNumber];
375 }
376 
378 {
379  //check tracking state
380  if (this->GetState() != Setup)
381  {
382  MITK_WARN << "Cannot open connection, device is already connected!";
383  return false;
384  }
385 
386  try
387  {
388  m_IGTLDeviceSource->Connect();
389  }
390  catch (std::runtime_error &e)
391  {
392  MITK_WARN << "Open IGT Link device retruned an error while trying to connect: " << e.what();
393  return false;
394  }
395  this->SetState(Ready);
396  return true;
397 }
398 
400 {
401  //check tracking state
402  if (this->GetState() != Ready)
403  {
404  MITK_WARN << "Cannot close connection, device is in the wrong state!";
405  return false;
406  }
407 
408  try
409  {
410  m_IGTLDeviceSource->Disconnect();
411  }
412  catch (std::runtime_error &e)
413  {
414  MITK_WARN << "Open IGT Link device retruned an error while trying to disconnect: " << e.what();
415  return false;
416  }
417 
418  this->SetState(Setup);
419 
420  return true;
421 }
422 
423 std::vector<mitk::OpenIGTLinkTrackingTool::Pointer> mitk::OpenIGTLinkTrackingDevice::GetAllTools()
424 {
425  return this->m_AllTools;
426 }
427 
428 mitk::OpenIGTLinkTrackingDevice::TrackingMessageType mitk::OpenIGTLinkTrackingDevice::GetMessageTypeFromString(const char* messageTypeString)
429 {
430  if (strcmp(messageTypeString, "TDATA") == 0)
431  {
432  return mitk::OpenIGTLinkTrackingDevice::TrackingMessageType::TDATA;
433  }
434  else if (strcmp(messageTypeString, "QTDATA") == 0)
435  {
436  return mitk::OpenIGTLinkTrackingDevice::TrackingMessageType::QTDATA;
437  }
438  else if (strcmp(messageTypeString, "TRANSFORM") == 0)
439  {
440  return mitk::OpenIGTLinkTrackingDevice::TrackingMessageType::TRANSFORM;
441  }
442  else
443  {
444  return mitk::OpenIGTLinkTrackingDevice::TrackingMessageType::UNKNOWN;
445  }
446 }
Interface for all Tracking Tools.
itk::SmartPointer< Self > Pointer
TrackingTool * GetTool(unsigned int toolNumber) const
#define MITK_INFO
Definition: mitkLogMacros.h:22
#define MITK_ERROR
Definition: mitkLogMacros.h:24
bool DiscoverTools(int WaitingTime=10000)
Discover the tools available from the connected OpenIGTLink device and adds these tools to this track...
DataCollection - Class to facilitate loading/accessing structured data.
OpenIGTLinkTrackingDevice()
Returns the update rate of the device in fps.
itk::MutexLockHolder< itk::FastMutexLock > MutexLockHolder
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...
#define MITK_WARN
Definition: mitkLogMacros.h:23
virtual bool StopTracking()
Stops the tracking.
virtual bool CloseConnection()
Closes the connection and clears all resources.
Interface for all Tracking Devices.
static TrackingDeviceData GetDeviceDataOpenIGTLinkTrackingDeviceConnection()
TrackingDeviceData m_Data
current device Data
mitk::IGTLTransformDeviceSource::Pointer m_IGTLDeviceSource
std::vector< OpenIGTLinkTrackingTool::Pointer > GetAllTools()
static void Setup()
virtual bool OpenConnection()
Opens the connection to the device. This have to be done before the tracking is started.
bool InternalAddTool(OpenIGTLinkTrackingTool::Pointer tool)
Adds a tool to the tracking device.
virtual bool StartTracking()
Starts the tracking.
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.