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> 24 #include <MotiveAPI.h> 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 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 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 74 class vtkPlusOptiTrack::vtkInternal
83 , MotiveDataDescriptionsUpdateTimeSec(1.0)
84 , LastMotiveDataDescriptionsUpdateTimestamp(-1)
88 virtual ~vtkInternal()
93 NatNetClient* NNClient;
97 #if MOTIVE_VERSION_MAJOR >= 2 99 std::string Calibration;
101 std::string ProjectFile;
104 std::string CalibrationFile;
105 std::vector<std::string> AdditionalRigidBodyFiles;
108 std::map<int, igsioTransformName> MapRBNameToTransform;
111 bool AttachToRunningMotive;
114 double LastMotiveDataDescriptionsUpdateTimestamp;
115 double MotiveDataDescriptionsUpdateTimeSec;
120 #if MOTIVE_VERSION_MAJOR >= 3 && MOTIVE_VERSION_MINOR >= 1 121 std::wstring GetMotiveErrorMessage(
ResultType result);
123 std::string GetMotiveErrorMessage(
ResultType result);
129 static void InternalCallback(sFrameOfMocapData*
data,
void* pUserData);
131 void UpdateMotiveDataDescriptions();
135 #if MOTIVE_VERSION_MAJOR >= 3 && MOTIVE_VERSION_MINOR >= 1 136 std::wstring vtkPlusOptiTrack::vtkInternal::GetMotiveErrorMessage(MotiveAPI::eResult result)
138 std::string vtkPlusOptiTrack::vtkInternal::GetMotiveErrorMessage(
ResultType result)
141 #if MOTIVE_VERSION_MAJOR >= 3 && MOTIVE_VERSION_MINOR >= 1 142 return std::wstring(MotiveAPI::MapToResultString(result));
150 void vtkPlusOptiTrack::vtkInternal::UpdateMotiveDataDescriptions()
152 LOG_TRACE(
"vtkPlusOptiTrack::vtkInternal::MatchTrackedTools");
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)
160 sDataDescription currentDescription = dataDescriptions->arrDataDescriptions[
i];
161 if (currentDescription.type == Descriptor_RigidBody)
164 igsioTransformName toolToTracker = igsioTransformName(currentDescription.Data.RigidBodyDescription->szName, referenceFrame);
165 this->MapRBNameToTransform[currentDescription.Data.RigidBodyDescription->ID] = toolToTracker;
169 this->LastMotiveDataDescriptionsUpdateTimestamp = vtkIGSIOAccurateTimer::GetSystemTime();
175 , Internal(new vtkInternal(this))
199 LOG_TRACE(
"vtkPlusOptiTrack::ReadConfiguration");
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);
206 XML_READ_STRING_ATTRIBUTE_NONMEMBER_REQUIRED(ProjectFile, this->Internal->ProjectFile, deviceConfig);
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);
211 XML_FIND_NESTED_ELEMENT_REQUIRED(dataSourcesElement, deviceConfig,
"DataSources");
212 for (
int nestedElementIndex = 0; nestedElementIndex < dataSourcesElement->GetNumberOfNestedElements(); nestedElementIndex++)
214 vtkXMLDataElement* toolDataElement = dataSourcesElement->GetNestedElement(nestedElementIndex);
215 if (STRCASECMP(toolDataElement->GetName(),
"DataSource") != 0)
220 if (toolDataElement->GetAttribute(
"Type") != NULL && STRCASECMP(toolDataElement->GetAttribute(
"Type"),
"Tool") != 0)
226 std::string toolId(toolDataElement->GetAttribute(
"Id"));
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.");
234 if (toolDataElement->GetAttribute(
"RigidBodyFile") != NULL)
237 const char* rigidBodyFile = toolDataElement->GetAttribute(
"RigidBodyFile");
238 this->Internal->AdditionalRigidBodyFiles.push_back(rigidBodyFile);
248 LOG_TRACE(
"vtkPlusOptiTrack::WriteConfiguration");
256 LOG_TRACE(
"vtkPlusOptiTrack::Probe");
263 LOG_TRACE(
"vtkPlusOptiTrack::InternalConnect");
264 if (!this->Internal->AttachToRunningMotive)
266 #if MOTIVE_VERSION_MAJOR >= 2 267 #if MOTIVE_VERSION_MAJOR >= 3 && MOTIVE_VERSION_MINOR >= 1 274 LOG_ERROR(
"Failed to start Motive. Another instance is already running.");
283 LOG_ERROR(
"Failed to start Motive.");
290 #if MOTIVE_VERSION_MAJOR >= 2 293 #if MOTIVE_VERSION_MAJOR < 3 296 std::wstring wProfilePath = vtksys::Encoding::ToWide(profilePath);
301 #if MOTIVE_VERSION_MAJOR < 3 311 #if MOTIVE_VERSION_MAJOR < 3 314 std::wstring wCalibrationPath = vtksys::Encoding::ToWide(calibrationPath);
319 #if MOTIVE_VERSION_MAJOR < 3 320 LOG_ERROR(
"Failed to load Motive calibration. Motive error: " <<
MotiveGetResultString(profileLoad));
322 LOG_ERROR_W(
"Failed to load Motive calibration. Motive error: " <<
MotiveGetResultString(profileLoad));
329 NPRESULT ttpLoad = TT_LoadProject(projectFilePath.c_str());
330 if (ttpLoad != NPRESULT_SUCCESS)
342 #if MOTIVE_VERSION_MAJOR < 3 343 LOG_ERROR(
"Failed to enable NatNet streaming. Motive error: " <<
MotiveGetResultString(streamEnable));
345 LOG_ERROR_W(
"Failed to enable NatNet streaming. Motive error: " <<
MotiveGetResultString(streamEnable));
351 std::string rbFilePath;
352 for (
auto it = this->Internal->AdditionalRigidBodyFiles.begin(); it != this->Internal->AdditionalRigidBodyFiles.end(); it++)
355 #if MOTIVE_VERSION_MAJOR < 3 358 std::wstring wRBFilePath = vtksys::Encoding::ToWide(rbFilePath);
363 #if MOTIVE_VERSION_MAJOR < 3 364 LOG_ERROR(
"Failed to enable NatNet streaming. Motive error: " <<
MotiveGetResultString(streamEnable));
366 LOG_ERROR_W(
"Failed to load rigid body file located at: " << wRBFilePath <<
". Motive error message: " <<
MotiveGetResultString(addRBResult));
372 LOG_INFO(
"\n---------------------------------MOTIVE SETTINGS--------------------------------");
374 LOG_INFO(
"Connected cameras:");
377 #if MOTIVE_VERSION_MAJOR < 3 380 wchar_t cameraName[256];
382 LOG_INFO_W(
i << L
": " << cameraName);
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);
390 LOG_INFO(
"\nUsing Motive project file located at:\n" << projectFilePath);
393 LOG_INFO(
"\nTracked rigid bodies:");
396 #if MOTIVE_VERSION_MAJOR < 3 399 wchar_t rigidBodyName[256];
401 LOG_INFO_W(rigidBodyName);
404 LOG_INFO(
"--------------------------------------------------------------------------------\n");
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);
415 int retCode = this->Internal->NNClient->Initialize(
"127.0.0.1",
"127.0.0.1");
419 if (this->Internal->NNClient->SendMessageAndWait(
"UnitsToMillimeters", &response, &nBytes) == ErrorCode_OK)
421 this->Internal->UnitsToMm = (*(
float*)response);
426 LOG_ERROR(
"Failed to connect to Motive. Please either set AttachToRunningMotive=FALSE or ensure that Motive is running and streaming is enabled.");
431 std::set<std::string> rigidBodies;
432 sDataDescriptions* dataDescriptions;
433 this->Internal->NNClient->GetDataDescriptions(&dataDescriptions);
434 for (
int i = 0;
i < dataDescriptions->nDataDescriptions; ++
i)
436 sDataDescription currentDescription = dataDescriptions->arrDataDescriptions[
i];
437 if (currentDescription.type == Descriptor_RigidBody)
440 if (!rigidBodies.insert(currentDescription.Data.RigidBodyDescription->szName).second)
442 LOG_ERROR(
"Duplicate rigid bodies with name: " << currentDescription.Data.RigidBodyDescription->szName);
449 this->Internal->LastMotiveDataDescriptionsUpdateTimestamp = -1;
457 LOG_TRACE(
"vtkPlusOptiTrack::InternalDisconnect");
458 if (!this->Internal->AttachToRunningMotive)
467 PlusStatus vtkPlusOptiTrack::InternalStartRecording()
469 LOG_TRACE(
"vtkPlusOptiTrack::InternalStartRecording");
474 PlusStatus vtkPlusOptiTrack::InternalStopRecording()
482 LOG_TRACE(
"vtkPlusOptiTrack::InternalUpdate");
484 #if MOTIVE_VERSION_MAJOR >= 3 486 #elif MOTIVE_VERSION_MAJOR >= 2 && MOTIVE_VERSION_MINOR >= 3 487 TT_UpdateLatestFrame();
495 void vtkPlusOptiTrack::vtkInternal::InternalCallback(sFrameOfMocapData*
data,
void* pUserData)
499 LOG_TRACE(
"vtkPlusOptiTrack::InternalCallback");
500 const double unfilteredTimestamp = vtkIGSIOAccurateTimer::GetSystemTime();
502 if (self->Internal->LastMotiveDataDescriptionsUpdateTimestamp < 0)
505 self->Internal->UpdateMotiveDataDescriptions();
508 if (self->Internal->AttachToRunningMotive && self->Internal->MotiveDataDescriptionsUpdateTimeSec >= 0)
510 double timeSinceMotiveDataDescriptionsUpdate = unfilteredTimestamp -
self->Internal->LastMotiveDataDescriptionsUpdateTimestamp;
511 if (timeSinceMotiveDataDescriptionsUpdate > self->Internal->MotiveDataDescriptionsUpdateTimeSec)
513 self->Internal->UpdateMotiveDataDescriptions();
517 int numberOfRigidBodies =
data->nRigidBodies;
518 sRigidBodyData* rigidBodies =
data->RigidBodies;
521 vtkSmartPointer<vtkMatrix4x4> rigidBodyToTrackerMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
523 for (
int rigidBodyId = 0; rigidBodyId < numberOfRigidBodies; ++rigidBodyId)
526 rigidBodyToTrackerMatrix->Identity();
527 sRigidBodyData currentRigidBody = rigidBodies[rigidBodyId];
529 if (currentRigidBody.MeanError != 0)
532 double translation[3] = { currentRigidBody.x *
self->Internal->UnitsToMm, currentRigidBody.y *
self->Internal->UnitsToMm, currentRigidBody.z *
self->Internal->UnitsToMm };
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);
540 for (
int i = 0;
i < 3; ++
i)
542 for (
int j = 0; j < 3; ++j)
544 rigidBodyToTrackerMatrix->SetElement(
i, j, rotation[
i][j]);
546 rigidBodyToTrackerMatrix->SetElement(
i, 3, translation[
i]);
550 bool bTrackingValid = currentRigidBody.params & 0x01;
553 igsioTransformName toolToTracker =
self->Internal->MapRBNameToTransform[currentRigidBody.ID];
554 self->ToolTimeStampedUpdate(toolToTracker.GetTransformName(), rigidBodyToTrackerMatrix, (bTrackingValid ? TOOL_OK : TOOL_INVALID), self->FrameNumber, unfilteredTimestamp);
559 igsioTransformName toolToTracker =
self->Internal->MapRBNameToTransform[currentRigidBody.ID];
560 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....
#define MotiveCameraCount
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *config)
static vtkPlusConfig * GetInstance()
unsigned long FrameNumber
#define MotiveTestConnection
#define MotiveRigidBodyCount
double InternalUpdateRate
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
#define MotiveAddRigidBodies
#define MotiveLoadCalibration
#define MotiveGetResultString
#define MotiveLoadProfile
bool StartThreadForInternalUpdates
void PrintSelf(ostream &os, vtkIndent indent)
vtkStandardNewMacro(vtkPlusOptiTrack)
std::string GetDeviceSetConfigurationPath(const std::string &subPath)
PlusStatus InternalConnect()
#define MotiveGetRigidBodyName
PlusStatus InternalUpdate()
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *config)