PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusLeapMotion.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 "vtkPlusLeapMotion.h"
10 #include "PlusMath.h"
11 
12 // VTK includes
13 #include <vtkImageImport.h>
14 #include <vtkMatrix4x4.h>
15 #include <vtkObjectFactory.h>
16 #include <vtkPlusDataSource.h>
17 #include <vtkQuaternion.h>
18 #include <vtkTransform.h>
19 #include <vtkXMLDataElement.h>
20 #include <vtksys/SystemTools.hxx>
21 
22 // OS includes
23 #include <math.h>
24 
25 // STL includes
26 #include <sstream>
27 
28 //-------------------------------------------------------------------------
29 
31 
32 //-------------------------------------------------------------------------
33 
34 namespace
35 {
36  static void* allocate(uint32_t size, eLeapAllocatorType typeHint, void* state)
37  {
38  void* ptr = malloc(size);
39  return ptr;
40  }
41 
42  static void deallocate(void* ptr, void* state)
43  {
44  if (!ptr)
45  {
46  return;
47  }
48  free(ptr);
49  }
50 }
51 
52 //-------------------------------------------------------------------------
54  : PollTimeoutMs(1000)
55  , Mutex(vtkIGSIORecursiveCriticalSection::New())
56  , LeapHMDPolicy(false)
57  , RefusePauseResumePolicy(false)
58  , Initialized(false)
59  , ImageInitialized(false)
60  , LeftCameraSource(nullptr)
61  , RightCameraSource(nullptr)
62  , InvertImage(false)
63 {
65  this->StartThreadForInternalUpdates = true; // polling based device
66  this->AcquisitionRate = 120;
67 }
68 
69 //-------------------------------------------------------------------------
71 {
72  this->Mutex->Delete();
73  if (this->Recording)
74  {
75  this->StopRecording();
76  }
77 }
78 
79 //-------------------------------------------------------------------------
80 void vtkPlusLeapMotion::PrintSelf(ostream& os, vtkIndent indent)
81 {
82  Superclass::PrintSelf(os, indent);
83 
84  os << "Poll timeout (ms)" << this->PollTimeoutMs << std::endl;
85  os << "Leap HMD policy" << (this->LeapHMDPolicy ? "TRUE" : "FALSE") << std::endl;
86  os << "Override pause/resume policy" << (this->RefusePauseResumePolicy ? "TRUE" : "FALSE") << std::endl;
87  os << "Invert image:" << (this->InvertImage ? "TRUE" : "FALSE") << std::endl;
88 }
89 
90 //----------------------------------------------------------------------------
91 PlusStatus vtkPlusLeapMotion::ReadConfiguration(vtkXMLDataElement* rootConfigElement)
92 {
93  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement);
94 
95  XML_READ_BOOL_ATTRIBUTE_OPTIONAL(LeapHMDPolicy, deviceConfig);
96  XML_READ_BOOL_ATTRIBUTE_OPTIONAL(RefusePauseResumePolicy, deviceConfig);
97  XML_READ_BOOL_ATTRIBUTE_OPTIONAL(InvertImage, deviceConfig);
98 
99  return PLUS_SUCCESS;
100 }
101 
102 //----------------------------------------------------------------------------
103 PlusStatus vtkPlusLeapMotion::WriteConfiguration(vtkXMLDataElement* rootConfigElement)
104 {
105  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement);
106 
107  XML_WRITE_BOOL_ATTRIBUTE(LeapHMDPolicy, deviceConfig);
108  XML_WRITE_BOOL_ATTRIBUTE(RefusePauseResumePolicy, deviceConfig);
109  XML_WRITE_BOOL_ATTRIBUTE(InvertImage, deviceConfig);
110 
111  return PLUS_SUCCESS;
112 }
113 
114 //-------------------------------------------------------------------------
116 {
117  LOG_TRACE("vtkPlusLeapMotion::Connect");
118 
119  if (this->Connected)
120  {
121  return PLUS_SUCCESS;
122  }
123  eLeapRS result;
124  if ((result = LeapCreateConnection(NULL, &this->Connection)) != eLeapRS_Success)
125  {
126  LOG_ERROR("Unable to create the connection to the LeapMotion device:" << this->ResultToString(result));
127  return PLUS_FAIL;
128  }
129  if ((result = LeapOpenConnection(this->Connection)) != eLeapRS_Success)
130  {
131  LOG_ERROR("Unable to open the connection to the LeapMotion device:" << this->ResultToString(result));
132  return PLUS_FAIL;
133  }
134 
135  LEAP_ALLOCATOR allocator = { allocate, deallocate, NULL };
136  if ((result = LeapSetAllocator(this->Connection, &allocator)) != eLeapRS_Success)
137  {
138  LOG_WARNING("Unable to set allocator. Some functionality may be missing.");
139  }
140 
141  return PLUS_SUCCESS;
142 }
143 
144 //-------------------------------------------------------------------------
146 {
147  LOG_TRACE("vtkPlusLeapMotion::Disconnect");
148 
149  LeapCloseConnection(this->Connection);
150  LeapDestroyConnection(this->Connection);
151 
152  return PLUS_SUCCESS;
153 }
154 
155 //----------------------------------------------------------------------------
157 {
158  LOG_TRACE("vtkPlusLeapMotion::InternalUpdate");
159  eLeapRS result = LeapPollConnection(this->Connection, this->PollTimeoutMs, &this->LastMessage);
160 
161  if (result == eLeapRS_Timeout)
162  {
163  this->PollTimeoutMs += 2;
164  return PLUS_SUCCESS;
165  }
166 
167  if (result != eLeapRS_Success)
168  {
169  LOG_ERROR("LeapC PollConnection call error: " << this->ResultToString(result));
170  return PLUS_FAIL;
171  }
172 
173  if (!this->Initialized)
174  {
175  // Set policy flags once
176  uint64_t set = eLeapPolicyFlag_Images;
177  uint64_t clear = 0;
178  if (this->RefusePauseResumePolicy)
179  {
180  clear |= eLeapPolicyFlag_AllowPauseResume;
181  }
182  else
183  {
184  set |= eLeapPolicyFlag_AllowPauseResume;
185  }
186 
187  if (this->LeapHMDPolicy)
188  {
189  set |= eLeapPolicyFlag_OptimizeHMD;
190  }
191  else
192  {
193  clear |= eLeapPolicyFlag_OptimizeHMD;
194  }
195 
196  if ((result = LeapSetPolicyFlags(this->Connection, set, clear)) != eLeapRS_Success)
197  {
198  LOG_WARNING("Unable to set HMD policy flag, tracking will be greatly degraded if attached to an HMD: " << this->ResultToString(result));
199  }
200  this->Initialized = true;
201  }
202 
203  switch (this->LastMessage.type)
204  {
205  case eLeapEventType_Connection:
206  return this->OnConnectionEvent(this->LastMessage.connection_event);
207  case eLeapEventType_ConnectionLost:
208  return this->OnConnectionLostEvent(this->LastMessage.connection_lost_event);
209  case eLeapEventType_Device:
210  return this->OnDeviceEvent(this->LastMessage.device_event);
211  case eLeapEventType_DeviceLost:
212  return this->OnDeviceLostEvent(this->LastMessage.device_event);
213  case eLeapEventType_DeviceFailure:
214  return this->OnDeviceFailureEvent(this->LastMessage.device_failure_event);
215  case eLeapEventType_Tracking:
216  return this->OnTrackingEvent(this->LastMessage.tracking_event);
217  case eLeapEventType_LogEvent:
218  return this->OnLogEvent(this->LastMessage.log_event);
219  case eLeapEventType_Policy:
220  return this->OnPolicyEvent(this->LastMessage.policy_event);
221  case eLeapEventType_ConfigChange:
222  return this->OnConfigChangeEvent(this->LastMessage.config_change_event);
223  case eLeapEventType_ConfigResponse:
224  return this->OnConfigResponseEvent(this->LastMessage.config_response_event);
225  case eLeapEventType_Image:
226  return this->OnImageEvent(this->LastMessage.image_event);
227  case eLeapEventType_PointMappingChange:
228  return this->OnPointMappingChangeEvent(this->LastMessage.point_mapping_change_event);
229  case eLeapEventType_LogEvents:
230  return this->OnLogEvents(this->LastMessage.log_events);
231  case eLeapEventType_HeadPose:
232  return this->OnHeadPoseEvent(this->LastMessage.head_pose_event);
233  case eLeapEventType_ImageComplete:
234  case eLeapEventType_ImageRequestError:
235  return PLUS_SUCCESS;
236  default:
237  LOG_WARNING("Unhandled event type " << EventToString(this->LastMessage.type));
238  }
239 
240  return PLUS_FAIL;
241 }
242 
243 //-------------------------------------------------------------------------
245 {
246  LOG_TRACE("vtkPlusLeapMotion::Probe");
247 
248  if (this->InternalConnect() == PLUS_SUCCESS)
249  {
250  return this->InternalDisconnect();
251  }
252  return PLUS_FAIL;
253 }
254 
255 //-------------------------------------------------------------------------
257 {
258  LOG_TRACE("vtkPlusLeapMotion::InternalStartRecording");
259 
260  eLeapRS result = LeapOpenConnection(this->Connection);
261  if (result == eLeapRS_Success)
262  {
263  return PLUS_SUCCESS;
264  }
265  return PLUS_FAIL;
266 }
267 
268 //-------------------------------------------------------------------------
270 {
271  LOG_TRACE("vtkPlusLeapMotion::InternalStopRecording");
272 
273  LeapCloseConnection(this->Connection);
274 
275  return PLUS_SUCCESS;
276 }
277 
278 #define CHECK_DATA_SOURCE(name) if(this->GetDataSource(std::string(#name) + "To" + this->ToolReferenceFrameName, aSource) != PLUS_SUCCESS){ LOG_WARNING("Data source with ID \"" << #name << "\" doesn't exist. Joint will not be tracked.");}
279 //----------------------------------------------------------------------------
281 {
282  vtkPlusDataSource* aSource(nullptr);
283 
284  // Check for 19 data sources per hand
285  CHECK_DATA_SOURCE(LeftThumbProximal);
286  CHECK_DATA_SOURCE(LeftThumbIntermediate);
287  CHECK_DATA_SOURCE(LeftThumbDistal);
288 
289  CHECK_DATA_SOURCE(LeftIndexMetacarpal);
290  CHECK_DATA_SOURCE(LeftIndexProximal);
291  CHECK_DATA_SOURCE(LeftIndexIntermediate);
292  CHECK_DATA_SOURCE(LeftIndexDistal);
293 
294  CHECK_DATA_SOURCE(LeftMiddleMetacarpal);
295  CHECK_DATA_SOURCE(LeftMiddleProximal);
296  CHECK_DATA_SOURCE(LeftMiddleIntermediate);
297  CHECK_DATA_SOURCE(LeftMiddleDistal);
298 
299  CHECK_DATA_SOURCE(LeftRingMetacarpal);
300  CHECK_DATA_SOURCE(LeftRingProximal);
301  CHECK_DATA_SOURCE(LeftRingIntermediate);
302  CHECK_DATA_SOURCE(LeftRingDistal);
303 
304  CHECK_DATA_SOURCE(LeftPinkyMetacarpal);
305  CHECK_DATA_SOURCE(LeftPinkyProximal);
306  CHECK_DATA_SOURCE(LeftPinkyIntermediate);
307  CHECK_DATA_SOURCE(LeftPinkyDistal);
308 
309  CHECK_DATA_SOURCE(RightThumbProximal);
310  CHECK_DATA_SOURCE(RightThumbIntermediate);
311  CHECK_DATA_SOURCE(RightThumbDistal);
312 
313  CHECK_DATA_SOURCE(RightIndexMetacarpal);
314  CHECK_DATA_SOURCE(RightIndexProximal);
315  CHECK_DATA_SOURCE(RightIndexIntermediate);
316  CHECK_DATA_SOURCE(RightIndexDistal);
317 
318  CHECK_DATA_SOURCE(RightMiddleMetacarpal);
319  CHECK_DATA_SOURCE(RightMiddleProximal);
320  CHECK_DATA_SOURCE(RightMiddleIntermediate);
321  CHECK_DATA_SOURCE(RightMiddleDistal);
322 
323  CHECK_DATA_SOURCE(RightRingMetacarpal);
324  CHECK_DATA_SOURCE(RightRingProximal);
325  CHECK_DATA_SOURCE(RightRingIntermediate);
326  CHECK_DATA_SOURCE(RightRingDistal);
327 
328  CHECK_DATA_SOURCE(RightPinkyMetacarpal);
329  CHECK_DATA_SOURCE(RightPinkyProximal);
330  CHECK_DATA_SOURCE(RightPinkyIntermediate);
331  CHECK_DATA_SOURCE(RightPinkyDistal);
332 
333  CHECK_DATA_SOURCE(LeftPalm);
334  CHECK_DATA_SOURCE(RightPalm);
335 
336  if (this->GetNumberOfTools() < 1)
337  {
338  LOG_ERROR("Must record at least one joint/palm. Please add a data source.");
339  return PLUS_FAIL;
340  }
341 
342  if (this->OutputChannelCount() < 1)
343  {
344  LOG_ERROR("Device must have at least one output channel.");
345  return PLUS_FAIL;
346  }
347 
348  if (this->GetNumberOfVideoSources() >= 2)
349  {
350  if (this->GetVideoSourceByIndex(0, this->LeftCameraSource) != PLUS_SUCCESS)
351  {
352  return PLUS_FAIL;
353  }
355  {
356  return PLUS_FAIL;
357  }
358  }
359 
360  // Add dummy transform into tool so that plus server doesn't complain about inability to retrieve a timestamp
361  vtkNew<vtkMatrix4x4> mat;
362  this->ToolTimeStampedUpdate(this->Tools.begin()->second->GetSourceId(), mat, TOOL_INVALID, 0, UNDEFINED_TIMESTAMP);
363 
364  this->PollTimeoutMs = 1000.0 / this->AcquisitionRate;
365  return PLUS_SUCCESS;
366 }
367 #undef CHECK_DATA_SOURCE
368 
369 //----------------------------------------------------------------------------
370 PlusStatus vtkPlusLeapMotion::ToolTimeStampedUpdateBone(std::string boneName, eLeapHandType handIndex, Finger fingerIndex, Bone boneIndex)
371 {
372  vtkPlusDataSource* aSource(nullptr);
373  if (this->GetDataSource(boneName + "To" + this->ToolReferenceFrameName, aSource) == PLUS_SUCCESS)
374  {
375  vtkNew<vtkTransform> pose;
376  bool found(false);
377  for (uint32_t i = 0; i < this->LastTrackingEvent.nHands; ++i)
378  {
379  LEAP_HAND& hand = this->LastTrackingEvent.pHands[i];
380  if (hand.type != handIndex)
381  {
382  continue;
383  }
384  LEAP_BONE& bone = hand.digits[fingerIndex].bones[boneIndex];
385 
386  vtkQuaternion<float> orientation;
387  orientation.Set(bone.rotation.w, bone.rotation.x, bone.rotation.y, bone.rotation.z);
388  float axis[3];
389  float angle = orientation.GetRotationAngleAndAxis(axis);
390  pose->Translate(bone.next_joint.x, bone.next_joint.y, bone.next_joint.z);
391  pose->RotateWXYZ(vtkMath::DegreesFromRadians(angle), axis);
392  float x = bone.next_joint.x - bone.prev_joint.x;
393  float y = bone.next_joint.y - bone.prev_joint.y;
394  float z = bone.next_joint.z - bone.prev_joint.z;
395  float mag = std::sqrtf(x * x + y * y + z * z);
396  igsioFieldMapType fields;
397  {
398  std::stringstream ss;
399  ss << mag;
400  fields[boneName + "To" + this->ToolReferenceFrameName + "lengthMm"].first = FRAMEFIELD_FORCE_SERVER_SEND;
401  fields[boneName + "To" + this->ToolReferenceFrameName + "lengthMm"].second = ss.str();
402  }
403 
404  {
405  std::stringstream ss;
406  ss << bone.width;
407  fields[boneName + "To" + this->ToolReferenceFrameName + "radiusMm"].first = FRAMEFIELD_FORCE_SERVER_SEND;
408  fields[boneName + "To" + this->ToolReferenceFrameName + "radiusMm"].second = ss.str();
409  }
410 
411  if (this->ToolTimeStampedUpdate(boneName + "To" + this->ToolReferenceFrameName, pose->GetMatrix(), TOOL_OK, this->FrameNumber, UNDEFINED_TIMESTAMP, &fields) != PLUS_SUCCESS)
412  {
413  LOG_ERROR("Unable to record " << boneName << " transform.");
414  return PLUS_FAIL;
415  }
416 
417  return PLUS_SUCCESS;
418  }
419 
420  if (!found)
421  {
422  vtkNew<vtkMatrix4x4> mat;
423  this->ToolTimeStampedUpdate(boneName + "To" + this->ToolReferenceFrameName, mat, TOOL_OUT_OF_VIEW, this->FrameNumber, UNDEFINED_TIMESTAMP);
424  }
425 
426  return PLUS_SUCCESS;
427  }
428 
429  return PLUS_FAIL;
430 }
431 
432 //----------------------------------------------------------------------------
433 PlusStatus vtkPlusLeapMotion::ToolTimeStampedUpdatePalm(const std::string& name, eLeapHandType handType)
434 {
435  vtkPlusDataSource* aSource(nullptr);
436  if (this->GetDataSource(name + "To" + this->ToolReferenceFrameName, aSource) == PLUS_SUCCESS)
437  {
438  vtkNew<vtkTransform> pose;
439  bool found(false);
440  for (uint32_t i = 0; i < this->LastTrackingEvent.nHands; ++i)
441  {
442  LEAP_HAND& hand = this->LastTrackingEvent.pHands[i];
443  if (hand.type != handType)
444  {
445  continue;
446  }
447  LEAP_PALM& palm = hand.palm;
448  vtkQuaternion<float> orientation;
449  orientation.Set(palm.orientation.w, palm.orientation.x, palm.orientation.y, palm.orientation.z);
450  pose->Translate(palm.position.x, palm.position.y, palm.position.z);
451  float axis[3];
452  float angle = orientation.GetRotationAngleAndAxis(axis);
453  pose->RotateWXYZ(angle, axis);
454  if (this->ToolTimeStampedUpdate(name + "To" + this->ToolReferenceFrameName, pose->GetMatrix(), TOOL_OK, this->FrameNumber, UNDEFINED_TIMESTAMP) != PLUS_SUCCESS)
455  {
456  LOG_ERROR("Unable to record " << name << " transform.");
457  return PLUS_FAIL;
458  }
459 
460  return PLUS_SUCCESS;
461  }
462  if (!found)
463  {
464  vtkNew<vtkMatrix4x4> mat;
465  this->ToolTimeStampedUpdate(name + "To" + this->ToolReferenceFrameName, mat, TOOL_OUT_OF_VIEW, this->FrameNumber, UNDEFINED_TIMESTAMP);
466  }
467 
468  return PLUS_SUCCESS;
469  }
470 
471  return PLUS_FAIL;
472 }
473 
474 //----------------------------------------------------------------------------
475 void vtkPlusLeapMotion::SetFrame(const LEAP_TRACKING_EVENT* trackingEvent)
476 {
477  this->Mutex->Lock();
478  this->LastTrackingEvent = *trackingEvent;
479  this->Mutex->Unlock();
480 }
481 
482 //----------------------------------------------------------------------------
483 LEAP_TRACKING_EVENT* vtkPlusLeapMotion::GetFrame()
484 {
485  return &this->LastTrackingEvent;
486 }
487 
488 //----------------------------------------------------------------------------
489 void vtkPlusLeapMotion::SetHeadPose(const LEAP_HEAD_POSE_EVENT* headPose)
490 {
491  this->Mutex->Lock();
492  this->LastHeadPoseEvent = *headPose;
493  this->Mutex->Unlock();
494 }
495 
496 //----------------------------------------------------------------------------
497 LEAP_HEAD_POSE_EVENT* vtkPlusLeapMotion::GetHeadPose()
498 {
499  return &this->LastHeadPoseEvent;
500 }
501 
502 //----------------------------------------------------------------------------
503 PlusStatus vtkPlusLeapMotion::OnConnectionEvent(const LEAP_CONNECTION_EVENT* connectionEvent)
504 {
505  return PLUS_SUCCESS;
506 }
507 
508 //----------------------------------------------------------------------------
509 PlusStatus vtkPlusLeapMotion::OnConnectionLostEvent(const LEAP_CONNECTION_LOST_EVENT* connectionLostEvent)
510 {
511  return PLUS_SUCCESS;
512 }
513 
514 //----------------------------------------------------------------------------
515 PlusStatus vtkPlusLeapMotion::OnDeviceEvent(const LEAP_DEVICE_EVENT* deviceEvent)
516 {
517  return PLUS_SUCCESS;
518 }
519 
520 //----------------------------------------------------------------------------
521 PlusStatus vtkPlusLeapMotion::OnDeviceLostEvent(const LEAP_DEVICE_EVENT* deviceEvent)
522 {
523  return PLUS_SUCCESS;
524 }
525 
526 //----------------------------------------------------------------------------
527 PlusStatus vtkPlusLeapMotion::OnDeviceFailureEvent(const LEAP_DEVICE_FAILURE_EVENT* deviceFailureEvent)
528 {
529  return PLUS_SUCCESS;
530 }
531 
532 //----------------------------------------------------------------------------
533 PlusStatus vtkPlusLeapMotion::OnPolicyEvent(const LEAP_POLICY_EVENT* policyEvent)
534 {
535  if ((policyEvent->current_policy & eLeapPolicyFlag_OptimizeHMD) == (this->LeapHMDPolicy ? eLeapPolicyFlag_OptimizeHMD : 0) &&
536  (policyEvent->current_policy & eLeapPolicyFlag_AllowPauseResume) == (this->RefusePauseResumePolicy ? 0 : eLeapPolicyFlag_AllowPauseResume) &&
537  (policyEvent->current_policy & eLeapPolicyFlag_Images) == eLeapPolicyFlag_Images)
538  {
539  LOG_INFO("Successfully changed policy.");
540  return PLUS_SUCCESS;
541  }
542  else
543  {
544  LOG_ERROR("Unable to change policy.");
545  return PLUS_FAIL;
546  }
547 }
548 
549 //----------------------------------------------------------------------------
550 PlusStatus vtkPlusLeapMotion::OnTrackingEvent(const LEAP_TRACKING_EVENT* trackingEvent)
551 {
552  this->SetFrame(trackingEvent);
553 
554  // Left
555  ToolTimeStampedUpdateBone("LeftThumbProximal", eLeapHandType_Left, Finger_Thumb, Bone_Proximal);
556  ToolTimeStampedUpdateBone("LeftThumbIntermediate", eLeapHandType_Left, Finger_Thumb, Bone_Intermediate);
557  ToolTimeStampedUpdateBone("LeftThumbDistal", eLeapHandType_Left, Finger_Thumb, Bone_Distal);
558 
559  ToolTimeStampedUpdateBone("LeftIndexMetacarpal", eLeapHandType_Left, Finger_Index, Bone_Metacarpal);
560  ToolTimeStampedUpdateBone("LeftIndexProximal", eLeapHandType_Left, Finger_Index, Bone_Proximal);
561  ToolTimeStampedUpdateBone("LeftIndexIntermediate", eLeapHandType_Left, Finger_Index, Bone_Intermediate);
562  ToolTimeStampedUpdateBone("LeftIndexDistal", eLeapHandType_Left, Finger_Index, Bone_Distal);
563 
564  ToolTimeStampedUpdateBone("LeftMiddleMetacarpal", eLeapHandType_Left, Finger_Middle, Bone_Metacarpal);
565  ToolTimeStampedUpdateBone("LeftMiddleProximal", eLeapHandType_Left, Finger_Middle, Bone_Proximal);
566  ToolTimeStampedUpdateBone("LeftMiddleIntermediate", eLeapHandType_Left, Finger_Middle, Bone_Intermediate);
567  ToolTimeStampedUpdateBone("LeftMiddleDistal", eLeapHandType_Left, Finger_Middle, Bone_Distal);
568 
569  ToolTimeStampedUpdateBone("LeftRingMetacarpal", eLeapHandType_Left, Finger_Ring, Bone_Metacarpal);
570  ToolTimeStampedUpdateBone("LeftRingProximal", eLeapHandType_Left, Finger_Ring, Bone_Proximal);
571  ToolTimeStampedUpdateBone("LeftRingIntermediate", eLeapHandType_Left, Finger_Ring, Bone_Intermediate);
572  ToolTimeStampedUpdateBone("LeftRingDistal", eLeapHandType_Left, Finger_Ring, Bone_Distal);
573 
574  ToolTimeStampedUpdateBone("LeftPinkyMetacarpal", eLeapHandType_Left, Finger_Pinky, Bone_Metacarpal);
575  ToolTimeStampedUpdateBone("LeftPinkyProximal", eLeapHandType_Left, Finger_Pinky, Bone_Proximal);
576  ToolTimeStampedUpdateBone("LeftPinkyIntermediate", eLeapHandType_Left, Finger_Pinky, Bone_Intermediate);
577  ToolTimeStampedUpdateBone("LeftPinkyDistal", eLeapHandType_Left, Finger_Pinky, Bone_Distal);
578 
579  // Right
580  ToolTimeStampedUpdateBone("RightThumbProximal", eLeapHandType_Right, Finger_Thumb, Bone_Proximal);
581  ToolTimeStampedUpdateBone("RightThumbIntermediate", eLeapHandType_Right, Finger_Thumb, Bone_Intermediate);
582  ToolTimeStampedUpdateBone("RightThumbDistal", eLeapHandType_Right, Finger_Thumb, Bone_Distal);
583 
584  ToolTimeStampedUpdateBone("RightIndexMetacarpal", eLeapHandType_Right, Finger_Index, Bone_Metacarpal);
585  ToolTimeStampedUpdateBone("RightIndexProximal", eLeapHandType_Right, Finger_Index, Bone_Proximal);
586  ToolTimeStampedUpdateBone("RightIndexIntermediate", eLeapHandType_Right, Finger_Index, Bone_Intermediate);
587  ToolTimeStampedUpdateBone("RightIndexDistal", eLeapHandType_Right, Finger_Index, Bone_Distal);
588 
589  ToolTimeStampedUpdateBone("RightMiddleMetacarpal", eLeapHandType_Right, Finger_Middle, Bone_Metacarpal);
590  ToolTimeStampedUpdateBone("RightMiddleProximal", eLeapHandType_Right, Finger_Middle, Bone_Proximal);
591  ToolTimeStampedUpdateBone("RightMiddleIntermediate", eLeapHandType_Right, Finger_Middle, Bone_Intermediate);
592  ToolTimeStampedUpdateBone("RightMiddleDistal", eLeapHandType_Right, Finger_Middle, Bone_Distal);
593 
594  ToolTimeStampedUpdateBone("RightRingMetacarpal", eLeapHandType_Right, Finger_Ring, Bone_Metacarpal);
595  ToolTimeStampedUpdateBone("RightRingProximal", eLeapHandType_Right, Finger_Ring, Bone_Proximal);
596  ToolTimeStampedUpdateBone("RightRingIntermediate", eLeapHandType_Right, Finger_Ring, Bone_Intermediate);
597  ToolTimeStampedUpdateBone("RightRingDistal", eLeapHandType_Right, Finger_Ring, Bone_Distal);
598 
599  ToolTimeStampedUpdateBone("RightPinkyMetacarpal", eLeapHandType_Right, Finger_Pinky, Bone_Metacarpal);
600  ToolTimeStampedUpdateBone("RightPinkyProximal", eLeapHandType_Right, Finger_Pinky, Bone_Proximal);
601  ToolTimeStampedUpdateBone("RightPinkyIntermediate", eLeapHandType_Right, Finger_Pinky, Bone_Intermediate);
602  ToolTimeStampedUpdateBone("RightPinkyDistal", eLeapHandType_Right, Finger_Pinky, Bone_Distal);
603 
604  ToolTimeStampedUpdatePalm("LeftPalm", eLeapHandType_Left);
605  ToolTimeStampedUpdatePalm("RightPalm", eLeapHandType_Right);
606 
607  this->FrameNumber++;
608 
609  return PLUS_SUCCESS;
610 }
611 
612 //----------------------------------------------------------------------------
613 PlusStatus vtkPlusLeapMotion::OnLogEvent(const LEAP_LOG_EVENT* logEvent)
614 {
615  switch (logEvent->severity)
616  {
617  case eLeapLogSeverity_Unknown:
618  case eLeapLogSeverity_Information:
619  LOG_INFO(logEvent->message);
620  return PLUS_SUCCESS;
621  case eLeapLogSeverity_Warning:
622  LOG_WARNING(logEvent->message);
623  return PLUS_SUCCESS;
624  case eLeapLogSeverity_Critical:
625  LOG_ERROR(logEvent->message);
626  return PLUS_SUCCESS;
627  default:
628  return PLUS_FAIL;
629  }
630 }
631 
632 //----------------------------------------------------------------------------
633 PlusStatus vtkPlusLeapMotion::OnLogEvents(const LEAP_LOG_EVENTS* logEvents)
634 {
635  for (uint32_t i = 0; i < logEvents->nEvents; ++i)
636  {
637  LEAP_LOG_EVENT& event = logEvents->events[i];
638  switch (event.severity)
639  {
640  case eLeapLogSeverity_Unknown:
641  case eLeapLogSeverity_Information:
642  LOG_INFO(event.message);
643  break;
644  case eLeapLogSeverity_Warning:
645  LOG_WARNING(event.message);
646  break;
647  case eLeapLogSeverity_Critical:
648  LOG_ERROR(event.message);
649  break;
650  }
651  }
652  return PLUS_SUCCESS;
653 }
654 
655 //----------------------------------------------------------------------------
656 PlusStatus vtkPlusLeapMotion::OnConfigChangeEvent(const LEAP_CONFIG_CHANGE_EVENT* configChangeEvent)
657 {
658  return PLUS_SUCCESS;
659 }
660 
661 //----------------------------------------------------------------------------
662 PlusStatus vtkPlusLeapMotion::OnConfigResponseEvent(const LEAP_CONFIG_RESPONSE_EVENT* configResponseEvent)
663 {
664  return PLUS_SUCCESS;
665 }
666 
667 //----------------------------------------------------------------------------
668 PlusStatus vtkPlusLeapMotion::OnImageEvent(const LEAP_IMAGE_EVENT* imageEvent)
669 {
670  if (this->GetNumberOfVideoSources() >= 2)
671  {
672  FrameSizeType leftFrameSize{ imageEvent->image[0].properties.width, imageEvent->image[0].properties.height, 1 };
673  FrameSizeType rightFrameSize{ imageEvent->image[1].properties.width, imageEvent->image[1].properties.height, 1 };
674  if (!this->ImageInitialized)
675  {
676  // First image received, set up the data sources
677  this->LeftCameraSource->SetInputFrameSize(leftFrameSize);
678  this->RightCameraSource->SetInputFrameSize(rightFrameSize);
679 
680  this->LeftCameraSource->SetPixelType(VTK_UNSIGNED_CHAR);
681  this->RightCameraSource->SetPixelType(VTK_UNSIGNED_CHAR);
682 
683  if (imageEvent->image[0].properties.format == eLeapImageFormat_RGBIr_Bayer)
684  {
685  this->LeftCameraSource->SetImageType(US_IMG_RGB_COLOR);
686  }
687  else
688  {
689  this->LeftCameraSource->SetImageType(US_IMG_BRIGHTNESS);
690  }
691 
692  if (imageEvent->image[1].properties.format == eLeapImageFormat_RGBIr_Bayer)
693  {
694  this->RightCameraSource->SetImageType(US_IMG_RGB_COLOR);
695  }
696  else
697  {
698  this->RightCameraSource->SetImageType(US_IMG_BRIGHTNESS);
699  }
700 
701  this->LeftCameraSource->SetNumberOfScalarComponents(imageEvent->image[0].properties.bpp);
702  this->RightCameraSource->SetNumberOfScalarComponents(imageEvent->image[1].properties.bpp);
703 
704  this->ImageInitialized = true;
705  }
706 
707  if (this->InvertImage)
708  {
709  // Invert left image
710  uint32_t byteCount = ((imageEvent->image[0].properties.format == eLeapImageFormat_RGBIr_Bayer)) ? 3 : 1 * leftFrameSize[0] * leftFrameSize[1] * leftFrameSize[2];
711  for (uint32_t i = 0; i < byteCount;)
712  {
713  ((unsigned char*)(imageEvent->image[0].data))[i] = 255 - ((unsigned char*)(imageEvent->image[0].data))[i];
714  if (imageEvent->image[1].properties.format == eLeapImageFormat_RGBIr_Bayer)
715  {
716  ((unsigned char*)(imageEvent->image[0].data))[i + 1] = 255 - ((unsigned char*)(imageEvent->image[0].data))[i + 1];
717  ((unsigned char*)(imageEvent->image[0].data))[i + 2] = 255 - ((unsigned char*)(imageEvent->image[0].data))[i + 2];
718  i = i + 3;
719  }
720  else
721  {
722  i++;
723  }
724  }
725 
726  // Invert right image
727  byteCount = ((imageEvent->image[1].properties.format == eLeapImageFormat_RGBIr_Bayer)) ? 3 : 1 * rightFrameSize[0] * rightFrameSize[1] * rightFrameSize[2];
728  for (uint32_t i = 0; i < rightFrameSize[0];)
729  {
730  ((unsigned char*)(imageEvent->image[1].data))[i] = 255 - ((unsigned char*)(imageEvent->image[1].data))[i];
731  if (imageEvent->image[1].properties.format == eLeapImageFormat_RGBIr_Bayer)
732  {
733  ((unsigned char*)(imageEvent->image[1].data))[i + 1] = 255 - ((unsigned char*)(imageEvent->image[1].data))[i + 1];
734  ((unsigned char*)(imageEvent->image[1].data))[i + 2] = 255 - ((unsigned char*)(imageEvent->image[1].data))[i + 2];
735  i = i + 3;
736  }
737  else
738  {
739  i++;
740  }
741  }
742  }
743 
744  this->LeftCameraSource->AddItem(imageEvent->image[0].data,
745  this->LeftCameraSource->GetInputImageOrientation(),
746  leftFrameSize,
747  VTK_UNSIGNED_CHAR,
748  imageEvent->image[0].properties.bpp,
749  (imageEvent->image[0].properties.format == eLeapImageFormat_RGBIr_Bayer) ? US_IMG_RGB_COLOR : US_IMG_BRIGHTNESS,
750  0,
751  this->FrameNumber); // For now, use plus timestamps, until figure out how to offset leap timestamp by plus timestamp
752  this->RightCameraSource->AddItem(imageEvent->image[0].data,
753  this->RightCameraSource->GetInputImageOrientation(),
754  rightFrameSize,
755  VTK_UNSIGNED_CHAR,
756  imageEvent->image[1].properties.bpp,
757  (imageEvent->image[1].properties.format == eLeapImageFormat_RGBIr_Bayer) ? US_IMG_RGB_COLOR : US_IMG_BRIGHTNESS,
758  0,
759  this->FrameNumber); // For now, use plus timestamps, until figure out how to offset leap timestamp by plus timestamp
760 
761  this->FrameNumber++;
762  }
763  else
764  {
765  LOG_DEBUG("Image event received but no video data sources are available.");
766  return PLUS_FAIL;
767  }
768 
769  return PLUS_SUCCESS;
770 }
771 
772 //----------------------------------------------------------------------------
773 PlusStatus vtkPlusLeapMotion::OnPointMappingChangeEvent(const LEAP_POINT_MAPPING_CHANGE_EVENT* pointMappingChangeEvent)
774 {
775  return PLUS_SUCCESS;
776 }
777 
778 //----------------------------------------------------------------------------
779 PlusStatus vtkPlusLeapMotion::OnHeadPoseEvent(const LEAP_HEAD_POSE_EVENT* headPoseEvent)
780 {
781  SetHeadPose(headPoseEvent);
782 
783  return PLUS_SUCCESS;
784 }
785 
786 //----------------------------------------------------------------------------
787 std::string vtkPlusLeapMotion::ResultToString(eLeapRS r)
788 {
789  switch (r)
790  {
791  case eLeapRS_Success:
792  return "eLeapRS_Success";
793  case eLeapRS_UnknownError:
794  return "eLeapRS_UnknownError";
795  case eLeapRS_InvalidArgument:
796  return "eLeapRS_InvalidArgument";
797  case eLeapRS_InsufficientResources:
798  return "eLeapRS_InsufficientResources";
799  case eLeapRS_InsufficientBuffer:
800  return "eLeapRS_InsufficientBuffer";
801  case eLeapRS_Timeout:
802  return "eLeapRS_Timeout";
803  case eLeapRS_NotConnected:
804  return "eLeapRS_NotConnected";
805  case eLeapRS_HandshakeIncomplete:
806  return "eLeapRS_HandshakeIncomplete";
807  case eLeapRS_BufferSizeOverflow:
808  return "eLeapRS_BufferSizeOverflow";
809  case eLeapRS_ProtocolError:
810  return "eLeapRS_ProtocolError";
811  case eLeapRS_InvalidClientID:
812  return "eLeapRS_InvalidClientID";
813  case eLeapRS_UnexpectedClosed:
814  return "eLeapRS_UnexpectedClosed";
815  case eLeapRS_UnknownImageFrameRequest:
816  return "eLeapRS_UnknownImageFrameRequest";
817  case eLeapRS_UnknownTrackingFrameID:
818  return "eLeapRS_UnknownTrackingFrameID";
819  case eLeapRS_RoutineIsNotSeer:
820  return "eLeapRS_RoutineIsNotSeer";
821  case eLeapRS_TimestampTooEarly:
822  return "eLeapRS_TimestampTooEarly";
823  case eLeapRS_ConcurrentPoll:
824  return "eLeapRS_ConcurrentPoll";
825  case eLeapRS_NotAvailable:
826  return "eLeapRS_NotAvailable";
827  case eLeapRS_NotStreaming:
828  return "eLeapRS_NotStreaming";
829  case eLeapRS_CannotOpenDevice:
830  return "eLeapRS_CannotOpenDevice";
831  default:
832  return "Unknown result type.";
833  }
834 }
835 
836 //----------------------------------------------------------------------------
837 std::string vtkPlusLeapMotion::EventToString(_eLeapEventType t)
838 {
839  switch (t)
840  {
841  case eLeapEventType_None:
842  return "eLeapEventType_None";
843  case eLeapEventType_Connection:
844  return "eLeapEventType_Connection";
845  case eLeapEventType_ConnectionLost:
846  return "eLeapEventType_ConnectionLost";
847  case eLeapEventType_Device:
848  return "eLeapEventType_Device";
849  case eLeapEventType_DeviceFailure:
850  return "eLeapEventType_DeviceFailure";
851  case eLeapEventType_Policy:
852  return "eLeapEventType_Policy";
853  case eLeapEventType_Tracking:
854  return "eLeapEventType_Tracking";
855  case eLeapEventType_ImageRequestError:
856  return "eLeapEventType_ImageRequestError";
857  case eLeapEventType_ImageComplete:
858  return "eLeapEventType_ImageComplete";
859  case eLeapEventType_LogEvent:
860  return "eLeapEventType_LogEvent";
861  case eLeapEventType_DeviceLost:
862  return "eLeapEventType_DeviceLost";
863  case eLeapEventType_ConfigResponse:
864  return "eLeapEventType_ConfigResponse";
865  case eLeapEventType_ConfigChange:
866  return "eLeapEventType_ConfigChange";
867  case eLeapEventType_DeviceStatusChange:
868  return "eLeapEventType_DeviceStatusChange";
869  case eLeapEventType_DroppedFrame:
870  return "eLeapEventType_DroppedFrame";
871  case eLeapEventType_Image:
872  return "eLeapEventType_Image";
873  case eLeapEventType_PointMappingChange:
874  return "eLeapEventType_PointMappingChange";
875  case eLeapEventType_LogEvents:
876  return "eLeapEventType_LogEvents";
877  case eLeapEventType_HeadPose:
878  return "eLeapEventType_HeadPose";
879  default:
880  return "Unknown event type.";
881  }
882 }
unsigned int PollTimeoutMs
PlusStatus GetDataSource(const char *aSourceId, vtkPlusDataSource *&aSource)
PlusStatus OnPolicyEvent(const LEAP_POLICY_EVENT *policyEvent)
std::string ToolReferenceFrameName
PlusStatus OnConfigChangeEvent(const LEAP_CONFIG_CHANGE_EVENT *configChangeEvent)
Interface for the LeapMotion hand tracker.
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
LEAP_CONNECTION Connection
virtual int GetNumberOfVideoSources() const
PlusStatus OnLogEvent(const LEAP_LOG_EVENT *logEvent)
LEAP_HEAD_POSE_EVENT LastHeadPoseEvent
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement)
LEAP_CONNECTION_MESSAGE LastMessage
PlusStatus OnDeviceLostEvent(const LEAP_DEVICE_EVENT *deviceEvent)
PlusStatus OnPointMappingChangeEvent(const LEAP_POINT_MAPPING_CHANGE_EVENT *pointMappingChangeEvent)
PlusStatus ToolTimeStampedUpdatePalm(const std::string &name, eLeapHandType hand)
PlusStatus OnConnectionLostEvent(const LEAP_CONNECTION_LOST_EVENT *connectionLostEvent)
PlusStatus OnDeviceEvent(const LEAP_DEVICE_EVENT *deviceEvent)
LEAP_TRACKING_EVENT * GetFrame()
igsioStatus PlusStatus
Definition: PlusCommon.h:40
PlusStatus GetVideoSourceByIndex(const unsigned int index, vtkPlusDataSource *&aVideoSource)
PlusStatus SetInputFrameSize(unsigned int x, unsigned int y, unsigned int z)
vtkPlusDataSource * RightCameraSource
virtual PlusStatus ToolTimeStampedUpdate(const std::string &aToolSourceId, vtkMatrix4x4 *matrix, ToolStatus status, unsigned long frameNumber, double unfilteredtimestamp, const igsioFieldMapType *customFields=NULL)
PlusStatus ToolTimeStampedUpdateBone(std::string boneName, eLeapHandType handIndex, Finger fingerIndex, Bone boneIndex)
virtual PlusStatus AddItem(vtkImageData *frame, US_IMAGE_ORIENTATION usImageOrientation, US_IMAGE_TYPE imageType, long frameNumber, double unfilteredTimestamp=UNDEFINED_TIMESTAMP, double filteredTimestamp=UNDEFINED_TIMESTAMP, const igsioFieldMapType *customFields=NULL)
bool RequirePortNameInDeviceSetConfiguration
PlusStatus OnLogEvents(const LEAP_LOG_EVENTS *logEvents)
PlusStatus SetImageType(US_IMAGE_TYPE imageType)
for i
LEAP_TRACKING_EVENT LastTrackingEvent
double AcquisitionRate
#define PLUS_FAIL
Definition: PlusCommon.h:43
vtkPlusDataSource * LeftCameraSource
DataSourceContainer Tools
void PrintSelf(ostream &os, vtkIndent indent)
LEAP_HEAD_POSE_EVENT * GetHeadPose()
virtual int GetNumberOfTools() const
virtual PlusStatus InternalStopRecording()
PlusStatus SetPixelType(igsioCommon::VTKScalarPixelType pixelType)
virtual PlusStatus InternalConnect()
virtual PlusStatus NotifyConfigured()
unsigned long FrameNumber
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
PlusStatus OnConnectionEvent(const LEAP_CONNECTION_EVENT *connectionEvent)
std::string ResultToString(eLeapRS)
PlusStatus OnDeviceFailureEvent(const LEAP_DEVICE_FAILURE_EVENT *deviceFailureEvent)
int * state
Definition: phidget22.h:3207
virtual PlusStatus StopRecording()
virtual PlusStatus InternalUpdate()
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *config)
PlusStatus OnImageEvent(const LEAP_IMAGE_EVENT *imageEvent)
std::string EventToString(_eLeapEventType)
int x
Definition: phidget22.h:4265
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *config)
bool StartThreadForInternalUpdates
virtual PlusStatus InternalDisconnect()
vtkIGSIORecursiveCriticalSection * Mutex
set(gca, 'XTick', axisXRange(1):1:axisXRange(2))
PlusStatus SetNumberOfScalarComponents(unsigned int numberOfScalarComponents)
PlusStatus OnTrackingEvent(const LEAP_TRACKING_EVENT *trackingEvent)
Direction vectors of rods y
Definition: algo3.m:15
void SetHeadPose(const LEAP_HEAD_POSE_EVENT *headPose)
#define CHECK_DATA_SOURCE(name)
vtkStandardNewMacro(vtkPlusLeapMotion)
for t
Definition: exploreFolders.m:9
virtual int OutputChannelCount() const
PlusStatus OnHeadPoseEvent(const LEAP_HEAD_POSE_EVENT *headPoseEvent)
void SetFrame(const LEAP_TRACKING_EVENT *trackingEvent)
PlusStatus OnConfigResponseEvent(const LEAP_CONFIG_RESPONSE_EVENT *configResponseEvent)
virtual PlusStatus InternalStartRecording()
Interface to a 3D positioning tool, video source, or generalized data stream.