LeapScene.cpp
Go to the documentation of this file.
00001 /******************************************************************************\
00002 * Copyright (C) Leap Motion, Inc. 2011-2013.                                   *
00003 * Leap Motion proprietary and  confidential.  Not for distribution.            *
00004 * Use subject to the terms of the Leap Motion SDK Agreement available at       *
00005 * https://developer.leapmotion.com/sdk_agreement, or another agreement between *
00006 * Leap Motion and you, your company or other organization.                     *
00007 \******************************************************************************/
00008 #include "LeapScene.h"
00009 #include <cfloat>
00010 #include <cstring>
00011 
00012 namespace Leap {
00013 
00014 using namespace LeapUtil;
00015 
00016 #if defined(LEAP_SCENE_USE_UTIL_GL)
00017   using namespace LeapUtilGL;
00018 #endif
00019 
00020 //***********************
00021 //
00022 // Scene public methods
00023 //
00024 //***********************
00025 
00026 Scene::Scene()
00027   : m_pUserData( NULL ),
00028     m_fDeltaTimeSeconds( 0.0f ),
00029     m_fPointableRadius( 1.0f ),
00030     m_fSelectHitTime( 1.0f ),
00031     m_uiNumObjects( 0 ),
00032     m_uiNumRayHits( 0 ),
00033     m_uiNumQueuedInteractions( 0 ),
00034     m_uiNumPendingRemovals( 0 ),
00035     m_uiNextSerial( 0 ),
00036     m_uiFlags( kF_UpdateRayCast | kF_UpdateContact )
00037 {
00038   memset( m_apObjects, 0, sizeof(m_apObjects) );
00039 }
00040 
00041 void Scene::RemoveObject( SceneObject* pObject )
00042 {
00043   if ( pObject && (pObject->m_pScene == this) && !pObject->m_bPendingRemoval )
00044   {
00045     pObject->m_bPendingRemoval = true;
00046     m_uiNumPendingRemovals++;
00047   }
00048 }
00049 
00050 void Scene::Reset()
00051 {
00052   for ( uint32_t i = 0; i < m_uiNumObjects; i++ )
00053   {
00054     if ( SceneObject* pObj = m_apObjects[i] )
00055     {
00056       pObj->m_pScene = NULL;
00057       pObj->m_index = kMaxObjects;
00058     }
00059 
00060     m_apObjects[i].Release();
00061   }
00062 
00063   m_uiNumObjects          = 0;
00064   m_uiNumPendingRemovals  = 0;
00065 
00066   clearInteractionQueue();
00067   clearRayHits();
00068 }
00069 
00070 void Scene::Update(const Frame& frame, float fDeltaTimeSeconds)
00071 {
00072   m_fDeltaTimeSeconds = fDeltaTimeSeconds;
00073 
00074   clearRayHits();
00075 
00076   clearInteractionQueue();
00077 
00078   processPendingRemovals();
00079 
00080   updateSelectionAndContact( frame );
00081 
00082   updateInteraction( frame );
00083 }
00084 
00085 void Scene::DeselectAll()
00086 {
00087   SceneInteraction deselection;
00088   deselection.m_uiFlags = kIT_SelectionChange;
00089 
00090   for (size_t i=0; i < m_uiNumObjects; i++)
00091   {
00092     m_apObjects[i]->SetSelected( false );
00093   }
00094 }
00095 
00096 const SceneObjectPtr& Scene::TestRayHit( const SceneRay& ray ) const
00097 {
00098   float fClosestHitDist = FLT_MAX;
00099   int closestHitIndex   = -1;
00100 
00101   for (uint32_t i = 0; i < m_uiNumObjects; i++)
00102   {
00103     float fHitDist = FLT_MAX;
00104     if (m_apObjects[i]->TestRayHit(ray, fHitDist) && (fHitDist < fClosestHitDist) )
00105     {
00106       closestHitIndex = static_cast<int>(i);
00107       fClosestHitDist = fHitDist;
00108     }
00109   }
00110 
00111   if (closestHitIndex >= 0)
00112   {
00113     return m_apObjects[closestHitIndex];
00114   }
00115 
00116   return SceneObjectPtr::Null();
00117 }
00118 
00119 #if defined(LEAP_SCENE_USE_UTIL_GL)
00120 void Scene::RayHitsDebugDrawGL() const
00121 {
00122     GLAttribScope attribScope( GL_CURRENT_BIT | GL_LIGHTING_BIT );
00123 
00124     glDisable( GL_LIGHTING );
00125     glColor3f(1, 1, 1);
00126 
00127     const float fHitSphereSize = m_fPointableRadius * 0.3f;
00128 
00129     for ( uint32_t i = 0, e = GetNumRayHits(); i < e; i++ )
00130     {
00131       const SceneRayHit&  rayHit  = m_aRayHits[i];
00132       rayHit.DebugDrawGL( fHitSphereSize );
00133     }
00134 }
00135 #endif // LEAP_SCENE_USE_UTIL_GL
00136 
00137 //***********************
00138 //
00139 // Scene internal methods
00140 //
00141 //***********************
00142 
00143 void Scene::deallocateObject( uint32_t idxToRemove )
00144 {
00145   if ( SceneObject* pObjToRemove = (idxToRemove < m_uiNumObjects) ? m_apObjects[idxToRemove].GetPointer() : NULL )
00146   {
00147     m_uiNumObjects--;
00148 
00149     // orphan the object
00150     pObjToRemove->m_pScene  = NULL;
00151 
00152     // assign an invalid index.
00153     pObjToRemove->m_index   = static_cast<uint32_t>(kMaxObjects);
00154 
00155     // if removing any object but the last one
00156     if ( idxToRemove != m_uiNumObjects )
00157     {
00158       // move the last object to the vacated slot - releases the reference to the outbound object.
00159       // increases the reference count on the the last object.
00160       m_apObjects[idxToRemove] = m_apObjects[m_uiNumObjects];
00161 
00162       // update its index to match
00163       m_apObjects[idxToRemove]->m_index = static_cast<uint16_t>(idxToRemove);
00164 
00165       // release the extra reference to the last object
00166       m_apObjects[m_uiNumObjects].Release();
00167     }
00168     else
00169     {
00170       // it was the last object - just release the reference to it.
00171       m_apObjects[idxToRemove].Release();
00172     }
00173 
00174   }
00175 }
00176 
00177 bool Scene::testRayHitClosest( SceneRayHit& hitResult )
00178 {
00179   float fClosestHitDist = FLT_MAX;
00180   int closestHitIndex   = -1;
00181 
00182   for (uint32_t i = 0; i < m_uiNumObjects; i++)
00183   {
00184     float fHitDist = FLT_MAX;
00185     if (m_apObjects[i]->TestRayHit(hitResult.m_ray, fHitDist) && (fHitDist < fClosestHitDist) )
00186     {
00187       closestHitIndex = static_cast<int>(i);
00188       fClosestHitDist = fHitDist;
00189     }
00190   }
00191 
00192   if (closestHitIndex >= 0)
00193   {
00194     hitResult.m_fHitDistance  = fClosestHitDist;
00195     hitResult.m_pHitObject    = m_apObjects[closestHitIndex];
00196     hitResult.m_hitPoint      = hitResult.m_ray.CalcPointOn( hitResult.m_fHitDistance );
00197 
00198     m_apObjects[closestHitIndex]->IncNumPointing();
00199 
00200     m_apObjects[closestHitIndex]->m_fTotalHitTime += m_fDeltaTimeSeconds;
00201 
00202     return true;
00203   }
00204 
00205   return false;
00206 }
00207 
00208 void Scene::updateContact( const SceneContactPoint& testPoint )
00209 {
00210   for (size_t i=0; i < m_uiNumObjects; i++)
00211   {
00212     if ( m_apObjects[i]->TestSphereHit( testPoint.m_vPoint, m_fPointableRadius ) )
00213     {
00214       m_apObjects[i]->IncNumContacts( testPoint );
00215       m_apObjects[i]->m_fTotalHitTime += m_fDeltaTimeSeconds;
00216     }
00217   }
00218 }
00219 
00220 void Scene::updateSelectionAndContact( const Frame& frame )
00221 {
00222   const PointableList& pointables = frame.pointables();
00223 
00224   if ( pointables.isEmpty() && frame.hands().isEmpty() )
00225   {
00226     queueDeselectAll();
00227   }
00228 
00229   for ( uint32_t j = 0, numPointables = pointables.count(); j < numPointables; j++ )
00230   {
00231     const Pointable& pointable    = pointables[j];
00232     const Vector  vPos            = TransformFramePoint( pointable.tipPosition() );
00233     const int     iPointableID    = pointable.id();
00234 
00235     if ( GetUpdateRayCast() && (m_uiNumRayHits < static_cast<uint32_t>(kMaxRayHits)) )
00236     {
00237       SceneRayHit&  rayHit    = m_aRayHits[m_uiNumRayHits];
00238 
00239       rayHit.m_ray            = SceneRay( vPos, TransformFrameDirection( pointable.direction() ) );
00240       rayHit.m_iPointableID   = iPointableID;
00241 
00242       if ( testRayHitClosest( rayHit ) )
00243       {
00244         m_uiNumRayHits++;
00245       }
00246     }
00247 
00248     if ( GetUpdateContact() )
00249     {
00250       updateContact( SceneContactPoint( vPos, iPointableID ) );
00251     }
00252   }
00253 }
00254 
00255 void Scene::updateInteraction( const Frame& frame )
00256 {
00257   static const uint8_t kMaxContactMissedFrames = 64;
00258 
00259   (void)frame;
00260 
00261   for (size_t i=0; i < m_uiNumObjects; i++)
00262   {
00263     const SceneObjectPtr& pObj = m_apObjects[i];
00264 
00265     if (!pObj->HasInitialContact() && pObj->GetNumContacts() == 0 && pObj->GetNumPointing() == 0)
00266     {
00267       pObj->m_fTotalHitTime = 0.0f;
00268     }
00270     else if ( !pObj->IsSelected() && pObj->m_fTotalHitTime >= m_fSelectHitTime )
00271     {
00272       SceneInteraction selection;
00273       selection.m_uiFlags = kIT_SelectionChange | kIT_IsSelected;
00274       selection.m_pObject = pObj;
00275       queueInteraction( selection );
00276     }
00278     else if ( pObj->IsSelected() )
00279     {
00280 
00281       if ( pObj->HasInitialContact() )
00282       {
00283         const SceneContactPoint& initContact  = pObj->m_initialContactPoint;
00284         Leap::Pointable contactPointable      = frame.pointable(initContact.m_iPointableID);
00285 
00286         if ( contactPointable.isValid() )
00287         {
00288             const Vector      vPointablePos  = TransformFramePoint(contactPointable.tipPosition());
00289             const Vector      vTrans         = (vPointablePos - pObj->GetCenter());
00290             SceneInteraction  translation;
00291 
00292             translation.m_mtxTransform.origin = vTrans;
00293             translation.m_uiFlags |= kIT_Translation;
00294             translation.m_pObject = pObj;
00295 
00296             queueInteraction( translation );
00297 
00298             pObj->m_uiHasInitialContact = kMaxContactMissedFrames;
00299         }
00300         else
00301         {
00302           pObj->m_uiHasInitialContact--;
00303 
00304           if ( !pObj->m_uiLastNumContacts )
00305           {
00306             pObj->ClearHits();
00307           }
00308         }
00309       }
00310       else
00311       {
00312         if ( pObj->GetNumContacts()  )
00313         {
00314           pObj->m_initialContactPoint = *(pObj->GetContactPoint(0));
00315           pObj->m_initialContactPoint.m_vPoint -= pObj->GetCenter();
00316           pObj->m_uiHasInitialContact = kMaxContactMissedFrames;
00317         }
00318         else if ( pObj->GetLastNumContacts() )
00319         {
00320           pObj->m_initialContactPoint = *(pObj->GetLastContactPoint(0));
00321           pObj->m_initialContactPoint.m_vPoint -= pObj->GetCenter();
00322           pObj->m_uiHasInitialContact = kMaxContactMissedFrames;
00323         }
00324       }
00325 
00327       if (pObj->GetLastNumContacts() >= 2 && pObj->GetNumContacts() >= 2)
00328       {
00329         const SceneContactPoint&  lastContact0  = *(pObj->GetLastContactPoint(0));
00330         const SceneContactPoint&  lastContact1  = *(pObj->GetLastContactPoint(1));
00331         const SceneContactPoint*  pCurContact0  = pObj->GetContactPointByPointableID( lastContact0.m_iPointableID );
00332         const SceneContactPoint*  pCurContact1  = pObj->GetContactPointByPointableID( lastContact1.m_iPointableID );
00333 
00334         if ( pCurContact0 && pCurContact1 )
00335         {
00336           const Vector lastVec = (lastContact1.m_vPoint - lastContact0.m_vPoint);
00337           const Vector newVec = (pCurContact1->m_vPoint - pCurContact0->m_vPoint);
00338 
00339           if ( !IsNearEqual(lastVec, newVec) && !IsNearZero(lastVec) )
00340           {
00341             const float   fLastDist = lastVec.magnitude();
00342             const float   fNewDist  = newVec.magnitude();
00344             const float   fScale    = fNewDist/fLastDist;
00345 
00347             const Vector  vLastDir  = lastVec * 1.0f/fLastDist;
00348             const Vector  vNewDir   = newVec  * 1.0f/fNewDist;
00349 
00350             const Vector  vAxis     = vNewDir.cross(vLastDir);
00351             const float   fAngle    = acosf( vNewDir.dot(vLastDir) );
00352 
00354             const Vector  vTrans    = ( (pCurContact0->m_vPoint - lastContact0.m_vPoint) +
00355                                         (pCurContact1->m_vPoint - lastContact1.m_vPoint) ) * 0.5f;
00356 
00357             SceneInteraction interaction;
00358 
00359             if ( !IsNearZero(fAngle) )
00360             {
00361               interaction.m_mtxTransform.setRotation( vAxis, fAngle );
00362               interaction.m_uiFlags |= kIT_Rotation;
00363             }
00364 
00365             if ( !IsNearEqual(fScale, 1.0f) )
00366             {
00367               interaction.m_fScale = fScale;
00368               interaction.m_uiFlags |= kIT_Scale;
00369             }
00370 
00371             if ( !IsNearZero( vTrans ) )
00372             {
00373               interaction.m_mtxTransform.origin = vTrans;
00374               interaction.m_uiFlags |= kIT_Translation;
00375             }
00376 
00377             if ( interaction.m_uiFlags )
00378             {
00379               interaction.m_pObject = pObj;
00380               queueInteraction( interaction );
00381             }
00382           }
00383         }
00384       }
00385     }
00386 
00387     pObj->rotateContactPoints();
00388     pObj->m_uiNumPointing = 0;
00389   }
00390 }
00391 
00392 void Scene::processPendingRemovals()
00393 {
00394   for ( uint32_t i = 0; (i < m_uiNumObjects) && m_uiNumPendingRemovals; m_uiNumPendingRemovals-- )
00395   {
00396     if ( m_apObjects[i]->m_bPendingRemoval )
00397     {
00398       deallocateObject( i );
00399     }
00400     else
00401     {
00402       i++;
00403     }
00404   }
00405 }
00406 
00407 void Scene::queueDeselectAll()
00408 {
00409   SceneInteraction deselection;
00410   deselection.m_uiFlags = kIT_SelectionChange;
00411 
00412   for (size_t i=0; i < m_uiNumObjects; i++)
00413   {
00414     if ( m_apObjects[i]->IsSelected() )
00415     {
00416       deselection.m_pObject = m_apObjects[i];
00417       queueInteraction( deselection );
00418     }
00419   }
00420 }
00421 
00422 //************************************
00423 //
00424 // SceneRayHit methods
00425 //
00426 //************************************
00427 
00428 #if defined(LEAP_SCENE_USE_UTIL_GL)
00429 void SceneRayHit::DebugDrawGL( float fHitSphereSize ) const
00430 {
00431     const Vector&       pos     = m_ray.m_vOrigin;
00432     const Vector&       pt      = m_hitPoint;
00433 
00434     glBegin(GL_LINES);
00435     glVertex3fv( &(pos.x) );
00436     glVertex3fv( &(pt.x) );
00437     glEnd();
00438 
00439     {
00440       GLMatrixScope matrixScope;
00441 
00442       glTranslatef(pt.x, pt.y, pt.z);
00443       glScalef( fHitSphereSize, fHitSphereSize, fHitSphereSize );
00444 
00445       drawSphere( kStyle_Solid );
00446     }
00447 }
00448 #endif // LEAP_SCENE_USE_UTIL_GL
00449 
00450 //************************************
00451 //
00452 // SceneObject methods
00453 //
00454 //************************************
00455 
00456 bool SceneBox::TestRayHit(const SceneRay& testRay, float& fHitDistOut) const
00457 {
00458   // by converting the test ray to object space the test is vs. an axis-aligned
00459   // box centered at the origin (0, 0, 0)
00460 
00461   SceneRay  testRayObj  = testRay.Transformed( GetWorldToObjectTransform() );
00462   Vector    vMax        = GetSize() * m_fScale * 0.5f;
00463   Vector    vMin        = -vMax;
00464   Vector    vDirScale   = ComponentWiseReciprocal(testRayObj.m_vDirection);
00465   Vector    vLower      = ComponentWiseScale(vMin - testRayObj.m_vOrigin, vDirScale);
00466   Vector    vUpper      = ComponentWiseScale(vMax - testRayObj.m_vOrigin, vDirScale);
00467 
00468   float fTMin           = MaxComponent(ComponentWiseMin(vLower, vUpper));
00469   float fTMax           = MinComponent(ComponentWiseMax(vLower, vUpper));
00470 
00471   if (fTMin < fTMax)
00472   {
00473     if (fTMin > 0)
00474     {
00475       fHitDistOut = fTMin;
00476       return true;
00477     }
00478 
00479     if (fTMax > 0)
00480     {
00481       fHitDistOut = fTMax;
00482       return true;
00483     }
00484   }
00485 
00486   return false;
00487 }
00488 
00489 bool SceneBox::TestSphereHit(const Vector& vTestPoint, float fTestRadius) const
00490 {
00491   // by converting the test point to object space it's a sphere vs. axis-aligned box test
00492   // where the box is centered at the origin (0, 0, 0).
00493   Vector vPos       = WorldToObjectPoint(vTestPoint);
00494   Vector vMax       = GetSize() * m_fScale * 0.5f;
00495   Vector vMin       = -vMax;
00496 
00497   return  ( ComponentWiseMin(vPos - vMin, Vector::zero()).magnitudeSquared() +
00498             ComponentWiseMax(vPos - vMax, Vector::zero()).magnitudeSquared() ) <= fTestRadius*fTestRadius;
00499 }
00500 
00501 #if defined(LEAP_SCENE_USE_UTIL_GL)
00502 void SceneBox::DebugDrawGL( eStyle drawStyle ) const
00503 {
00504   GLMatrixScope     matrixScope;
00505   const Vector      vSize   = GetSize() * GetScale();
00506 
00507   glMultMatrixf( GetTransform().toArray4x4() );
00508 
00509   glScalef( vSize.x, vSize.y, vSize.z );
00510 
00511   drawBox( drawStyle );
00512 
00513   if ( IsSelected() )
00514   {
00515     GLAttribScope attribScope( GL_CURRENT_BIT|GL_DEPTH_BUFFER_BIT );
00516 
00517     if ( drawStyle != kStyle_Outline )
00518     {
00519       glColor3f(1.0f, 1.0f, 1.0f);
00520       drawBox( kStyle_Outline );
00521     }
00522 
00523     glDisable(GL_DEPTH_TEST);
00524     const Vector vScale = LeapUtil::ComponentWiseReciprocal(vSize) * 0.125f;
00525     glScalef( vScale.x, vScale.y, vScale.z );
00526 
00527     drawAxes();
00528   }
00529 }
00530 #endif // LEAP_SCENE_USE_UTIL_GL
00531 
00532 bool SceneCylinder::TestRayHit(const SceneRay& testRay, float& fHitDistOut) const
00533 {
00534   SceneRay testRayObj = testRay.Transformed( GetWorldToObjectTransform() );
00535 
00536   const Vector& vAxis = Vector::yAxis();
00537   float radius        = m_fScale * m_fRadius;
00538   float height        = m_fScale * m_fHeight;
00539   Vector RxA          = testRayObj.m_vDirection.cross(vAxis);
00540   float norm          = RxA.magnitude();
00541 
00542   if (norm > 0)
00543   {
00544     Vector D = RxA/norm;
00545     float d = fabs(testRayObj.m_vOrigin.dot(D));
00546     if (d >= radius) {
00547       return false;
00548     }
00549     Vector O = D.cross(vAxis).normalized();
00550     float s = fabs(sqrt(radius*radius - d*d)/(testRayObj.m_vDirection.dot(O)));
00551     float temp = -((testRayObj.m_vOrigin).cross(vAxis)).dot(D)/norm;
00552     float tin = temp - s;
00553     float tout = temp + s;
00554 
00555     if (tin > 0 && fabs(testRayObj.CalcPointOn(tin).y) <= height/2.0)
00556     {
00557       fHitDistOut = tin;
00558       return true;
00559     }
00560 
00561     if (tout > 0 && fabs(testRayObj.CalcPointOn(tout).y) <= height/2.0)
00562     {
00563       fHitDistOut = tout;
00564       return true;
00565     }
00566   }
00567   return false;
00568 }
00569 
00570 
00571 bool SceneCylinder::TestSphereHit(const Vector& vTestPoint, float fTestRadius) const
00572 {
00573   // by converting test point to object space the test is simplified.
00574   // we can check the test sphere against a cylinder centered at 0,0,0
00575   // with an axis along y+ (0,1,0)
00576   const Vector  vTestPosObj         = WorldToObjectPoint(vTestPoint);
00577   // scale-adjusted values of the cylinder
00578   const float   fCylRadius          = m_fRadius * m_fScale;
00579   const float   fHalfCylHeight      = m_fHeight * m_fScale * 0.5f;
00580   // vector from infinite line of cylinder axis to test point
00581   const Vector  vAxisToPoint        = Vector(vTestPosObj.x, 0, vTestPosObj.z);
00582   // square of distance from infinite line of cylinder axis to test point
00583   const float   fAxisToPointDistSq  = vAxisToPoint.magnitudeSquared();
00584 
00585   // only bother with the rest of the checks if the distance to the axis is less than
00586   // the sum of the cylinder radius and test sphere radius. any farther and they could not be touching.
00587   if (fAxisToPointDistSq < (fTestRadius + fCylRadius)*(fTestRadius + fCylRadius))
00588   {
00589     // distance from the vertical center of the cylinder to the test point projected onto the axis.
00590     const float fAbsDistAlongAxis = fabs(vTestPosObj.y);
00591 
00592     // simplest case - sphere vs. wall of cylinder.
00593     // the first check was whether or not the test sphere was within contact of the axis.
00594     // if the distance along the axis is inside the cylinder the sphere is in contact with the wall.
00595     if (fAbsDistAlongAxis < fHalfCylHeight)
00596     {
00597       return true;
00598     }
00599 
00600     // next simplest case - sphere vs. centers of cylinder end caps.
00601     // if the distance from the axis is within the cylinder
00602     // and the the test point along the axis is within the sphere radius of the end
00603     // it's touching.
00604     if (fAxisToPointDistSq < (fCylRadius*fCylRadius) && fAbsDistAlongAxis < (fHalfCylHeight + fTestRadius) )
00605     {
00606       return true;
00607     }
00608 
00609     // final case - sphere vs. edges (corners) of cylinder end caps
00610 
00611     // this is the closest point on the cylinder edge to the test point.
00612     const Vector  vClosest =  fCylRadius*vAxisToPoint.normalized() +
00613                               Vector( 0, fHalfCylHeight * ((vTestPosObj.y < 0.0f) ? -1.0f : 1.0f), 0 );
00614 
00615     // if the distance from the closest point to the test point is within the radius of
00616     // the test sphere it is in contact.
00617     if ((vTestPosObj-vClosest).magnitudeSquared() < fTestRadius*fTestRadius)
00618     {
00619       return true;
00620     }
00621   }
00622 
00623   return false;
00624 }
00625 
00626 #if defined(LEAP_SCENE_USE_UTIL_GL)
00627 void SceneCylinder::DebugDrawGL( eStyle drawStyle ) const
00628 {
00629   GLMatrixScope matrixScope;
00630   const float   fHeight = GetHeight() * GetScale();
00631   const float   fRadius = GetRadius() * GetScale();
00632 
00633   glMultMatrixf( GetTransform().toArray4x4() );
00634 
00635   glScalef( fRadius * 2, fHeight, fRadius * 2 );
00636 
00637   drawCylinder( drawStyle, kAxis_Y );
00638 
00639   if ( IsSelected() )
00640   {
00641     GLAttribScope attribScope( GL_CURRENT_BIT|GL_DEPTH_BUFFER_BIT );
00642 
00643     if ( drawStyle != kStyle_Outline )
00644     {
00645       glColor3f(1.0f, 1.0f, 1.0f);
00646       drawCylinder( kStyle_Outline, kAxis_Y );
00647     }
00648 
00649     glDisable(GL_DEPTH_TEST);
00650     const float fScaleXZ = 1.0f/(fRadius + fRadius) * 0.125f;
00651     glScalef( fScaleXZ, 1.0f/fHeight * 0.125f, fScaleXZ );
00652     drawAxes();
00653   }
00654 }
00655 #endif // LEAP_SCENE_USE_UTIL_GL
00656 
00657 bool SceneDisk::TestRayHit(const SceneRay& testRay, float& fHitDistOut) const
00658 {
00659   // by converting ray to object space we can do simpler testing.
00660   // in object space the normal is the z axis (0, 0, 1) and the
00661   // disk is a circle in the x/y plane centered at the origin (0, 0, 0)
00662   SceneRay  testRayObj   = testRay.Transformed( GetWorldToObjectTransform() );
00663   float     fRadius      = m_fScale * m_fRadius;
00664   // cosine of angle between test ray direction and surface normal of the disk
00665   //float     fCosRayAngle = testRayObj.m_vDirection.z;
00666 
00667   // if the z component of the ray direction is 0 the direction is all on the x/y plane
00668   // which means it is parallel to the disk and will not intersect.
00669   if (fabs(testRayObj.m_vDirection.z) < kfEpsilon)
00670   {
00671     return false;
00672   }
00673 
00674   // distance from the ray origin to the disk plane along the path of the ray
00675   float fPlaneHitDist = -testRayObj.m_vOrigin.z/testRayObj.m_vDirection.z;
00676 
00677   // if the plane hit distance is negative the ray is pointing away from the disk
00678   // if positive it is pointing towards the plane.
00679   if ( fPlaneHitDist > 0 )
00680   {
00681     // intersection point of the ray with the plane of the disk
00682     const Vector vPointOnPlane = testRayObj.CalcPointOn( fPlaneHitDist );
00683 
00684     // check if the point is within the disk - if so, it's a hit, otherwise not.
00685     if ( vPointOnPlane.magnitudeSquared() < fRadius * fRadius )
00686     {
00687       fHitDistOut = fPlaneHitDist;
00688       return true;
00689     }
00690   }
00691 
00692   return false;
00693 }
00694 
00695 bool SceneDisk::TestSphereHit(const Vector& vTestPoint, float fTestRadius) const
00696 {
00697   // by converting the test point to object space we can do simpler testing.
00698   // in object space the normal is the z axis (0, 0, 1) and the
00699   // disk is a circle in the x/y plane centered at the origin (0, 0, 0)
00700   const Vector  vPos    = WorldToObjectPoint(vTestPoint);
00701   const float   fDiskRadius = (m_fScale*m_fRadius);
00702 
00703   // the test point has to be within the test sphere radius of the disk plane or it isn't touching.
00704   if (fabs(vPos.z) < fTestRadius)
00705   {
00706     // projection of the test point onto the plane of the disk.
00707     const Vector  vOnPlane( vPos.x, vPos.y, 0 );
00708     const float   fSin = vPos.z/fTestRadius;
00709     const float   fCos = sqrtf(1 - fSin*fSin);
00710 
00711     // fCos * fTestRadius is the radius of the circular intersection of the test sphere and the plane of the disk
00712     // add the two together and that's the maximum distance the projection of the test point onto the disk plane
00713     // can be from the center and still be in contact.
00714     fTestRadius =  fCos * fTestRadius + fDiskRadius;
00715 
00716     if (vOnPlane.magnitudeSquared() < fTestRadius * fTestRadius)
00717     {
00718       return true;
00719     }
00720   }
00721 
00722   return false;
00723 }
00724 
00725 #if defined(LEAP_SCENE_USE_UTIL_GL)
00726 void SceneDisk::DebugDrawGL( eStyle drawStyle ) const
00727 {
00728   GLMatrixScope   matrixScope;
00729   const float     fRadius = GetRadius() * GetScale();
00730 
00731   glMultMatrixf( GetTransform().toArray4x4() );
00732 
00733   glScalef( fRadius + fRadius, fRadius + fRadius, fRadius + fRadius );
00734 
00735   drawDisk( drawStyle, kPlane_XY );
00736 
00737   if ( IsSelected() )
00738   {
00739     GLAttribScope attribScope( GL_CURRENT_BIT|GL_DEPTH_BUFFER_BIT );
00740 
00741     if ( drawStyle != kStyle_Outline )
00742     {
00743       glColor3f(1.0f, 1.0f, 1.0f);
00744       drawDisk( kStyle_Outline, kPlane_XY );
00745     }
00746 
00747     glDisable(GL_DEPTH_TEST);
00748     const float fScale = 1.0f/(fRadius + fRadius) * 0.125f;
00749     glScalef( fScale, fScale, fScale );
00750     drawAxes();
00751   }
00752 }
00753 #endif // LEAP_SCENE_USE_UTIL_GL
00754 
00755 bool ScenePlane::TestRayHit(const SceneRay& testRay, float& fHitDistOut) const
00756 {
00757   const float fRayAngleCos = GetNormal().dot( testRay.m_vDirection );
00758 
00759   if (fabs(fRayAngleCos) < kfEpsilon)
00760   {
00761     return false;
00762   }
00763 
00764   // direct distance from the ray starting position to the plane
00765   const float fRayOriginPlaneDist = GetNormal().dot(GetCenter() - testRay.m_vOrigin);
00766 
00767   // distance from the ray origin point to the plane along the path of the ray
00768   const float fPlaneHitDist = fRayOriginPlaneDist/fRayAngleCos;
00769 
00770   if (fPlaneHitDist > 0)
00771   {
00772     fHitDistOut = fPlaneHitDist;
00773     return true;
00774   }
00775 
00776   return false;
00777 }
00778 
00779 bool ScenePlane::TestSphereHit(const Vector& vTestPoint, float fTestRadius) const
00780 {
00781   return fabs((vTestPoint - GetCenter()).dot(GetNormal())) < fTestRadius;
00782 }
00783 
00784 #if defined(LEAP_SCENE_USE_UTIL_GL)
00785 void ScenePlane::DebugDrawGL( eStyle drawStyle ) const
00786 {
00787   (void)drawStyle;
00788 }
00789 #endif // LEAP_SCENE_USE_UTIL_GL
00790 
00791 bool SceneSphere::TestRayHit(const SceneRay& testRay, float& fHitDistOut) const
00792 {
00793   const float   fRadius = m_fScale * m_fRadius;
00794   const Vector  O       = testRay.m_vOrigin - GetCenter();
00795   const float   b       = O.dot(testRay.m_vDirection);
00796   const float   c       = O.dot(O) - fRadius*fRadius;
00797   const float   disc    = b*b - c;
00798 
00799   if (disc > 0)
00800   {
00801     float sdisc = sqrtf(disc);
00802     float root = (-b - sdisc);
00803 
00804     if (root > 0)
00805     {
00806       fHitDistOut = root;
00807       return true;
00808     }
00809 
00810     root = (-b + sdisc);
00811 
00812     if (root > 0)
00813     {
00814       fHitDistOut = root;
00815       return true;
00816     }
00817   }
00818 
00819   return false;
00820 }
00821 
00822 bool SceneSphere::TestSphereHit(const Vector& vTestPoint, float fTestRadius) const
00823 {
00824   const float fMaxDist = (m_fScale*m_fRadius + fTestRadius);
00825   return (GetCenter() - vTestPoint).magnitudeSquared() < (fMaxDist * fMaxDist);
00826 }
00827 
00828 #if defined(LEAP_SCENE_USE_UTIL_GL)
00829 void SceneSphere::DebugDrawGL( eStyle drawStyle ) const
00830 {
00831   GLMatrixScope matrixScope;
00832 
00833   const float   fRadius  = GetRadius() * GetScale();
00834 
00835   glMultMatrixf( GetTransform().toArray4x4() );
00836 
00837   glScalef( fRadius+fRadius, fRadius+fRadius, fRadius+fRadius );
00838 
00839   drawSphere( drawStyle );
00840 
00841   if ( IsSelected() )
00842   {
00843     GLAttribScope attribScope( GL_CURRENT_BIT|GL_DEPTH_BUFFER_BIT );
00844 
00845     if ( drawStyle != kStyle_Outline )
00846     {
00847       glColor3f(1.0f, 1.0f, 1.0f);
00848       drawSphere( kStyle_Outline );
00849     }
00850 
00851     glDisable(GL_DEPTH_TEST);
00852 
00853     const float fScale = 1.0f/(fRadius + fRadius) * 0.125f;
00854     glScalef( fScale, fScale, fScale );
00855 
00856     drawAxes();
00857   }
00858 }
00859 #endif // LEAP_SCENE_USE_UTIL_GL
00860 
00861 } // namespace Leap


leap_motion
Author(s): Florian Lier , Mirza Shah , Isaac IY Saito
autogenerated on Sat Jun 8 2019 18:47:25