1
/*****************************************************************************
3
* grail - Gesture Recognition And Instantiation Library
5
* Copyright (C) 2010 Canonical Ltd.
6
* Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
8
* This program is free software: you can redistribute it and/or modify it
9
* under the terms of the GNU General Public License as published by the
10
* Free Software Foundation, either version 3 of the License, or (at your
11
* option) any later version.
13
* This program is distributed in the hope that it will be useful, but
14
* WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* General Public License for more details.
18
* You should have received a copy of the GNU General Public License along
19
* with this program. If not, see <http://www.gnu.org/licenses/>.
21
****************************************************************************/
23
#include "grail-impl.h"
28
static void set_center_velocity_and_radius(struct grail_impl *impl,
29
struct grail_element *slot)
31
const struct utouch_contact **tc = slot->touches;
32
double x, y, vx, vy, r2, dx, dy;
35
switch (slot->num_touches) {
44
dx = 0.5 * (tc[1]->x - tc[0]->x);
45
dy = 0.5 * (tc[1]->y - tc[0]->y);
48
vx = 0.5 * (tc[0]->vx + tc[1]->vx);
49
vy = 0.5 * (tc[0]->vy + tc[1]->vy);
50
r2 = dx * dx + dy * dy;
53
x = y = vx = vy = r2 = 0;
54
for (i = 0; i < slot->num_touches; i++) {
60
x /= slot->num_touches;
61
y /= slot->num_touches;
62
vx /= slot->num_touches;
63
vy /= slot->num_touches;
64
for (i = 0; i < slot->num_touches; i++) {
67
r2 += dx * dx + dy * dy;
69
r2 /= slot->num_touches;
75
slot->velocity.x = 1000 * vx;
76
slot->velocity.y = 1000 * vy;
80
static void set_moveness_pivot_and_drag(struct grail_impl *impl,
81
struct grail_element *slot,
84
const struct grail_element *pslot = slot->prev;
85
double mx = slot->center.x - pslot->center.x;
86
double my = slot->center.y - pslot->center.y;
87
float *T = slot->transform;
90
slot->pivot = pslot->center;
92
if (slot->num_touches > 1) {
93
double wx = (1 - dc) * mx + ds * my;
94
double wy = (1 - dc) * my - ds * mx;
95
double w2 = wx * wx + wy * wy;
97
double s = sqrt(pslot->radius2 / w2);
98
double q = (mx * mx + my * my) / w2;
100
slot->moveness = 1 - s / q;
101
slot->pivot.x += s * wx;
102
slot->pivot.y += s * wy;
105
slot->pivot.x += q * wx;
106
slot->pivot.y += q * wy;
111
mx *= slot->moveness;
112
my *= slot->moveness;
116
T[2] = (1 - dc) * slot->pivot.x - ds * slot->pivot.y + mx;
119
T[5] = (1 - dc) * slot->pivot.y + ds * slot->pivot.x + my;
121
slot->drag.x = pslot->drag.x + mx;
122
slot->drag.y = pslot->drag.y + my;
125
static void start_slot(struct grail_impl *impl,
126
struct grail_element *slot,
127
const struct utouch_frame *touch)
129
float *T = slot->transform;
131
slot->id = impl->seqid++ & GRAIL_ID_MAX;
132
slot->expect_mask = GRAIL_EXPECT_MASK;
133
slot->active_mask = 0;
134
slot->start_time = touch->time;
135
set_center_velocity_and_radius(impl, slot);
137
T[1] = T[2] = T[3] = T[5] = 0;
138
slot->pivot = slot->center;
145
static void update_slot(struct grail_impl *impl,
146
struct grail_element *slot,
147
double ds, double dc)
149
const struct grail_element *pslot = slot->prev;
151
slot->id = pslot->id;
152
slot->start_time = pslot->start_time;
153
slot->expect_mask = pslot->expect_mask;
154
slot->active_mask = pslot->active_mask;
156
set_center_velocity_and_radius(impl, slot);
157
set_moveness_pivot_and_drag(impl, slot, ds, dc);
159
slot->scale2 = pslot->scale2 * (ds * ds + dc * dc);
160
slot->angle = pslot->angle + ds / dc; /* atan2(ds, dc) */
163
static void stop_slot(struct grail_impl *impl,
164
struct grail_element *slot)
166
const struct grail_element *pslot = slot->prev;
167
float *T = slot->transform;
170
slot->num_touches = 0;
171
slot->start_time = pslot->start_time;
172
slot->expect_mask = 0;
173
slot->active_mask = pslot->active_mask;
174
slot->center = pslot->center;
175
slot->velocity = pslot->velocity;
176
slot->radius2 = pslot->radius2;
178
T[1] = T[2] = T[3] = T[5] = 0;
180
slot->pivot = pslot->pivot;
181
slot->drag = pslot->drag;
182
slot->scale2 = pslot->scale2;
183
slot->angle = pslot->angle;
186
static void set_slot_one(struct grail_impl *impl,
187
struct grail_element *slot,
188
const struct utouch_frame *touch,
189
const struct utouch_contact *t1)
191
const struct grail_element *pslot = slot->prev;
192
const struct utouch_contact *p1 = pslot->touches[0];
195
stop_slot(impl, slot);
199
slot->touches[0] = t1;
200
slot->num_touches = 1;
202
if (pslot->num_touches != slot->num_touches || t1->id != p1->id) {
203
start_slot(impl, slot, touch);
207
update_slot(impl, slot, 0, 1);
210
static void set_slot_two(struct grail_impl *impl,
211
struct grail_element *slot,
212
const struct utouch_frame *touch,
213
const struct utouch_contact *t1,
214
const struct utouch_contact *t2)
216
const struct grail_element *pslot = slot->prev;
217
const struct utouch_contact *p1 = pslot->touches[0];
218
const struct utouch_contact *p2 = pslot->touches[1];
219
double tx, ty, px, py, d2;
221
if (!t1->active || !t2->active) {
222
stop_slot(impl, slot);
226
slot->touches[0] = t1;
227
slot->touches[1] = t2;
228
slot->num_touches = 2;
230
if (pslot->num_touches != slot->num_touches ||
231
t1->id != p1->id || t2->id != p2->id) {
232
start_slot(impl, slot, touch);
241
d2 = px * px + py * py;
247
update_slot(impl, slot, tx * py - ty * px, tx * px + ty * py);
250
static void set_slot_multi(struct grail_impl *impl,
251
struct grail_element *slot,
252
struct grail_frame *frame,
253
const struct utouch_frame *touch)
255
const struct grail_element *pslot = slot->prev;
256
struct grail_element **slots = frame->slots;
257
int i, j, n = impl->num_touches;
258
struct grail_element *best = 0;
260
if (touch->num_active < 3) {
261
stop_slot(impl, slot);
265
memcpy(slot->touches, touch->active,
266
touch->num_active * sizeof(slot->touches[0]));
267
slot->num_touches = touch->num_active;
269
if (pslot->num_touches != slot->num_touches) {
270
start_slot(impl, slot, touch);
274
for (i = 0; i < slot->num_touches; i++) {
275
if (slot->touches[i]->id != pslot->touches[i]->id) {
276
start_slot(impl, slot, touch);
281
for (i = 0; i < impl->num_touches; i++) {
282
for (j = i + 1; j < impl->num_touches; j++) {
283
struct grail_element *s = slots[n++];
286
if (!best || s->radius2 > best->radius2)
291
update_slot(impl, slot, best->transform[1], best->transform[0]);
294
static void set_slots(struct grail_impl *impl,
295
struct grail_frame *frame,
296
const struct utouch_frame *touch)
298
struct grail_element **slots = frame->slots;
299
struct utouch_contact *const *tc = touch->slots;
302
for (i = 0; i < impl->num_touches; i++)
303
set_slot_one(impl, slots[n++], touch, tc[i]);
305
for (i = 0; i < impl->num_touches; i++)
306
for (j = i + 1; j < impl->num_touches; j++)
307
set_slot_two(impl, slots[n++], touch, tc[i], tc[j]);
309
set_slot_multi(impl, slots[n++], frame, touch);
312
static void collect_transforms(struct grail_impl *impl,
313
struct grail_frame *frame,
314
const struct utouch_frame *touch)
316
const struct utouch_surface *s = utouch_frame_get_surface(impl->fh);
317
const struct grail_control *ctl = impl->ctl;
318
float dx = ctl->bar_x * (s->mapped_max_x - s->mapped_min_x);
319
float dy = ctl->bar_y * (s->mapped_max_y - s->mapped_min_y);
320
float ds2 = ctl->bar_scale * ctl->bar_scale;
324
for (i = 0; i < impl->num_slots; i++) {
325
struct grail_element *s = frame->slots[i];
330
dt = touch->time - s->start_time;
331
if (dt > ctl->glue_ms) {
332
unsigned int mask = s->active_mask;
334
if (s->moveness > ctl->thresh_drag) {
335
if (fabs(s->drag.x) > dx)
336
mask |= GRAIL_EXPECT_X;
337
if (fabs(s->drag.y) > dy)
338
mask |= GRAIL_EXPECT_Y;
340
if (s->moveness < ctl->thresh_scale) {
341
if (fabs(s->scale2 - 1) > ds2)
342
mask |= GRAIL_EXPECT_SCALE;
343
if (fabs(s->angle) > ctl->bar_angle)
344
mask |= GRAIL_EXPECT_ANGLE;
347
s->active_mask = mask;
349
if (dt < ctl->drop_x_ms)
350
mask |= GRAIL_EXPECT_X;
351
if (dt < ctl->drop_y_ms)
352
mask |= GRAIL_EXPECT_Y;
353
if (dt < ctl->drop_scale_ms)
354
mask |= GRAIL_EXPECT_SCALE;
355
if (dt < ctl->drop_angle_ms)
356
mask |= GRAIL_EXPECT_ANGLE;
358
s->expect_mask &= mask;
361
frame->ongoing[frame->num_ongoing++] = s;
365
const struct grail_frame *grail_pump_frame(grail_handle ge,
366
const struct utouch_frame *touch)
368
struct grail_impl *impl = ge->impl;
369
struct grail_frame *frame = impl->frames[impl->nextframe];
370
const struct grail_frame *prev = frame->prev;
373
if (touch->slot_revision == touch->prev->slot_revision &&
377
frame->touch = touch;
378
frame->num_ongoing = 0;
379
for (i = 0; i < impl->num_slots; i++)
380
frame->slots[i]->prev = prev->slots[i];
382
set_slots(impl, frame, touch);
383
collect_transforms(impl, frame, touch);
385
impl->nextframe = (impl->nextframe + 1) % impl->num_frames;