8 #include "PlusConfigure.h" 12 #include <vtkSmartPointer.h> 13 #include <vtkMatrix4x4.h> 15 #include <vtkXMLDataElement.h> 16 #include <vtksys/Encoding.hxx> 19 #include <NatNetClient.h> 20 #include <NatNetTypes.h> 21 #if MOTIVE_VERSION_MAJOR < 3 22 #include <NPTrackingTools.h> 23 #define ResultType NPRESULT 24 #define ResultSuccess NPRESULT_SUCCESS 25 #elif MOTIVE_VERSION_MAJOR >= 3 26 #include <MotiveAPI.h> 27 #define ResultType eMotiveAPIResult 28 #define ResultSuccess kApiResult_Success 37 class vtkPlusOptiTrack::vtkInternal
46 , MotiveDataDescriptionsUpdateTimeSec(1.0)
47 , LastMotiveDataDescriptionsUpdateTimestamp(-1)
51 virtual ~vtkInternal()
56 NatNetClient* NNClient;
60 #if MOTIVE_VERSION_MAJOR >= 2 62 std::string Calibration;
64 std::string ProjectFile;
67 std::string CalibrationFile;
68 std::vector<std::string> AdditionalRigidBodyFiles;
71 std::map<int, igsioTransformName> MapRBNameToTransform;
74 bool AttachToRunningMotive;
77 double LastMotiveDataDescriptionsUpdateTimestamp;
78 double MotiveDataDescriptionsUpdateTimeSec;
83 std::string GetMotiveErrorMessage(
ResultType result);
88 static void InternalCallback(sFrameOfMocapData*
data,
void* pUserData);
90 void UpdateMotiveDataDescriptions();
94 std::string vtkPlusOptiTrack::vtkInternal::GetMotiveErrorMessage(
ResultType result)
101 void vtkPlusOptiTrack::vtkInternal::UpdateMotiveDataDescriptions()
103 LOG_TRACE(
"vtkPlusOptiTrack::vtkInternal::MatchTrackedTools");
105 std::string referenceFrame = this->External->GetToolReferenceFrameName();
106 this->MapRBNameToTransform.clear();
107 sDataDescriptions* dataDescriptions;
108 this->NNClient->GetDataDescriptions(&dataDescriptions);
109 for (
int i = 0;
i < dataDescriptions->nDataDescriptions; ++
i)
111 sDataDescription currentDescription = dataDescriptions->arrDataDescriptions[
i];
112 if (currentDescription.type == Descriptor_RigidBody)
115 igsioTransformName toolToTracker = igsioTransformName(currentDescription.Data.RigidBodyDescription->szName, referenceFrame);
116 this->MapRBNameToTransform[currentDescription.Data.RigidBodyDescription->ID] = toolToTracker;
120 this->LastMotiveDataDescriptionsUpdateTimestamp = vtkIGSIOAccurateTimer::GetSystemTime();
126 , Internal(new vtkInternal(this))
150 LOG_TRACE(
"vtkPlusOptiTrack::ReadConfiguration");
153 #if MOTIVE_VERSION_MAJOR >= 2 154 XML_READ_STRING_ATTRIBUTE_NONMEMBER_REQUIRED(Profile, this->Internal->Profile, deviceConfig);
155 XML_READ_STRING_ATTRIBUTE_NONMEMBER_REQUIRED(Calibration, this->Internal->Calibration, deviceConfig);
157 XML_READ_STRING_ATTRIBUTE_NONMEMBER_REQUIRED(ProjectFile, this->Internal->ProjectFile, deviceConfig);
159 XML_READ_BOOL_ATTRIBUTE_NONMEMBER_REQUIRED(AttachToRunningMotive, this->Internal->AttachToRunningMotive, deviceConfig);
160 XML_READ_SCALAR_ATTRIBUTE_NONMEMBER_OPTIONAL(
double, MotiveDataDescriptionsUpdateTimeSec, this->Internal->MotiveDataDescriptionsUpdateTimeSec, deviceConfig);
162 XML_FIND_NESTED_ELEMENT_REQUIRED(dataSourcesElement, deviceConfig,
"DataSources");
163 for (
int nestedElementIndex = 0; nestedElementIndex < dataSourcesElement->GetNumberOfNestedElements(); nestedElementIndex++)
165 vtkXMLDataElement* toolDataElement = dataSourcesElement->GetNestedElement(nestedElementIndex);
166 if (STRCASECMP(toolDataElement->GetName(),
"DataSource") != 0)
171 if (toolDataElement->GetAttribute(
"Type") != NULL && STRCASECMP(toolDataElement->GetAttribute(
"Type"),
"Tool") != 0)
177 std::string toolId(toolDataElement->GetAttribute(
"Id"));
181 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.");
185 if (toolDataElement->GetAttribute(
"RigidBodyFile") != NULL)
188 const char* rigidBodyFile = toolDataElement->GetAttribute(
"RigidBodyFile");
189 this->Internal->AdditionalRigidBodyFiles.push_back(rigidBodyFile);
199 LOG_TRACE(
"vtkPlusOptiTrack::WriteConfiguration");
207 LOG_TRACE(
"vtkPlusOptiTrack::Probe");
214 LOG_TRACE(
"vtkPlusOptiTrack::InternalConnect");
215 if (!this->Internal->AttachToRunningMotive)
217 #if MOTIVE_VERSION_MAJOR >= 2 220 LOG_ERROR(
"Failed to start Motive. Another instance is already running.");
229 LOG_ERROR(
"Failed to start Motive.");
236 #if MOTIVE_VERSION_MAJOR >= 2 239 #if MOTIVE_VERSION_MAJOR < 3 240 ResultType profileLoad = TT_LoadProfile(profilePath.c_str());
242 std::wstring wProfilePath = vtksys::Encoding::ToWide(profilePath);
243 ResultType profileLoad = TT_LoadProfile(wProfilePath.c_str());
247 #if MOTIVE_VERSION_MAJOR < 3 248 LOG_ERROR(
"Failed to load Motive profile. Motive error: " << TT_GetResultString(profileLoad));
250 LOG_ERROR_W(
"Failed to load Motive profile. Motive error: " << TT_GetResultString(profileLoad));
257 #if MOTIVE_VERSION_MAJOR < 3 258 ResultType calLoad = TT_LoadCalibration(calibrationPath.c_str());
260 std::wstring wCalibrationPath = vtksys::Encoding::ToWide(calibrationPath);
261 ResultType calLoad = TT_LoadCalibration(wCalibrationPath.c_str());
265 #if MOTIVE_VERSION_MAJOR < 3 266 LOG_ERROR(
"Failed to load Motive calibration. Motive error: " << TT_GetResultString(profileLoad));
268 LOG_ERROR_W(
"Failed to load Motive calibration. Motive error: " << TT_GetResultString(profileLoad));
275 NPRESULT ttpLoad = TT_LoadProject(projectFilePath.c_str());
276 if (ttpLoad != NPRESULT_SUCCESS)
278 LOG_ERROR(
"Failed to load Motive project file. Motive error: " << TT_GetResultString(ttpLoad));
288 #if MOTIVE_VERSION_MAJOR < 3 289 LOG_ERROR(
"Failed to enable NatNet streaming. Motive error: " << TT_GetResultString(streamEnable));
291 LOG_ERROR_W(
"Failed to enable NatNet streaming. Motive error: " << TT_GetResultString(streamEnable));
297 std::string rbFilePath;
298 for (
auto it = this->Internal->AdditionalRigidBodyFiles.begin(); it != this->Internal->AdditionalRigidBodyFiles.end(); it++)
301 #if MOTIVE_VERSION_MAJOR < 3 302 ResultType addRBResult = TT_AddRigidBodies(rbFilePath.c_str());
304 std::wstring wRBFilePath = vtksys::Encoding::ToWide(rbFilePath);
305 ResultType addRBResult = TT_AddRigidBodies(wRBFilePath.c_str());
309 LOG_ERROR(
"Failed to load rigid body file located at: " << rbFilePath <<
". Motive error message: " << this->Internal->GetMotiveErrorMessage(addRBResult));
314 LOG_INFO(
"\n---------------------------------MOTIVE SETTINGS--------------------------------");
316 LOG_INFO(
"Connected cameras:");
317 for (
int i = 0;
i < TT_CameraCount();
i++)
319 #if MOTIVE_VERSION_MAJOR < 3 320 LOG_INFO(
i <<
": " << TT_CameraName(
i));
322 wchar_t cameraName[256];
323 TT_CameraName(
i, cameraName, (
int)
sizeof(cameraName));
324 LOG_INFO_W(
i << L
": " << cameraName);
328 #if MOTIVE_VERSION_MAJOR >= 2 329 LOG_INFO(
"\nUsing Motive profile located at:\n" << profilePath);
330 LOG_INFO(
"\nUsing Motive calibration located at:\n" << calibrationPath);
332 LOG_INFO(
"\nUsing Motive project file located at:\n" << projectFilePath);
335 LOG_INFO(
"\nTracked rigid bodies:");
336 for (
int i = 0;
i < TT_RigidBodyCount(); ++
i)
338 #if MOTIVE_VERSION_MAJOR < 3 339 LOG_INFO(TT_RigidBodyName(
i));
341 wchar_t rigidBodyName[256];
342 TT_RigidBodyName(
i, rigidBodyName, (
int)
sizeof(rigidBodyName));
343 LOG_INFO_W(rigidBodyName);
346 LOG_INFO(
"--------------------------------------------------------------------------------\n");
352 this->Internal->NNClient =
new NatNetClient(ConnectionType_Multicast);
353 this->Internal->NNClient->SetVerbosityLevel(Verbosity_None);
354 this->Internal->NNClient->SetVerbosityLevel(Verbosity_Warning);
355 this->Internal->NNClient->SetDataCallback(vtkPlusOptiTrack::vtkInternal::InternalCallback,
this);
357 int retCode = this->Internal->NNClient->Initialize(
"127.0.0.1",
"127.0.0.1");
361 if (this->Internal->NNClient->SendMessageAndWait(
"UnitsToMillimeters", &response, &nBytes) == ErrorCode_OK)
363 this->Internal->UnitsToMm = (*(
float*)response);
368 LOG_ERROR(
"Failed to connect to Motive. Please either set AttachToRunningMotive=FALSE or ensure that Motive is running and streaming is enabled.");
373 std::set<std::string> rigidBodies;
374 sDataDescriptions* dataDescriptions;
375 this->Internal->NNClient->GetDataDescriptions(&dataDescriptions);
376 for (
int i = 0;
i < dataDescriptions->nDataDescriptions; ++
i)
378 sDataDescription currentDescription = dataDescriptions->arrDataDescriptions[
i];
379 if (currentDescription.type == Descriptor_RigidBody)
382 if (!rigidBodies.insert(currentDescription.Data.RigidBodyDescription->szName).second)
384 LOG_ERROR(
"Duplicate rigid bodies with name: " << currentDescription.Data.RigidBodyDescription->szName);
391 this->Internal->LastMotiveDataDescriptionsUpdateTimestamp = -1;
399 LOG_TRACE(
"vtkPlusOptiTrack::InternalDisconnect");
400 if (!this->Internal->AttachToRunningMotive)
409 PlusStatus vtkPlusOptiTrack::InternalStartRecording()
411 LOG_TRACE(
"vtkPlusOptiTrack::InternalStartRecording");
416 PlusStatus vtkPlusOptiTrack::InternalStopRecording()
424 LOG_TRACE(
"vtkPlusOptiTrack::InternalUpdate");
426 #if MOTIVE_VERSION_MAJOR >= 3 428 #elif MOTIVE_VERSION_MAJOR >= 2 && MOTIVE_VERSION_MINOR >= 3 429 TT_UpdateLatestFrame();
437 void vtkPlusOptiTrack::vtkInternal::InternalCallback(sFrameOfMocapData*
data,
void* pUserData)
441 LOG_TRACE(
"vtkPlusOptiTrack::InternalCallback");
442 const double unfilteredTimestamp = vtkIGSIOAccurateTimer::GetSystemTime();
444 if (self->Internal->LastMotiveDataDescriptionsUpdateTimestamp < 0)
447 self->Internal->UpdateMotiveDataDescriptions();
450 if (self->Internal->AttachToRunningMotive && self->Internal->MotiveDataDescriptionsUpdateTimeSec >= 0)
452 double timeSinceMotiveDataDescriptionsUpdate = unfilteredTimestamp -
self->Internal->LastMotiveDataDescriptionsUpdateTimestamp;
453 if (timeSinceMotiveDataDescriptionsUpdate > self->Internal->MotiveDataDescriptionsUpdateTimeSec)
455 self->Internal->UpdateMotiveDataDescriptions();
459 int numberOfRigidBodies =
data->nRigidBodies;
460 sRigidBodyData* rigidBodies =
data->RigidBodies;
463 vtkSmartPointer<vtkMatrix4x4> rigidBodyToTrackerMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
465 for (
int rigidBodyId = 0; rigidBodyId < numberOfRigidBodies; ++rigidBodyId)
468 rigidBodyToTrackerMatrix->Identity();
469 sRigidBodyData currentRigidBody = rigidBodies[rigidBodyId];
471 if (currentRigidBody.MeanError != 0)
474 double translation[3] = { currentRigidBody.x *
self->Internal->UnitsToMm, currentRigidBody.y *
self->Internal->UnitsToMm, currentRigidBody.z *
self->Internal->UnitsToMm };
477 double quaternion[4] = { currentRigidBody.qw, currentRigidBody.qx, currentRigidBody.qy, currentRigidBody.qz };
478 double rotation[3][3] = { 0,0,0, 0,0,0, 0,0,0 };
479 vtkMath::QuaternionToMatrix3x3(quaternion, rotation);
482 for (
int i = 0;
i < 3; ++
i)
484 for (
int j = 0; j < 3; ++j)
486 rigidBodyToTrackerMatrix->SetElement(
i, j, rotation[
i][j]);
488 rigidBodyToTrackerMatrix->SetElement(
i, 3, translation[
i]);
492 bool bTrackingValid = currentRigidBody.params & 0x01;
495 igsioTransformName toolToTracker =
self->Internal->MapRBNameToTransform[currentRigidBody.ID];
496 self->ToolTimeStampedUpdate(toolToTracker.GetTransformName(), rigidBodyToTrackerMatrix, (bTrackingValid ? TOOL_OK : TOOL_INVALID), self->FrameNumber, unfilteredTimestamp);
501 igsioTransformName toolToTracker =
self->Internal->MapRBNameToTransform[currentRigidBody.ID];
502 self->ToolTimeStampedUpdate(toolToTracker.GetTransformName(), rigidBodyToTrackerMatrix, TOOL_OUT_OF_VIEW,
self->FrameNumber, unfilteredTimestamp);
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
Abstract interface for tracker and video devices.
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement)
virtual PlusStatus InternalDisconnect()
Interface to the OptiTrack trackers This class talks with a OptiTrack Tracker over the NatNet SDK....
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *config)
static vtkPlusConfig * GetInstance()
unsigned long FrameNumber
double InternalUpdateRate
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
bool StartThreadForInternalUpdates
void PrintSelf(ostream &os, vtkIndent indent)
vtkStandardNewMacro(vtkPlusOptiTrack)
std::string GetDeviceSetConfigurationPath(const std::string &subPath)
PlusStatus InternalConnect()
PlusStatus InternalUpdate()
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *config)