PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
AtracsysTracker.cxx
Go to the documentation of this file.
1 /*=Plus=header=begin======================================================
2 Program: Plus
3 Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved.
4 See License.txt for details.
5 =========================================================Plus=header=end*/
6 
7 // Local includes
8 #include "AtracsysTracker.h"
9 
10 // System includes
11 #include <algorithm>
12 #include <cmath>
13 #include <fstream>
14 #include <map>
15 #include <string>
16 
17 // Atracsys includes
18 #include "ftkErrors.h"
19 #include "ftkEvent.h"
20 #include "ftkOptions.h"
21 #include "ftkInterface.h"
22 #include "ftkPlatform.h"
23 #include "ftkTypes.h"
24 
25 #include <igsioCommon.h>
26 
27 #define ATRACSYS_BUFFER_SIZE 1024
28 #define RESET_DROPPED_FRAME_COUNT 1
29 
30 //----------------------------------------------------------------------------
31 // this method from https://thispointer.com/find-and-replace-all-occurrences-of-a-sub-string-in-c/
32 void stringFindAndReplaceAll(std::string& data, std::string toSearch, std::string replaceStr)
33 {
34  // Get the first occurrence
35  size_t pos = data.find(toSearch);
36 
37  // Repeat till end is reached
38  while (pos != std::string::npos)
39  {
40  // Replace this occurrence of Sub String
41  data.replace(pos, toSearch.size(), replaceStr);
42  // Get the next occurrence from the current position
43  pos = data.find(toSearch, pos + replaceStr.size());
44  }
45 }
46 
47 //----------------------------------------------------------------------------
48 bool Atracsys::strToInt32(const std::string& str, int& var)
49 {
50  bool noexception = false;
51  try
52  {
53  var = std::atoi(str.c_str());
54  noexception = true;
55  }
56  catch (std::invalid_argument& e)
57  {
58  LOG_WARNING(std::string("Cannot convert ") + str + std::string(" to int32"));
59  }
60  catch (std::out_of_range& e)
61  {
62  LOG_WARNING(str + std::string(" is out of range for int32"));
63  }
64  return noexception;
65 }
66 
67 //----------------------------------------------------------------------------
68 bool Atracsys::strToFloat32(const std::string& str, float& var)
69 {
70  bool noexception = false;
71  try
72  {
73  var = std::atof(str.c_str());
74  noexception = true;
75  }
76  catch (std::invalid_argument& e)
77  {
78  LOG_WARNING(std::string("Cannot convert ") + str + std::string(" to float"));
79  }
80  catch (std::out_of_range& e)
81  {
82  LOG_WARNING(str + std::string(" is out of range for float"));
83  }
84  return noexception;
85 }
86 
87 //==============================================================================
88 namespace Geometry
89 {
90  class IniFile // Based on code from ATRACSYS
91  {
92  protected:
93  //----------------------------------------------------------------------------
94  long findEOL(char& c, char* addr, size_t size)
95  {
96  for (long u = 0; u < (long)size; u++)
97  {
98  c = addr[u];
99  if (c == 0 || c == '\n') // note that MAX may only have a '\r'
100  {
101  return u;
102  }
103  }
104  return -1;
105  }
106 
107  //----------------------------------------------------------------------------
108  bool parseLine(std::string& line)
109  {
110  size_t first_bracket = line.find_first_of("["),
111  last_bracket = line.find_last_of("]"),
112  equal = line.find_first_of("=");
113 
114  if (first_bracket != std::string::npos &&
115  last_bracket != std::string::npos)
116  {
117  // Found section
118  _currentSection = line.substr(first_bracket + 1,
119  last_bracket - first_bracket - 1);
120  sections[_currentSection] = KeyValues();
121  }
122  else if (equal != std::string::npos && _currentSection != "")
123  {
124  // Found property in a section
125  std::string key = line.substr(0, equal),
126  val = line.substr(equal + 1);
127  sections[_currentSection][key] = val;
128  }
129  else
130  {
131  // If the line is empty, just skip it, if not and is a comment, just
132  // skip it
133  // as well, otherwise the parsing cannot be done.
134  line.erase(remove_if(line.begin(),
135  line.end(), isspace), line.end());
136  if (!line.empty() && line.substr(0, 1) != ";")
137  {
138  return false;
139  }
140  }
141  return true;
142  }
143  std::string _currentSection;
144 
145  public:
146  typedef std::map< std::string, std::string > KeyValues;
147  typedef std::map< std::string, KeyValues > Sections;
148 
149  Sections sections;
150 
151  //----------------------------------------------------------------------------
152  bool parse(char* addr, size_t size)
153  {
154  sections.clear();
155  _currentSection = "";
156 
157  std::string strLine;
158 
159  while (size)
160  {
161  char c;
162  long lineSize = findEOL(c, addr, size);
163 
164  if (lineSize != 0)
165  {
166  strLine = (lineSize > 0) ? std::string(addr, lineSize) : std::string(addr);
167  strLine.erase(remove(strLine.begin(), strLine.end(), '\r'), strLine.end());
168  if (!parseLine(strLine))
169  {
170  return false;
171  }
172 
173  if (lineSize < 0)
174  {
175  return true; // EOF at the end of the line
176  }
177  }
178  if (c == 0 || size == size_t(lineSize))
179  {
180  return true; // !!! eof not reached
181  }
182  addr += lineSize + 1;
183  size -= lineSize + 1;
184  }
185  return true;
186  }
187 
188  //----------------------------------------------------------------------------
189  // Return false in case of syntax error
190  bool save(std::string str)
191  {
192  FILE* file = fopen(str.c_str(), "wb");
193  if (!file)
194  {
195  return false;
196  }
197 
198  Sections::iterator iterS = sections.begin();
199 
200  while (iterS != sections.end())
201  {
202  fprintf(file, "[%s]\n", iterS->first.c_str());
203 
204  KeyValues& kw = iterS->second;
205  KeyValues::iterator iterK = kw.begin();
206 
207  while (iterK != kw.end())
208  {
209  fprintf(file, "%s=%s\n",
210  iterK->first.c_str(), iterK->second.c_str());
211  iterK++;
212  }
213  iterS++;
214  }
215  fclose(file);
216  return true;
217  }
218 
219  //----------------------------------------------------------------------------
220  bool toBuffer(char** out, size_t& outSize)
221  {
222  if (!out)
223  {
224  return false;
225  }
226 
227  std::string buffer;
228  char temp[ATRACSYS_BUFFER_SIZE];
229 
230  Sections::iterator iterS = sections.begin();
231 
232  while (iterS != sections.end())
233  {
234  sprintf(temp, "[%s]\n", iterS->first.c_str());
235  buffer += temp;
236 
237  KeyValues& kw = iterS->second;
238  KeyValues::iterator iterK = kw.begin();
239 
240  while (iterK != kw.end())
241  {
242  sprintf(temp, "%s=%s\n",
243  iterK->first.c_str(), iterK->second.c_str());
244  buffer += temp;
245  iterK++;
246  }
247  iterS++;
248  }
249 
250  outSize = buffer.length() + 1;
251  char* str = new (std::nothrow) char[outSize];
252 
253  if (!str)
254  {
255  return false;
256  }
257 
258  strncpy(str, buffer.c_str(), outSize - 1);
259  str[outSize - 1] = 0;
260  *out = str;
261 
262  return true;
263  } // Buffer must be unallocated by user
264  };
265 
266  //----------------------------------------------------------------------------
267  bool checkSection(IniFile& p, const std::string& section)
268  {
269  if (p.sections.find(section) == p.sections.end())
270  {
271  return false;
272  }
273  return true;
274  }
275 
276  //----------------------------------------------------------------------------
277  bool checkKey(IniFile& p, const std::string& section, const std::string& key)
278  {
279  if (p.sections[section].find(key) == p.sections[section].end())
280  {
281  return false;
282  }
283 
284  return true;
285  }
286 
287  //----------------------------------------------------------------------------
288  bool assignUint32(IniFile& p, const std::string& section, const std::string& key,
289  uint32* variable)
290  {
291  if (!checkKey(p, section, key))
292  {
293  return false;
294  }
295 
296  char* pEnd;
297  std::string val(p.sections[section][key]);
298 
299  *variable = uint32(strtol(val.c_str(), &pEnd, 10));
300 
301  return true;
302  }
303 
304  //----------------------------------------------------------------------------
305  bool assignFloatXX(IniFile& p, const std::string& section, const std::string& key,
306  floatXX* variable)
307  {
308  if (!checkKey(p, section, key))
309  {
310  return false;
311  }
312 
313  char* pEnd;
314 
315  *variable =
316  floatXX(strtod(p.sections[section][key].c_str(), &pEnd));
317 
318  return true;
319  }
320 } // end of Geometry namespace
321 
322 using namespace Atracsys;
323 
324 //==============================================================================
325 class Tracker::Internal
326 {
327 public:
328  Internal()
329  {
330  // populate result to string
331  ResultToStringMap[ERROR_UNABLE_TO_GET_FTK_HANDLE] = "Unable to get Atracsys library handle.";
332  ResultToStringMap[ERROR_NO_DEVICE_CONNECTED] = "No Atracsys device connected.";
333  ResultToStringMap[ERROR_UNABLE_TO_LOAD_MARKER] = "Unable to load marker.";
334  ResultToStringMap[ERROR_FAILURE_TO_LOAD_INI] = "Failed to load marker's ini file.";
335  ResultToStringMap[ERROR_OPTION_AVAILABLE_ONLY_ON_FTK] = "Attempted to call fusionTrack only option with non-fusionTrack device connected.";
336  ResultToStringMap[ERROR_OPTION_AVAILABLE_ONLY_ON_STK] = "Attempted to call spryTrack only option with non-spryTrack device connected.";
337  ResultToStringMap[ERROR_FAILED_TO_CLOSE_SDK] = "Failed to close the Atracsys SDK.";
338  ResultToStringMap[ERROR_FAILED_TO_EXPORT_CALIB] = "Failed to export cameras calibration.";
339  ResultToStringMap[ERROR_FAILED_TO_EXTRACT_FRAME_INFO] = "Failed to extract frame info.";
340  ResultToStringMap[ERROR_CANNOT_CREATE_FRAME_INSTANCE] = "Failed to create frame.";
341  ResultToStringMap[ERROR_CANNOT_INITIALIZE_FRAME] = "Failed to initialize frame.";
342  ResultToStringMap[ERROR_NO_FRAME_AVAILABLE] = "No frame available from tracker.";
343  ResultToStringMap[ERROR_INVALID_FRAME] = "Invalid frame received from tracker.";
344  ResultToStringMap[ERROR_TOO_MANY_MARKERS] = "Too many markers in frame.";
345  ResultToStringMap[ERROR_ENABLE_LASER] = "Failed to enable laser, this is a spryTrack only option.";
346  ResultToStringMap[ERROR_SET_USER_LED] = "Failed to set the user LED.";
347  ResultToStringMap[ERROR_ENABLE_USER_LED] = "Failed to enable / disable the user LED.";
348  ResultToStringMap[ERROR_ENABLE_IMAGE_STREAMING] = "Failed to enable / disable image streaming.";
349  ResultToStringMap[ERROR_ENABLE_WIRELESS_MARKER_PAIRING] = "Failed to enable / disable wireless marker pairing.";
350  ResultToStringMap[ERROR_ENABLE_WIRELESS_MARKER_STATUS_STREAMING] = "Failed to enable / disable wireless marker status streaming.";
351  ResultToStringMap[ERROR_ENABLE_WIRELESS_MARKER_BATTERY_STREAMING] = "Failed to enable / disable wireless marker battery streaming.";
352  ResultToStringMap[ERROR_DISCONNECT_ATTEMPT_WHEN_NOT_CONNECTED] = "Disconnect called when not connected to tracker.";
353  ResultToStringMap[ERROR_CANNOT_GET_MARKER_INFO] = "Cannot get info about paired wireless markers.";
354  ResultToStringMap[ERROR_FAILED_TO_SET_STK_PROCESSING_TYPE] = "Failed to set spryTrack image processing type.";
355  }
356 
357  virtual ~Internal()
358  {
359  FtkLib = nullptr;
360  LibVersion = "";
361  CalibrationDate = "";
362  TrackerSN = 0;
363  }
364 
365  // is virtual device or not
366  bool isVirtual = false;
367 
368  // is paused or not
369  bool isPaused = true;
370 
371  // handle to FtkLib library
372  ftkLibrary FtkLib = nullptr;
373 
374  // library version
375  std::string LibVersion;
376 
377  // calibration date
378  std::string CalibrationDate;
379 
380  // serial number of tracker
381  uint64 TrackerSN = 0;
382 
383  // ftk frame data
384  ftkFrameQuery* Frame = nullptr;
385 
386  // mapping error code to user readable result string
387  std::map<RESULT, std::string> ResultToStringMap;
388 
389  // helper function to load ftkGeometry from file
390  RESULT LoadFtkGeometryFromFile(const std::string& filename, ftkGeometry& geom);
391 
392  // helper function to load ftkGeometry from string
393  RESULT LoadFtkGeometryFromString(const std::string& geomString, ftkGeometry& geom);
394 
395  std::map<int, std::vector<std::array<float, 3>>> Geometries;
396 
397  // correspondence between atracsys option name and its actual id in the sdk
398  // this map is filled automatically by the sdk, DO NOT hardcode/change any id
399  std::map<std::string, ftkOptionsInfo> DeviceOptionMap{};
400 
401  //----------------------------------------------------------------------------
402  // callback function stores all option id
403  static void DeviceOptionEnumerator(uint64_t serialNumber, void* userData, ftkOptionsInfo* option)
404  {
405  Tracker::Internal* ptr =
406  reinterpret_cast<Tracker::Internal*>(userData);
407  if (!ptr)
408  {
409  return;
410  }
411  ptr->DeviceOptionMap.emplace(option->name, *option);
412  }
413 
414  //----------------------------------------------------------------------------
415  bool LoadIniFile(std::ifstream& is, ftkGeometry& geometry)
416  {
417  std::string line, fileContent("");
418 
419  while (!is.eof())
420  {
421  getline(is, line);
422  fileContent += line + "\n";
423  }
424 
425  return ParseIniFile(fileContent, geometry);
426  }
427 
428  //----------------------------------------------------------------------------
429  bool ParseIniFile(std::string fileContent, ftkGeometry& geometry)
430  {
431  stringFindAndReplaceAll(fileContent, "\\n", "\n");
432 
433  Geometry::IniFile parser;
434 
435  if (!parser.parse(const_cast<char*>(fileContent.c_str()),
436  fileContent.size()))
437  {
438  return false;
439  }
440 
441  if (!checkSection(parser, "geometry"))
442  {
443  return false;
444  }
445 
446  uint32 tmp;
447 
448  if (!assignUint32(parser, "geometry", "count", &tmp))
449  {
450  return false;
451  }
452  geometry.version = 0u;
453  geometry.pointsCount = tmp;
454  if (!assignUint32(parser, "geometry", "id", &geometry.geometryId))
455  {
456  return false;
457  }
458 
459  char sectionName[10u];
460 
461  for (uint32 i(0u); i < geometry.pointsCount; ++i)
462  {
463  sprintf(sectionName, "fiducial%u", i);
464 
465  if (!checkSection(parser, sectionName))
466  {
467  return false;
468  }
469 
470  if (!assignFloatXX(parser, sectionName, "x",
471  &geometry.positions[i].x))
472  {
473  return false;
474  }
475  if (!assignFloatXX(parser, sectionName, "y",
476  &geometry.positions[i].y))
477  {
478  return false;
479  }
480  if (!assignFloatXX(parser, sectionName, "z",
481  &geometry.positions[i].z))
482  {
483  return false;
484  }
485  }
486 
487  std::vector<std::array<float, 3>> pts;
488  for (uint32 i(0u); i < geometry.pointsCount; ++i)
489  {
490  std::array<float, 3> pt = { geometry.positions[i].x, geometry.positions[i].y, geometry.positions[i].z };
491  pts.push_back(pt);
492  }
493  this->Geometries[geometry.geometryId] = pts;
494 
495  return true;
496  }
497 }; // end of Tracker::Internal
498 
499 //----------------------------------------------------------------------------
500 struct DeviceData
501 {
502  uint64 SerialNumber;
503  ftkDeviceType Type;
504 };
505 
506 //----------------------------------------------------------------------------
507 void FusionTrackEnumerator(uint64 sn, void* user, ftkDeviceType devType)
508 {
509  if (user != 0)
510  {
511  DeviceData* ptr = reinterpret_cast<DeviceData*>(user);
512  ptr->SerialNumber = sn;
513  ptr->Type = devType;
514  }
515 }
516 
517 //----------------------------------------------------------------------------
518 Tracker::RESULT Tracker::Internal::LoadFtkGeometryFromFile(const std::string& filename, ftkGeometry& geom)
519 {
520  std::ifstream input;
521  input.open(filename.c_str());
522 
523  if (!input.fail() && this->LoadIniFile(input, geom))
524  {
525  return ERROR_FAILURE_TO_LOAD_INI;
526  }
527  else
528  {
529  ftkBuffer buffer;
530  buffer.reset();
531  if (ftkGetData(this->FtkLib, this->TrackerSN, this->DeviceOptionMap["Data Directory"].id, &buffer) != ftkError::FTK_OK || buffer.size < 1u)
532  {
533  return ERROR_FAILURE_TO_LOAD_INI;
534  }
535 
536  std::string fullFile(reinterpret_cast<char*>(buffer.data));
537  fullFile += "\\" + filename;
538 
539  input.open(fullFile.c_str());
540 
541  if (!input.fail() && this->LoadIniFile(input, geom))
542  {
543  return SUCCESS;
544  }
545  }
546 
547  return ERROR_FAILURE_TO_LOAD_INI;
548 }
549 
550 //----------------------------------------------------------------------------
551 Tracker::RESULT Tracker::Internal::LoadFtkGeometryFromString(const std::string& geomString, ftkGeometry& geom)
552 {
553  if (this->ParseIniFile(geomString, geom))
554  {
555  return SUCCESS;
556  }
557  return ERROR_FAILURE_TO_LOAD_INI;
558 }
559 
560 //----------------------------------------------------------------------------
561 // provided an option name with Atracsys' nomenclature, this method returns the pointer
562 // to the corresponding ftkOptionsInfo which contains various information about the option
563 // (notably its id and value type)
564 bool Tracker::GetOptionInfo(const std::string& optionName, const ftkOptionsInfo*& info)
565 {
566  std::map<std::string, ftkOptionsInfo>::const_iterator it = this->InternalObj->DeviceOptionMap.find(optionName);
567  if (it == this->InternalObj->DeviceOptionMap.cend())
568  {
569  return false;
570  }
571  else
572  {
573  info = &(it->second);
574  return true;
575  }
576 }
577 
578 //----------------------------------------------------------------------------
579 // this method sets a value to an option in the device. The option name follows Atracsys' nomenclature.
580 Tracker::RESULT Tracker::SetOption(const std::string& optionName, const std::string& attributeValue)
581 {
582  if (this->InternalObj->isVirtual)
583  {
584  return SUCCESS;
585  }
586 
587  std::string optionStr{ optionName };
588  // if Embedded processing is on and the option has an Embedded variant, add the prefix
589  if (isOnboardProcessing && this->InternalObj->DeviceOptionMap.find("Embedded " + optionName) != this->InternalObj->DeviceOptionMap.end())
590  {
591  optionStr = "Embedded " + optionStr;
592  }
593 
594  const ftkOptionsInfo* info;
595 
596  if (!this->GetOptionInfo(optionStr, info))
597  {
598  LOG_WARNING(std::string("Info for option \"") + optionStr + std::string("\" not found."));
599  return ERROR_OPTION_NOT_FOUND;
600  }
601 
602  if (info->type == ftkOptionType::FTK_INT32)
603  {
604  int32_t val;
605  if (!strToInt32(attributeValue, val))
606  {
607  return ERROR_SET_OPTION;
608  }
609 
610  if (ftkSetInt32(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, info->id, val) != ftkError::FTK_OK)
611  {
612  ftkBuffer buffer{};
613  if (ftkGetLastErrorString(this->InternalObj->FtkLib, sizeof(buffer.data), buffer.data) == ftkError::FTK_OK)
614  {
615  LOG_WARNING(std::string(buffer.data));
616  }
617  else
618  {
619  LOG_WARNING(std::string("Unknown error setting option ") + optionStr);
620  }
621  }
622  }
623  else if (info->type == ftkOptionType::FTK_FLOAT32)
624  {
625  float_t val;
626  if (!strToFloat32(attributeValue, val))
627  {
628  return ERROR_SET_OPTION;
629  }
630 
631  if (ftkSetFloat32(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, info->id, val) != ftkError::FTK_OK)
632  {
633  ftkBuffer buffer{};
634  if (ftkGetLastErrorString(this->InternalObj->FtkLib, sizeof(buffer.data), buffer.data) == ftkError::FTK_OK)
635  {
636  LOG_WARNING(std::string(buffer.data));
637  }
638  else
639  {
640  LOG_WARNING(std::string("Unknown error setting option ") + optionStr);
641  }
642  }
643  }
644  else if (info->type == ftkOptionType::FTK_DATA)
645  {
646  LOG_WARNING(std::string("Option of type \"data\" not supported yet"));
647  }
648  LOG_INFO(std::string("Option \"") + optionStr + std::string("\" successfully set at value ") + attributeValue);
649 
650  return SUCCESS;
651 }
652 
653 // ------------------------------------------
654 // universally available options & methods
655 // ------------------------------------------
656 
658  : InternalObj(new Internal()) {}
659 
661 {
662  delete InternalObj;
663  InternalObj = nullptr;
664 }
665 
666 //----------------------------------------------------------------------------
667 void Tracker::Pause(bool tof)
668 {
669  this->InternalObj->isPaused = tof;
670 }
671 
672 //----------------------------------------------------------------------------
674 {
675  return isOnboardProcessing;
676 }
677 
678 //----------------------------------------------------------------------------
680 {
681  return this->InternalObj->isVirtual;
682 }
683 
684 //----------------------------------------------------------------------------
686 {
687  if (this->InternalObj->FtkLib != nullptr && this->InternalObj->TrackerSN != 0)
688  {
689  // already connected
690  return SUCCESS;
691  }
692 
693  // initialize SDK
694  this->InternalObj->FtkLib = ftkInit();
695 
696  if (this->InternalObj->FtkLib == NULL)
697  {
699  }
700 
701  DeviceData device;
702  device.SerialNumber = 0uLL;
703 
704  // scan for devices
705  ftkError err = ftkEnumerateDevices(this->InternalObj->FtkLib, FusionTrackEnumerator, &device);
706  if (err != ftkError::FTK_OK && err != ftkError::FTK_WAR_USB_TOO_SLOW)
707  {
708  ftkClose(&this->InternalObj->FtkLib);
709  this->InternalObj->FtkLib = nullptr;
711  }
712 
713  if (device.SerialNumber == 0uLL)
714  {
715  ftkClose(&this->InternalObj->FtkLib);
716  this->InternalObj->FtkLib = nullptr;
718  }
719 
720  this->InternalObj->TrackerSN = device.SerialNumber;
721 
722  ftkBuffer sdkVersion;
723  ftkVersion(&sdkVersion);
724  this->InternalObj->LibVersion = sdkVersion.data;
725 
726  switch (device.Type)
727  {
728  case ftkDeviceType::DEV_SPRYTRACK_180:
729  this->DeviceType = SPRYTRACK_180;
730  break;
731  case ftkDeviceType::DEV_SPRYTRACK_300:
732  this->DeviceType = SPRYTRACK_300;
733  break;
734  case ftkDeviceType::DEV_FUSIONTRACK_500:
735  this->DeviceType = FUSIONTRACK_500;
736  break;
737  case ftkDeviceType::DEV_FUSIONTRACK_250:
738  this->DeviceType = FUSIONTRACK_250;
739  break;
740  default:
741  this->DeviceType = UNKNOWN_DEVICE;
742  }
743 
744  // allocate memory for ftk frame to be used throughout life of the object
745  this->InternalObj->Frame = ftkCreateFrame();
746 
747  if (this->InternalObj->Frame == nullptr)
748  {
749  ftkDeleteFrame(this->InternalObj->Frame);
750  this->InternalObj->Frame = nullptr;
752  }
753 
754  if (ftkSetFrameOptions(false, this->MaxAdditionalEventsNumber,
755  this->Max2dFiducialsNumber, this->Max2dFiducialsNumber,
756  this->Max3dFiducialsNumber, this->MaxMarkersNumber,
757  this->InternalObj->Frame) != ftkError::FTK_OK)
758  {
759  ftkDeleteFrame(this->InternalObj->Frame);
760  this->InternalObj->Frame = nullptr;
762  }
763 
764  if (ftkEnumerateOptions(this->InternalObj->FtkLib, this->InternalObj->TrackerSN,
765  &Tracker::Internal::DeviceOptionEnumerator, this->InternalObj) != ftkError::FTK_OK
766  || this->InternalObj->DeviceOptionMap.find("Data Directory") == this->InternalObj->DeviceOptionMap.cend())
767  {
768  return ERROR_OPTION_NOT_FOUND;
769  }
770 
771  // Needs to be after the device option enumeration
772  const ftkOptionsInfo* info;
773  if (!this->GetOptionInfo("Calibration processing datetime", info))
774  {
775  LOG_ERROR("Option unknown: \"Calibration processing datetime\"");
776  return ERROR_OPTION_NOT_FOUND;
777  }
778  ftkBuffer buff;
779  ftkGetData(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, info->id, &buff);
780  this->InternalObj->CalibrationDate = std::string(buff.data);
781 
782  // Check whether onboard processing is off or on (spryTrack only)
783  if (this->DeviceType == SPRYTRACK_180 || this->DeviceType == SPRYTRACK_300)
784  {
785  if (!this->GetOptionInfo("Enable embedded processing", info))
786  {
787  LOG_WARNING(std::string("Embedded processing not part of the option list."));
788  return ERROR_OPTION_NOT_FOUND;
789  }
790  else
791  {
792  int32 val;
793  ftkGetInt32(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, info->id, &val, ftkOptionGetter::FTK_VALUE);
794  isOnboardProcessing = (val == 1) ? true : false;
795  LOG_INFO("Embedded processing is initially " << (isOnboardProcessing ? "enabled" : "disabled"));
796  }
797  }
798 
799  return SUCCESS;
800 }
801 
802 //----------------------------------------------------------------------------
804 {
805  if (this->InternalObj->isVirtual)
806  {
807  return SUCCESS;
808  }
809 
810  if (this->InternalObj->FtkLib == nullptr && this->InternalObj->TrackerSN == 0)
811  {
813  }
814 
815  // de-allocate memory for frame
816  ftkDeleteFrame(this->InternalObj->Frame);
817  this->InternalObj->Frame = nullptr;
818 
819  ftkError err = ftkClose(&this->InternalObj->FtkLib);
820  if (err != ftkError::FTK_OK)
821  {
823  }
824  return SUCCESS;
825 }
826 
827 //----------------------------------------------------------------------------
829 {
830  version = this->InternalObj->LibVersion;
831  return SUCCESS;
832 }
833 
834 //----------------------------------------------------------------------------
836 {
837  date = this->InternalObj->CalibrationDate;
838  return SUCCESS;
839 }
840 
841 //----------------------------------------------------------------------------
843 {
844  deviceType = this->DeviceType;
845  return SUCCESS;
846 }
847 
848 //----------------------------------------------------------------------------
850  std::array<float, 10>& leftIntrinsic, std::array<float, 10>& rightIntrinsic,
851  std::array<float, 3>& rightPosition, std::array<float, 3>& rightOrientation)
852 {
853  if (!this->InternalObj->isVirtual || this->SetOption("Calibration export", "1") != SUCCESS)
854  {
855  LOG_ERROR("Could not export calibration.");
857  }
858  else
859  {
860  if (ftkGetLastFrame(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, this->InternalObj->Frame, 20) != ftkError::FTK_OK)
861  {
863  }
864  else
865  {
866  ftkFrameInfoData info;
867  info.WantedInformation = ftkInformationType::CalibrationParameters;
868  if (ftkExtractFrameInfo(this->InternalObj->Frame, &info) != ftkError::FTK_OK)
869  {
871  }
872  else
873  {
874  ftkStereoParameters sps = info.Calibration;
875  leftIntrinsic = { sps.LeftCamera.FocalLength[0], sps.LeftCamera.FocalLength[1],
876  sps.LeftCamera.OpticalCentre[0], sps.LeftCamera.OpticalCentre[1],
877  sps.LeftCamera.Distorsions[0], sps.LeftCamera.Distorsions[1], sps.LeftCamera.Distorsions[2],
878  sps.LeftCamera.Distorsions[3], sps.LeftCamera.Distorsions[4], sps.LeftCamera.Skew };
879  rightIntrinsic = { sps.RightCamera.FocalLength[0], sps.RightCamera.FocalLength[1],
880  sps.RightCamera.OpticalCentre[0], sps.RightCamera.OpticalCentre[1],
881  sps.RightCamera.Distorsions[0], sps.RightCamera.Distorsions[1], sps.RightCamera.Distorsions[2],
882  sps.RightCamera.Distorsions[3], sps.RightCamera.Distorsions[4], sps.RightCamera.Skew };
883  rightPosition = { sps.Translation[0], sps.Translation[1], sps.Translation[2] };
884  rightOrientation = { sps.Rotation[0], sps.Rotation[1], sps.Rotation[2] };
885  }
886  }
887  }
888  return SUCCESS;
889 }
890 
891 //----------------------------------------------------------------------------
893 {
894  id = this->InternalObj->TrackerSN;
895  return SUCCESS;
896 }
897 
898 //----------------------------------------------------------------------------
899 Tracker::RESULT Tracker::LoadMarkerGeometryFromFile(std::string filePath, int& geometryId)
900 {
901  ftkGeometry geom;
902  this->InternalObj->LoadFtkGeometryFromFile(filePath, geom);
903  if (!this->InternalObj->isVirtual &&
904  ftkSetGeometry(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, &geom) != ftkError::FTK_OK)
905  {
907  }
908  geometryId = geom.geometryId;
909  return SUCCESS;
910 }
911 
912 //----------------------------------------------------------------------------
913 Tracker::RESULT Tracker::LoadMarkerGeometryFromString(std::string geomString, int& geometryId)
914 {
915  ftkGeometry geom;
916  this->InternalObj->LoadFtkGeometryFromString(geomString, geom);
917  if (!this->InternalObj->isVirtual &&
918  ftkSetGeometry(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, &geom) != ftkError::FTK_OK)
919  {
921  }
922  geometryId = geom.geometryId;
923  return SUCCESS;
924 }
925 
926 //----------------------------------------------------------------------------
927 Tracker::RESULT Tracker::GetMarkerInfo(std::string& markerInfo)
928 {
929  if (this->InternalObj->isVirtual)
930  {
932  }
933 
934  // get correct device option number
935  const ftkOptionsInfo* info;
936  if (!this->GetOptionInfo("Active Wireless Markers info", info))
937  {
938  return ERROR_OPTION_NOT_FOUND;
939  }
940 
941  ftkBuffer buffer;
942  if (ftkGetData(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, info->id, &buffer) != ftkError::FTK_OK)
943  {
945  }
946  markerInfo = std::string(buffer.data, buffer.data + buffer.size);
947  return SUCCESS;
948 }
949 
950 //----------------------------------------------------------------------------
951 Tracker::RESULT Tracker::GetLoadedGeometries(std::map<int, std::vector<std::array<float, 3>>>& geometries)
952 {
953  geometries = this->InternalObj->Geometries;
954  return SUCCESS;
955 }
956 
957 //----------------------------------------------------------------------------
959 {
960  std::map<Tracker::RESULT, std::string>::iterator it;
961  it = this->InternalObj->ResultToStringMap.find(result);
962  if (it != std::end(this->InternalObj->ResultToStringMap))
963  {
964  return it->second;
965  }
966  return std::string("Unknown error has occured. Result value: " + result);
967 }
968 
969 //----------------------------------------------------------------------------
970 Tracker::RESULT Tracker::GetFiducialsInFrame(std::vector<Fiducial>& fiducials,
971  std::map<std::string, std::string>& events, uint64_t& sdkTimestamp)
972 {
973  ftkError err = ftkGetLastFrame(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, this->InternalObj->Frame, 20);
974  if (err != ftkError::FTK_OK)
975  {
977  }
978 
979  switch (this->InternalObj->Frame->markersStat)
980  {
981  case ftkQueryStatus::QS_WAR_SKIPPED:
982  return ERROR_INVALID_FRAME;
983  case ftkQueryStatus::QS_ERR_INVALID_RESERVED_SIZE:
984  return ERROR_INVALID_FRAME;
985  case ftkQueryStatus::QS_OK:
986  break;
987  default:
988  return ERROR_INVALID_FRAME;
989  }
990 
991  if (this->InternalObj->Frame->markersStat == ftkQueryStatus::QS_ERR_OVERFLOW)
992  {
993  return ERROR_TOO_MANY_MARKERS;
994  }
995 
996  // make sure fiducials vector is empty before populating
997  fiducials.clear();
998 
999  for (uint32 f = 0; f < this->InternalObj->Frame->threeDFiducialsCount; f++)
1000  {
1001  Fiducial fid;
1002  // 3D stuff
1003  const ftk3DFiducial& ftkFid3d = this->InternalObj->Frame->threeDFiducials[f];
1004  fid.Fid3dStatus = ftkFid3d.status;
1005  fid.xMm = ftkFid3d.positionMM.x;
1006  fid.yMm = ftkFid3d.positionMM.y;
1007  fid.zMm = ftkFid3d.positionMM.z;
1008  fid.epipolarErrorPx = ftkFid3d.epipolarErrorPixels;
1009  fid.probability = ftkFid3d.probability;
1010  fid.triangulErrorMm = ftkFid3d.triangulationErrorMM;
1011  // Left 2D stuff
1012  const ftkRawData& leftRaw = this->InternalObj->Frame->rawDataLeft[ftkFid3d.leftIndex];
1013  fid.Fid2dLeftStatus = leftRaw.status;
1014  fid.xLeftPx = leftRaw.centerXPixels;
1015  fid.yLeftPx = leftRaw.centerYPixels;
1016  fid.heightLeftPx = leftRaw.height;
1017  fid.widthLeftPx = leftRaw.width;
1018  fid.pixCountLeft = leftRaw.pixelsCount;
1019  // Right 2D stuff
1020  const ftkRawData& rightRaw = this->InternalObj->Frame->rawDataRight[ftkFid3d.rightIndex];
1021  fid.Fid2dRightStatus = rightRaw.status;
1022  fid.xRightPx = rightRaw.centerXPixels;
1023  fid.yRightPx = rightRaw.centerYPixels;
1024  fid.heightRightPx = rightRaw.height;
1025  fid.widthRightPx = rightRaw.width;
1026  fid.pixCountRight = rightRaw.pixelsCount;
1027 
1028  fiducials.push_back(fid);
1029  }
1030 
1031  // make sure events map is empty before populating
1032  events.clear();
1033 
1034  // Parse events
1035  for (size_t e = 0; e < this->InternalObj->Frame->eventsCount; e++)
1036  {
1037  const ftkEvent& event = *this->InternalObj->Frame->events[e];
1038 
1039  if (event.Type == FtkEventType::fetTempV4)
1040  {
1041  std::stringstream ss;
1042  const EvtTemperatureV4Payload* ptr = reinterpret_cast<EvtTemperatureV4Payload*>(event.Data);
1043  for (unsigned int i = 0; i < event.Payload / sizeof(EvtTemperatureV4Payload) - 1; i++, ++ptr)
1044  {
1045  ss << ptr->SensorId << " " << ptr->SensorValue << " ";
1046  }
1047  ss << ptr->SensorId << " " << ptr->SensorValue;
1048  events.emplace("tempv4", ss.str());
1049  }
1050  }
1051 
1052  // Save sdk timestamp
1053  sdkTimestamp = this->InternalObj->Frame->imageHeader->timestampUS;
1054 
1055  return SUCCESS;
1056 }
1057 
1058 //----------------------------------------------------------------------------
1059 Tracker::RESULT Tracker::GetMarkersInFrame(std::vector<Marker>& markers,
1060  std::map<std::string, std::string>& events, uint64_t& sdkTimestamp)
1061 {
1062  ftkError err = ftkGetLastFrame(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, this->InternalObj->Frame, 20);
1063  if (err != ftkError::FTK_OK)
1064  {
1065  return ERROR_NO_FRAME_AVAILABLE;
1066  }
1067 
1068  switch (this->InternalObj->Frame->markersStat)
1069  {
1070  case ftkQueryStatus::QS_WAR_SKIPPED:
1071  return ERROR_INVALID_FRAME;
1072  case ftkQueryStatus::QS_ERR_INVALID_RESERVED_SIZE:
1073  return ERROR_INVALID_FRAME;
1074  case ftkQueryStatus::QS_OK:
1075  break;
1076  default:
1077  return ERROR_INVALID_FRAME;
1078  }
1079 
1080  if (this->InternalObj->Frame->markersStat == ftkQueryStatus::QS_ERR_OVERFLOW)
1081  {
1082  return ERROR_TOO_MANY_MARKERS;
1083  }
1084 
1085  // make sure markers vector is empty before populating
1086  markers.clear();
1087 
1088  for (size_t m = 0; m < this->InternalObj->Frame->markersCount; m++)
1089  {
1090  const ftkMarker& marker = this->InternalObj->Frame->markers[m];
1091 
1092  // A marker
1093  vtkNew<vtkMatrix4x4> toolToTracker;
1094  for (int row = 0; row < 3; row++)
1095  {
1096  toolToTracker->SetElement(row, 3, marker.translationMM[row]);
1097  for (int column = 0; column < 3; column++)
1098  {
1099  toolToTracker->SetElement(row, column, marker.rotation[row][column]);
1100  }
1101  }
1102 
1103  Marker atracsysMarker(marker.status, marker.id, marker.geometryId,
1104  toolToTracker.GetPointer(), marker.geometryPresenceMask, marker.registrationErrorMM);
1105 
1106  // Add the corresponding 3D fiducials
1107  for (size_t f3 = 0; f3 < FTK_MAX_FIDUCIALS; f3++)
1108  {
1109  const uint32 f = marker.fiducialCorresp[f3];
1110  if (f == INVALID_ID) // no more 3D fids for this marker
1111  {
1112  continue;
1113  }
1114  else
1115  {
1116  Fiducial fid;
1117  // 3D stuff
1118  const ftk3DFiducial& ftkFid3d = this->InternalObj->Frame->threeDFiducials[f];
1119  fid.Fid3dStatus = ftkFid3d.status;
1120  fid.xMm = ftkFid3d.positionMM.x;
1121  fid.yMm = ftkFid3d.positionMM.y;
1122  fid.zMm = ftkFid3d.positionMM.z;
1123  fid.epipolarErrorPx = ftkFid3d.epipolarErrorPixels;
1124  fid.probability = ftkFid3d.probability;
1125  fid.triangulErrorMm = ftkFid3d.triangulationErrorMM;
1126  // Left 2D stuff
1127  const ftkRawData& leftRaw = this->InternalObj->Frame->rawDataLeft[ftkFid3d.leftIndex];
1128  fid.Fid2dLeftStatus = leftRaw.status;
1129  fid.xLeftPx = leftRaw.centerXPixels;
1130  fid.yLeftPx = leftRaw.centerYPixels;
1131  fid.heightLeftPx = leftRaw.height;
1132  fid.widthLeftPx = leftRaw.width;
1133  fid.pixCountLeft = leftRaw.pixelsCount;
1134  // Right 2D stuff
1135  const ftkRawData& rightRaw = this->InternalObj->Frame->rawDataRight[ftkFid3d.rightIndex];
1136  fid.Fid2dRightStatus = rightRaw.status;
1137  fid.xRightPx = rightRaw.centerXPixels;
1138  fid.yRightPx = rightRaw.centerYPixels;
1139  fid.heightRightPx = rightRaw.height;
1140  fid.widthRightPx = rightRaw.width;
1141  fid.pixCountRight = rightRaw.pixelsCount;
1142 
1143  if (!atracsysMarker.AddFiducial(fid))
1144  {
1145  return ERROR_TOO_MANY_FIDUCIALS;
1146  }
1147  }
1148  }
1149  markers.push_back(atracsysMarker);
1150  }
1151 
1152  // make sure events map is empty before populating
1153  events.clear();
1154 
1155  // Parse events
1156  for (size_t e = 0; e < this->InternalObj->Frame->eventsCount; e++)
1157  {
1158  const ftkEvent& event = *this->InternalObj->Frame->events[e];
1159 
1160  if (event.Type == FtkEventType::fetTempV4)
1161  {
1162  std::stringstream ss;
1163  const EvtTemperatureV4Payload* ptr = reinterpret_cast<EvtTemperatureV4Payload*>(event.Data);
1164  for (unsigned int i = 0; i < event.Payload / sizeof(EvtTemperatureV4Payload) - 1; i++, ++ptr)
1165  {
1166  ss << ptr->SensorId << " " << ptr->SensorValue << " ";
1167  }
1168  ss << ptr->SensorId << " " << ptr->SensorValue;
1169  events.emplace("tempv4", ss.str());
1170  }
1171  }
1172 
1173  // Save sdk timestamp
1174  sdkTimestamp = this->InternalObj->Frame->imageHeader->timestampUS;
1175 
1176  return SUCCESS;
1177 }
1178 
1179 //----------------------------------------------------------------------------
1180 Tracker::RESULT Tracker::SetUserLEDState(int red, int green, int blue, int frequency, bool enabled /* = true */)
1181 {
1182  if (this->InternalObj->isVirtual)
1183  {
1184  return SUCCESS;
1185  }
1186 
1187  // get correct device option number
1188  const ftkOptionsInfo* info;
1189  if (!this->GetOptionInfo("User-LED frequency", info))
1190  {
1191  return ERROR_OPTION_NOT_FOUND;
1192  }
1193  if (ftkSetInt32(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, info->id, frequency) != ftkError::FTK_OK)
1194  {
1195  return ERROR_SET_USER_LED;
1196  }
1197  if (!this->GetOptionInfo("User-LED red component", info))
1198  {
1199  return ERROR_OPTION_NOT_FOUND;
1200  }
1201  if (ftkSetInt32(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, info->id, red) != ftkError::FTK_OK)
1202  {
1203  return ERROR_SET_USER_LED;
1204  }
1205  if (!this->GetOptionInfo("User-LED green component", info))
1206  {
1207  return ERROR_OPTION_NOT_FOUND;
1208  }
1209  if (ftkSetInt32(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, info->id, green) != ftkError::FTK_OK)
1210  {
1211  return ERROR_SET_USER_LED;
1212  }
1213  if (!this->GetOptionInfo("User-LED blue component", info))
1214  {
1215  return ERROR_OPTION_NOT_FOUND;
1216  }
1217  if (ftkSetInt32(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, info->id, blue) != ftkError::FTK_OK)
1218  {
1219  return ERROR_SET_USER_LED;
1220  }
1221  // enable user LED
1222  return this->EnableUserLED(enabled);
1223 }
1224 
1225 //----------------------------------------------------------------------------
1227 {
1228  if (this->InternalObj->isVirtual)
1229  {
1230  return SUCCESS;
1231  }
1232 
1233  // get correct device option number
1234  const ftkOptionsInfo* info;
1235  if (!this->GetOptionInfo("Enables the user-LED", info))
1236  {
1237  return ERROR_OPTION_NOT_FOUND;
1238  }
1239  if (ftkSetInt32(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, info->id, enabled) != ftkError::FTK_OK)
1240  {
1241  return ERROR_ENABLE_USER_LED;
1242  }
1243  return SUCCESS;
1244 }
1245 
1246 //----------------------------------------------------------------------------
1248 {
1249  if (this->InternalObj->isVirtual)
1250  {
1251  return SUCCESS;
1252  }
1253 
1254  // get correct device option number
1255  const ftkOptionsInfo* info;
1256  if (!this->GetOptionInfo("Enables lasers", info))
1257  {
1258  return ERROR_OPTION_NOT_FOUND;
1259  }
1260 
1261  int laserEnabledValue = enabled ? 3 : 0; // 3 = both lasers on
1262 
1263  if (ftkSetInt32(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, info->id, laserEnabledValue) != ftkError::FTK_OK)
1264  {
1265  return ERROR_ENABLE_LASER;
1266  }
1267  return SUCCESS;
1268 }
1269 
1270 //----------------------------------------------------------------------------
1272 {
1273  if (this->InternalObj->isVirtual)
1274  {
1275  return SUCCESS;
1276  }
1277 
1278  // get correct device option number
1279  const ftkOptionsInfo* info;
1280  if (!this->GetOptionInfo("Active Wireless Pairing Enable", info))
1281  {
1282  return ERROR_OPTION_NOT_FOUND;
1283  }
1284 
1285  if (ftkSetInt32(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, info->id, enabled) != ftkError::FTK_OK)
1286  {
1288  }
1289  return SUCCESS;
1290 }
1291 
1292 //----------------------------------------------------------------------------
1294 {
1295  if (this->InternalObj->isVirtual)
1296  {
1297  return SUCCESS;
1298  }
1299 
1300  // get correct device option number
1301  const ftkOptionsInfo* info;
1302  if (!this->GetOptionInfo("Active Wireless button statuses streaming", info))
1303  {
1304  return ERROR_OPTION_NOT_FOUND;
1305  }
1306 
1307  if (ftkSetInt32(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, info->id, enabled) != ftkError::FTK_OK)
1308  {
1310  }
1311  return SUCCESS;
1312 }
1313 
1314 //----------------------------------------------------------------------------
1316 {
1317  if (this->InternalObj->isVirtual)
1318  {
1319  return SUCCESS;
1320  }
1321 
1322  // get correct device option number
1323  const ftkOptionsInfo* info;
1324  if (!this->GetOptionInfo("Active Wireless battery state streaming", info))
1325  {
1326  return ERROR_OPTION_NOT_FOUND;
1327  }
1328 
1329  if (ftkSetInt32(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, info->id, enabled) != ftkError::FTK_OK)
1330  {
1332  }
1333  return SUCCESS;
1334 }
1335 
1336 //----------------------------------------------------------------------------
1338 {
1339  if (n < 0)
1340  {
1341  return ERROR_SET_OPTION;
1342  }
1343  this->MaxAdditionalEventsNumber = n;
1344  return SUCCESS;
1345 }
1346 
1347 //----------------------------------------------------------------------------
1349 {
1350  if (n < 0)
1351  {
1352  return ERROR_SET_OPTION;
1353  }
1354  this->Max2dFiducialsNumber = n;
1355  return SUCCESS;
1356 }
1357 
1358 //----------------------------------------------------------------------------
1360 {
1361  if (n < 0)
1362  {
1363  return ERROR_SET_OPTION;
1364  }
1365  this->Max3dFiducialsNumber = n;
1366  return SUCCESS;
1367 }
1368 
1369 //----------------------------------------------------------------------------
1371 {
1372  if (n < 0)
1373  {
1374  return ERROR_SET_OPTION;
1375  }
1376  this->MaxMarkersNumber = n;
1377  return SUCCESS;
1378 }
1379 
1380 // ------------------------------------------
1381 // spryTrack only options
1382 // ------------------------------------------
1383 
1385 {
1386  if (this->InternalObj->isVirtual)
1387  {
1388  return SUCCESS;
1389  }
1390 
1391  // get correct device option number
1392  const ftkOptionsInfo* info;
1393  if (!this->GetOptionInfo("Enable embedded processing", info))
1394  {
1395  return ERROR_OPTION_NOT_FOUND;
1396  }
1397 
1398  if (ftkSetInt32(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, info->id, enabled) != ftkError::FTK_OK)
1399  {
1401  }
1402  LOG_INFO("Embedded processing successfully " << (enabled ? "enabled" : "disabled"));
1403  return SUCCESS;
1404 }
1405 
1406 //----------------------------------------------------------------------------
1408 {
1409  if (this->InternalObj->isVirtual)
1410  {
1411  return SUCCESS;
1412  }
1413 
1414  // get correct device option number
1415  const ftkOptionsInfo* info;
1416  if (!this->GetOptionInfo("Enable images sending", info))
1417  {
1418  return ERROR_OPTION_NOT_FOUND;
1419  }
1420 
1421  if (ftkSetInt32(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, info->id, enabled) != ftkError::FTK_OK)
1422  {
1424  }
1425  LOG_INFO("Image streaming successfully " << (enabled ? "enabled" : "disabled"));
1426  return SUCCESS;
1427 }
1428 
1429 //----------------------------------------------------------------------------
1431 {
1432  if (this->DeviceType != SPRYTRACK_180 && this->DeviceType != SPRYTRACK_300)
1433  {
1434  LOG_WARNING("Embedded processing is available only on spryTracks.");
1436  }
1437  bool succeeded = true;
1438  if (processingType == PROCESSING_ONBOARD)
1439  {
1440  succeeded = succeeded && (this->EnableOnboardProcessing(true) == SUCCESS);
1441  succeeded = succeeded && (this->EnableImageStreaming(false) == SUCCESS);
1442  isOnboardProcessing = true;
1443  }
1444  else if (processingType == PROCESSING_ON_PC)
1445  {
1446  succeeded = succeeded && (this->EnableOnboardProcessing(false) == SUCCESS);
1447  succeeded = succeeded && (this->EnableImageStreaming(true) == SUCCESS);
1448  isOnboardProcessing = false;
1449  }
1450 
1451  if (!succeeded)
1452  {
1454  }
1455  return SUCCESS;
1456 }
1457 
1458 // ------------------------------------------
1459 // fusionTrack only options
1460 // ------------------------------------------
1461 
1463 {
1464  if (this->InternalObj->isVirtual)
1465  {
1466  droppedFrameCount = 0;
1467  return SUCCESS;
1468  }
1469 
1470  if (this->DeviceType == FUSIONTRACK_250 || this->DeviceType == FUSIONTRACK_500)
1471  {
1472  int32 lost = 0, corrupted = 0;
1473  // get correct device option number
1474  const ftkOptionsInfo* info;
1475  if (!this->GetOptionInfo("Counter of lost frames", info))
1476  {
1477  return ERROR_OPTION_NOT_FOUND;
1478  }
1479  ftkGetInt32(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, info->id, &lost, ftkOptionGetter::FTK_VALUE);
1480  if (!this->GetOptionInfo("Counter of corrupted frames", info))
1481  {
1482  return ERROR_OPTION_NOT_FOUND;
1483  }
1484  ftkGetInt32(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, info->id, &corrupted, ftkOptionGetter::FTK_VALUE);
1485 
1486  droppedFrameCount = lost + corrupted;
1487  return SUCCESS;
1488  }
1490 }
1491 
1492 //----------------------------------------------------------------------------
1494 {
1495  if (this->InternalObj->isVirtual)
1496  {
1497  return SUCCESS;
1498  }
1499 
1500  if (this->DeviceType == FUSIONTRACK_250 || this->DeviceType == FUSIONTRACK_500)
1501  {
1502  // get correct device option number
1503  const ftkOptionsInfo* info;
1504  if (!this->GetOptionInfo("Resets lost counters", info))
1505  {
1506  return ERROR_OPTION_NOT_FOUND;
1507  }
1508  ftkSetInt32(this->InternalObj->FtkLib, this->InternalObj->TrackerSN, info->id, RESET_DROPPED_FRAME_COUNT);
1509  return SUCCESS;
1510  }
1512 }
1513 
1514 //============================================================================
1515 // ------------------------------------------
1516 // Fiducial methods
1517 // ------------------------------------------
1518 
1519 // any 2 fiducials within this 3D distance in mm will be considered equal
1520 const float EQUALITY_DISTANCE_MM = 2.0;
1521 
1522 bool Fiducial::operator==(const Fiducial& f) const
1523 {
1524  // pow is much slower than just x*x for squaring numbers
1525  float dist2 = (this->xMm - f.xMm) * (this->xMm - f.xMm) + (this->yMm - f.yMm) * (this->yMm - f.yMm) + (this->zMm - f.zMm) * (this->zMm - f.zMm);
1526  return sqrt(dist2) < EQUALITY_DISTANCE_MM;
1527 }
1528 
1529 bool Fiducial::operator<(const Fiducial& f) const
1530 {
1531  float distF1 = sqrt(this->xMm * this->xMm + this->yMm * this->yMm + this->zMm * this->zMm);
1532  float distF2 = sqrt(f.xMm * f.xMm + f.yMm * f.yMm + f.zMm * f.zMm);
1533  return distF1 < distF2;
1534 }
1535 
1536 // ------------------------------------------
1537 // Marker methods
1538 // ------------------------------------------
1539 
1541 {
1542  this->MarkerStatus = 0;
1543  this->TrackingId = -1;
1544  this->GeometryId = -1;
1545  this->GeometryPresenceMask = -1;
1546  this->RegistrationErrorMm = 0.0;
1547 }
1548 Marker::Marker(int status, int trackingId, int geometryId,
1549  vtkMatrix4x4* toolToTracker, int geometryPresenceMask, float registrationErrorMM)
1550 {
1551  this->MarkerStatus = status;
1552  this->TrackingId = trackingId;
1553  this->GeometryId = geometryId;
1554  this->ToolToTracker->DeepCopy(toolToTracker);
1555  this->GeometryPresenceMask = geometryPresenceMask;
1556  this->RegistrationErrorMm = registrationErrorMM;
1557 }
1558 
1560 {
1561  this->MarkerStatus = obj.MarkerStatus;
1562  this->TrackingId = obj.TrackingId;
1563  this->GeometryId = obj.GeometryId;
1564  this->ToolToTracker->DeepCopy(obj.ToolToTracker.GetPointer());
1565  this->GeometryPresenceMask = obj.GeometryPresenceMask;
1566  this->RegistrationErrorMm = obj.RegistrationErrorMm;
1567  this->fiducials = obj.fiducials;
1568 }
1569 
1571 {
1572  if (fiducials.size() < FTK_MAX_FIDUCIALS)
1573  {
1574  fiducials.push_back(fid);
1575  return true;
1576  }
1577  else
1578  {
1579  return false;
1580  }
1581 }
const uint32_t * data
Definition: phidget22.h:3971
#define ATRACSYS_BUFFER_SIZE
const char * key
Definition: phidget22.h:5111
#define RESET_DROPPED_FRAME_COUNT
bool operator<(const Fiducial &f) const
RESULT SetUserLEDState(int red, int green, int blue, int frequency, bool enabled=true)
const char int line
Definition: phidget22.h:2458
void Pause(bool tof)
bool operator==(const Fiducial &f) const
RESULT EnableOnboardProcessing(bool enabled)
RESULT EnableUserLED(bool enabled)
RESULT GetLoadedGeometries(std::map< int, std::vector< std::array< float, 3 >>> &geometries)
void stringFindAndReplaceAll(std::string &data, std::string toSearch, std::string replaceStr)
for i
RESULT SetMaxAdditionalEventsNumber(int n)
RESULT SetMaxMarkersNumber(int n)
RESULT EnableWirelessMarkerStatusStreaming(bool enabled)
Image slice number p
Definition: algo4.m:14
RESULT SetSpryTrackProcessingType(SPRYTRACK_IMAGE_PROCESSING_TYPE processingType)
RESULT LoadMarkerGeometryFromString(std::string filePath, int &geometryId)
RESULT EnableWirelessMarkerBatteryStreaming(bool enabled)
RESULT SetMax2dFiducialsNumber(int n)
int enabled
Definition: phidget22.h:3369
bool checkKey(IniFile &p, const std::string &section, const std::string &key)
bool strToFloat32(const std::string &str, float &var)
RESULT GetCamerasCalibration(std::array< float, 10 > &leftIntrinsic, std::array< float, 10 > &rightIntrinsic, std::array< float, 3 > &rightPosition, std::array< float, 3 > &rightOrientation)
bool assignUint32(IniFile &p, const std::string &section, const std::string &key, uint32 *variable)
RESULT GetMarkerInfo(std::string &markerInfo)
RESULT SetMax3dFiducialsNumber(int n)
RESULT LoadMarkerGeometryFromFile(std::string filePath, int &geometryId)
bool strToInt32(const std::string &str, int &var)
RESULT SetLaserEnabled(bool enabled)
RESULT GetSDKversion(std::string &version)
RESULT EnableImageStreaming(bool enabled)
RESULT GetDeviceType(DEVICE_TYPE &deviceType)
RESULT EnableWirelessMarkerPairing(bool enabled)
PhidgetGPS_Date * date
Definition: phidget22.h:3617
RESULT SetOption(const std::string &, const std::string &)
bool AddFiducial(Fiducial fid)
bool assignFloatXX(IniFile &p, const std::string &section, const std::string &key, floatXX *variable)
void FusionTrackEnumerator(uint64 sn, void *user, ftkDeviceType devType)
RESULT GetFiducialsInFrame(std::vector< Fiducial > &fiducials, std::map< std::string, std::string > &events, uint64_t &sdkTimestamp)
RESULT GetMarkersInFrame(std::vector< Marker > &markers, std::map< std::string, std::string > &events, uint64_t &sdkTimestamp)
RESULT GetDroppedFrameCount(int &droppedFrameCount)
double frequency
Definition: phidget22.h:3246
const float EQUALITY_DISTANCE_MM
bool GetOptionInfo(const std::string &, const ftkOptionsInfo *&)
RESULT GetCalibrationDate(std::string &date)
RESULT GetDeviceId(uint64_t &id)
std::string ResultToString(RESULT result)
bool checkSection(IniFile &p, const std::string &section)