LeapScene.cpp
Go to the documentation of this file.
1 /******************************************************************************\
2 * Copyright (C) Leap Motion, Inc. 2011-2013. *
3 * Leap Motion proprietary and confidential. Not for distribution. *
4 * Use subject to the terms of the Leap Motion SDK Agreement available at *
5 * https://developer.leapmotion.com/sdk_agreement, or another agreement between *
6 * Leap Motion and you, your company or other organization. *
7 \******************************************************************************/
8 #include "LeapScene.h"
9 #include <cfloat>
10 #include <cstring>
11 
12 namespace Leap {
13 
14 using namespace LeapUtil;
15 
16 #if defined(LEAP_SCENE_USE_UTIL_GL)
17  using namespace LeapUtilGL;
18 #endif
19 
20 //***********************
21 //
22 // Scene public methods
23 //
24 //***********************
25 
27  : m_pUserData( NULL ),
28  m_fDeltaTimeSeconds( 0.0f ),
29  m_fPointableRadius( 1.0f ),
30  m_fSelectHitTime( 1.0f ),
31  m_uiNumObjects( 0 ),
32  m_uiNumRayHits( 0 ),
33  m_uiNumQueuedInteractions( 0 ),
34  m_uiNumPendingRemovals( 0 ),
35  m_uiNextSerial( 0 ),
36  m_uiFlags( kF_UpdateRayCast | kF_UpdateContact )
37 {
38  memset( m_apObjects, 0, sizeof(m_apObjects) );
39 }
40 
42 {
43  if ( pObject && (pObject->m_pScene == this) && !pObject->m_bPendingRemoval )
44  {
45  pObject->m_bPendingRemoval = true;
47  }
48 }
49 
51 {
52  for ( uint32_t i = 0; i < m_uiNumObjects; i++ )
53  {
54  if ( SceneObject* pObj = m_apObjects[i] )
55  {
56  pObj->m_pScene = NULL;
57  pObj->m_index = kMaxObjects;
58  }
59 
60  m_apObjects[i].Release();
61  }
62 
63  m_uiNumObjects = 0;
65 
67  clearRayHits();
68 }
69 
70 void Scene::Update(const Frame& frame, float fDeltaTimeSeconds)
71 {
72  m_fDeltaTimeSeconds = fDeltaTimeSeconds;
73 
74  clearRayHits();
75 
77 
79 
81 
82  updateInteraction( frame );
83 }
84 
86 {
87  SceneInteraction deselection;
88  deselection.m_uiFlags = kIT_SelectionChange;
89 
90  for (size_t i=0; i < m_uiNumObjects; i++)
91  {
92  m_apObjects[i]->SetSelected( false );
93  }
94 }
95 
96 const SceneObjectPtr& Scene::TestRayHit( const SceneRay& ray ) const
97 {
98  float fClosestHitDist = FLT_MAX;
99  int closestHitIndex = -1;
100 
101  for (uint32_t i = 0; i < m_uiNumObjects; i++)
102  {
103  float fHitDist = FLT_MAX;
104  if (m_apObjects[i]->TestRayHit(ray, fHitDist) && (fHitDist < fClosestHitDist) )
105  {
106  closestHitIndex = static_cast<int>(i);
107  fClosestHitDist = fHitDist;
108  }
109  }
110 
111  if (closestHitIndex >= 0)
112  {
113  return m_apObjects[closestHitIndex];
114  }
115 
116  return SceneObjectPtr::Null();
117 }
118 
119 #if defined(LEAP_SCENE_USE_UTIL_GL)
120 void Scene::RayHitsDebugDrawGL() const
121 {
122  GLAttribScope attribScope( GL_CURRENT_BIT | GL_LIGHTING_BIT );
123 
124  glDisable( GL_LIGHTING );
125  glColor3f(1, 1, 1);
126 
127  const float fHitSphereSize = m_fPointableRadius * 0.3f;
128 
129  for ( uint32_t i = 0, e = GetNumRayHits(); i < e; i++ )
130  {
131  const SceneRayHit& rayHit = m_aRayHits[i];
132  rayHit.DebugDrawGL( fHitSphereSize );
133  }
134 }
135 #endif // LEAP_SCENE_USE_UTIL_GL
136 
137 //***********************
138 //
139 // Scene internal methods
140 //
141 //***********************
142 
143 void Scene::deallocateObject( uint32_t idxToRemove )
144 {
145  if ( SceneObject* pObjToRemove = (idxToRemove < m_uiNumObjects) ? m_apObjects[idxToRemove].GetPointer() : NULL )
146  {
147  m_uiNumObjects--;
148 
149  // orphan the object
150  pObjToRemove->m_pScene = NULL;
151 
152  // assign an invalid index.
153  pObjToRemove->m_index = static_cast<uint32_t>(kMaxObjects);
154 
155  // if removing any object but the last one
156  if ( idxToRemove != m_uiNumObjects )
157  {
158  // move the last object to the vacated slot - releases the reference to the outbound object.
159  // increases the reference count on the the last object.
160  m_apObjects[idxToRemove] = m_apObjects[m_uiNumObjects];
161 
162  // update its index to match
163  m_apObjects[idxToRemove]->m_index = static_cast<uint16_t>(idxToRemove);
164 
165  // release the extra reference to the last object
167  }
168  else
169  {
170  // it was the last object - just release the reference to it.
171  m_apObjects[idxToRemove].Release();
172  }
173 
174  }
175 }
176 
178 {
179  float fClosestHitDist = FLT_MAX;
180  int closestHitIndex = -1;
181 
182  for (uint32_t i = 0; i < m_uiNumObjects; i++)
183  {
184  float fHitDist = FLT_MAX;
185  if (m_apObjects[i]->TestRayHit(hitResult.m_ray, fHitDist) && (fHitDist < fClosestHitDist) )
186  {
187  closestHitIndex = static_cast<int>(i);
188  fClosestHitDist = fHitDist;
189  }
190  }
191 
192  if (closestHitIndex >= 0)
193  {
194  hitResult.m_fHitDistance = fClosestHitDist;
195  hitResult.m_pHitObject = m_apObjects[closestHitIndex];
196  hitResult.m_hitPoint = hitResult.m_ray.CalcPointOn( hitResult.m_fHitDistance );
197 
198  m_apObjects[closestHitIndex]->IncNumPointing();
199 
200  m_apObjects[closestHitIndex]->m_fTotalHitTime += m_fDeltaTimeSeconds;
201 
202  return true;
203  }
204 
205  return false;
206 }
207 
208 void Scene::updateContact( const SceneContactPoint& testPoint )
209 {
210  for (size_t i=0; i < m_uiNumObjects; i++)
211  {
212  if ( m_apObjects[i]->TestSphereHit( testPoint.m_vPoint, m_fPointableRadius ) )
213  {
214  m_apObjects[i]->IncNumContacts( testPoint );
216  }
217  }
218 }
219 
221 {
222  const PointableList& pointables = frame.pointables();
223 
224  if ( pointables.isEmpty() && frame.hands().isEmpty() )
225  {
227  }
228 
229  for ( uint32_t j = 0, numPointables = pointables.count(); j < numPointables; j++ )
230  {
231  const Pointable& pointable = pointables[j];
232  const Vector vPos = TransformFramePoint( pointable.tipPosition() );
233  const int iPointableID = pointable.id();
234 
235  if ( GetUpdateRayCast() && (m_uiNumRayHits < static_cast<uint32_t>(kMaxRayHits)) )
236  {
238 
239  rayHit.m_ray = SceneRay( vPos, TransformFrameDirection( pointable.direction() ) );
240  rayHit.m_iPointableID = iPointableID;
241 
242  if ( testRayHitClosest( rayHit ) )
243  {
244  m_uiNumRayHits++;
245  }
246  }
247 
248  if ( GetUpdateContact() )
249  {
250  updateContact( SceneContactPoint( vPos, iPointableID ) );
251  }
252  }
253 }
254 
255 void Scene::updateInteraction( const Frame& frame )
256 {
257  static const uint8_t kMaxContactMissedFrames = 64;
258 
259  (void)frame;
260 
261  for (size_t i=0; i < m_uiNumObjects; i++)
262  {
263  const SceneObjectPtr& pObj = m_apObjects[i];
264 
265  if (!pObj->HasInitialContact() && pObj->GetNumContacts() == 0 && pObj->GetNumPointing() == 0)
266  {
267  pObj->m_fTotalHitTime = 0.0f;
268  }
270  else if ( !pObj->IsSelected() && pObj->m_fTotalHitTime >= m_fSelectHitTime )
271  {
272  SceneInteraction selection;
274  selection.m_pObject = pObj;
275  queueInteraction( selection );
276  }
278  else if ( pObj->IsSelected() )
279  {
280 
281  if ( pObj->HasInitialContact() )
282  {
283  const SceneContactPoint& initContact = pObj->m_initialContactPoint;
284  Leap::Pointable contactPointable = frame.pointable(initContact.m_iPointableID);
285 
286  if ( contactPointable.isValid() )
287  {
288  const Vector vPointablePos = TransformFramePoint(contactPointable.tipPosition());
289  const Vector vTrans = (vPointablePos - pObj->GetCenter());
290  SceneInteraction translation;
291 
292  translation.m_mtxTransform.origin = vTrans;
293  translation.m_uiFlags |= kIT_Translation;
294  translation.m_pObject = pObj;
295 
296  queueInteraction( translation );
297 
298  pObj->m_uiHasInitialContact = kMaxContactMissedFrames;
299  }
300  else
301  {
302  pObj->m_uiHasInitialContact--;
303 
304  if ( !pObj->m_uiLastNumContacts )
305  {
306  pObj->ClearHits();
307  }
308  }
309  }
310  else
311  {
312  if ( pObj->GetNumContacts() )
313  {
314  pObj->m_initialContactPoint = *(pObj->GetContactPoint(0));
315  pObj->m_initialContactPoint.m_vPoint -= pObj->GetCenter();
316  pObj->m_uiHasInitialContact = kMaxContactMissedFrames;
317  }
318  else if ( pObj->GetLastNumContacts() )
319  {
320  pObj->m_initialContactPoint = *(pObj->GetLastContactPoint(0));
321  pObj->m_initialContactPoint.m_vPoint -= pObj->GetCenter();
322  pObj->m_uiHasInitialContact = kMaxContactMissedFrames;
323  }
324  }
325 
327  if (pObj->GetLastNumContacts() >= 2 && pObj->GetNumContacts() >= 2)
328  {
329  const SceneContactPoint& lastContact0 = *(pObj->GetLastContactPoint(0));
330  const SceneContactPoint& lastContact1 = *(pObj->GetLastContactPoint(1));
331  const SceneContactPoint* pCurContact0 = pObj->GetContactPointByPointableID( lastContact0.m_iPointableID );
332  const SceneContactPoint* pCurContact1 = pObj->GetContactPointByPointableID( lastContact1.m_iPointableID );
333 
334  if ( pCurContact0 && pCurContact1 )
335  {
336  const Vector lastVec = (lastContact1.m_vPoint - lastContact0.m_vPoint);
337  const Vector newVec = (pCurContact1->m_vPoint - pCurContact0->m_vPoint);
338 
339  if ( !IsNearEqual(lastVec, newVec) && !IsNearZero(lastVec) )
340  {
341  const float fLastDist = lastVec.magnitude();
342  const float fNewDist = newVec.magnitude();
344  const float fScale = fNewDist/fLastDist;
345 
347  const Vector vLastDir = lastVec * 1.0f/fLastDist;
348  const Vector vNewDir = newVec * 1.0f/fNewDist;
349 
350  const Vector vAxis = vNewDir.cross(vLastDir);
351  const float fAngle = acosf( vNewDir.dot(vLastDir) );
352 
354  const Vector vTrans = ( (pCurContact0->m_vPoint - lastContact0.m_vPoint) +
355  (pCurContact1->m_vPoint - lastContact1.m_vPoint) ) * 0.5f;
356 
357  SceneInteraction interaction;
358 
359  if ( !IsNearZero(fAngle) )
360  {
361  interaction.m_mtxTransform.setRotation( vAxis, fAngle );
362  interaction.m_uiFlags |= kIT_Rotation;
363  }
364 
365  if ( !IsNearEqual(fScale, 1.0f) )
366  {
367  interaction.m_fScale = fScale;
368  interaction.m_uiFlags |= kIT_Scale;
369  }
370 
371  if ( !IsNearZero( vTrans ) )
372  {
373  interaction.m_mtxTransform.origin = vTrans;
374  interaction.m_uiFlags |= kIT_Translation;
375  }
376 
377  if ( interaction.m_uiFlags )
378  {
379  interaction.m_pObject = pObj;
380  queueInteraction( interaction );
381  }
382  }
383  }
384  }
385  }
386 
387  pObj->rotateContactPoints();
388  pObj->m_uiNumPointing = 0;
389  }
390 }
391 
393 {
394  for ( uint32_t i = 0; (i < m_uiNumObjects) && m_uiNumPendingRemovals; m_uiNumPendingRemovals-- )
395  {
396  if ( m_apObjects[i]->m_bPendingRemoval )
397  {
398  deallocateObject( i );
399  }
400  else
401  {
402  i++;
403  }
404  }
405 }
406 
408 {
409  SceneInteraction deselection;
410  deselection.m_uiFlags = kIT_SelectionChange;
411 
412  for (size_t i=0; i < m_uiNumObjects; i++)
413  {
414  if ( m_apObjects[i]->IsSelected() )
415  {
416  deselection.m_pObject = m_apObjects[i];
417  queueInteraction( deselection );
418  }
419  }
420 }
421 
422 //************************************
423 //
424 // SceneRayHit methods
425 //
426 //************************************
427 
428 #if defined(LEAP_SCENE_USE_UTIL_GL)
429 void SceneRayHit::DebugDrawGL( float fHitSphereSize ) const
430 {
431  const Vector& pos = m_ray.m_vOrigin;
432  const Vector& pt = m_hitPoint;
433 
434  glBegin(GL_LINES);
435  glVertex3fv( &(pos.x) );
436  glVertex3fv( &(pt.x) );
437  glEnd();
438 
439  {
440  GLMatrixScope matrixScope;
441 
442  glTranslatef(pt.x, pt.y, pt.z);
443  glScalef( fHitSphereSize, fHitSphereSize, fHitSphereSize );
444 
446  }
447 }
448 #endif // LEAP_SCENE_USE_UTIL_GL
449 
450 //************************************
451 //
452 // SceneObject methods
453 //
454 //************************************
455 
456 bool SceneBox::TestRayHit(const SceneRay& testRay, float& fHitDistOut) const
457 {
458  // by converting the test ray to object space the test is vs. an axis-aligned
459  // box centered at the origin (0, 0, 0)
460 
461  SceneRay testRayObj = testRay.Transformed( GetWorldToObjectTransform() );
462  Vector vMax = GetSize() * m_fScale * 0.5f;
463  Vector vMin = -vMax;
464  Vector vDirScale = ComponentWiseReciprocal(testRayObj.m_vDirection);
465  Vector vLower = ComponentWiseScale(vMin - testRayObj.m_vOrigin, vDirScale);
466  Vector vUpper = ComponentWiseScale(vMax - testRayObj.m_vOrigin, vDirScale);
467 
468  float fTMin = MaxComponent(ComponentWiseMin(vLower, vUpper));
469  float fTMax = MinComponent(ComponentWiseMax(vLower, vUpper));
470 
471  if (fTMin < fTMax)
472  {
473  if (fTMin > 0)
474  {
475  fHitDistOut = fTMin;
476  return true;
477  }
478 
479  if (fTMax > 0)
480  {
481  fHitDistOut = fTMax;
482  return true;
483  }
484  }
485 
486  return false;
487 }
488 
489 bool SceneBox::TestSphereHit(const Vector& vTestPoint, float fTestRadius) const
490 {
491  // by converting the test point to object space it's a sphere vs. axis-aligned box test
492  // where the box is centered at the origin (0, 0, 0).
493  Vector vPos = WorldToObjectPoint(vTestPoint);
494  Vector vMax = GetSize() * m_fScale * 0.5f;
495  Vector vMin = -vMax;
496 
497  return ( ComponentWiseMin(vPos - vMin, Vector::zero()).magnitudeSquared() +
498  ComponentWiseMax(vPos - vMax, Vector::zero()).magnitudeSquared() ) <= fTestRadius*fTestRadius;
499 }
500 
501 #if defined(LEAP_SCENE_USE_UTIL_GL)
502 void SceneBox::DebugDrawGL( eStyle drawStyle ) const
503 {
504  GLMatrixScope matrixScope;
505  const Vector vSize = GetSize() * GetScale();
506 
507  glMultMatrixf( GetTransform().toArray4x4() );
508 
509  glScalef( vSize.x, vSize.y, vSize.z );
510 
511  drawBox( drawStyle );
512 
513  if ( IsSelected() )
514  {
515  GLAttribScope attribScope( GL_CURRENT_BIT|GL_DEPTH_BUFFER_BIT );
516 
517  if ( drawStyle != kStyle_Outline )
518  {
519  glColor3f(1.0f, 1.0f, 1.0f);
521  }
522 
523  glDisable(GL_DEPTH_TEST);
524  const Vector vScale = LeapUtil::ComponentWiseReciprocal(vSize) * 0.125f;
525  glScalef( vScale.x, vScale.y, vScale.z );
526 
527  drawAxes();
528  }
529 }
530 #endif // LEAP_SCENE_USE_UTIL_GL
531 
532 bool SceneCylinder::TestRayHit(const SceneRay& testRay, float& fHitDistOut) const
533 {
534  SceneRay testRayObj = testRay.Transformed( GetWorldToObjectTransform() );
535 
536  const Vector& vAxis = Vector::yAxis();
537  float radius = m_fScale * m_fRadius;
538  float height = m_fScale * m_fHeight;
539  Vector RxA = testRayObj.m_vDirection.cross(vAxis);
540  float norm = RxA.magnitude();
541 
542  if (norm > 0)
543  {
544  Vector D = RxA/norm;
545  float d = fabs(testRayObj.m_vOrigin.dot(D));
546  if (d >= radius) {
547  return false;
548  }
549  Vector O = D.cross(vAxis).normalized();
550  float s = fabs(sqrt(radius*radius - d*d)/(testRayObj.m_vDirection.dot(O)));
551  float temp = -((testRayObj.m_vOrigin).cross(vAxis)).dot(D)/norm;
552  float tin = temp - s;
553  float tout = temp + s;
554 
555  if (tin > 0 && fabs(testRayObj.CalcPointOn(tin).y) <= height/2.0)
556  {
557  fHitDistOut = tin;
558  return true;
559  }
560 
561  if (tout > 0 && fabs(testRayObj.CalcPointOn(tout).y) <= height/2.0)
562  {
563  fHitDistOut = tout;
564  return true;
565  }
566  }
567  return false;
568 }
569 
570 
571 bool SceneCylinder::TestSphereHit(const Vector& vTestPoint, float fTestRadius) const
572 {
573  // by converting test point to object space the test is simplified.
574  // we can check the test sphere against a cylinder centered at 0,0,0
575  // with an axis along y+ (0,1,0)
576  const Vector vTestPosObj = WorldToObjectPoint(vTestPoint);
577  // scale-adjusted values of the cylinder
578  const float fCylRadius = m_fRadius * m_fScale;
579  const float fHalfCylHeight = m_fHeight * m_fScale * 0.5f;
580  // vector from infinite line of cylinder axis to test point
581  const Vector vAxisToPoint = Vector(vTestPosObj.x, 0, vTestPosObj.z);
582  // square of distance from infinite line of cylinder axis to test point
583  const float fAxisToPointDistSq = vAxisToPoint.magnitudeSquared();
584 
585  // only bother with the rest of the checks if the distance to the axis is less than
586  // the sum of the cylinder radius and test sphere radius. any farther and they could not be touching.
587  if (fAxisToPointDistSq < (fTestRadius + fCylRadius)*(fTestRadius + fCylRadius))
588  {
589  // distance from the vertical center of the cylinder to the test point projected onto the axis.
590  const float fAbsDistAlongAxis = fabs(vTestPosObj.y);
591 
592  // simplest case - sphere vs. wall of cylinder.
593  // the first check was whether or not the test sphere was within contact of the axis.
594  // if the distance along the axis is inside the cylinder the sphere is in contact with the wall.
595  if (fAbsDistAlongAxis < fHalfCylHeight)
596  {
597  return true;
598  }
599 
600  // next simplest case - sphere vs. centers of cylinder end caps.
601  // if the distance from the axis is within the cylinder
602  // and the the test point along the axis is within the sphere radius of the end
603  // it's touching.
604  if (fAxisToPointDistSq < (fCylRadius*fCylRadius) && fAbsDistAlongAxis < (fHalfCylHeight + fTestRadius) )
605  {
606  return true;
607  }
608 
609  // final case - sphere vs. edges (corners) of cylinder end caps
610 
611  // this is the closest point on the cylinder edge to the test point.
612  const Vector vClosest = fCylRadius*vAxisToPoint.normalized() +
613  Vector( 0, fHalfCylHeight * ((vTestPosObj.y < 0.0f) ? -1.0f : 1.0f), 0 );
614 
615  // if the distance from the closest point to the test point is within the radius of
616  // the test sphere it is in contact.
617  if ((vTestPosObj-vClosest).magnitudeSquared() < fTestRadius*fTestRadius)
618  {
619  return true;
620  }
621  }
622 
623  return false;
624 }
625 
626 #if defined(LEAP_SCENE_USE_UTIL_GL)
627 void SceneCylinder::DebugDrawGL( eStyle drawStyle ) const
628 {
629  GLMatrixScope matrixScope;
630  const float fHeight = GetHeight() * GetScale();
631  const float fRadius = GetRadius() * GetScale();
632 
633  glMultMatrixf( GetTransform().toArray4x4() );
634 
635  glScalef( fRadius * 2, fHeight, fRadius * 2 );
636 
637  drawCylinder( drawStyle, kAxis_Y );
638 
639  if ( IsSelected() )
640  {
641  GLAttribScope attribScope( GL_CURRENT_BIT|GL_DEPTH_BUFFER_BIT );
642 
643  if ( drawStyle != kStyle_Outline )
644  {
645  glColor3f(1.0f, 1.0f, 1.0f);
647  }
648 
649  glDisable(GL_DEPTH_TEST);
650  const float fScaleXZ = 1.0f/(fRadius + fRadius) * 0.125f;
651  glScalef( fScaleXZ, 1.0f/fHeight * 0.125f, fScaleXZ );
652  drawAxes();
653  }
654 }
655 #endif // LEAP_SCENE_USE_UTIL_GL
656 
657 bool SceneDisk::TestRayHit(const SceneRay& testRay, float& fHitDistOut) const
658 {
659  // by converting ray to object space we can do simpler testing.
660  // in object space the normal is the z axis (0, 0, 1) and the
661  // disk is a circle in the x/y plane centered at the origin (0, 0, 0)
662  SceneRay testRayObj = testRay.Transformed( GetWorldToObjectTransform() );
663  float fRadius = m_fScale * m_fRadius;
664  // cosine of angle between test ray direction and surface normal of the disk
665  //float fCosRayAngle = testRayObj.m_vDirection.z;
666 
667  // if the z component of the ray direction is 0 the direction is all on the x/y plane
668  // which means it is parallel to the disk and will not intersect.
669  if (fabs(testRayObj.m_vDirection.z) < kfEpsilon)
670  {
671  return false;
672  }
673 
674  // distance from the ray origin to the disk plane along the path of the ray
675  float fPlaneHitDist = -testRayObj.m_vOrigin.z/testRayObj.m_vDirection.z;
676 
677  // if the plane hit distance is negative the ray is pointing away from the disk
678  // if positive it is pointing towards the plane.
679  if ( fPlaneHitDist > 0 )
680  {
681  // intersection point of the ray with the plane of the disk
682  const Vector vPointOnPlane = testRayObj.CalcPointOn( fPlaneHitDist );
683 
684  // check if the point is within the disk - if so, it's a hit, otherwise not.
685  if ( vPointOnPlane.magnitudeSquared() < fRadius * fRadius )
686  {
687  fHitDistOut = fPlaneHitDist;
688  return true;
689  }
690  }
691 
692  return false;
693 }
694 
695 bool SceneDisk::TestSphereHit(const Vector& vTestPoint, float fTestRadius) const
696 {
697  // by converting the test point to object space we can do simpler testing.
698  // in object space the normal is the z axis (0, 0, 1) and the
699  // disk is a circle in the x/y plane centered at the origin (0, 0, 0)
700  const Vector vPos = WorldToObjectPoint(vTestPoint);
701  const float fDiskRadius = (m_fScale*m_fRadius);
702 
703  // the test point has to be within the test sphere radius of the disk plane or it isn't touching.
704  if (fabs(vPos.z) < fTestRadius)
705  {
706  // projection of the test point onto the plane of the disk.
707  const Vector vOnPlane( vPos.x, vPos.y, 0 );
708  const float fSin = vPos.z/fTestRadius;
709  const float fCos = sqrtf(1 - fSin*fSin);
710 
711  // fCos * fTestRadius is the radius of the circular intersection of the test sphere and the plane of the disk
712  // add the two together and that's the maximum distance the projection of the test point onto the disk plane
713  // can be from the center and still be in contact.
714  fTestRadius = fCos * fTestRadius + fDiskRadius;
715 
716  if (vOnPlane.magnitudeSquared() < fTestRadius * fTestRadius)
717  {
718  return true;
719  }
720  }
721 
722  return false;
723 }
724 
725 #if defined(LEAP_SCENE_USE_UTIL_GL)
726 void SceneDisk::DebugDrawGL( eStyle drawStyle ) const
727 {
728  GLMatrixScope matrixScope;
729  const float fRadius = GetRadius() * GetScale();
730 
731  glMultMatrixf( GetTransform().toArray4x4() );
732 
733  glScalef( fRadius + fRadius, fRadius + fRadius, fRadius + fRadius );
734 
735  drawDisk( drawStyle, kPlane_XY );
736 
737  if ( IsSelected() )
738  {
739  GLAttribScope attribScope( GL_CURRENT_BIT|GL_DEPTH_BUFFER_BIT );
740 
741  if ( drawStyle != kStyle_Outline )
742  {
743  glColor3f(1.0f, 1.0f, 1.0f);
745  }
746 
747  glDisable(GL_DEPTH_TEST);
748  const float fScale = 1.0f/(fRadius + fRadius) * 0.125f;
749  glScalef( fScale, fScale, fScale );
750  drawAxes();
751  }
752 }
753 #endif // LEAP_SCENE_USE_UTIL_GL
754 
755 bool ScenePlane::TestRayHit(const SceneRay& testRay, float& fHitDistOut) const
756 {
757  const float fRayAngleCos = GetNormal().dot( testRay.m_vDirection );
758 
759  if (fabs(fRayAngleCos) < kfEpsilon)
760  {
761  return false;
762  }
763 
764  // direct distance from the ray starting position to the plane
765  const float fRayOriginPlaneDist = GetNormal().dot(GetCenter() - testRay.m_vOrigin);
766 
767  // distance from the ray origin point to the plane along the path of the ray
768  const float fPlaneHitDist = fRayOriginPlaneDist/fRayAngleCos;
769 
770  if (fPlaneHitDist > 0)
771  {
772  fHitDistOut = fPlaneHitDist;
773  return true;
774  }
775 
776  return false;
777 }
778 
779 bool ScenePlane::TestSphereHit(const Vector& vTestPoint, float fTestRadius) const
780 {
781  return fabs((vTestPoint - GetCenter()).dot(GetNormal())) < fTestRadius;
782 }
783 
784 #if defined(LEAP_SCENE_USE_UTIL_GL)
785 void ScenePlane::DebugDrawGL( eStyle drawStyle ) const
786 {
787  (void)drawStyle;
788 }
789 #endif // LEAP_SCENE_USE_UTIL_GL
790 
791 bool SceneSphere::TestRayHit(const SceneRay& testRay, float& fHitDistOut) const
792 {
793  const float fRadius = m_fScale * m_fRadius;
794  const Vector O = testRay.m_vOrigin - GetCenter();
795  const float b = O.dot(testRay.m_vDirection);
796  const float c = O.dot(O) - fRadius*fRadius;
797  const float disc = b*b - c;
798 
799  if (disc > 0)
800  {
801  float sdisc = sqrtf(disc);
802  float root = (-b - sdisc);
803 
804  if (root > 0)
805  {
806  fHitDistOut = root;
807  return true;
808  }
809 
810  root = (-b + sdisc);
811 
812  if (root > 0)
813  {
814  fHitDistOut = root;
815  return true;
816  }
817  }
818 
819  return false;
820 }
821 
822 bool SceneSphere::TestSphereHit(const Vector& vTestPoint, float fTestRadius) const
823 {
824  const float fMaxDist = (m_fScale*m_fRadius + fTestRadius);
825  return (GetCenter() - vTestPoint).magnitudeSquared() < (fMaxDist * fMaxDist);
826 }
827 
828 #if defined(LEAP_SCENE_USE_UTIL_GL)
829 void SceneSphere::DebugDrawGL( eStyle drawStyle ) const
830 {
831  GLMatrixScope matrixScope;
832 
833  const float fRadius = GetRadius() * GetScale();
834 
835  glMultMatrixf( GetTransform().toArray4x4() );
836 
837  glScalef( fRadius+fRadius, fRadius+fRadius, fRadius+fRadius );
838 
839  drawSphere( drawStyle );
840 
841  if ( IsSelected() )
842  {
843  GLAttribScope attribScope( GL_CURRENT_BIT|GL_DEPTH_BUFFER_BIT );
844 
845  if ( drawStyle != kStyle_Outline )
846  {
847  glColor3f(1.0f, 1.0f, 1.0f);
849  }
850 
851  glDisable(GL_DEPTH_TEST);
852 
853  const float fScale = 1.0f/(fRadius + fRadius) * 0.125f;
854  glScalef( fScale, fScale, fScale );
855 
856  drawAxes();
857  }
858 }
859 #endif // LEAP_SCENE_USE_UTIL_GL
860 
861 } // namespace Leap
void drawCylinder(eStyle style, eAxis axis)
Definition: LeapUtilGL.cpp:375
d
uint8_t m_uiHasInitialContact
Definition: LeapScene.h:705
Vector CalcPointOn(float fDistFromOrigin) const
returns a point that is the specified distance down the ray.
Definition: LeapScene.h:60
uint8_t m_uiLastNumContacts
Definition: LeapScene.h:704
virtual LEAP_EXPORT bool TestRayHit(const SceneRay &testRay, float &fHitDistOut) const
Definition: LeapScene.cpp:532
LEAP_EXPORT bool isValid() const
virtual LEAP_EXPORT bool TestSphereHit(const Vector &vTestPoint, float fTestRadius) const
Definition: LeapScene.cpp:571
static const SmartPointer & Null()
convenient static method for returning in cases where a null return value is needed.
Definition: LeapUtil.h:882
void updateInteraction(const Frame &frame)
Definition: LeapScene.cpp:255
bool GetUpdateRayCast() const
Definition: LeapScene.h:318
uint32_t m_uiNumRayHits
Definition: LeapScene.h:398
bool IsNearEqual(const T &a, const T &b)
works with Vectors as well as floats
Definition: LeapUtil.h:96
f
virtual LEAP_EXPORT bool TestRayHit(const SceneRay &testRay, float &fHitDistOut) const
Definition: LeapScene.cpp:755
TFSIMD_FORCE_INLINE Vector3 cross(const Vector3 &v) const
Vector cross(const Vector &other) const
Definition: LeapMath.h:360
uint32_t GetLastNumContacts() const
Definition: LeapScene.h:593
bool IsNearZero(float fVal)
Definition: LeapUtil.h:84
uint16_t m_index
Definition: LeapScene.h:711
Vector m_vDirection
Definition: LeapScene.h:76
void drawSphere(eStyle style)
Definition: LeapUtilGL.cpp:121
contact point between a pointable (finger or tool) and a scene object.
Definition: LeapScene.h:162
XmlRpcServer s
SceneObjectPtr m_apObjects[kMaxObjects]
Definition: LeapScene.h:393
float MinComponent(const Leap::Vector &vVec)
Definition: LeapUtil.h:144
void deallocateObject(uint32_t idxToRemove)
Definition: LeapScene.cpp:143
void rotateContactPoints()
Definition: LeapScene.h:682
uint32_t m_uiNumPendingRemovals
Definition: LeapScene.h:400
LEAP_EXPORT Vector tipPosition() const
void IncNumPointing()
Definition: LeapScene.h:605
LEAP_EXPORT void Reset()
Definition: LeapScene.cpp:50
uint32_t GetNumRayHits() const
the number of ray tests that resulted in hits from the last update
Definition: LeapScene.h:280
Vector m_hitPoint
Definition: LeapScene.h:86
float m_fSelectHitTime
Definition: LeapScene.h:388
const SceneContactPoint * GetContactPointByPointableID(int iPointableID) const
Definition: LeapScene.h:641
void drawBox(eStyle style)
Definition: LeapUtilGL.cpp:237
Vector TransformFrameDirection(const Vector &vFrameDirection)
transform a direction from the LeapAPI (e.g. Pointable::direction()) into scene space ...
Definition: LeapScene.h:304
Definition: Leap.h:48
LEAP_EXPORT bool isEmpty() const
bool queueInteraction(const SceneInteraction &interaction)
Definition: LeapScene.h:331
SceneRayHit m_aRayHits[kMaxRayHits]
Definition: LeapScene.h:394
float m_fDeltaTimeSeconds
Definition: LeapScene.h:386
SceneRay m_ray
Definition: LeapScene.h:87
const Vector & GetCenter() const
Definition: LeapScene.h:570
virtual LEAP_EXPORT bool TestRayHit(const SceneRay &testRay, float &fHitDistOut) const
Definition: LeapScene.cpp:657
utility class for caching and restoring GL attributes via the glPushAttrib/glPopAttrib calls...
Definition: LeapUtilGL.h:93
const SceneContactPoint * GetLastContactPoint(uint32_t uiIndex) const
Definition: LeapScene.h:631
uint32_t GetNumContacts() const
Definition: LeapScene.h:589
float MaxComponent(const Leap::Vector &vVec)
Definition: LeapUtil.h:149
void clearInteractionQueue()
Definition: LeapScene.h:341
void drawAxes()
Definition: LeapUtilGL.cpp:519
uint8_t m_uiNumPointing
Definition: LeapScene.h:702
SceneObjectPtr m_pObject
Definition: LeapScene.h:156
void processPendingRemovals()
Definition: LeapScene.cpp:392
uint8_t m_bPendingRemoval
Definition: LeapScene.h:710
const SceneObjectPtr & TestRayHit(const SceneRay &ray) const
allows for casting an arbitrary ray and finding out what it hits (if anything)
Definition: LeapScene.cpp:96
virtual LEAP_EXPORT bool TestSphereHit(const Vector &vTestPoint, float fTestRadius) const
Definition: LeapScene.cpp:489
float magnitudeSquared() const
Definition: LeapMath.h:209
float m_fHitDistance
Definition: LeapScene.h:89
LEAP_EXPORT void Update(const Frame &frame, float fDeltaTimeSeconds)
Definition: LeapScene.cpp:70
Leap::Vector ComponentWiseReciprocal(const Leap::Vector &vVec)
Definition: LeapUtil.h:139
ray used for ray hit tests
Definition: LeapScene.h:53
void drawDisk(eStyle style, ePlane plane)
disk is double-side
Definition: LeapUtilGL.cpp:431
float m_fPointableRadius
Definition: LeapScene.h:387
void queueDeselectAll()
Definition: LeapScene.cpp:407
virtual LEAP_EXPORT bool TestSphereHit(const Vector &vTestPoint, float fTestRadius) const
Definition: LeapScene.cpp:695
void SetSelected(bool selected)
Definition: LeapScene.h:580
static const Vector & yAxis()
Definition: LeapMath.h:113
Vector origin
Definition: LeapMath.h:1045
Scene * m_pScene
Definition: LeapScene.h:713
float dot(const Vector &other) const
Definition: LeapMath.h:340
LEAP_EXPORT Scene()
Definition: LeapScene.cpp:26
virtual LEAP_EXPORT bool TestSphereHit(const Vector &vPoint, float fRadius) const
Definition: LeapScene.cpp:779
TFSIMD_FORCE_INLINE tfScalar dot(const Quaternion &q1, const Quaternion &q2)
Leap::Vector ComponentWiseMax(const Leap::Vector &vLHS, const Leap::Vector &vRHS)
Definition: LeapUtil.h:129
virtual LEAP_EXPORT bool TestRayHit(const SceneRay &testRay, float &fHitDistOut) const
Definition: LeapScene.cpp:791
uint32_t m_uiNumObjects
Definition: LeapScene.h:397
virtual LEAP_EXPORT bool TestRayHit(const SceneRay &testRay, float &fHitDistOut) const
Definition: LeapScene.cpp:456
LEAP_EXPORT void RemoveObject(SceneObject *pObject)
Definition: LeapScene.cpp:41
void clearRayHits()
Definition: LeapScene.h:348
bool testRayHitClosest(SceneRayHit &hitResult)
Definition: LeapScene.cpp:177
Vector TransformFramePoint(const Vector &vFramePoint)
transforms a point from the Leap API (e.g. Pointable::tipPosition()) into scene space ...
Definition: LeapScene.h:298
Vector m_vOrigin
Definition: LeapScene.h:75
void setRotation(const Vector &axis, float angleRadians)
Definition: LeapMath.h:780
stores the result of a ray test that hit something
Definition: LeapScene.h:80
SceneRay Transformed(const Matrix &mtxTransform) const
Definition: LeapScene.h:69
LEAP_EXPORT int count() const
static const Vector & zero()
Definition: LeapMath.h:92
virtual LEAP_EXPORT bool TestSphereHit(const Vector &vTestCenter, float fTestRadius) const
Definition: LeapScene.cpp:822
bool HasInitialContact() const
Definition: LeapScene.h:595
bool GetUpdateContact() const
Definition: LeapScene.h:311
LEAP_EXPORT void DeselectAll()
does not queue interactions, sets all objects to deselected state immediately.
Definition: LeapScene.cpp:85
float m_fTotalHitTime
Definition: LeapScene.h:699
static const float kfEpsilon
Definition: LeapUtil.h:43
SceneContactPoint m_initialContactPoint
Definition: LeapScene.h:694
SceneObjectPtr m_pHitObject
Definition: LeapScene.h:90
const SceneContactPoint * GetContactPoint(uint32_t uiIndex) const
Definition: LeapScene.h:626
Leap::Vector ComponentWiseMin(const Leap::Vector &vLHS, const Leap::Vector &vRHS)
Definition: LeapUtil.h:124
void IncNumContacts(const SceneContactPoint &contactPoint)
Definition: LeapScene.h:607
void updateContact(const SceneContactPoint &testPoint)
Definition: LeapScene.cpp:208
void updateSelectionAndContact(const Frame &frame)
Definition: LeapScene.cpp:220
utility class for keeping the gl matrix stack push/pop operations paired up correctly.
Definition: LeapUtilGL.h:81
bool IsSelected() const
Definition: LeapScene.h:578
uint32_t GetNumPointing() const
Definition: LeapScene.h:591
Leap::Vector ComponentWiseScale(const Leap::Vector &vLHS, const Leap::Vector &vRHS)
Definition: LeapUtil.h:134
LEAP_EXPORT Pointable pointable(int32_t id) const


leap_motion
Author(s): Florian Lier , Mirza Shah , Isaac IY Saito
autogenerated on Tue Jun 2 2020 03:58:01