www.pudn.com > reacTIVision-1.3.rar > FingerObject.cpp


/*  reacTIVision fiducial tracking framework
    FiducialObject.cpp
    Copyright (C) 2006 Martin Kaltenbrunner 

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "FingerObject.h"
#include 

FingerObject::FingerObject (int width, int height) {

	this->session_id    = 0;
	this->width     = (float)width;
	this->height    = (float)height;
	
	updated = false;
	alive   = false;

	unsent = 0;
	lost_frames = 0;
	total_frames = 0;

	current.xpos = current.ypos  = -100.0f;
	current.raw_xpos = current.raw_ypos = -100.0f;
	current.motion_speed = current.motion_accel = 0.0f;
	current.motion_speed_x = current.motion_speed_y = 0.0f; 
	current.time = 0;
	
	sprintf(message," ");
	saveLastFrame();
}

FingerObject::~FingerObject() {}

void FingerObject::update (float x, float y) {

	current.time = getCurrentTime();
	
	current.raw_xpos = x;
	current.raw_ypos = y;
	
	// fix possible position and angle jitter
	positionFilter();
	// calculate movement and rotation speed and acceleration
	computeSpeedAccel();
	
	updated = true;
	lost_frames = 0;
}

void FingerObject::saveLastFrame() {

	last.time = current.time;
	last.xpos = current.xpos;
	last.ypos = current.ypos;
	last.motion_speed = current.motion_speed;
}

void FingerObject::positionFilter() {
	
	// TODO 
	// most definitely there is a more sophisticated way
	// to remove position and angle jitter
	// rather than defining a one pixel threshold 

	float threshold = 1.0;
	
	if (fabs(current.raw_xpos-last.xpos)>threshold) current.xpos = current.raw_xpos;
	else current.xpos = last.xpos;

	if (fabs(current.raw_ypos-last.ypos)>threshold) current.ypos = current.raw_ypos;
	else current.ypos = last.ypos;
}

void FingerObject::computeSpeedAccel() {

	if (last.time==0) return;

	int   dt = current.time - last.time;
	float dx = current.xpos - last.xpos;
	float dy = current.ypos - last.ypos;
	float dist = sqrt(dx*dx+dy*dy);

	current.motion_speed  = dist/dt;
	current.motion_speed_x = fabs(dx/dt);
	current.motion_speed_y = fabs(dy/dt);
	current.motion_accel = (current.motion_speed-last.motion_speed)/dt;
}

int FingerObject::checkStatus(unsigned long s_id) {

	int message = FINGER_CANDIDATE;

	if ((!alive) && (total_frames>3)) {
		alive = true;
		session_id = s_id+1;
		return FINGER_ADDED;
	}
	
	total_frames++;
	
	if(removalFilter()) {
		if (session_id>0) message = FINGER_REMOVED;
		else  message = FINGER_EXPIRED;
	} else if (alive) message = FINGER_ALIVE;
	
	return message;
	
}

bool FingerObject::removalFilter() {
	// we remove the cursor if it hasn't appeared in the last sqrt(fps) frames

	if (!updated) {
		int frame_threshold  = (int)floor(sqrt((float)portVideoSDL::current_fps));
		if ((lost_frames>frame_threshold) || (total_frames<=3)) {

			alive = false;
			current.xpos = current.ypos  = -100.0f;
			current.raw_xpos = current.raw_ypos = -100.0f;
			current.motion_speed = current.motion_accel = 0.0f;
			current.motion_speed_x = current.motion_speed_y = 0.0f; 
			current.time = 0;
			lost_frames = 0;
			return true;
		} else {
			current.time = getCurrentTime();
			current.xpos = last.xpos;
			current.ypos = last.ypos;
			computeSpeedAccel();
			updated = true;
			lost_frames++;
		}
	}

	return false;	
}

void FingerObject::reset() {
	lost_frames = 100;
}	

float FingerObject::distance(float x, float y) {

	// returns the distance to the current position
	float dx = x - current.xpos;
	float dy = y - current.ypos;
	return sqrt(dx*dx+dy*dy);
}

char* FingerObject::addSetMessage (TuioServer *tserver) {

	if(updated) {
		updated = false;
		// see if anything has changed compared to the last appearence
		if (( current.xpos!=last.xpos) || ( current.ypos!=last.ypos) ) {
			
			int s_id = session_id;
			float x = current.xpos/width;
			float y = current.ypos/height;
			float X = current.motion_speed_x;
			float Y = current.motion_speed_y;
			float m = current.motion_accel;

			unsent = 0;
			saveLastFrame();

			if(alive) {
				tserver->addCurSet(s_id,x,y,X,Y,m); 
				sprintf(message,"set cur %d %f %f %f %f %f",s_id,x,y,X,Y,m);
			} else return NULL;

			return message;
		} else unsent++;
	}

	saveLastFrame();
	return NULL;

}

void FingerObject::redundantSetMessage (TuioServer *server) {

	int s_id = session_id;
	float x = current.xpos/width;
	float y = current.ypos/height;
	float X = current.motion_speed_x;
	float Y = current.motion_speed_y;
	float m = current.motion_accel;
	
	server->addCurSet(s_id,x,y,X,Y,m);	
	unsent = 0;
}

long FingerObject::getCurrentTime() {

	#ifdef WIN32
		long timestamp = GetTickCount();
	#else
		struct timeval tv;
		struct timezone tz;
		gettimeofday(&tv,&tz);
		long timestamp = (tv.tv_sec*1000)+(tv.tv_usec/1000);
	#endif
	
	return timestamp;
}