JointHitDetector:: JointHitDetector ( XnSkeletonJoint joint, XnSkeletonJoint refJoint, string name, float requiredLength)
: mPointHistorySize( 5 )
, mRequiredLength( requiredLength)
, mMessageWorldJointPos( 0 )
, mMessageBodyJointPos( 0 )
, mMessageScreenJointPos( 0 )
, mJoint( joint)
, mRefJoint( refJoint)
, mName( name)
JointHitDetector:: ~JointHitDetector( )
{
TheMessenger- > RemoveListener( this ) ;
}
void JointHitDetector:: Poll ( float dt)
const ofxVec3f vUp( 0 ,1 ,0 ) ;
const ofxVec3f vDown( 0 ,- 1 ,0 ) ;
const ofxVec3f vLeft( - 1 ,0 ,0 ) ;
const ofxVec3f vRight( 1 ,0 ,0 ) ;
const ofxVec3f vBack( 0 ,0 ,1 ) ;
const ofxVec3f vForward( 0 ,0 ,- 1 ) ;
if ( DetectHit( vDir) && ( refDist > 300 || ! NeedDistFromRef( ) ) && confidence > .3f )
{
vDir.normalize ( ) ;
if ( MatchesDir( vUp, vDir, vRefToJoint) )
{
TheMessenger- > SendStringMessage( mName, "up" ) ;
mHitAreaDisplay[ kHitUp] = _hitAreaDisplayTime;
}
else if ( MatchesDir( vDown, vDir, vRefToJoint) )
{
TheMessenger- > SendStringMessage( mName, "down" ) ;
mHitAreaDisplay[ kHitDown] = _hitAreaDisplayTime;
}
else if ( MatchesDir( vRight, vDir, vRefToJoint) )
{
TheMessenger- > SendStringMessage( mName, "right" ) ;
mHitAreaDisplay[ kHitRight] = _hitAreaDisplayTime;
}
else if ( MatchesDir( vForward, vDir, vRefToJoint) )
{
TheMessenger- > SendStringMessage( mName, "forward" ) ;
mHitAreaDisplay[ kHitForward] = _hitAreaDisplayTime;
}
else if ( MatchesDir( vLeft, vDir, vRefToJoint) )
{
TheMessenger- > SendStringMessage( mName, "left" ) ;
mHitAreaDisplay[ kHitLeft] = _hitAreaDisplayTime;
}
else if ( MatchesDir( vBack, vDir, vRefToJoint) )
{
TheMessenger- > SendStringMessage( mName, "back" ) ;
mHitAreaDisplay[ kHitBack] = _hitAreaDisplayTime;
}
}
}
}
bool JointHitDetector:: MatchesDir ( const ofxVec3f& vMatchDir, const ofxVec3f& vCheckDir, const ofxVec3f& vRefDir) const
{
const float cos45 = 0.707106781f ;
return vMatchDir.dot ( vCheckDir) > cos45 && ( vMatchDir.dot ( vRefDir) > .3f || ! NeedDistFromRef( ) ) ;
}
bool JointHitDetector:: DetectHit ( ofxVec3f& vDir)
{
int numTrackedPoints = mPoints.size ( ) ;
if ( numTrackedPoints < 3 )
return false ;
ofxVec3f A = mPoints[ 1 ] - mPoints[ 0 ] ;
ofxVec3f B = mPoints[ 2 ] - mPoints[ 1 ] ;
for ( int i= 2 ; i<= numTrackedPoints; ++ i)
{
//printf("*** i = %i\n", i);
//printf("A = (%f,%f,%f) B = (%f,%f,%f)\n", A.x, A.y, A.z, B.x, B.y, B.z);
ofxVec3f C = mPoints[ numTrackedPoints > i ? i : i- 1 ] - mPoints[ i- 1 ] ;
ofxVec3f normA = A.getNormalized ( ) ;
ofxVec3f normB = B.getNormalized ( ) ;
static float _shortEnough = 30.0f ;
if ( LongEnough( A) && ( normA.dot ( normB) < .1f || B.length ( ) < _shortEnough) )
{
vDir = A;
for ( int j= 0 ; j< i; ++ j) //erase the A part, keep the B
mPoints.erase ( mPoints.begin ( ) ) ;
return true ;
}
else if ( normA.dot ( normB) > .8f || ( LongEnough( A) && normA.dot ( normB) > .4f ) )
{
A = A+ B; B = C;
}
else
{
A = B; B = C;
}
}
return false ;
}
bool JointHitDetector:: LongEnough ( const ofxVec3f& vec) const
{
return vec.lengthSquared ( ) > mRequiredLength * mRequiredLength;
}
void JointHitDetector:: Draw ( ) const
{
for ( int i= 1 ; i< mPoints.size ( ) ; ++ i)
{
glPushMatrix( ) ;
glLineWidth( 3 ) ;
glColor3f( 0 ,0 ,1 ) ;
glBegin( GL_LINES) ;
glVertex2f( 320 + mPoints[ i- 1 ] .x * .5f , 240 - mPoints[ i- 1 ] .y * .5f ) ;
glVertex2f( 320 + mPoints[ i] .x * .5f , 240 - mPoints[ i] .y * .5f ) ;
glEnd( ) ;
glPopMatrix( ) ;
}
for ( int i= 0 ; i< kNumHitDirections; ++ i)
DrawHitDirection( ( HitDirection) i) ;
}
CkpvaW50SGl0RGV0ZWN0b3I6OkpvaW50SGl0RGV0ZWN0b3IoWG5Ta2VsZXRvbkpvaW50IGpvaW50LCBYblNrZWxldG9uSm9pbnQgcmVmSm9pbnQsIHN0cmluZyBuYW1lLCBmbG9hdCByZXF1aXJlZExlbmd0aCkKICAgOiBtUG9pbnRIaXN0b3J5U2l6ZSg1KQogICAsIG1SZXF1aXJlZExlbmd0aChyZXF1aXJlZExlbmd0aCkKICAgLCBtTWVzc2FnZVdvcmxkSm9pbnRQb3MoMCkKICAgLCBtTWVzc2FnZUJvZHlKb2ludFBvcygwKQogICAsIG1NZXNzYWdlU2NyZWVuSm9pbnRQb3MoMCkKICAgLCBtSm9pbnQoam9pbnQpCiAgICwgbVJlZkpvaW50KHJlZkpvaW50KQogICAsIG1OYW1lKG5hbWUpCgpKb2ludEhpdERldGVjdG9yOjp+Sm9pbnRIaXREZXRlY3RvcigpCnsKICAgVGhlTWVzc2VuZ2VyLT5SZW1vdmVMaXN0ZW5lcih0aGlzKTsKfQoKdm9pZCBKb2ludEhpdERldGVjdG9yOjpQb2xsKGZsb2F0IGR0KQoKICAgICAgY29uc3Qgb2Z4VmVjM2YgdlVwKDAsMSwwKTsKICAgICAgY29uc3Qgb2Z4VmVjM2YgdkRvd24oMCwtMSwwKTsKICAgICAgY29uc3Qgb2Z4VmVjM2YgdkxlZnQoLTEsMCwwKTsKICAgICAgY29uc3Qgb2Z4VmVjM2YgdlJpZ2h0KDEsMCwwKTsKICAgICAgY29uc3Qgb2Z4VmVjM2YgdkJhY2soMCwwLDEpOwogICAgICBjb25zdCBvZnhWZWMzZiB2Rm9yd2FyZCgwLDAsLTEpOwogICAgICBpZiAoRGV0ZWN0SGl0KHZEaXIpICYmIChyZWZEaXN0ID4gMzAwIHx8ICFOZWVkRGlzdEZyb21SZWYoKSkgJiYgY29uZmlkZW5jZSA+IC4zZikKICAgICAgewogICAgICAgICB2RGlyLm5vcm1hbGl6ZSgpOwogICAgICAgICBpZiAoTWF0Y2hlc0Rpcih2VXAsIHZEaXIsIHZSZWZUb0pvaW50KSkKICAgICAgICAgewogICAgICAgICAgICBUaGVNZXNzZW5nZXItPlNlbmRTdHJpbmdNZXNzYWdlKG1OYW1lLCAidXAiKTsKICAgICAgICAgICAgbUhpdEFyZWFEaXNwbGF5W2tIaXRVcF0gPSBfaGl0QXJlYURpc3BsYXlUaW1lOwogICAgICAgICB9CiAgICAgICAgIGVsc2UgaWYgKE1hdGNoZXNEaXIodkRvd24sIHZEaXIsIHZSZWZUb0pvaW50KSkKICAgICAgICAgewogICAgICAgICAgICBUaGVNZXNzZW5nZXItPlNlbmRTdHJpbmdNZXNzYWdlKG1OYW1lLCAiZG93biIpOwogICAgICAgICAgICBtSGl0QXJlYURpc3BsYXlba0hpdERvd25dID0gX2hpdEFyZWFEaXNwbGF5VGltZTsKICAgICAgICAgfQogICAgICAgICBlbHNlIGlmIChNYXRjaGVzRGlyKHZSaWdodCwgdkRpciwgdlJlZlRvSm9pbnQpKQogICAgICAgICB7CiAgICAgICAgICAgIFRoZU1lc3Nlbmdlci0+U2VuZFN0cmluZ01lc3NhZ2UobU5hbWUsICJyaWdodCIpOwogICAgICAgICAgICBtSGl0QXJlYURpc3BsYXlba0hpdFJpZ2h0XSA9IF9oaXRBcmVhRGlzcGxheVRpbWU7CiAgICAgICAgIH0KICAgICAgICAgZWxzZSBpZiAoTWF0Y2hlc0Rpcih2Rm9yd2FyZCwgdkRpciwgdlJlZlRvSm9pbnQpKQogICAgICAgICB7CiAgICAgICAgICAgIFRoZU1lc3Nlbmdlci0+U2VuZFN0cmluZ01lc3NhZ2UobU5hbWUsICJmb3J3YXJkIik7CiAgICAgICAgICAgIG1IaXRBcmVhRGlzcGxheVtrSGl0Rm9yd2FyZF0gPSBfaGl0QXJlYURpc3BsYXlUaW1lOwogICAgICAgICB9CiAgICAgICAgIGVsc2UgaWYgKE1hdGNoZXNEaXIodkxlZnQsIHZEaXIsIHZSZWZUb0pvaW50KSkKICAgICAgICAgewogICAgICAgICAgICBUaGVNZXNzZW5nZXItPlNlbmRTdHJpbmdNZXNzYWdlKG1OYW1lLCAibGVmdCIpOwogICAgICAgICAgICBtSGl0QXJlYURpc3BsYXlba0hpdExlZnRdID0gX2hpdEFyZWFEaXNwbGF5VGltZTsKICAgICAgICAgfQogICAgICAgICBlbHNlIGlmIChNYXRjaGVzRGlyKHZCYWNrLCB2RGlyLCB2UmVmVG9Kb2ludCkpCiAgICAgICAgIHsKICAgICAgICAgICAgVGhlTWVzc2VuZ2VyLT5TZW5kU3RyaW5nTWVzc2FnZShtTmFtZSwgImJhY2siKTsKICAgICAgICAgICAgbUhpdEFyZWFEaXNwbGF5W2tIaXRCYWNrXSA9IF9oaXRBcmVhRGlzcGxheVRpbWU7CiAgICAgICAgIH0KICAgICAgfQogICB9Cn0KCmJvb2wgSm9pbnRIaXREZXRlY3Rvcjo6TWF0Y2hlc0Rpcihjb25zdCBvZnhWZWMzZiYgdk1hdGNoRGlyLCBjb25zdCBvZnhWZWMzZiYgdkNoZWNrRGlyLCBjb25zdCBvZnhWZWMzZiYgdlJlZkRpcikgY29uc3QKewogICBjb25zdCBmbG9hdCBjb3M0NSA9IDAuNzA3MTA2NzgxZjsKICAgcmV0dXJuIHZNYXRjaERpci5kb3QodkNoZWNrRGlyKSA+IGNvczQ1ICYmICh2TWF0Y2hEaXIuZG90KHZSZWZEaXIpID4gLjNmIHx8ICFOZWVkRGlzdEZyb21SZWYoKSk7Cn0KCmJvb2wgSm9pbnRIaXREZXRlY3Rvcjo6RGV0ZWN0SGl0KG9meFZlYzNmJiB2RGlyKQp7CglpbnQgbnVtVHJhY2tlZFBvaW50cyA9IG1Qb2ludHMuc2l6ZSgpOwoJaWYgKG51bVRyYWNrZWRQb2ludHMgPCAzKQoJCXJldHVybiBmYWxzZTsKICAgCglvZnhWZWMzZiBBID0gbVBvaW50c1sxXSAtIG1Qb2ludHNbMF07CglvZnhWZWMzZiBCID0gbVBvaW50c1syXSAtIG1Qb2ludHNbMV07CiAgIAoJZm9yIChpbnQgaT0yOyBpPD1udW1UcmFja2VkUG9pbnRzOyArK2kpCgl7CiAgICAgIC8vcHJpbnRmKCIqKiogaSA9ICVpXG4iLCBpKTsKICAgICAgLy9wcmludGYoIkEgPSAoJWYsJWYsJWYpICAgQiA9ICglZiwlZiwlZilcbiIsIEEueCwgQS55LCBBLnosIEIueCwgQi55LCBCLnopOwoJCW9meFZlYzNmIEMgPSBtUG9pbnRzW251bVRyYWNrZWRQb2ludHMgPiBpID8gaSA6IGktMV0gLSBtUG9pbnRzW2ktMV07CiAgICAgIG9meFZlYzNmIG5vcm1BID0gQS5nZXROb3JtYWxpemVkKCk7CiAgICAgIG9meFZlYzNmIG5vcm1CID0gQi5nZXROb3JtYWxpemVkKCk7CiAgICAgIAogICAgICBzdGF0aWMgZmxvYXQgX3Nob3J0RW5vdWdoID0gMzAuMGY7CiAgICAgIGlmIChMb25nRW5vdWdoKEEpICYmIChub3JtQS5kb3Qobm9ybUIpIDwgLjFmIHx8IEIubGVuZ3RoKCkgPCBfc2hvcnRFbm91Z2gpKQogICAgICB7CiAgICAgICAgIHZEaXIgPSBBOwogICAgICAgICBmb3IgKGludCBqPTA7IGo8aTsgKytqKSAvL2VyYXNlIHRoZSBBIHBhcnQsIGtlZXAgdGhlIEIKICAgICAgICAgICAgbVBvaW50cy5lcmFzZShtUG9pbnRzLmJlZ2luKCkpOwogICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgfQoJCWVsc2UgaWYgKG5vcm1BLmRvdChub3JtQikgPiAuOGYgfHwgKExvbmdFbm91Z2goQSkgJiYgbm9ybUEuZG90KG5vcm1CKSA+IC40ZikpCgkJewoJCQlBID0gQStCOyBCID0gQzsKCQl9CgkJZWxzZQoJCXsKCQkJQSA9IEI7IEIgPSBDOwoJCX0KCX0KICAgCglyZXR1cm4gZmFsc2U7Cn0KCmJvb2wgSm9pbnRIaXREZXRlY3Rvcjo6TG9uZ0Vub3VnaChjb25zdCBvZnhWZWMzZiYgdmVjKSBjb25zdAp7CiAgIHJldHVybiB2ZWMubGVuZ3RoU3F1YXJlZCgpID4gbVJlcXVpcmVkTGVuZ3RoICogbVJlcXVpcmVkTGVuZ3RoOwp9Cgp2b2lkIEpvaW50SGl0RGV0ZWN0b3I6OkRyYXcoKSBjb25zdAp7CiAgIGZvciAoaW50IGk9MTsgaTxtUG9pbnRzLnNpemUoKTsgKytpKQogICB7CiAgICAgIGdsUHVzaE1hdHJpeCgpOwoJCWdsTGluZVdpZHRoKDMpOwoJCWdsQ29sb3IzZigwLDAsMSk7CgkJZ2xCZWdpbihHTF9MSU5FUyk7CiAgICAgIGdsVmVydGV4MmYoMzIwICsgbVBvaW50c1tpLTFdLnggKiAuNWYsIDI0MCAtIG1Qb2ludHNbaS0xXS55ICogLjVmKTsKICAgICAgZ2xWZXJ0ZXgyZigzMjAgKyBtUG9pbnRzW2ldLnggKiAuNWYsIDI0MCAtIG1Qb2ludHNbaV0ueSAqIC41Zik7CgkJZ2xFbmQoKTsKCQlnbFBvcE1hdHJpeCgpOwogICB9CiAgIAogICBmb3IgKGludCBpPTA7IGk8a051bUhpdERpcmVjdGlvbnM7ICsraSkKICAgICAgRHJhd0hpdERpcmVjdGlvbigoSGl0RGlyZWN0aW9uKWkpOwp9CgoKCg==