PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusOptiTrack.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 "PlusConfigure.h"
9 #include "vtkPlusOptiTrack.h"
10 
11 // VTK includes
12 #include <vtkSmartPointer.h>
13 #include <vtkMatrix4x4.h>
14 #include <vtkMath.h>
15 #include <vtkXMLDataElement.h>
16 #include <vtksys/Encoding.hxx>
17 
18 // Motive API includes
19 #include <NatNetClient.h>
20 #include <NatNetTypes.h>
21 #if MOTIVE_VERSION_MAJOR < 3
22 #include <NPTrackingTools.h>
23 #else
24 #include <MotiveAPI.h>
25 #endif
26 
27 #if MOTIVE_VERSION_MAJOR < 3
28 #define ResultType NPRESULT
29 #define ResultSuccess NPRESULT_SUCCESS
30 #elif MOTIVE_VERSION_MAJOR >= 3 && MOTIVE_VERSION_MINOR >= 1
31 #define ResultType MotiveAPI::eResult
32 #define ResultSuccess ResultType::kApiResult_Success
33 #elif MOTIVE_VERSION_MAJOR >= 3
34 #define ResultType eMotiveAPIResult
35 #define ResultSuccess kApiResult_Success
36 #endif
37 
38 #if MOTIVE_VERSION_MAJOR >= 3 && MOTIVE_VERSION_MINOR >= 1
39 #define MotiveTestConnection MotiveAPI::CanConnectToDevices
40 #define MotiveInitialize MotiveAPI::Initialize
41 #define MotiveUpdate MotiveAPI::Update
42 #define MotiveLoadProfile MotiveAPI::LoadProfile
43 #define MotiveGetResultString MotiveAPI::MapToResultString
44 #define MotiveLoadCalibration MotiveAPI::LoadCalibration
45 #define MotiveStreamNP MotiveAPI::StreamNP
46 #define MotiveAddRigidBodies MotiveAPI::AddRigidBodies
47 #define MotiveCameraCount MotiveAPI::CameraCount
48 #define MotiveCameraName MotiveAPI::CameraName
49 #define MotiveRigidBodyCount MotiveAPI::RigidBodyCount
50 #define MotiveGetRigidBodyName MotiveAPI::RigidBodyName
51 #define MotiveShutdown MotiveAPI::Shutdown
52 #else
53 #define MotiveTestConnection TT_TestSoftwareMutex
54 #define MotiveInitialize TT_Initialize
55 #define MotiveUpdate TT_Update
56 #define MotiveLoadProfile TT_LoadProfile
57 #define MotiveGetResultString TT_GetResultString
58 #define MotiveLoadCalibration TT_LoadCalibration
59 #define MotiveStreamNP TT_StreamNP
60 #define MotiveAddRigidBodies TT_AddRigidBodies
61 #define MotiveCameraCount TT_CameraCount
62 #define MotiveCameraName TT_CameraName
63 #define MotiveRigidBodyCount TT_RigidBodyCount
64 #define MotiveGetRigidBodyName TT_RigidBodyName
65 #define MotiveShutdown TT_Shutdown
66 #endif
67 
68 // std includes
69 #include <set>
70 
72 
73 //----------------------------------------------------------------------------
74 class vtkPlusOptiTrack::vtkInternal
75 {
76 public:
77  vtkPlusOptiTrack* External;
78 
79  vtkInternal(vtkPlusOptiTrack* external)
80  : External(external)
81  , NNClient(nullptr)
82  , UnitsToMm(1.0)
83  , MotiveDataDescriptionsUpdateTimeSec(1.0)
84  , LastMotiveDataDescriptionsUpdateTimestamp(-1)
85  {
86  }
87 
88  virtual ~vtkInternal()
89  {
90  }
91 
92  // NatNet client, parameters, and callback function
93  NatNetClient* NNClient;
94  float UnitsToMm;
95 
96  // Motive Files
97 #if MOTIVE_VERSION_MAJOR >= 2
98  std::string Profile;
99  std::string Calibration;
100 #else
101  std::string ProjectFile;
102 #endif
103 
104  std::string CalibrationFile;
105  std::vector<std::string> AdditionalRigidBodyFiles;
106 
107  // Maps rigid body names to transform names
108  std::map<int, igsioTransformName> MapRBNameToTransform;
109 
110  // Flag to run Motive in background if user doesn't need GUI
111  bool AttachToRunningMotive;
112 
113  // Time of last tool update
114  double LastMotiveDataDescriptionsUpdateTimestamp;
115  double MotiveDataDescriptionsUpdateTimeSec;
116 
120 #if MOTIVE_VERSION_MAJOR >= 3 && MOTIVE_VERSION_MINOR >= 1
121  std::wstring GetMotiveErrorMessage(ResultType result);
122 #else
123  std::string GetMotiveErrorMessage(ResultType result);
124 #endif
125 
129  static void InternalCallback(sFrameOfMocapData* data, void* pUserData);
130 
131  void UpdateMotiveDataDescriptions();
132 };
133 
134 //-----------------------------------------------------------------------
135 #if MOTIVE_VERSION_MAJOR >= 3 && MOTIVE_VERSION_MINOR >= 1
136 std::wstring vtkPlusOptiTrack::vtkInternal::GetMotiveErrorMessage(MotiveAPI::eResult result)
137 #else
138 std::string vtkPlusOptiTrack::vtkInternal::GetMotiveErrorMessage(ResultType result)
139 #endif
140 {
141 #if MOTIVE_VERSION_MAJOR >= 3 && MOTIVE_VERSION_MINOR >= 1
142  return std::wstring(MotiveAPI::MapToResultString(result));
143 #else
144 return "";
145 #endif
146 
147 }
148 
149 //-----------------------------------------------------------------------
150 void vtkPlusOptiTrack::vtkInternal::UpdateMotiveDataDescriptions()
151 {
152  LOG_TRACE("vtkPlusOptiTrack::vtkInternal::MatchTrackedTools");
153 
154  std::string referenceFrame = this->External->GetToolReferenceFrameName();
155  this->MapRBNameToTransform.clear();
156  sDataDescriptions* dataDescriptions;
157  this->NNClient->GetDataDescriptions(&dataDescriptions);
158  for (int i = 0; i < dataDescriptions->nDataDescriptions; ++i)
159  {
160  sDataDescription currentDescription = dataDescriptions->arrDataDescriptions[i];
161  if (currentDescription.type == Descriptor_RigidBody)
162  {
163  // Map the numerical ID of the tracked tool from motive to the name of the tool
164  igsioTransformName toolToTracker = igsioTransformName(currentDescription.Data.RigidBodyDescription->szName, referenceFrame);
165  this->MapRBNameToTransform[currentDescription.Data.RigidBodyDescription->ID] = toolToTracker;
166  }
167  }
168 
169  this->LastMotiveDataDescriptionsUpdateTimestamp = vtkIGSIOAccurateTimer::GetSystemTime();
170 }
171 
172 //-----------------------------------------------------------------------
174  : vtkPlusDevice()
175  , Internal(new vtkInternal(this))
176 {
177  this->FrameNumber = 0;
178  // always uses NatNet's callback to update
179  this->InternalUpdateRate = 120;
180  this->StartThreadForInternalUpdates = false;
181 }
182 
183 //----------------------------------------------------------------------------
185 {
186  delete Internal;
187  Internal = nullptr;
188 }
189 
190 //----------------------------------------------------------------------------
191 void vtkPlusOptiTrack::PrintSelf(ostream& os, vtkIndent indent)
192 {
193  Superclass::PrintSelf(os, indent);
194 }
195 
196 //----------------------------------------------------------------------------
197 PlusStatus vtkPlusOptiTrack::ReadConfiguration(vtkXMLDataElement* rootConfigElement)
198 {
199  LOG_TRACE("vtkPlusOptiTrack::ReadConfiguration");
200  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement);
201 
202 #if MOTIVE_VERSION_MAJOR >= 2
203  XML_READ_STRING_ATTRIBUTE_NONMEMBER_REQUIRED(Profile, this->Internal->Profile, deviceConfig);
204  XML_READ_STRING_ATTRIBUTE_NONMEMBER_REQUIRED(Calibration, this->Internal->Calibration, deviceConfig);
205 #else
206  XML_READ_STRING_ATTRIBUTE_NONMEMBER_REQUIRED(ProjectFile, this->Internal->ProjectFile, deviceConfig);
207 #endif
208  XML_READ_BOOL_ATTRIBUTE_NONMEMBER_REQUIRED(AttachToRunningMotive, this->Internal->AttachToRunningMotive, deviceConfig);
209  XML_READ_SCALAR_ATTRIBUTE_NONMEMBER_OPTIONAL(double, MotiveDataDescriptionsUpdateTimeSec, this->Internal->MotiveDataDescriptionsUpdateTimeSec, deviceConfig);
210 
211  XML_FIND_NESTED_ELEMENT_REQUIRED(dataSourcesElement, deviceConfig, "DataSources");
212  for (int nestedElementIndex = 0; nestedElementIndex < dataSourcesElement->GetNumberOfNestedElements(); nestedElementIndex++)
213  {
214  vtkXMLDataElement* toolDataElement = dataSourcesElement->GetNestedElement(nestedElementIndex);
215  if (STRCASECMP(toolDataElement->GetName(), "DataSource") != 0)
216  {
217  // if this is not a data source element, skip it
218  continue;
219  }
220  if (toolDataElement->GetAttribute("Type") != NULL && STRCASECMP(toolDataElement->GetAttribute("Type"), "Tool") != 0)
221  {
222  // if this is not a Tool element, skip it
223  continue;
224  }
225 
226  std::string toolId(toolDataElement->GetAttribute("Id"));
227  if (toolId.empty())
228  {
229  // tool doesn't have ID needed to generate transform
230  LOG_ERROR("Failed to initialize OptiTrack tool: DataSource Id is missing. This should be the name of the Motive Rigid Body that tracks the tool.");
231  continue;
232  }
233 
234  if (toolDataElement->GetAttribute("RigidBodyFile") != NULL)
235  {
236  // this tool has an associated rigid body definition
237  const char* rigidBodyFile = toolDataElement->GetAttribute("RigidBodyFile");
238  this->Internal->AdditionalRigidBodyFiles.push_back(rigidBodyFile);
239  }
240  }
241 
242  return PLUS_SUCCESS;
243 }
244 
245 //----------------------------------------------------------------------------
246 PlusStatus vtkPlusOptiTrack::WriteConfiguration(vtkXMLDataElement* rootConfigElement)
247 {
248  LOG_TRACE("vtkPlusOptiTrack::WriteConfiguration");
249  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement);
250  return PLUS_SUCCESS;
251 }
252 
253 //----------------------------------------------------------------------------
255 {
256  LOG_TRACE("vtkPlusOptiTrack::Probe");
257  return PLUS_SUCCESS;
258 }
259 
260 //-------------------------------------------------------------------------
262 {
263  LOG_TRACE("vtkPlusOptiTrack::InternalConnect");
264  if (!this->Internal->AttachToRunningMotive)
265  {
266 #if MOTIVE_VERSION_MAJOR >= 2
267 #if MOTIVE_VERSION_MAJOR >= 3 && MOTIVE_VERSION_MINOR >= 1
268  if (MotiveTestConnection())
269 #else
271 #endif
272 
273  {
274  LOG_ERROR("Failed to start Motive. Another instance is already running.");
275  return PLUS_FAIL;
276  }
277 #endif
278 
279  // RUN MOTIVE IN BACKGROUND
280  // initialize the API
282  {
283  LOG_ERROR("Failed to start Motive.");
284  return PLUS_FAIL;
285  }
286 
287  // pick up recently-arrived cameras
288  MotiveUpdate();
289 
290 #if MOTIVE_VERSION_MAJOR >= 2
291  // open project file
292  std::string profilePath = vtkPlusConfig::GetInstance()->GetDeviceSetConfigurationPath(this->Internal->Profile);
293 #if MOTIVE_VERSION_MAJOR < 3
294  ResultType profileLoad = MotiveLoadProfile(profilePath.c_str());
295 #else
296  std::wstring wProfilePath = vtksys::Encoding::ToWide(profilePath);
297  ResultType profileLoad = MotiveLoadProfile(wProfilePath.c_str());
298 #endif
299  if (profileLoad != ResultSuccess)
300  {
301 #if MOTIVE_VERSION_MAJOR < 3
302  LOG_ERROR("Failed to load Motive profile. Motive error: " << MotiveGetResultString(profileLoad));
303 #else
304  LOG_ERROR_W("Failed to load Motive profile. Motive error: " << MotiveGetResultString(profileLoad));
305 #endif
306  return PLUS_FAIL;
307  }
308 
309  // load calibration
310  std::string calibrationPath = vtkPlusConfig::GetInstance()->GetDeviceSetConfigurationPath(this->Internal->Calibration);
311 #if MOTIVE_VERSION_MAJOR < 3
312  ResultType calLoad = MotiveLoadCalibration(calibrationPath.c_str());
313 #else
314  std::wstring wCalibrationPath = vtksys::Encoding::ToWide(calibrationPath);
315  ResultType calLoad = MotiveLoadCalibration(wCalibrationPath.c_str());
316 #endif
317  if (profileLoad != ResultSuccess)
318  {
319 #if MOTIVE_VERSION_MAJOR < 3
320  LOG_ERROR("Failed to load Motive calibration. Motive error: " << MotiveGetResultString(profileLoad));
321 #else
322  LOG_ERROR_W("Failed to load Motive calibration. Motive error: " << MotiveGetResultString(profileLoad));
323 #endif
324  return PLUS_FAIL;
325  }
326 #else
327  // open project file
328  std::string projectFilePath = vtkPlusConfig::GetInstance()->GetDeviceSetConfigurationPath(this->Internal->ProjectFile);
329  NPRESULT ttpLoad = TT_LoadProject(projectFilePath.c_str());
330  if (ttpLoad != NPRESULT_SUCCESS)
331  {
332  LOG_ERROR("Failed to load Motive project file. Motive error: " << MotiveGetResultString(ttpLoad));
333  return PLUS_FAIL;
334  }
335 #endif
336 
337  // enforce NatNet streaming enabled, this is required for PLUS tracking
338  // this is the equivalent to checking the "Broadcast Frame Data" button in the Motive GUI
339  ResultType streamEnable = MotiveStreamNP(true);
340  if (streamEnable != ResultSuccess)
341  {
342 #if MOTIVE_VERSION_MAJOR < 3
343  LOG_ERROR("Failed to enable NatNet streaming. Motive error: " << MotiveGetResultString(streamEnable));
344 #else
345  LOG_ERROR_W("Failed to enable NatNet streaming. Motive error: " << MotiveGetResultString(streamEnable));
346 #endif
347  return PLUS_FAIL;
348  }
349 
350  // add any additional rigid body files to project
351  std::string rbFilePath;
352  for (auto it = this->Internal->AdditionalRigidBodyFiles.begin(); it != this->Internal->AdditionalRigidBodyFiles.end(); it++)
353  {
355 #if MOTIVE_VERSION_MAJOR < 3
356  ResultType addRBResult = MotiveAddRigidBodies(rbFilePath.c_str());
357 #else
358  std::wstring wRBFilePath = vtksys::Encoding::ToWide(rbFilePath);
359  ResultType addRBResult = MotiveAddRigidBodies(wRBFilePath.c_str());
360 #endif
361  if (addRBResult != ResultSuccess)
362  {
363 #if MOTIVE_VERSION_MAJOR < 3
364  LOG_ERROR("Failed to enable NatNet streaming. Motive error: " << MotiveGetResultString(streamEnable));
365 #else
366  LOG_ERROR_W("Failed to load rigid body file located at: " << wRBFilePath << ". Motive error message: " << MotiveGetResultString(addRBResult));
367 #endif
368  return PLUS_FAIL;
369  }
370  }
371 
372  LOG_INFO("\n---------------------------------MOTIVE SETTINGS--------------------------------");
373  // list connected cameras
374  LOG_INFO("Connected cameras:");
375  for (int i = 0; i < MotiveCameraCount(); i++)
376  {
377 #if MOTIVE_VERSION_MAJOR < 3
378  LOG_INFO(i << ": " << MotiveCameraName(i));
379 #else
380  wchar_t cameraName[256];
381  //MotiveCameraName(i, cameraName, (int)sizeof(cameraName));
382  LOG_INFO_W(i << L": " << cameraName);
383 #endif
384  }
385  // list project file
386 #if MOTIVE_VERSION_MAJOR >= 2
387  LOG_INFO("\nUsing Motive profile located at:\n" << profilePath);
388  LOG_INFO("\nUsing Motive calibration located at:\n" << calibrationPath);
389 #else
390  LOG_INFO("\nUsing Motive project file located at:\n" << projectFilePath);
391 #endif
392  // list rigid bodies
393  LOG_INFO("\nTracked rigid bodies:");
394  for (int i = 0; i < MotiveRigidBodyCount(); ++i)
395  {
396 #if MOTIVE_VERSION_MAJOR < 3
397  LOG_INFO(MotiveGetRigidBodyName(i));
398 #else
399  wchar_t rigidBodyName[256];
400  MotiveGetRigidBodyName(i, rigidBodyName, (int)sizeof(rigidBodyName));
401  LOG_INFO_W(rigidBodyName);
402 #endif
403  }
404  LOG_INFO("--------------------------------------------------------------------------------\n");
405 
406  this->StartThreadForInternalUpdates = true;
407  }
408 
409  // CONFIGURE NATNET CLIENT
410  this->Internal->NNClient = new NatNetClient(ConnectionType_Multicast);
411  this->Internal->NNClient->SetVerbosityLevel(Verbosity_None);
412  this->Internal->NNClient->SetVerbosityLevel(Verbosity_Warning);
413  this->Internal->NNClient->SetDataCallback(vtkPlusOptiTrack::vtkInternal::InternalCallback, this);
414 
415  int retCode = this->Internal->NNClient->Initialize("127.0.0.1", "127.0.0.1");
416 
417  void* response;
418  int nBytes;
419  if (this->Internal->NNClient->SendMessageAndWait("UnitsToMillimeters", &response, &nBytes) == ErrorCode_OK)
420  {
421  this->Internal->UnitsToMm = (*(float*)response);
422  }
423  else
424  {
425  // Fail if motive is not running
426  LOG_ERROR("Failed to connect to Motive. Please either set AttachToRunningMotive=FALSE or ensure that Motive is running and streaming is enabled.");
427  return PLUS_FAIL;
428  }
429 
430  // verify all rigid bodies in Motive have unique names
431  std::set<std::string> rigidBodies;
432  sDataDescriptions* dataDescriptions;
433  this->Internal->NNClient->GetDataDescriptions(&dataDescriptions);
434  for (int i = 0; i < dataDescriptions->nDataDescriptions; ++i)
435  {
436  sDataDescription currentDescription = dataDescriptions->arrDataDescriptions[i];
437  if (currentDescription.type == Descriptor_RigidBody)
438  {
439  // Map the numerical ID of the tracked tool from motive to the name of the tool
440  if (!rigidBodies.insert(currentDescription.Data.RigidBodyDescription->szName).second)
441  {
442  LOG_ERROR("Duplicate rigid bodies with name: " << currentDescription.Data.RigidBodyDescription->szName);
443  return PLUS_FAIL;
444  }
445  }
446  }
447 
448  // cause update of tools from Motive
449  this->Internal->LastMotiveDataDescriptionsUpdateTimestamp = -1;
450 
451  return PLUS_SUCCESS;
452 }
453 
454 //-------------------------------------------------------------------------
456 {
457  LOG_TRACE("vtkPlusOptiTrack::InternalDisconnect");
458  if (!this->Internal->AttachToRunningMotive)
459  {
460  MotiveShutdown();
461  }
462 
463  return PLUS_SUCCESS;
464 }
465 
466 //----------------------------------------------------------------------------
467 PlusStatus vtkPlusOptiTrack::InternalStartRecording()
468 {
469  LOG_TRACE("vtkPlusOptiTrack::InternalStartRecording");
470  return PLUS_SUCCESS;
471 }
472 
473 //----------------------------------------------------------------------------
474 PlusStatus vtkPlusOptiTrack::InternalStopRecording()
475 {
476  return PLUS_SUCCESS;
477 }
478 
479 //----------------------------------------------------------------------------
481 {
482  LOG_TRACE("vtkPlusOptiTrack::InternalUpdate");
483  // InternalUpdate is only called if using Motive API.
484 #if MOTIVE_VERSION_MAJOR >= 3
485  MotiveUpdate(); // In Motive 3.X, only updates the latest frame.
486 #elif MOTIVE_VERSION_MAJOR >= 2 && MOTIVE_VERSION_MINOR >= 3
487  TT_UpdateLatestFrame();
488 #else
489  TT_Update();
490 #endif
491  return PLUS_SUCCESS;
492 }
493 
494 //-------------------------------------------------------------------------
495 void vtkPlusOptiTrack::vtkInternal::InternalCallback(sFrameOfMocapData* data, void* pUserData)
496 {
497  vtkPlusOptiTrack* self = (vtkPlusOptiTrack*)pUserData;
498 
499  LOG_TRACE("vtkPlusOptiTrack::InternalCallback");
500  const double unfilteredTimestamp = vtkIGSIOAccurateTimer::GetSystemTime();
501 
502  if (self->Internal->LastMotiveDataDescriptionsUpdateTimestamp < 0)
503  {
504  // do an initial match of tracked tools
505  self->Internal->UpdateMotiveDataDescriptions();
506  }
507 
508  if (self->Internal->AttachToRunningMotive && self->Internal->MotiveDataDescriptionsUpdateTimeSec >= 0)
509  {
510  double timeSinceMotiveDataDescriptionsUpdate = unfilteredTimestamp - self->Internal->LastMotiveDataDescriptionsUpdateTimestamp;
511  if (timeSinceMotiveDataDescriptionsUpdate > self->Internal->MotiveDataDescriptionsUpdateTimeSec)
512  {
513  self->Internal->UpdateMotiveDataDescriptions();
514  }
515  }
516 
517  int numberOfRigidBodies = data->nRigidBodies;
518  sRigidBodyData* rigidBodies = data->RigidBodies;
519 
520  // identity transform for tools out of view
521  vtkSmartPointer<vtkMatrix4x4> rigidBodyToTrackerMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
522 
523  for (int rigidBodyId = 0; rigidBodyId < numberOfRigidBodies; ++rigidBodyId)
524  {
525  // TOOL IN VIEW
526  rigidBodyToTrackerMatrix->Identity();
527  sRigidBodyData currentRigidBody = rigidBodies[rigidBodyId];
528 
529  if (currentRigidBody.MeanError != 0)
530  {
531  // convert translation to mm
532  double translation[3] = { currentRigidBody.x * self->Internal->UnitsToMm, currentRigidBody.y * self->Internal->UnitsToMm, currentRigidBody.z * self->Internal->UnitsToMm };
533 
534  // convert rotation from quaternion to 3x3 matrix
535  double quaternion[4] = { currentRigidBody.qw, currentRigidBody.qx, currentRigidBody.qy, currentRigidBody.qz };
536  double rotation[3][3] = { 0,0,0, 0,0,0, 0,0,0 };
537  vtkMath::QuaternionToMatrix3x3(quaternion, rotation);
538 
539  // construct the transformation matrix from the rotation and translation components
540  for (int i = 0; i < 3; ++i)
541  {
542  for (int j = 0; j < 3; ++j)
543  {
544  rigidBodyToTrackerMatrix->SetElement(i, j, rotation[i][j]);
545  }
546  rigidBodyToTrackerMatrix->SetElement(i, 3, translation[i]);
547  }
548 
549  // check if tool is in view
550  bool bTrackingValid = currentRigidBody.params & 0x01;
551 
552  // make sure the tool was specified in the Config file
553  igsioTransformName toolToTracker = self->Internal->MapRBNameToTransform[currentRigidBody.ID];
554  self->ToolTimeStampedUpdate(toolToTracker.GetTransformName(), rigidBodyToTrackerMatrix, (bTrackingValid ? TOOL_OK : TOOL_INVALID), self->FrameNumber, unfilteredTimestamp);
555  }
556  else
557  {
558  // TOOL OUT OF VIEW
559  igsioTransformName toolToTracker = self->Internal->MapRBNameToTransform[currentRigidBody.ID];
560  self->ToolTimeStampedUpdate(toolToTracker.GetTransformName(), rigidBodyToTrackerMatrix, TOOL_OUT_OF_VIEW, self->FrameNumber, unfilteredTimestamp);
561  }
562 
563  }
564 
565  self->FrameNumber++;
566 }
const uint32_t * data
Definition: phidget22.h:3971
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
Abstract interface for tracker and video devices.
Definition: vtkPlusDevice.h:60
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement)
virtual PlusStatus InternalDisconnect()
#define ResultSuccess
Interface to the OptiTrack trackers This class talks with a OptiTrack Tracker over the NatNet SDK....
igsioStatus PlusStatus
Definition: PlusCommon.h:40
#define MotiveCameraCount
#define MotiveShutdown
for i
#define MotiveStreamNP
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *config)
#define PLUS_FAIL
Definition: PlusCommon.h:43
static vtkPlusConfig * GetInstance()
#define MotiveCameraName
unsigned long FrameNumber
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
#define MotiveTestConnection
#define MotiveInitialize
#define MotiveRigidBodyCount
double InternalUpdateRate
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
#define ResultType
#define MotiveAddRigidBodies
#define MotiveLoadCalibration
#define MotiveGetResultString
#define MotiveLoadProfile
bool StartThreadForInternalUpdates
void PrintSelf(ostream &os, vtkIndent indent)
#define MotiveUpdate
vtkStandardNewMacro(vtkPlusOptiTrack)
std::string GetDeviceSetConfigurationPath(const std::string &subPath)
PlusStatus InternalConnect()
#define MotiveGetRigidBodyName
PlusStatus InternalUpdate()
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *config)