/*****************************************************************************
*
* grail - Gesture Recognition And Instantiation Library
*
* Copyright (C) 2010 Canonical Ltd.
*
* 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 3 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, see .
*
* Authors:
* Henrik Rydberg
*
****************************************************************************/
#include "grail-recognizer.h"
#include
static const float SN_MOVE = 50;
static const float SN_ZOOM = 50;
static const float SN_ROTATE = 200;
static const float BAR_MOVE = 1;
static const float BAR_ZOOM = 2;
static const float BAR_ROTATE = 4;
static void compute_position(float *x, float *y,
const struct touch_frame *frame)
{
int i, n = frame->nactive;
*x = 0;
*y = 0;
if (n < 1)
return;
for (i = 0; i < n; i++) {
const struct touch *t = frame->active[i];
*x += t->prop[TP_POS_X];
*y += t->prop[TP_POS_Y];
}
*x /= n;
*y /= n;
}
static float compute_radius(float x, float y,
const struct touch_frame *frame)
{
int i, n = frame->nactive;
float r = 0, r2 = 0;
if (n < 2)
return r;
for (i = 0; i < n; i++) {
const struct touch *t = frame->active[i];
float dx = t->prop[TP_POS_X] - x;
float dy = t->prop[TP_POS_Y] - y;
r2 += dx * dx + dy * dy;
}
r2 /= n;
r = sqrt(r2);
return r;
}
static float compute_rotation(float x, float y, float r,
const struct touch_frame *prev,
const struct touch_frame *frame)
{
int i, n = frame->nactive;
float da = 0, da2 = 0;
if (n < 2)
return da;
for (i = 0; i < n; i++) {
const struct touch *t = frame->active[i];
const struct touch *ot = &prev->touch[t->slot];
float dx = t->prop[TP_POS_X] - x;
float dy = t->prop[TP_POS_Y] - y;
float mx = t->prop[TP_POS_X] - ot->prop[TP_POS_X];
float my = t->prop[TP_POS_Y] - ot->prop[TP_POS_Y];
da2 += dx * my - dy * mx;
}
da2 /= n;
da = da2 / r;
return da;
}
static float move_filter(float x, float x0, float fuzz)
{
if (x > x0 - fuzz / 2 && x < x0 + fuzz / 2)
return x0;
if (x > x0 - fuzz && x < x0 + fuzz)
return (x0 * 3 + x) / 4;
if (x > x0 - fuzz * 2 && x < x0 + fuzz * 2)
return (x0 + x) / 2;
return x;
}
void gru_init_motion(struct grail *ge, const struct touch_dev_caps *caps)
{
struct gesture_recognizer *gru = ge->gru;
struct move_model *state = &gru->move;
float x = caps->info[TP_POS_X].maximum - caps->info[TP_POS_X].minimum;
float y = caps->info[TP_POS_Y].maximum - caps->info[TP_POS_Y].minimum;
float r = sqrt(x * x + y * y);
state->xfuzz = x / SN_MOVE;
state->yfuzz = y / SN_MOVE;
state->rfuzz = r / SN_ZOOM;
state->afuzz = r / SN_ROTATE;
state->xbar = BAR_MOVE * state->xfuzz;
state->ybar = BAR_MOVE * state->yfuzz;
state->rbar = BAR_ZOOM * state->rfuzz;
state->abar = BAR_ROTATE * state->afuzz;
}
void gru_reset_motion(struct grail *ge,
const struct touch_frame *frame)
{
struct gesture_recognizer *gru = ge->gru;
struct move_model *state = &gru->move;
compute_position(&state->x, &state->y, frame);
state->r = compute_radius(state->x, state->y, frame);
state->a = 0;
state->ntouch = frame->nactive;
}
void gru_compute_motion(struct grail *ge,
const struct touch_frame *frame)
{
struct gesture_inserter *gin = ge->gin;
struct gesture_recognizer *gru = ge->gru;
struct move_model *state = &gru->move;
float x, y, r, a;
compute_position(&x, &y, frame);
x = move_filter(x, state->x, state->xfuzz);
y = move_filter(y, state->y, state->yfuzz);
r = compute_radius(x, y, frame);
r = move_filter(r, state->r, state->rfuzz);
a = state->a + compute_rotation(x, y, r, &gru->frame, frame);
a = move_filter(a, state->a, state->afuzz);
state->x = x;
state->y = y;
state->r = r;
state->a = a;
state->ntouch = frame->nactive;
}