Merge lp:~chasedouglas/grail/pivot_type into lp:~oif-team/grail/grail2

Proposed by Chase Douglas
Status: Rejected
Rejected by: Chase Douglas
Proposed branch: lp:~chasedouglas/grail/pivot_type
Merge into: lp:~oif-team/grail/grail2
Diff against target: 2417 lines (+743/-1170)
23 files modified
include/grail-bits.h (+1/-0)
include/grail.h (+46/-36)
src/Makefile.am (+0/-7)
src/gestures-drag.c (+0/-135)
src/gestures-pinch.c (+0/-129)
src/gestures-rotate.c (+0/-128)
src/gestures-tapping.c (+0/-100)
src/gestures-touch.c (+0/-98)
src/grail-api.c (+12/-96)
src/grail-bits.c (+9/-0)
src/grail-frame.c (+159/-48)
src/grail-gestures.c (+0/-210)
src/grail-gestures.h (+0/-115)
src/grail-impl.h (+1/-0)
src/grail-init.c (+0/-2)
src/grail-inserter.c (+0/-32)
src/grail-inserter.h (+0/-2)
src/grail-legacy.c (+104/-0)
src/grail-recognizer.c (+353/-16)
src/grail-recognizer.h (+39/-4)
tools/grail-test-mtdev.c (+0/-1)
tools/grail-transform.c (+17/-11)
utouch-grail.sym.in (+2/-0)
To merge this branch: bzr merge lp:~chasedouglas/grail/pivot_type
Reviewer Review Type Date Requested Status
Henrik Rydberg (community) Disapprove
Review via email: mp+59272@code.launchpad.net

Description of the change

RFC for this changeset that adds configuration of where the pivot should be determined.

To post a comment you must log in.
Revision history for this message
Henrik Rydberg (rydberg) wrote :

Removing the moveness threshold values, i can live with that, no biggie

The transform matrix should include the pivot, or it would no be useful for other programs which expect a linear transform, which is also the most efficient.

What you call the center of rotation is precisely the same as the moveness = 0 special case,
so configuration could instead be done by allowing the cutoff radius to vary, instead of having separate "algorithms".

The rest seems to be a reproduction of what is in grail2, only less efficiently coded.

All in all, I can imagine reducing this to a ten-line patch, on top of the other grail2 branches, handling mode switches. We should also think about how/if we should model the degrees of freedom depending on what gesture types are being asked for, or if this should really be controllable by the app, or if simply all data should be sent.

Because the patch should really go on top of the original gesture frames branch, I am rejecting this particular merge request.

review: Disapprove
lp:~chasedouglas/grail/pivot_type updated
151. By Chase Douglas

Make the pivot point determination configurable

* Remove moveness from grail_element
* Remove thresh_scale and thresh_drag from control
* Introduce a control for the pivot type
* Fix translation computation
* Fix grail_element_transform so it uses the pivot point
* Add new functionality for computing different pivot points
* Determine the drag value based on strictly on the centroid motion
  - This should fix grail 1 translation errors

152. By Chase Douglas

Use a red dot to denote the pivot point

The pivot point is also now drawn after the touches so it is visible when
on top of a touch point. Some drawing code was simplified by using
clear_screen.

153. By Chase Douglas

As an example, tell grail to use the convex hull pivot confinement in
grail-transform.

154. By Chase Douglas

Merge in grail 2 to grail 1 translation layer

Unmerged revisions

154. By Chase Douglas

Merge in grail 2 to grail 1 translation layer

153. By Chase Douglas

As an example, tell grail to use the convex hull pivot confinement in
grail-transform.

152. By Chase Douglas

Use a red dot to denote the pivot point

The pivot point is also now drawn after the touches so it is visible when
on top of a touch point. Some drawing code was simplified by using
clear_screen.

151. By Chase Douglas

Make the pivot point determination configurable

* Remove moveness from grail_element
* Remove thresh_scale and thresh_drag from control
* Introduce a control for the pivot type
* Fix translation computation
* Fix grail_element_transform so it uses the pivot point
* Add new functionality for computing different pivot points
* Determine the drag value based on strictly on the centroid motion
  - This should fix grail 1 translation errors

150. By Henrik Rydberg

Update copyright information

The license information was always right, but the copyright information
for this particular project was never quite right. Corrected with this
patch. No functional changes.

Signed-off-by: Henrik Rydberg <email address hidden>

149. By Henrik Rydberg

Introduce the grail transform tool

This tool tests the transform capabilities of grail. Similar to a
map application, one can use a single finger, two fingers, a whole
hand or two hands to move the rectangle around, scale and rotate it.

Signed-off-by: Henrik Rydberg <email address hidden>

148. By Henrik Rydberg

Introduce test-mtdev

A new tool (test-mtdev) is added, showing the usage of gesture frames.

Signed-off-by: Henrik Rydberg <email address hidden>

147. By Henrik Rydberg

Add gesture transform unit tests

Start the gesture frame test suite with some basic coordinate
mapping tests.

Signed-off-by: Henrik Rydberg <email address hidden>

146. By Henrik Rydberg

Document the gesture frame logic

Add some notes on the math of the gesture frame computations.

Signed-off-by: Henrik Rydberg <email address hidden>

145. By Henrik Rydberg

Introduce gesture frames

This patch extends the API with parallel new/delete functions,
aiming to eventually replace the open/close function. The new
functions give access to the grail gesture frames, containing
gestural transform information. This information is useful in its
own right, and will eventually replace the internal recognizer.

Signed-off-by: Henrik Rydberg <email address hidden>

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/grail-bits.h'
2--- include/grail-bits.h 2011-04-12 16:35:37 +0000
3+++ include/grail-bits.h 2011-04-27 19:43:23 +0000
4@@ -49,6 +49,7 @@
5
6 void grail_mask_set_mask(grail_mask_t *a, const grail_mask_t *b, int bytes);
7 void grail_mask_clear_mask(grail_mask_t *a, const grail_mask_t *b, int bytes);
8+int grail_mask_inner(const grail_mask_t *a, const grail_mask_t *b, int bytes);
9
10 int grail_mask_count(const grail_mask_t *mask, int bytes);
11 int grail_mask_get_first(const grail_mask_t *mask, int bytes);
12
13=== modified file 'include/grail.h'
14--- include/grail.h 2011-04-12 16:35:37 +0000
15+++ include/grail.h 2011-04-27 19:43:23 +0000
16@@ -128,6 +128,27 @@
17 */
18 const struct grail_frame *grail_pump_frame(grail_handle ge,
19 const struct utouch_frame *frame);
20+/**
21+ * grail_pivot_type - Option for determining location of pivot point
22+ * @GRAIL_CENTROID: use the centroid of the touch points as the pivot point
23+ * @GRAIL_CENTER_OF_ROTATION: set the pivot point such that there is no
24+ translation in the transformation matrix ("instant center of rotation")
25+ * @GRAIL_CONVEX_HULL_RADIUS: Minimize translation while confining the pivot
26+ point to a circle around the centroid approximating the radius of the
27+ convex hull of the touch points
28+ *
29+ * The gesture transformation matrix and pivot point are dependent. This means
30+ * a transformation can be found for any given pivot point. Depending on the use
31+ * case, one pivot point location may be better than another. If the use case
32+ * involves only dragging gestures, GRAIL_CENTROID is best. If the use case
33+ * involves only rotation gestures, GRAIL_CENTER_OF_ROTATION or
34+ * may be better GRAIL_CONVEX_HULL_RADIUS.
35+ */
36+enum grail_pivot_type {
37+ GRAIL_CENTROID = 0,
38+ GRAIL_CENTER_OF_ROTATION,
39+ GRAIL_CONVEX_HULL_RADIUS
40+};
41
42 /**
43 * struct grail_client_id - Gesture client information
44@@ -157,8 +178,6 @@
45 /**
46 * struct grail_control - control parameters of grail
47 * @glue_ms: minimum time to hold activation (ms)
48- * @thresh_drag: minimum moveness for drag
49- * @thresh_scale: maximum moveness for rotate and scale
50 * @bar_x: minimum horizontal distance to activate (surface width fraction)
51 * @bar_y: minimum vertical distance to activate (surface height fraction)
52 * @bar_scale: minimum scaling to activate (fraction)
53@@ -170,17 +189,11 @@
54 *
55 * The parameters are used to tune the behavior of the gesture recognition.
56 *
57- * The moveness is a number between zero and one denoting the
58- * character of the current transform. Zero means pure rotate and
59- * scale, one means pure drag.
60- *
61 * Later versions of this struct may grow in size, but will remain
62 * binary compatible with older versions.
63 */
64 struct grail_control {
65 float glue_ms;
66- float thresh_drag;
67- float thresh_scale;
68 float bar_x;
69 float bar_y;
70 float bar_scale;
71@@ -189,6 +202,7 @@
72 float drop_y_ms;
73 float drop_scale_ms;
74 float drop_angle_ms;
75+ enum grail_pivot_type pivot_type;
76 };
77
78 /**
79@@ -262,7 +276,6 @@
80 struct grail_coord velocity;
81 float radius2;
82 float transform[6];
83- float moveness;
84 struct grail_coord pivot;
85 struct grail_coord drag;
86 float scale2;
87@@ -283,8 +296,12 @@
88 const struct grail_coord *p)
89 {
90 const float *T = slot->transform;
91- q->x = T[0] * p->x + T[1] * p->y + T[2];
92- q->y = T[3] * p->x + T[4] * p->y + T[5];
93+ q->x = T[0] * (p->x - slot->pivot.x) +
94+ T[1] * (p->y - slot->pivot.y) +
95+ T[2] + slot->pivot.x;
96+ q->y = T[3] * (p->x - slot->pivot.x) +
97+ T[4] * (p->y - slot->pivot.y) +
98+ T[5] + slot->pivot.y;
99 }
100
101 /**
102@@ -349,21 +366,6 @@
103 };
104
105 /**
106- * grail_open - open a grail device
107- * @ge: the grail device to open
108- * @fd: file descriptor of the kernel device
109- *
110- * Initialize the internal grail structures and configure it by reading the
111- * protocol capabilities through the file descriptor.
112- *
113- * The callbacks, parameters and priv pointer should be set prior to this
114- * call.
115- *
116- * Returns zero on success, negative error number otherwise.
117- */
118-int grail_open(struct grail *ge, int fd);
119-
120-/**
121 * grail_idle - check state of kernel device
122 * @ge: the grail device in use
123 * @fd: file descriptor of the kernel device
124@@ -391,16 +393,6 @@
125 int grail_pull(struct grail *ge, int fd);
126
127 /**
128- * grail_close - close the grail device
129- * @ge: the grail device to close
130- * @fd: file descriptor of the kernel device
131- *
132- * Deallocates all memory associated with grail, and clears the grail
133- * structure.
134- */
135-void grail_close(struct grail *ge, int fd);
136-
137-/**
138 * grail_set_bbox - set the grail unit bounding box
139 * @ge: the grail device in use
140 * @min: the minimum (lower-left) corner of the bounding box
141@@ -443,6 +435,22 @@
142 */
143 const struct utouch_frame *grail_get_contact_frame(const struct grail *ge);
144
145+/**
146+ * grail_get_gesture_frame - get current gesture frame
147+ * @ge: the grail device in use
148+ *
149+ * Return the gesture frame currently being processed. If called from
150+ * within a gesture callback, it is guaranteed to return the frame
151+ * corresponding to the gesture.
152+ *
153+ * The returned pointer can be NULL if no input has yet been extracted
154+ * through the grail instance.
155+ *
156+ * The frame pointer is ABI agnostic, owned by the grail instance, and
157+ * has grail scope.
158+ */
159+const struct grail_frame *grail_get_gesture_frame(const struct grail *ge);
160+
161 #ifndef GRAIL_NO_LEGACY_API
162
163 struct grail_contact {
164@@ -457,6 +465,8 @@
165 float pressure;
166 };
167
168+int grail_open(struct grail *ge, int fd);
169+void grail_close(struct grail *ge, int fd);
170 void grail_filter_abs_events(struct grail *ge, int usage);
171
172 int grail_get_contacts(const struct grail *ge,
173
174=== modified file 'src/Makefile.am'
175--- src/Makefile.am 2011-04-12 16:35:23 +0000
176+++ src/Makefile.am 2011-04-27 19:43:23 +0000
177@@ -15,13 +15,6 @@
178 grail-bits.c \
179 grail-inserter.c \
180 grail-inserter.h \
181- grail-gestures.c \
182- grail-gestures.h \
183- gestures-touch.c \
184- gestures-drag.c \
185- gestures-pinch.c \
186- gestures-rotate.c \
187- gestures-tapping.c \
188 grail-recognizer.c \
189 grail-recognizer.h \
190 grail-event.c \
191
192=== removed file 'src/gestures-drag.c'
193--- src/gestures-drag.c 2011-04-12 16:35:37 +0000
194+++ src/gestures-drag.c 1970-01-01 00:00:00 +0000
195@@ -1,135 +0,0 @@
196-/*****************************************************************************
197- *
198- * grail - Gesture Recognition And Instantiation Library
199- *
200- * Copyright (C) 2010-2011 Canonical Ltd.
201- *
202- * This program is free software: you can redistribute it and/or modify it
203- * under the terms of the GNU General Public License as published by the
204- * Free Software Foundation, either version 3 of the License, or (at your
205- * option) any later version.
206- *
207- * This program is distributed in the hope that it will be useful, but
208- * WITHOUT ANY WARRANTY; without even the implied warranty of
209- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
210- * General Public License for more details.
211- *
212- * You should have received a copy of the GNU General Public License along
213- * with this program. If not, see <http://www.gnu.org/licenses/>.
214- *
215- ****************************************************************************/
216-
217-#include "grail-recognizer.h"
218-#include <math.h>
219-#include <stdio.h>
220-
221-static const int getype[DIM_TOUCH + 1] = {
222- -1,
223- GRAIL_TYPE_DRAG1,
224- GRAIL_TYPE_DRAG2,
225- GRAIL_TYPE_DRAG3,
226- GRAIL_TYPE_DRAG4,
227- GRAIL_TYPE_DRAG5,
228-};
229-
230-static void set_props(const struct gesture_inserter *gin,
231- struct combo_model *s, const struct move_model *m,
232- const struct utouch_frame *frame)
233-{
234- if (m->single) {
235- s->prop[GRAIL_PROP_DRAG_DX] = m->fm[FM_X].raw_delta;
236- s->prop[GRAIL_PROP_DRAG_DY] = m->fm[FM_Y].raw_delta;
237- } else {
238- s->prop[GRAIL_PROP_DRAG_DX] = m->fm[FM_X].action_delta;
239- s->prop[GRAIL_PROP_DRAG_DY] = m->fm[FM_Y].action_delta;
240- }
241- s->prop[GRAIL_PROP_DRAG_VX] = m->fm[FM_X].velocity;
242- s->prop[GRAIL_PROP_DRAG_VY] = m->fm[FM_Y].velocity;
243- s->prop[GRAIL_PROP_DRAG_X] = m->fm[FM_X].value;
244- s->prop[GRAIL_PROP_DRAG_Y] = m->fm[FM_Y].value;
245- s->nprop = 6;
246- s->nprop += gin_add_contact_props(gin, s->prop + s->nprop, frame);
247-}
248-
249-static const int fm_mask = 0x03;
250-
251-int gru_drag(struct grail *ge,
252- const struct utouch_frame *frame)
253-{
254- struct gesture_recognizer *gru = ge->gru;
255- struct combo_model *state = &gru->drag;
256- struct move_model *move = &gru->move;
257- int mask = state->active ? (move->active & fm_mask) : fm_mask;
258- if (!move->multi && !move->single) {
259- if (state->active) {
260- gru_end(ge, state->gid, move,
261- state->prop, state->nprop);
262- state->active = 0;
263- }
264- }
265- if ((move->timeout & fm_mask) == fm_mask) {
266- if (state->active) {
267- gin_gid_timeout(ge, state->gid);
268- }
269- }
270- if (!state->active) {
271- int type = getype[move->ntouch];
272- if (type < 0)
273- return 0;
274- state->gid = gin_gid_begin(ge, type, PRIO_GESTURE, frame);
275- state->active = 1;
276- }
277- if (!(move->tickle & mask))
278- return 0;
279- if (!(move->active & fm_mask))
280- return 0;
281- set_props(ge->gin, state, move, frame);
282- gru_event(ge, state->gid, move, state->prop, state->nprop);
283- return 1;
284-}
285-
286-int gru_windrag(struct grail *ge,
287- const struct utouch_frame *frame)
288-{
289- struct gesture_recognizer *gru = ge->gru;
290- struct combo_model *state = &gru->windrag;
291- struct move_model *move = &gru->move;
292- int mask = state->active ? (move->active & fm_mask) : fm_mask;
293- if (!move->multi && !move->single) {
294- if (state->active && out_of_bounds(state, move)) {
295- gru_end(ge, state->gid, move,
296- state->prop, state->nprop);
297- state->active = 0;
298- }
299- }
300- if ((move->timeout & fm_mask) == fm_mask) {
301- if (state->active) {
302- gin_gid_timeout(ge, state->gid);
303- }
304- }
305- if (!state->active) {
306- if (move->ntouch == 4) {
307- state->gid = gin_gid_begin(ge, GRAIL_TYPE_MDRAG,
308- PRIO_META, frame);
309- state->mintouch = 1;
310- state->maxtouch = 4;
311- state->active = 1;
312- } else if (move->ntouch == 3) {
313- state->gid = gin_gid_begin(ge, GRAIL_TYPE_EDRAG,
314- PRIO_ENV, frame);
315- state->mintouch = 1;
316- state->maxtouch = 3;
317- state->active = 1;
318- } else {
319- return 0;
320- }
321- }
322- if (!(move->tickle & mask))
323- return 0;
324- if (!(move->active & fm_mask))
325- return 0;
326- set_props(ge->gin, state, move, frame);
327- gru_event(ge, state->gid, move, state->prop, state->nprop);
328- return 1;
329-}
330-
331
332=== removed file 'src/gestures-pinch.c'
333--- src/gestures-pinch.c 2011-04-12 16:35:37 +0000
334+++ src/gestures-pinch.c 1970-01-01 00:00:00 +0000
335@@ -1,129 +0,0 @@
336-/*****************************************************************************
337- *
338- * grail - Gesture Recognition And Instantiation Library
339- *
340- * Copyright (C) 2010-2011 Canonical Ltd.
341- *
342- * This program is free software: you can redistribute it and/or modify it
343- * under the terms of the GNU General Public License as published by the
344- * Free Software Foundation, either version 3 of the License, or (at your
345- * option) any later version.
346- *
347- * This program is distributed in the hope that it will be useful, but
348- * WITHOUT ANY WARRANTY; without even the implied warranty of
349- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
350- * General Public License for more details.
351- *
352- * You should have received a copy of the GNU General Public License along
353- * with this program. If not, see <http://www.gnu.org/licenses/>.
354- *
355- ****************************************************************************/
356-
357-#include "grail-recognizer.h"
358-#include <math.h>
359-#include <stdio.h>
360-
361-static const int getype[DIM_TOUCH + 1] = {
362- 0,
363- 0,
364- GRAIL_TYPE_PINCH2,
365- GRAIL_TYPE_PINCH3,
366- GRAIL_TYPE_PINCH4,
367- GRAIL_TYPE_PINCH5,
368-};
369-
370-static const int fm_mask = 0x04;
371-
372-static void set_props(const struct gesture_inserter *gin,
373- struct combo_model *s,
374- const struct move_model *m,
375- const struct utouch_frame *frame)
376-{
377- s->prop[GRAIL_PROP_PINCH_DR] = m->fm[FM_R].action_delta;
378- s->prop[GRAIL_PROP_PINCH_VR] = m->fm[FM_R].velocity;
379- s->prop[GRAIL_PROP_PINCH_R] = m->fm[FM_R].value;
380- s->nprop = 3;
381- s->nprop += gin_add_contact_props(gin, s->prop + s->nprop, frame);
382-}
383-
384-int gru_pinch(struct grail *ge,
385- const struct utouch_frame *frame)
386-{
387- struct gesture_recognizer *gru = ge->gru;
388- struct combo_model *state = &gru->pinch;
389- struct move_model *move = &gru->move;
390- int mask = state->active ? (move->active & fm_mask) : fm_mask;
391- if (!move->multi && !move->single) {
392- if (state->active) {
393- gru_end(ge, state->gid, move,
394- state->prop, state->nprop);
395- state->active = 0;
396- }
397- return 0;
398- }
399- if ((move->timeout & fm_mask) == fm_mask) {
400- if (state->active) {
401- gin_gid_timeout(ge, state->gid);
402- }
403- }
404- if (!(move->tickle & mask))
405- return 0;
406- if (!state->active) {
407- int type = getype[move->ntouch];
408- if (!type)
409- return 0;
410- state->gid = gin_gid_begin(ge, type, PRIO_GESTURE, frame);
411- state->active = 1;
412- }
413- if (!(move->active & fm_mask))
414- return 0;
415- set_props(ge->gin, state, move, frame);
416- gru_event(ge, state->gid, move, state->prop, state->nprop);
417- return 1;
418-}
419-
420-int gru_winpinch(struct grail *ge,
421- const struct utouch_frame *frame)
422-{
423- struct gesture_recognizer *gru = ge->gru;
424- struct combo_model *state = &gru->winpinch;
425- struct move_model *move = &gru->move;
426- int mask = state->active ? (move->active & fm_mask) : fm_mask;
427- if (!move->multi) {
428- if (state->active && out_of_bounds(state, move)) {
429- gru_end(ge, state->gid, move,
430- state->prop, state->nprop);
431- state->active = 0;
432- }
433- return 0;
434- }
435- if ((move->timeout & fm_mask) == fm_mask) {
436- if (state->active) {
437- gin_gid_timeout(ge, state->gid);
438- }
439- }
440- if (!(move->tickle & mask))
441- return 0;
442- if (!state->active) {
443- if (move->ntouch == 4) {
444- state->gid = gin_gid_begin(ge, GRAIL_TYPE_MPINCH,
445- PRIO_META, frame);
446- state->mintouch = 2;
447- state->maxtouch = 4;
448- state->active = 1;
449- } else if (move->ntouch == 3) {
450- state->gid = gin_gid_begin(ge, GRAIL_TYPE_EPINCH,
451- PRIO_ENV, frame);
452- state->mintouch = 2;
453- state->maxtouch = 3;
454- state->active = 1;
455- } else {
456- return 0;
457- }
458- }
459- if (!(move->active & fm_mask))
460- return 0;
461- set_props(ge->gin, state, move, frame);
462- gru_event(ge, state->gid, move, state->prop, state->nprop);
463- return 1;
464-}
465
466=== removed file 'src/gestures-rotate.c'
467--- src/gestures-rotate.c 2011-04-12 16:35:37 +0000
468+++ src/gestures-rotate.c 1970-01-01 00:00:00 +0000
469@@ -1,128 +0,0 @@
470-/*****************************************************************************
471- *
472- * grail - Gesture Recognition And Instantiation Library
473- *
474- * Copyright (C) 2010-2011 Canonical Ltd.
475- *
476- * This program is free software: you can redistribute it and/or modify it
477- * under the terms of the GNU General Public License as published by the
478- * Free Software Foundation, either version 3 of the License, or (at your
479- * option) any later version.
480- *
481- * This program is distributed in the hope that it will be useful, but
482- * WITHOUT ANY WARRANTY; without even the implied warranty of
483- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
484- * General Public License for more details.
485- *
486- * You should have received a copy of the GNU General Public License along
487- * with this program. If not, see <http://www.gnu.org/licenses/>.
488- *
489- ****************************************************************************/
490-
491-#include "grail-recognizer.h"
492-#include <math.h>
493-#include <stdio.h>
494-
495-static const int getype[DIM_TOUCH + 1] = {
496- 0,
497- 0,
498- GRAIL_TYPE_ROTATE2,
499- GRAIL_TYPE_ROTATE3,
500- GRAIL_TYPE_ROTATE4,
501- GRAIL_TYPE_ROTATE5,
502-};
503-
504-static const int fm_mask = 0x08;
505-
506-static void set_props(const struct gesture_inserter *gin,
507- struct combo_model *s, const struct move_model *m,
508- const struct utouch_frame *frame)
509-{
510- s->prop[GRAIL_PROP_ROTATE_DA] = m->fm[FM_A].action_delta;
511- s->prop[GRAIL_PROP_ROTATE_VA] = m->fm[FM_A].velocity;
512- s->prop[GRAIL_PROP_ROTATE_A] = m->fm[FM_A].value;
513- s->nprop = 3;
514- s->nprop += gin_add_contact_props(gin, s->prop + s->nprop, frame);
515-}
516-
517-int gru_rotate(struct grail *ge,
518- const struct utouch_frame *frame)
519-{
520- struct gesture_recognizer *gru = ge->gru;
521- struct combo_model *state = &gru->rotate;
522- struct move_model *move = &gru->move;
523- int mask = state->active ? (move->active & fm_mask) : fm_mask;
524- if (!move->multi && !move->single) {
525- if (state->active) {
526- gru_end(ge, state->gid, move,
527- state->prop, state->nprop);
528- state->active = 0;
529- }
530- return 0;
531- }
532- if ((move->timeout & fm_mask) == fm_mask) {
533- if (state->active) {
534- gin_gid_timeout(ge, state->gid);
535- }
536- }
537- if (!(move->tickle & mask))
538- return 0;
539- if (!state->active) {
540- int type = getype[move->ntouch];
541- if (!type)
542- return 0;
543- state->gid = gin_gid_begin(ge, type, PRIO_GESTURE, frame);
544- state->active = 1;
545- }
546- if (!(move->active & fm_mask))
547- return 0;
548- set_props(ge->gin, state, move, frame);
549- gru_event(ge, state->gid, move, state->prop, state->nprop);
550- return 1;
551-}
552-
553-int gru_winrotate(struct grail *ge,
554- const struct utouch_frame *frame)
555-{
556- struct gesture_recognizer *gru = ge->gru;
557- struct combo_model *state = &gru->winrotate;
558- struct move_model *move = &gru->move;
559- int mask = state->active ? (move->active & fm_mask) : fm_mask;
560- if (!move->multi) {
561- if (state->active && out_of_bounds(state, move)) {
562- gru_end(ge, state->gid, move,
563- state->prop, state->nprop);
564- state->active = 0;
565- }
566- return 0;
567- }
568- if ((move->timeout & fm_mask) == fm_mask) {
569- if (state->active) {
570- gin_gid_timeout(ge, state->gid);
571- }
572- }
573- if (!(move->tickle & mask))
574- return 0;
575- if (!state->active) {
576- if (move->ntouch == 4) {
577- state->gid = gin_gid_begin(ge, GRAIL_TYPE_MROTATE,
578- PRIO_META, frame);
579- state->mintouch = 2;
580- state->maxtouch = 4;
581- state->active = 1;
582- } else if (move->ntouch == 3) {
583- state->gid = gin_gid_begin(ge, GRAIL_TYPE_EROTATE,
584- PRIO_ENV, frame);
585- state->mintouch = 2;
586- state->maxtouch = 3;
587- state->active = 1;
588- } else {
589- return 0;
590- }
591- }
592- if (!(move->active & fm_mask))
593- return 0;
594- set_props(ge->gin, state, move, frame);
595- gru_event(ge, state->gid, move, state->prop, state->nprop);
596- return 1;
597-}
598
599=== removed file 'src/gestures-tapping.c'
600--- src/gestures-tapping.c 2011-04-12 16:35:37 +0000
601+++ src/gestures-tapping.c 1970-01-01 00:00:00 +0000
602@@ -1,100 +0,0 @@
603-/*****************************************************************************
604- *
605- * grail - Gesture Recognition And Instantiation Library
606- *
607- * Copyright (C) 2010-2011 Canonical Ltd.
608- *
609- * This program is free software: you can redistribute it and/or modify it
610- * under the terms of the GNU General Public License as published by the
611- * Free Software Foundation, either version 3 of the License, or (at your
612- * option) any later version.
613- *
614- * This program is distributed in the hope that it will be useful, but
615- * WITHOUT ANY WARRANTY; without even the implied warranty of
616- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
617- * General Public License for more details.
618- *
619- * You should have received a copy of the GNU General Public License along
620- * with this program. If not, see <http://www.gnu.org/licenses/>.
621- *
622- ****************************************************************************/
623-
624-#include "grail-recognizer.h"
625-#include <math.h>
626-
627-static const int fm_mask = 0x07;
628-
629-static void set_props(const struct gesture_inserter *gin,
630- struct tapping_model *s, const struct move_model *m,
631- const struct utouch_frame *frame)
632-{
633- s->prop[GRAIL_PROP_TAP_DT] = m->time - s->start;
634- s->prop[GRAIL_PROP_TAP_X] = m->fm[FM_X].value;
635- s->prop[GRAIL_PROP_TAP_Y] = m->fm[FM_Y].value;
636- s->nprop = 3;
637- s->nprop += gin_add_contact_props(gin, s->prop + s->nprop, frame);
638-}
639-
640-int gru_tapping(struct grail *ge,
641- const struct utouch_frame *frame)
642-{
643- struct gesture_recognizer *gru = ge->gru;
644- struct tapping_model *state = &gru->tapping;
645- struct move_model *move = &gru->move;
646- state->tap = 0;
647- if (frame->num_active && !frame->prev->num_active) {
648- state->mintouch = 0;
649- state->maxtouch = 0;
650- }
651- if (move->ntouch > state->maxtouch) {
652- if (state->active) {
653- gin_gid_discard(ge, state->gid);
654- state->active = 0;
655- }
656- state->start = move->time;
657- state->maxtouch = move->ntouch;
658- set_props(ge->gin, state, move, frame);
659- if (state->maxtouch <= 5) {
660- int type = GRAIL_TYPE_TAP1 + state->maxtouch - 1;
661- state->gid = gin_gid_begin(ge, type, PRIO_TAP, frame);
662- state->active = 1;
663- }
664- return 0;
665- }
666- if (!state->active) {
667- state->mintouch = move->ntouch;
668- state->maxtouch = move->ntouch;
669- return 0;
670- }
671- if (move->ntouch <= state->mintouch) {
672- int x = state->prop[GRAIL_PROP_TAP_X];
673- int y = state->prop[GRAIL_PROP_TAP_Y];
674- int t = move->time - state->start;
675- if (t > move->fm[FM_X].bar_ms) {
676- gin_gid_discard(ge, state->gid);
677- state->mintouch = move->ntouch;
678- state->maxtouch = move->ntouch;
679- state->active = 0;
680- return 0;
681- }
682- state->tap = state->maxtouch;
683- state->prop[GRAIL_PROP_TAP_DT] = t;
684- gin_gid_event(ge, state->gid, x, y, state->maxtouch,
685- state->prop, state->nprop, 1);
686- state->mintouch = move->ntouch;
687- state->maxtouch = move->ntouch;
688- state->active = 0;
689- return 1;
690- }
691- if (!move->ntouch)
692- return 0;
693- state->prop[GRAIL_PROP_TAP_DT] = move->time - state->start;
694- if ((move->active & fm_mask) ||
695- move->time - state->start > move->fm[FM_X].bar_ms) {
696- gin_gid_discard(ge, state->gid);
697- state->mintouch = move->ntouch;
698- state->maxtouch = move->ntouch;
699- state->active = 0;
700- }
701- return 0;
702-}
703
704=== removed file 'src/gestures-touch.c'
705--- src/gestures-touch.c 2011-04-04 17:27:38 +0000
706+++ src/gestures-touch.c 1970-01-01 00:00:00 +0000
707@@ -1,98 +0,0 @@
708-/*****************************************************************************
709- *
710- * grail - Gesture Recognition And Instantiation Library
711- *
712- * Copyright (C) 2010 Canonical Ltd.
713- * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
714- *
715- * This program is free software: you can redistribute it and/or modify it
716- * under the terms of the GNU General Public License as published by the
717- * Free Software Foundation, either version 3 of the License, or (at your
718- * option) any later version.
719- *
720- * This program is distributed in the hope that it will be useful, but
721- * WITHOUT ANY WARRANTY; without even the implied warranty of
722- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
723- * General Public License for more details.
724- *
725- * You should have received a copy of the GNU General Public License along
726- * with this program. If not, see <http://www.gnu.org/licenses/>.
727- *
728- ****************************************************************************/
729-
730-#include "grail-recognizer.h"
731-#include <math.h>
732-#include <stdio.h>
733-
734-static const int getype[DIM_TOUCH + 1] = {
735- -1,
736- GRAIL_TYPE_TOUCH1,
737- GRAIL_TYPE_TOUCH2,
738- GRAIL_TYPE_TOUCH3,
739- GRAIL_TYPE_TOUCH4,
740- GRAIL_TYPE_TOUCH5,
741-};
742-
743-int gru_touch(struct grail *ge,
744- const struct utouch_frame *frame)
745-{
746- struct gesture_recognizer *gru = ge->gru;
747- struct combo_model *state = &gru->touch;
748- struct move_model *move = &gru->move;
749- if (frame->slot_revision != frame->prev->slot_revision) {
750- if (state->active) {
751- gru_end(ge, state->gid, move,
752- state->prop, state->nprop);
753- state->active = 0;
754- }
755- }
756- if (!state->active) {
757- int type = getype[move->ntouch];
758- if (type <= 0)
759- return 0;
760- state->gid = gin_gid_begin(ge, type, -PRIO_GESTURE, frame);
761- state->active = 1;
762- }
763- if (move->time - move->fm[FM_X].original_ms <= move->fm[FM_X].hold_ms)
764- return 0;
765- state->nprop = gin_add_contact_props(ge->gin, state->prop, frame);
766- gru_event(ge, state->gid, move, state->prop, state->nprop);
767- return 1;
768-}
769-
770-int gru_wintouch(struct grail *ge,
771- const struct utouch_frame *frame)
772-{
773- struct gesture_recognizer *gru = ge->gru;
774- struct combo_model *state = &gru->wintouch;
775- struct move_model *move = &gru->move;
776- if (frame->slot_revision != frame->prev->slot_revision) {
777- if (state->active && out_of_bounds(state, move)) {
778- gru_end(ge, state->gid, move,
779- state->prop, state->nprop);
780- state->active = 0;
781- }
782- }
783- if (!state->active) {
784- if (move->ntouch == 4) {
785- state->gid = gin_gid_begin(ge, GRAIL_TYPE_MTOUCH,
786- -PRIO_META, frame);
787- state->mintouch = 1;
788- state->maxtouch = 4;
789- state->active = 1;
790- } else if (move->ntouch == 3) {
791- state->gid = gin_gid_begin(ge, GRAIL_TYPE_ETOUCH,
792- -PRIO_ENV, frame);
793- state->mintouch = 1;
794- state->maxtouch = 3;
795- state->active = 1;
796- } else {
797- return 0;
798- }
799- }
800- if (move->time - move->fm[FM_X].original_ms <= move->fm[FM_X].hold_ms)
801- return 0;
802- state->nprop = gin_add_contact_props(ge->gin, state->prop, frame);
803- gru_event(ge, state->gid, move, state->prop, state->nprop);
804- return 1;
805-}
806
807=== modified file 'src/grail-api.c'
808--- src/grail-api.c 2011-04-12 16:35:37 +0000
809+++ src/grail-api.c 2011-04-27 19:43:23 +0000
810@@ -30,104 +30,11 @@
811 #include <errno.h>
812 #include <stdlib.h>
813
814-#define DIM_FRAMES 100
815-#define FRAME_RATE 100
816-
817 unsigned int grail_get_version(void)
818 {
819 return GRAIL_VERSION;
820 }
821-
822-int grail_open(struct grail *ge, int fd)
823-{
824- struct grail_impl *x;
825- struct stat fs;
826- int ret;
827-
828- ret = fstat(fd, &fs);
829- if (ret)
830- return ret;
831-
832- x = calloc(1, sizeof(*x));
833- if (!x)
834- return -ENOMEM;
835-
836- if (!fs.st_rdev)
837- x->fptest = fdopen(fd, "r");
838-
839- x->evemu = evemu_new(x->fptest ? "fptest" : 0);
840- if (!x->evemu) {
841- ret = -ENOMEM;
842- goto freemem;
843- }
844- if (x->fptest)
845- ret = evemu_read(x->evemu, x->fptest) <= 0;
846- else
847- ret = evemu_extract(x->evemu, fd);
848- if (ret)
849- goto freemem;
850- if (!utouch_frame_is_supported_mtdev(x->evemu)) {
851- ret = -ENODEV;
852- goto freemem;
853- }
854-
855- if (!x->fptest) {
856- x->mtdev = mtdev_new_open(fd);
857- if (!x->mtdev) {
858- ret = -ENOMEM;
859- goto freemem;
860- }
861- }
862- x->fh = utouch_frame_new_engine(DIM_FRAMES, DIM_TOUCH, FRAME_RATE);
863- if (!x->fh) {
864- ret = -ENOMEM;
865- goto freedev;
866- }
867- ret = utouch_frame_init_mtdev(x->fh, x->evemu);
868- if (ret)
869- goto freeframe;
870-
871- ge->impl = x;
872-
873- ret = gin_init(ge);
874- if (ret)
875- goto freeframe;
876-
877- ret = gru_init(ge);
878- if (ret)
879- goto freegin;
880-
881- return 0;
882- freegin:
883- gin_destroy(ge);
884- freeframe:
885- utouch_frame_delete_engine(x->fh);
886- freedev:
887- if (x->mtdev)
888- mtdev_close_delete(x->mtdev);
889- freemem:
890- evemu_delete(x->evemu);
891- if (x->fptest)
892- fclose(x->fptest);
893- free(x);
894- ge->impl = 0;
895- return ret;
896-}
897-
898-void grail_close(struct grail *ge, int fd)
899-{
900- struct grail_impl *x = ge->impl;
901- gru_destroy(ge);
902- gin_destroy(ge);
903- utouch_frame_delete_engine(x->fh);
904- if (x->mtdev)
905- mtdev_close_delete(x->mtdev);
906- evemu_delete(x->evemu);
907- if (x->fptest)
908- fclose(x->fptest);
909- free(x);
910- ge->impl = 0;
911-}
912+static const float TIMEOUT_MS = 300;
913
914 int grail_idle(struct grail *ge, int fd, int ms)
915 {
916@@ -154,6 +61,11 @@
917 return ge->impl->touch;
918 }
919
920+const struct grail_frame *grail_get_gesture_frame(const struct grail *ge)
921+{
922+ return ge->impl->frame;
923+}
924+
925 static void flush_events(struct grail *ge)
926 {
927 struct grail_impl *impl = ge->impl;
928@@ -219,7 +131,7 @@
929 struct gesture_inserter *gin = ge->gin;
930
931 return grail_mask_count(gin->used, sizeof(gin->used)) == 0 &&
932- frame->time - frame->mod_time > gru->move.fm[FM_X].hold_ms;
933+ frame->time - frame->mod_time > TIMEOUT_MS;
934 }
935
936 static void report_frame(struct grail *ge,
937@@ -227,9 +139,13 @@
938 const struct input_event *syn)
939 {
940 struct grail_impl *impl = ge->impl;
941+ const struct grail_frame *frame;
942 struct grail_event gev;
943
944+ frame = grail_pump_frame(ge, touch);
945+
946 impl->touch = touch;
947+ impl->frame = frame;
948
949 if (touch->num_active && !touch->prev->num_active) {
950 impl->ongoing = 1;
951@@ -240,7 +156,7 @@
952 return;
953
954 gin_frame_begin(ge, touch);
955- gru_recognize(ge, touch);
956+ gru_recognize(ge, frame, touch);
957 gin_frame_end(ge, touch);
958
959 if (!grailbuf_empty(&impl->gbuf))
960
961=== modified file 'src/grail-bits.c'
962--- src/grail-bits.c 2011-04-12 16:35:37 +0000
963+++ src/grail-bits.c 2011-04-27 19:43:23 +0000
964@@ -57,6 +57,15 @@
965 *a++ &= ~*b++;
966 }
967
968+int grail_mask_inner(const grail_mask_t *a, const grail_mask_t *b, int bytes)
969+{
970+ int k;
971+ for (k = 0; k < bytes; k++)
972+ if (a[k] & b[k])
973+ return 1;
974+ return 0;
975+}
976+
977 int grail_mask_count(const grail_mask_t *mask, int bytes)
978 {
979 int count = 0;
980
981=== modified file 'src/grail-frame.c'
982--- src/grail-frame.c 2011-04-12 16:35:37 +0000
983+++ src/grail-frame.c 2011-04-27 19:43:23 +0000
984@@ -71,51 +71,26 @@
985
986 slot->center.x = x;
987 slot->center.y = y;
988+ slot->pivot = slot->center;
989 slot->velocity.x = 1000 * vx;
990 slot->velocity.y = 1000 * vy;
991 slot->radius2 = r2;
992 }
993
994-static void set_moveness_pivot_and_drag(struct grail_impl *impl,
995- struct grail_element *slot,
996- double ds, double dc)
997+static void set_transform(struct grail_impl *impl, struct grail_element *slot,
998+ double ds, double dc)
999 {
1000 const struct grail_element *pslot = slot->prev;
1001 double mx = slot->center.x - pslot->center.x;
1002 double my = slot->center.y - pslot->center.y;
1003 float *T = slot->transform;
1004
1005- slot->moveness = 1;
1006- slot->pivot = pslot->center;
1007-
1008- if (slot->num_touches > 1) {
1009- double wx = (1 - dc) * mx + ds * my;
1010- double wy = (1 - dc) * my - ds * mx;
1011- double w2 = wx * wx + wy * wy;
1012- if (w2 > 0) {
1013- double s = sqrt(pslot->radius2 / w2);
1014- double q = (mx * mx + my * my) / w2;
1015- if (s < q) {
1016- slot->moveness = 1 - s / q;
1017- slot->pivot.x += s * wx;
1018- slot->pivot.y += s * wy;
1019- } else {
1020- slot->moveness = 0;
1021- slot->pivot.x += q * wx;
1022- slot->pivot.y += q * wy;
1023- }
1024- }
1025- }
1026-
1027- mx *= slot->moveness;
1028- my *= slot->moveness;
1029-
1030 T[0] = dc;
1031 T[1] = ds;
1032- T[2] = (1 - dc) * slot->pivot.x - ds * slot->pivot.y + mx;
1033+ T[2] = mx;
1034 T[3] = -ds;
1035 T[4] = dc;
1036- T[5] = (1 - dc) * slot->pivot.y + ds * slot->pivot.x + my;
1037+ T[5] = my;
1038
1039 slot->drag.x = pslot->drag.x + mx;
1040 slot->drag.y = pslot->drag.y + my;
1041@@ -134,7 +109,6 @@
1042 set_center_velocity_and_radius(impl, slot);
1043 T[0] = T[4] = 1;
1044 T[1] = T[2] = T[3] = T[5] = 0;
1045- slot->pivot = slot->center;
1046 slot->drag.x = 0;
1047 slot->drag.y = 0;
1048 slot->scale2 = 1;
1049@@ -153,7 +127,7 @@
1050 slot->active_mask = pslot->active_mask;
1051
1052 set_center_velocity_and_radius(impl, slot);
1053- set_moveness_pivot_and_drag(impl, slot, ds, dc);
1054+ set_transform(impl, slot, ds, dc);
1055
1056 slot->scale2 = pslot->scale2 * (ds * ds + dc * dc);
1057 slot->angle = pslot->angle + ds / dc; /* atan2(ds, dc) */
1058@@ -175,8 +149,6 @@
1059 slot->radius2 = pslot->radius2;
1060 T[0] = T[4] = 1;
1061 T[1] = T[2] = T[3] = T[5] = 0;
1062- slot->moveness = 1;
1063- slot->pivot = pslot->pivot;
1064 slot->drag = pslot->drag;
1065 slot->scale2 = pslot->scale2;
1066 slot->angle = pslot->angle;
1067@@ -308,6 +280,141 @@
1068 set_slot_multi(impl, slots[n++], frame, touch);
1069 }
1070
1071+/**
1072+ * Determine the pivot point where the transformation matrix has zero
1073+ * translation. Thus, T1 is equal to:
1074+ *
1075+ * T1: [ a -b 0 ]
1076+ * [ b a 0 ]
1077+ * [ 0 0 1 ]
1078+ *
1079+ * Using the equation noted in the comment for set_pivot we can solve for P1.
1080+ */
1081+static inline int center_of_rotation(float a, float b, float c, float d,
1082+ float x0, float y0, float *x1, float *y1)
1083+{
1084+ float div = a*a - 2*a + b*b + 1;
1085+
1086+ if (div == 0)
1087+ return 0;
1088+
1089+ *x1 = (a*a*x0 - a*(2*x0+c) + b*b*x0 - b*d + c + x0) / div;
1090+ *y1 = (a*a*y0 - a*(2*y0+d) + b*b*y0 + b*c + d + y0) / div;
1091+
1092+ return 1;
1093+}
1094+
1095+/**
1096+ * Determine a new pivot point and modify the transformation matrix to
1097+ * match.
1098+ *
1099+ * For any given point q that is transformed by a 2D affine transformation
1100+ * matrix T about pivot point P the new point q' may be determined by the
1101+ * following equation:
1102+ *
1103+ * q' = T * (q - P) + P
1104+ *
1105+ * T and P are dependent, so we can modify one and find a new value for the
1106+ * other. We will label the original T and P as T0 and P0, and the new values
1107+ * will be labeled T1 and P1. We can find new values by solving the following
1108+ * equation:
1109+ *
1110+ * q' = T0 * (q - P0) + P0 = T1 * (q - P1) + P1
1111+ *
1112+ * In the calculations below, we use standard variables for the scalar values
1113+ * that make up T0 and P0:
1114+ *
1115+ * T0: [ a -b c0 ] P0: [ x0 ]
1116+ * [ b a d0 ] [ y0 ]
1117+ * [ 0 0 1 ] [ 0 ]
1118+ *
1119+ * Note that rotation and scaling are independent of the pivot point, so
1120+ * a0 == a1 and b0 == b1. Thus, the variable names are left as just a and b.
1121+ */
1122+static void set_pivot(struct grail_element *e, enum grail_pivot_type type)
1123+{
1124+ float *T = e->transform;
1125+ float a = T[0];
1126+ float b = T[3];
1127+ float c0 = T[2];
1128+ float d0 = T[5];
1129+ float x0 = e->pivot.x;
1130+ float y0 = e->pivot.y;
1131+ float x1;
1132+ float y1;
1133+
1134+ switch (type) {
1135+ case GRAIL_CENTROID:
1136+ /* Grail computation is performed on the centroid already. */
1137+ break;
1138+
1139+ case GRAIL_CENTER_OF_ROTATION:
1140+ /* If this fails, transformation is pure translation. We can't
1141+ * do anything in this case. */
1142+ if (center_of_rotation(a, b, c0, d0, x0, y0, &x1, &y1)) {
1143+ T[2] = T[5] = 0;
1144+ e->pivot.x = x1;
1145+ e->pivot.y = y1;
1146+ }
1147+ break;
1148+
1149+ /**
1150+ * We define an approximation of the convex hull of the touches as a
1151+ * circle centered at the centroid of the touch points and with a radius
1152+ * equal to the average distance of each touch point to the centroid. We
1153+ * then determine the pivot point within the circle that minimizes
1154+ * translation. To accomplish this, first determine the center of
1155+ * rotation point as above. Then check if it is within the confining
1156+ * circle. If it is, then stop. Otherwise, determine the intersection of
1157+ * the circle and the line defined by the centroid of the touch points
1158+ * and the center of rotation point. The intersection is the new pivot.
1159+ *
1160+ * Lastly, determine the new translation values c1 and d1 in the T1
1161+ * transformation matrix. To do this, we set P1 as:
1162+ *
1163+ * P1: [ x1 ]
1164+ * [ y1 ]
1165+ * [ 0 ]
1166+ *
1167+ * and then we solve the equation noted above for T1.
1168+ */
1169+ case GRAIL_CONVEX_HULL_RADIUS: {
1170+ float d2;
1171+ float scale;
1172+
1173+ /* If this fails, transformation is pure translation. We can't
1174+ * do anything in this case, and the pivot point will remain at
1175+ * the centroid which matches the criteria. */
1176+ if (!center_of_rotation(a, b, c0, d0, x0, y0, &x1, &y1))
1177+ break;
1178+
1179+ /* If the center of rotation falls within the circle, we've
1180+ * reached an optimal state. */
1181+ d2 = (x1 - x0)*(x1-x0) + (y1 - y0)*(y1-y0);
1182+ if (d2 <= e->radius2) {
1183+ T[2] = T[5] = 0;
1184+ e->pivot.x = x1;
1185+ e->pivot.y = y1;
1186+ break;
1187+ }
1188+
1189+ /* Intersect line from centroid to center of rotation to find
1190+ * the best pivot point. */
1191+ scale = sqrtf(e->radius2 / d2);
1192+ x1 = x0 + (x1 - x0) * scale;
1193+ y1 = y0 + (y1 - y0) * scale;
1194+
1195+ /* Compute the new translation values by solving the equation
1196+ * above. */
1197+ T[2] = a*(x1 - x0) + b*(y0 - y1) + c0 + x0 - x1;
1198+ T[5] = a*(y1 - y0) + b*(y1 - y0) + d0 + y0 - y1;
1199+ e->pivot.x = x1;
1200+ e->pivot.y = y1;
1201+ break;
1202+ }
1203+ }
1204+}
1205+
1206 static void collect_transforms(struct grail_impl *impl,
1207 struct grail_frame *frame,
1208 const struct utouch_frame *touch)
1209@@ -326,22 +433,20 @@
1210 if (!s->num_touches)
1211 continue;
1212
1213+ set_pivot(s, ctl->pivot_type);
1214+
1215 dt = touch->time - s->start_time;
1216 if (dt > ctl->glue_ms) {
1217 unsigned int mask = s->active_mask;
1218
1219- if (s->moveness > ctl->thresh_drag) {
1220- if (fabs(s->drag.x) > dx)
1221- mask |= GRAIL_EXPECT_X;
1222- if (fabs(s->drag.y) > dy)
1223- mask |= GRAIL_EXPECT_Y;
1224- }
1225- if (s->moveness < ctl->thresh_scale) {
1226- if (fabs(s->scale2 - 1) > ds2)
1227- mask |= GRAIL_EXPECT_SCALE;
1228- if (fabs(s->angle) > ctl->bar_angle)
1229- mask |= GRAIL_EXPECT_ANGLE;
1230- }
1231+ if (fabs(s->drag.x) > dx)
1232+ mask |= GRAIL_EXPECT_X;
1233+ if (fabs(s->drag.y) > dy)
1234+ mask |= GRAIL_EXPECT_Y;
1235+ if (fabs(s->scale2 - 1) > ds2)
1236+ mask |= GRAIL_EXPECT_SCALE;
1237+ if (fabs(s->angle) > ctl->bar_angle)
1238+ mask |= GRAIL_EXPECT_ANGLE;
1239
1240 s->active_mask = mask;
1241
1242@@ -365,10 +470,16 @@
1243 const struct utouch_frame *touch)
1244 {
1245 struct grail_impl *impl = ge->impl;
1246- struct grail_frame *frame = impl->frames[impl->nextframe];
1247- const struct grail_frame *prev = frame->prev;
1248+ struct grail_frame *frame;
1249+ const struct grail_frame *prev;
1250 int i;
1251
1252+ if (!impl->frames)
1253+ return 0;
1254+
1255+ frame = impl->frames[impl->nextframe];
1256+ prev = frame->prev;
1257+
1258 if (touch->slot_revision == touch->prev->slot_revision &&
1259 !prev->num_ongoing)
1260 return 0;
1261
1262=== removed file 'src/grail-gestures.c'
1263--- src/grail-gestures.c 2011-04-12 16:35:37 +0000
1264+++ src/grail-gestures.c 1970-01-01 00:00:00 +0000
1265@@ -1,210 +0,0 @@
1266-/*****************************************************************************
1267- *
1268- * grail - Gesture Recognition And Instantiation Library
1269- *
1270- * Copyright (C) 2010-2011 Canonical Ltd.
1271- *
1272- * This program is free software: you can redistribute it and/or modify it
1273- * under the terms of the GNU General Public License as published by the
1274- * Free Software Foundation, either version 3 of the License, or (at your
1275- * option) any later version.
1276- *
1277- * This program is distributed in the hope that it will be useful, but
1278- * WITHOUT ANY WARRANTY; without even the implied warranty of
1279- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1280- * General Public License for more details.
1281- *
1282- * You should have received a copy of the GNU General Public License along
1283- * with this program. If not, see <http://www.gnu.org/licenses/>.
1284- *
1285- ****************************************************************************/
1286-
1287-#include "grail-recognizer.h"
1288-#include "grail-impl.h"
1289-#include <math.h>
1290-
1291-static const float FM_SN[DIM_FM] = { 1000, 1000, 1000, 1000 };
1292-static const float FM_BAR[DIM_FM] = { 50, 50, 50, 50 };
1293-static const grail_time_t FM_HOLD_MS[DIM_FM] = { 60, 60, 60, 60 };
1294-static const grail_time_t FM_BAR_MS[DIM_FM] = { 300, 300, 500, 500 };
1295-static const grail_time_t SAMPLE_MS = 10;
1296-static const float EPS = 1e-3;
1297-
1298-static void compute_position(float *x, float *y,
1299- const struct utouch_frame *frame)
1300-{
1301- int i, n = frame->num_active;
1302- *x = 0;
1303- *y = 0;
1304- if (n < 1)
1305- return;
1306- for (i = 0; i < n; i++) {
1307- const struct utouch_contact *t = frame->active[i];
1308- *x += t->x;
1309- *y += t->y;
1310- }
1311- *x /= n;
1312- *y /= n;
1313-}
1314-
1315-static float compute_radius(float x, float y,
1316- const struct utouch_frame *frame)
1317-{
1318- int i, n = frame->num_active;
1319- float r = 0, r2 = 0;
1320- if (n < 2)
1321- return r;
1322- for (i = 0; i < n; i++) {
1323- const struct utouch_contact *t = frame->active[i];
1324- float dx = t->x - x;
1325- float dy = t->y - y;
1326- r2 += dx * dx + dy * dy;
1327- }
1328- r2 /= n;
1329- r = sqrt(r2);
1330- return r;
1331-}
1332-
1333-static float compute_rotation(float x, float y, float r,
1334- const struct utouch_frame *frame)
1335-{
1336- int i, n = frame->num_active;
1337- float da = 0, darc2 = 0;
1338- if (n < 2)
1339- return da;
1340- for (i = 0; i < n; i++) {
1341- const struct utouch_contact *t = frame->active[i];
1342- const struct utouch_contact *ot = t->prev;
1343- float dx = t->x - x;
1344- float dy = t->y - y;
1345- float mx = t->x - ot->x;
1346- float my = t->y - ot->y;
1347- darc2 += dx * my - dy * mx;
1348- }
1349- darc2 /= n;
1350- da = darc2 / (r * r);
1351- return da;
1352-}
1353-
1354-static void move_reset(struct move_model *m, int i, float x, grail_time_t t)
1355-{
1356- struct filter_model *fm = &m->fm[i];
1357- fm->raw_delta = 0;
1358- fm->action_delta = 0;
1359- fm->velocity = 0;
1360- fm->value = x;
1361- fm->original = x;
1362- fm->original_ms = t;
1363- fm->sample = x;
1364- fm->sample_ms = t;
1365- m->tickle &= ~(1 << i);
1366- m->active &= ~(1 << i);
1367- m->timeout &= ~(1 << i);
1368-}
1369-
1370-static void move_update(struct move_model *m, int i, float x, grail_time_t t)
1371-{
1372- struct filter_model *fm = &m->fm[i];
1373- float dt = t - fm->sample_ms;
1374- fm->raw_delta = x - fm->value;
1375- fm->action_delta = fm->raw_delta;
1376- fm->value = x;
1377- if (dt > SAMPLE_MS) {
1378- fm->velocity = (x - fm->sample) / dt;
1379- fm->sample = x;
1380- fm->sample_ms = t;
1381- }
1382- if (fabs(fm->raw_delta) > EPS)
1383- m->tickle |= (1 << i);
1384- else
1385- m->tickle &= ~(1 << i);
1386- if (m->active & (1 << i))
1387- return;
1388- fm->action_delta = 0;
1389- if (fabs(x - fm->original) > fm->bar) {
1390- if (t - fm->original_ms > fm->hold_ms) {
1391- m->active |= (1 << i);
1392- fm->action_delta = x - fm->original;
1393- }
1394- } else if (t - fm->original_ms > fm->bar_ms) {
1395- m->timeout |= (1 << i);
1396- }
1397-}
1398-
1399-void gru_init_motion(struct grail *ge)
1400-{
1401- struct utouch_surface *s = utouch_frame_get_surface(ge->impl->fh);
1402- struct gesture_recognizer *gru = ge->gru;
1403- struct move_model *m = &gru->move;
1404- float D[DIM_FM];
1405- int i;
1406- D[FM_X] = s->mapped_max_x - s->mapped_min_x;
1407- D[FM_Y] = s->mapped_max_y - s->mapped_min_y;
1408- D[FM_R] = sqrt(D[FM_X] * D[FM_X] + D[FM_Y] * D[FM_Y]);
1409- D[FM_A] = 2 * M_PI;
1410- for (i = 0; i < DIM_FM; i++) {
1411- m->fm[i].fuzz = D[i] / FM_SN[i];
1412- m->fm[i].bar = D[i] / FM_BAR[i];
1413- m->fm[i].hold_ms = FM_HOLD_MS[i];
1414- m->fm[i].bar_ms = FM_BAR_MS[i];
1415- }
1416-}
1417-
1418-void gru_motion(struct grail *ge,
1419- const struct utouch_frame *frame)
1420-{
1421- const struct utouch_surface *s = utouch_frame_get_surface(ge->impl->fh);
1422- struct gesture_recognizer *gru = ge->gru;
1423- struct move_model *m = &gru->move;
1424- grail_time_t t = frame->time;
1425- float x, y, r, a;
1426-
1427- compute_position(&x, &y, frame);
1428- if (frame->prev->revision != frame->revision) {
1429- r = compute_radius(x, y, frame);
1430- a = 0;
1431- move_reset(m, FM_X, x, t);
1432- move_reset(m, FM_Y, y, t);
1433- move_reset(m, FM_R, r, t);
1434- move_reset(m, FM_A, a, t);
1435- m->single = 0;
1436- m->multi = 0;
1437- } else if (frame->num_active < 2) {
1438- r = 0;
1439- a = 0;
1440- move_update(m, FM_X, x, t);
1441- move_update(m, FM_Y, y, t);
1442- move_reset(m, FM_R, r, t);
1443- move_reset(m, FM_A, a, t);
1444- m->single = 1;
1445- m->multi = 0;
1446- } else {
1447- r = compute_radius(x, y, frame);
1448- a = m->fm[FM_A].value;
1449- if (!s->is_semi_mt)
1450- a += compute_rotation(x, y, r, frame);
1451- move_update(m, FM_X, x, t);
1452- move_update(m, FM_Y, y, t);
1453- move_update(m, FM_R, r, t);
1454- move_update(m, FM_A, a, t);
1455- m->single = 0;
1456- m->multi = 1;
1457- }
1458- m->ntouch = frame->num_active;
1459- m->time = t;
1460-}
1461-
1462-void gru_event(struct grail *ge, int gid,
1463- const struct move_model *m,
1464- const grail_prop_t *prop, int nprop)
1465-{
1466- gin_gid_event(ge, gid, m->fm[FM_X].value, m->fm[FM_Y].value, m->ntouch,
1467- prop, nprop, 0);
1468-}
1469-
1470-void gru_end(struct grail *ge, int gid, const struct move_model *m,
1471- const grail_prop_t *prop, int nprop)
1472-{
1473- gin_gid_end(ge, gid, m->fm[FM_X].value, m->fm[FM_Y].value, m->ntouch,
1474- prop, nprop);
1475-}
1476
1477=== removed file 'src/grail-gestures.h'
1478--- src/grail-gestures.h 2011-04-12 16:35:37 +0000
1479+++ src/grail-gestures.h 1970-01-01 00:00:00 +0000
1480@@ -1,115 +0,0 @@
1481-/*****************************************************************************
1482- *
1483- * grail - Gesture Recognition And Instantiation Library
1484- *
1485- * Copyright (C) 2010-2011 Canonical Ltd.
1486- *
1487- * This program is free software: you can redistribute it and/or modify it
1488- * under the terms of the GNU General Public License as published by the
1489- * Free Software Foundation, either version 3 of the License, or (at your
1490- * option) any later version.
1491- *
1492- * This program is distributed in the hope that it will be useful, but
1493- * WITHOUT ANY WARRANTY; without even the implied warranty of
1494- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1495- * General Public License for more details.
1496- *
1497- * You should have received a copy of the GNU General Public License along
1498- * with this program. If not, see <http://www.gnu.org/licenses/>.
1499- *
1500- ****************************************************************************/
1501-
1502-#ifndef _GRAIL_GESTURES_H
1503-#define _GRAIL_GESTURES_H
1504-
1505-#include "grail-inserter.h"
1506-
1507-#define PRIO_POINTER 1
1508-#define PRIO_GESTURE 2
1509-#define PRIO_ENV 3
1510-#define PRIO_META 4
1511-#define PRIO_TAP 5
1512-
1513-#define DIM_FM 4
1514-
1515-#define FM_X 0
1516-#define FM_Y 1
1517-#define FM_R 2
1518-#define FM_A 3
1519-
1520-struct filter_model {
1521- float raw_delta;
1522- float action_delta;
1523- float velocity;
1524- float value;
1525- float original;
1526- float sample;
1527- float fuzz;
1528- float bar;
1529- grail_time_t original_ms;
1530- grail_time_t sample_ms;
1531- grail_time_t hold_ms;
1532- grail_time_t bar_ms;
1533-};
1534-
1535-struct move_model {
1536- struct filter_model fm[DIM_FM];
1537- int tickle, active, timeout;
1538- int single, multi, ntouch;
1539- grail_time_t time;
1540-};
1541-
1542-void gru_init_motion(struct grail *ge);
1543-void gru_motion(struct grail *ge,
1544- const struct utouch_frame *frame);
1545-void gru_event(struct grail *ge, int gid,
1546- const struct move_model *move,
1547- const grail_prop_t *prop, int nprop);
1548-void gru_end(struct grail *ge, int gid,
1549- const struct move_model *move,
1550- const grail_prop_t *prop, int nprop);
1551-
1552-struct combo_model {
1553- int active, gid;
1554- int mintouch, maxtouch;
1555- int nprop;
1556- grail_prop_t prop[DIM_GRAIL_PROP];
1557-};
1558-
1559-int gru_touch(struct grail *ge,
1560- const struct utouch_frame *frame);
1561-int gru_drag(struct grail *ge,
1562- const struct utouch_frame *frame);
1563-int gru_pinch(struct grail *ge,
1564- const struct utouch_frame *frame);
1565-int gru_rotate(struct grail *ge,
1566- const struct utouch_frame *frame);
1567-
1568-static inline int out_of_bounds(const struct combo_model *s,
1569- const struct move_model *m)
1570-{
1571- return m->ntouch < s->mintouch || m->ntouch > s->maxtouch;
1572-}
1573-
1574-int gru_wintouch(struct grail *ge,
1575- const struct utouch_frame *frame);
1576-int gru_windrag(struct grail *ge,
1577- const struct utouch_frame *frame);
1578-int gru_winpinch(struct grail *ge,
1579- const struct utouch_frame *frame);
1580-int gru_winrotate(struct grail *ge,
1581- const struct utouch_frame *frame);
1582-
1583-struct tapping_model {
1584- grail_time_t start;
1585- int mintouch, maxtouch;
1586- int active, gid, tap;
1587- int nprop;
1588- grail_prop_t prop[DIM_GRAIL_PROP];
1589-};
1590-
1591-int gru_tapping(struct grail *ge,
1592- const struct utouch_frame *frame);
1593-
1594-#endif
1595-
1596
1597=== modified file 'src/grail-impl.h'
1598--- src/grail-impl.h 2011-04-12 16:35:37 +0000
1599+++ src/grail-impl.h 2011-04-27 19:43:23 +0000
1600@@ -82,6 +82,7 @@
1601 unsigned int frame_size;
1602 unsigned int slot_size;
1603 struct grail_frame **frames;
1604+ const struct grail_frame *frame;
1605 };
1606
1607 #endif
1608
1609=== modified file 'src/grail-init.c'
1610--- src/grail-init.c 2011-04-12 16:35:37 +0000
1611+++ src/grail-init.c 2011-04-27 19:43:23 +0000
1612@@ -32,8 +32,6 @@
1613 return 0;
1614
1615 c->glue_ms = 60;
1616- c->thresh_drag = 0.8;
1617- c->thresh_scale = 0.2;
1618 c->bar_x = 0.03;
1619 c->bar_y = 0.03;
1620 c->bar_scale = 0.3;
1621
1622=== modified file 'src/grail-inserter.c'
1623--- src/grail-inserter.c 2011-04-12 16:35:37 +0000
1624+++ src/grail-inserter.c 2011-04-27 19:43:23 +0000
1625@@ -37,18 +37,6 @@
1626 return -1;
1627 }
1628
1629-static int mask_overlap(const grail_mask_t *a, const grail_mask_t *b,
1630- int bytes)
1631-{
1632- int i;
1633-
1634- for (i = 0; i < bytes; i++)
1635- if (a[i] & b[i])
1636- return 1;
1637-
1638- return 0;
1639-}
1640-
1641 // todo: spanning tree for multi-user case
1642 static void setup_new_gestures(struct grail *ge,
1643 const struct utouch_frame *frame)
1644@@ -157,15 +145,6 @@
1645
1646 grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
1647 struct slot_state *s = &gin->state[i];
1648- if (!s->timeout)
1649- continue;
1650- if (mask_overlap(keep, s->span, sizeof(keep)))
1651- continue;
1652- gin_gid_discard(ge, s->id);
1653- }
1654-
1655- grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
1656- struct slot_state *s = &gin->state[i];
1657 struct gesture_event ev;
1658 grail_mask_set(gin->types, s->type);
1659 if (s->priority < hold[s->slice] && !s->sent)
1660@@ -202,7 +181,6 @@
1661 s->priority = priority;
1662 s->slice = 0;
1663 }
1664- s->timeout = 0;
1665 s->sent = 0;
1666 s->id = gin->gestureid++ & MAX_GESTURE_ID;
1667 s->status = GRAIL_STATUS_BEGIN;
1668@@ -230,13 +208,6 @@
1669 grail_mask_set(gin->unused, i);
1670 }
1671
1672-void gin_gid_timeout(struct grail *ge, int gid)
1673-{
1674- int i = find_gslot(ge->gin, gid);
1675- if (i >= 0)
1676- ge->gin->state[i].timeout = 1;
1677-}
1678-
1679 void gin_gid_event(struct grail *ge, int gid,
1680 float x, float y, int ntouch,
1681 const grail_prop_t *prop, int nprop,
1682@@ -297,7 +268,4 @@
1683 s->mapped_min_y = tmin->y;
1684 s->mapped_max_x = tmax->x;
1685 s->mapped_max_y = tmax->y;
1686-
1687- if (ge->gru)
1688- gru_init_motion(ge);
1689 }
1690
1691=== modified file 'src/grail-inserter.h'
1692--- src/grail-inserter.h 2011-04-12 16:35:37 +0000
1693+++ src/grail-inserter.h 2011-04-27 19:43:23 +0000
1694@@ -37,7 +37,6 @@
1695 int type;
1696 int priority;
1697 int slice;
1698- int timeout;
1699 int sent;
1700 int id;
1701 int status;
1702@@ -80,7 +79,6 @@
1703 int gin_gid_begin(struct grail *ge, int type, int priority,
1704 const struct utouch_frame *frame);
1705 void gin_gid_discard(struct grail *ge, int gid);
1706-void gin_gid_timeout(struct grail *ge, int gid);
1707
1708 void gin_gid_event(struct grail *ge, int gid,
1709 float x, float y, int ntouch,
1710
1711=== modified file 'src/grail-legacy.c'
1712--- src/grail-legacy.c 2011-04-12 16:35:37 +0000
1713+++ src/grail-legacy.c 2011-04-27 19:43:23 +0000
1714@@ -31,6 +31,110 @@
1715
1716 #ifndef GRAIL_NO_LEGACY_ABI
1717
1718+#define DIM_FRAMES 100
1719+#define FRAME_RATE 100
1720+
1721+int grail_open(struct grail *ge, int fd)
1722+{
1723+ struct grail_impl *x;
1724+ struct stat fs;
1725+ int ret;
1726+
1727+ ret = fstat(fd, &fs);
1728+ if (ret)
1729+ return ret;
1730+
1731+ x = calloc(1, sizeof(*x));
1732+ if (!x)
1733+ return -ENOMEM;
1734+
1735+ if (!fs.st_rdev)
1736+ x->fptest = fdopen(fd, "r");
1737+
1738+ x->evemu = evemu_new(x->fptest ? "fptest" : 0);
1739+ if (!x->evemu) {
1740+ ret = -ENOMEM;
1741+ goto freemem;
1742+ }
1743+ if (x->fptest)
1744+ ret = evemu_read(x->evemu, x->fptest) <= 0;
1745+ else
1746+ ret = evemu_extract(x->evemu, fd);
1747+ if (ret)
1748+ goto freemem;
1749+ if (!utouch_frame_is_supported_mtdev(x->evemu)) {
1750+ ret = -ENODEV;
1751+ goto freemem;
1752+ }
1753+
1754+ if (!x->fptest) {
1755+ x->mtdev = mtdev_new_open(fd);
1756+ if (!x->mtdev) {
1757+ ret = -ENOMEM;
1758+ goto freemem;
1759+ }
1760+ }
1761+ x->fh = utouch_frame_new_engine(DIM_FRAMES, DIM_TOUCH, FRAME_RATE);
1762+ if (!x->fh) {
1763+ ret = -ENOMEM;
1764+ goto freedev;
1765+ }
1766+ ret = utouch_frame_init_mtdev(x->fh, x->evemu);
1767+ if (ret)
1768+ goto freeframe;
1769+
1770+ ret = create_grail2(x, x->fh, DIM_FRAMES, NULL,
1771+ GRAIL_VERSION,
1772+ sizeof(struct grail_control),
1773+ sizeof(struct grail_frame),
1774+ sizeof(struct grail_element));
1775+ if (ret)
1776+ goto freeframe;
1777+
1778+ ge->impl = x;
1779+
1780+ ret = gin_init(ge);
1781+ if (ret)
1782+ goto freegrail2;
1783+
1784+ ret = gru_init(ge);
1785+ if (ret)
1786+ goto freegin;
1787+
1788+ return 0;
1789+ freegin:
1790+ gin_destroy(ge);
1791+ freegrail2:
1792+ destroy_grail2(x);
1793+ freeframe:
1794+ utouch_frame_delete_engine(x->fh);
1795+ freedev:
1796+ if (x->mtdev)
1797+ mtdev_close_delete(x->mtdev);
1798+ freemem:
1799+ evemu_delete(x->evemu);
1800+ if (x->fptest)
1801+ fclose(x->fptest);
1802+ free(x);
1803+ ge->impl = 0;
1804+ return ret;
1805+}
1806+
1807+void grail_close(struct grail *ge, int fd)
1808+{
1809+ struct grail_impl *x = ge->impl;
1810+ gru_destroy(ge);
1811+ gin_destroy(ge);
1812+ destroy_grail2(x);
1813+ utouch_frame_delete_engine(x->fh);
1814+ if (x->mtdev)
1815+ mtdev_close_delete(x->mtdev);
1816+ evemu_delete(x->evemu);
1817+ if (x->fptest)
1818+ fclose(x->fptest);
1819+ free(x);
1820+ ge->impl = 0;
1821+}
1822 void grail_filter_abs_events(struct grail *ge, int usage)
1823 {
1824 struct grail_impl *x = ge->impl;
1825
1826=== modified file 'src/grail-recognizer.c'
1827--- src/grail-recognizer.c 2011-04-12 16:35:37 +0000
1828+++ src/grail-recognizer.c 2011-04-27 19:43:23 +0000
1829@@ -23,6 +23,178 @@
1830 #include <string.h>
1831 #include <malloc.h>
1832 #include <errno.h>
1833+#include <math.h>
1834+
1835+static const float TAP_TIME_MS = 300;
1836+static const int MAX_TOUCH_GESTURE = 5;
1837+
1838+static void touch_props(const struct gesture_inserter *gin,
1839+ struct combo_model *s, const struct grail_element *m,
1840+ const struct utouch_frame *frame)
1841+{
1842+ s->nprop = 0;
1843+}
1844+
1845+static void drag_props(const struct gesture_inserter *gin,
1846+ struct combo_model *s, const struct grail_element *m,
1847+ const struct utouch_frame *frame)
1848+{
1849+ s->prop[GRAIL_PROP_DRAG_DX] = m->drag.x - m->prev->drag.x;
1850+ s->prop[GRAIL_PROP_DRAG_DY] = m->drag.y - m->prev->drag.y;
1851+ s->prop[GRAIL_PROP_DRAG_VX] = m->velocity.x;
1852+ s->prop[GRAIL_PROP_DRAG_VY] = m->velocity.y;
1853+ s->prop[GRAIL_PROP_DRAG_X] = m->drag.x;
1854+ s->prop[GRAIL_PROP_DRAG_Y] = m->drag.y;
1855+ s->nprop = 6;
1856+}
1857+
1858+static void pinch_props(const struct gesture_inserter *gin,
1859+ struct combo_model *s, const struct grail_element *m,
1860+ const struct utouch_frame *frame)
1861+{
1862+ s->prop[GRAIL_PROP_PINCH_DR] =
1863+ sqrt(m->radius2) - sqrt(m->prev->radius2);
1864+ s->prop[GRAIL_PROP_PINCH_VR] = 0;
1865+ s->prop[GRAIL_PROP_PINCH_R] = sqrt(m->radius2);
1866+ s->nprop = 3;
1867+}
1868+
1869+static void rotate_props(const struct gesture_inserter *gin,
1870+ struct combo_model *s, const struct grail_element *m,
1871+ const struct utouch_frame *frame)
1872+{
1873+ s->prop[GRAIL_PROP_ROTATE_DA] = m->angle - m->prev->angle;
1874+ s->prop[GRAIL_PROP_ROTATE_VA] = 0;
1875+ s->prop[GRAIL_PROP_ROTATE_A] = m->angle;
1876+ s->nprop = 3;
1877+}
1878+
1879+static void tap_props(const struct gesture_inserter *gin,
1880+ struct combo_model *s, const struct grail_element *m,
1881+ const struct utouch_frame *frame)
1882+{
1883+ s->prop[GRAIL_PROP_TAP_DT] = frame->time - s->start;
1884+ s->prop[GRAIL_PROP_TAP_X] = m->center.x;
1885+ s->prop[GRAIL_PROP_TAP_Y] = m->center.y;
1886+ s->nprop = 3;
1887+}
1888+
1889+static const struct gesture_handler touch_handler = {
1890+ GRAIL_EXPECT_X | GRAIL_EXPECT_Y,
1891+ {
1892+ { -1, 0, 0, 0 },
1893+ { GRAIL_TYPE_TOUCH1, 1, 1, PRIO_GESTURE },
1894+ { GRAIL_TYPE_TOUCH2, 2, 2, PRIO_GESTURE },
1895+ { GRAIL_TYPE_TOUCH3, 3, 3, PRIO_GESTURE },
1896+ { GRAIL_TYPE_TOUCH4, 4, 4, PRIO_GESTURE },
1897+ { GRAIL_TYPE_TOUCH5, 5, 5, PRIO_GESTURE }
1898+ },
1899+ touch_props
1900+};
1901+
1902+static const struct gesture_handler drag_handler = {
1903+ GRAIL_EXPECT_X | GRAIL_EXPECT_Y,
1904+ {
1905+ { -1, 0, 0, 0 },
1906+ { GRAIL_TYPE_DRAG1, 1, 1, PRIO_GESTURE },
1907+ { GRAIL_TYPE_DRAG2, 2, 2, PRIO_GESTURE },
1908+ { GRAIL_TYPE_DRAG3, 3, 3, PRIO_GESTURE },
1909+ { GRAIL_TYPE_DRAG4, 4, 4, PRIO_GESTURE },
1910+ { GRAIL_TYPE_DRAG5, 5, 5, PRIO_GESTURE }
1911+ },
1912+ drag_props
1913+};
1914+
1915+static const struct gesture_handler pinch_handler = {
1916+ GRAIL_EXPECT_SCALE,
1917+ {
1918+ { -1, 0, 0, 0 },
1919+ { -1, 0, 0, 0 },
1920+ { GRAIL_TYPE_PINCH2, 2, 2, PRIO_GESTURE },
1921+ { GRAIL_TYPE_PINCH3, 3, 3, PRIO_GESTURE },
1922+ { GRAIL_TYPE_PINCH4, 4, 4, PRIO_GESTURE },
1923+ { GRAIL_TYPE_PINCH5, 5, 5, PRIO_GESTURE }
1924+ },
1925+ pinch_props
1926+};
1927+
1928+static const struct gesture_handler rotate_handler = {
1929+ GRAIL_EXPECT_ANGLE,
1930+ {
1931+ { -1, 0, 0, 0 },
1932+ { -1, 0, 0, 0 },
1933+ { GRAIL_TYPE_ROTATE2, 2, 2, PRIO_GESTURE },
1934+ { GRAIL_TYPE_ROTATE3, 3, 3, PRIO_GESTURE },
1935+ { GRAIL_TYPE_ROTATE4, 4, 4, PRIO_GESTURE },
1936+ { GRAIL_TYPE_ROTATE5, 5, 5, PRIO_GESTURE }
1937+ },
1938+ rotate_props
1939+};
1940+
1941+static const struct gesture_handler tap_handler = {
1942+ GRAIL_EXPECT_MASK,
1943+ {
1944+ { -1, 0, 0, 0 },
1945+ { GRAIL_TYPE_TAP1, 1, 1, PRIO_TAP },
1946+ { GRAIL_TYPE_TAP2, 2, 2, PRIO_TAP },
1947+ { GRAIL_TYPE_TAP3, 3, 3, PRIO_TAP },
1948+ { GRAIL_TYPE_TAP4, 4, 4, PRIO_TAP },
1949+ { GRAIL_TYPE_TAP5, 5, 5, PRIO_TAP }
1950+ },
1951+ tap_props
1952+};
1953+
1954+static const struct gesture_handler wintouch_handler = {
1955+ GRAIL_EXPECT_X | GRAIL_EXPECT_Y,
1956+ {
1957+ { -1, 0, 0, 0 },
1958+ { -1, 0, 0, 0 },
1959+ { -1, 0, 0, 0 },
1960+ { GRAIL_TYPE_ETOUCH, 1, 3, PRIO_ENV },
1961+ { GRAIL_TYPE_MTOUCH, 1, 4, PRIO_META },
1962+ { -1, 0, 0, 0 },
1963+ },
1964+ touch_props
1965+};
1966+
1967+static const struct gesture_handler windrag_handler = {
1968+ GRAIL_EXPECT_X | GRAIL_EXPECT_Y,
1969+ {
1970+ { -1, 0, 0, 0 },
1971+ { -1, 0, 0, 0 },
1972+ { -1, 0, 0, 0 },
1973+ { GRAIL_TYPE_EDRAG, 1, 3, PRIO_ENV },
1974+ { GRAIL_TYPE_MDRAG, 1, 4, PRIO_META },
1975+ { -1, 0, 0, 0 },
1976+ },
1977+ drag_props
1978+};
1979+
1980+static const struct gesture_handler winpinch_handler = {
1981+ GRAIL_EXPECT_SCALE,
1982+ {
1983+ { -1, 0, 0, 0 },
1984+ { -1, 0, 0, 0 },
1985+ { -1, 0, 0, 0 },
1986+ { GRAIL_TYPE_EPINCH, 2, 3, PRIO_ENV },
1987+ { GRAIL_TYPE_MPINCH, 2, 4, PRIO_META },
1988+ { -1, 0, 0, 0 },
1989+ },
1990+ pinch_props
1991+};
1992+
1993+static const struct gesture_handler winrotate_handler = {
1994+ GRAIL_EXPECT_ANGLE,
1995+ {
1996+ { -1, 0, 0, 0 },
1997+ { -1, 0, 0, 0 },
1998+ { -1, 0, 0, 0 },
1999+ { GRAIL_TYPE_EROTATE, 2, 3, PRIO_ENV },
2000+ { GRAIL_TYPE_MROTATE, 2, 4, PRIO_META },
2001+ { -1, 0, 0, 0 },
2002+ },
2003+ rotate_props
2004+};
2005
2006 int gru_init(struct grail *ge)
2007 {
2008@@ -30,8 +202,18 @@
2009 gru = calloc(1, sizeof(struct gesture_recognizer));
2010 if (!gru)
2011 return -ENOMEM;
2012+
2013+ gru->touch.handler = &touch_handler;
2014+ gru->drag.handler = &drag_handler;
2015+ gru->pinch.handler = &pinch_handler;
2016+ gru->rotate.handler = &rotate_handler;
2017+ gru->tapping.handler = &tap_handler;
2018+ gru->wintouch.handler = &wintouch_handler;
2019+ gru->windrag.handler = &windrag_handler;
2020+ gru->winpinch.handler = &winpinch_handler;
2021+ gru->winrotate.handler = &winrotate_handler;
2022+
2023 ge->gru = gru;
2024- gru_init_motion(ge);
2025 return 0;
2026 }
2027
2028@@ -41,18 +223,173 @@
2029 ge->gru = NULL;
2030 }
2031
2032-void gru_recognize(struct grail *ge, const struct utouch_frame *frame)
2033-{
2034- if (!ge->gin || !ge->gru)
2035- return;
2036- gru_motion(ge, frame);
2037- gru_touch(ge, frame);
2038- gru_drag(ge, frame);
2039- gru_pinch(ge, frame);
2040- gru_rotate(ge, frame);
2041- gru_wintouch(ge, frame);
2042- gru_windrag(ge, frame);
2043- gru_winpinch(ge, frame);
2044- gru_winrotate(ge, frame);
2045- gru_tapping(ge, frame);
2046-}
2047+static void set_props(struct grail *ge,
2048+ struct combo_model *s,
2049+ const struct utouch_frame *frame)
2050+{
2051+ const struct gesture_handler *gh = s->handler;
2052+ gh->set_props(ge->gin, s, ge->gru->move, frame);
2053+ s->nprop += gin_add_contact_props(ge->gin, s->prop + s->nprop, frame);
2054+}
2055+
2056+static int gru_touch_handler(struct grail *ge,
2057+ struct combo_model *state,
2058+ const struct utouch_frame *frame)
2059+{
2060+ struct gesture_recognizer *gru = ge->gru;
2061+ struct gesture_inserter *gin = ge->gin;
2062+ struct grail_element *move = gru->move;
2063+ const struct gesture_handler *gh = state->handler;
2064+ int ntouch = move->num_touches;
2065+ if (frame->slot_revision != frame->prev->slot_revision) {
2066+ if (state->active) {
2067+ gin_gid_end(ge, state->gid, move->center.x,
2068+ move->center.y, ntouch,
2069+ state->prop, state->nprop);
2070+ state->active = 0;
2071+ }
2072+ }
2073+ if (ntouch > MAX_TOUCH_GESTURE)
2074+ return 0;
2075+ if (!state->active) {
2076+ struct gesture_head h = gh->getype[ntouch];
2077+ if (h.type < 0)
2078+ return 0;
2079+ state->gid = gin_gid_begin(ge, h.type, -h.priority, frame);
2080+ state->mintouch = h.mintouch;
2081+ state->maxtouch = h.maxtouch;
2082+ state->active = 1;
2083+ }
2084+ set_props(ge, state, frame);
2085+ gin_gid_event(ge, state->gid, move->center.x, move->center.y,
2086+ ntouch, state->prop, state->nprop, 0);
2087+ return 1;
2088+}
2089+
2090+static int gru_gesture_handler(struct grail *ge,
2091+ struct combo_model *state,
2092+ const struct utouch_frame *frame)
2093+{
2094+ struct gesture_recognizer *gru = ge->gru;
2095+ struct gesture_inserter *gin = ge->gin;
2096+ struct grail_element *move = gru->move;
2097+ const struct gesture_handler *gh = state->handler;
2098+ int expect = move->expect_mask & gh->fm_mask;
2099+ int active = move->active_mask & gh->fm_mask;
2100+ int ntouch = move->num_touches;
2101+ if (state->active &&
2102+ (!expect || ntouch < state->mintouch || ntouch > state->maxtouch)) {
2103+ gin_gid_end(ge, state->gid, move->center.x,
2104+ move->center.y,ntouch,
2105+ state->prop, state->nprop);
2106+ state->active = 0;
2107+ return 0;
2108+ }
2109+ if (!expect || !active || ntouch > MAX_TOUCH_GESTURE)
2110+ return 0;
2111+ if (!state->active) {
2112+ struct gesture_head h = gh->getype[ntouch];
2113+ if (h.type < 0)
2114+ return 0;
2115+ state->gid = gin_gid_begin(ge, h.type, h.priority, frame);
2116+ state->mintouch = h.mintouch;
2117+ state->maxtouch = h.maxtouch;
2118+ state->active = 1;
2119+ }
2120+ set_props(ge, state, frame);
2121+ gin_gid_event(ge, state->gid, move->center.x, move->center.y,
2122+ ntouch, state->prop, state->nprop, 0);
2123+ return 1;
2124+}
2125+
2126+static int gru_tap_handler(struct grail *ge,
2127+ struct combo_model *state,
2128+ const struct utouch_frame *frame)
2129+{
2130+ struct gesture_recognizer *gru = ge->gru;
2131+ struct grail_element *move = gru->move;
2132+ const struct gesture_handler *gh = state->handler;
2133+ int active = move->active_mask & gh->fm_mask;
2134+ int ntouch = move->num_touches;
2135+ state->tap = 0;
2136+ if (frame->num_active && !frame->prev->num_active) {
2137+ state->mintouch = 0;
2138+ state->maxtouch = 0;
2139+ }
2140+ if (ntouch > state->maxtouch) {
2141+ if (state->active) {
2142+ gin_gid_discard(ge, state->gid);
2143+ state->active = 0;
2144+ }
2145+ state->start = frame->time;
2146+ state->maxtouch = ntouch;
2147+ set_props(ge, state, frame);
2148+ if (state->maxtouch <= MAX_TOUCH_GESTURE) {
2149+ struct gesture_head h = gh->getype[ntouch];
2150+ if (h.type < 0)
2151+ return 0;
2152+ state->gid = gin_gid_begin(ge, h.type, h.priority,
2153+ frame);
2154+ state->active = 1;
2155+ }
2156+ return 0;
2157+ }
2158+ if (!state->active) {
2159+ state->mintouch = ntouch;
2160+ state->maxtouch = ntouch;
2161+ return 0;
2162+ }
2163+ if (ntouch <= state->mintouch) {
2164+ int x = state->prop[GRAIL_PROP_TAP_X];
2165+ int y = state->prop[GRAIL_PROP_TAP_Y];
2166+ int t = frame->time - state->start;
2167+ if (t > TAP_TIME_MS) {
2168+ gin_gid_discard(ge, state->gid);
2169+ state->mintouch = ntouch;
2170+ state->maxtouch = ntouch;
2171+ state->active = 0;
2172+ return 0;
2173+ }
2174+ state->tap = state->maxtouch;
2175+ state->prop[GRAIL_PROP_TAP_DT] = t;
2176+ gin_gid_event(ge, state->gid, x, y, state->maxtouch,
2177+ state->prop, state->nprop, 1);
2178+ state->mintouch = ntouch;
2179+ state->maxtouch = ntouch;
2180+ state->active = 0;
2181+ return 1;
2182+ }
2183+ if (!ntouch)
2184+ return 0;
2185+ state->prop[GRAIL_PROP_TAP_DT] = frame->time - state->start;
2186+ if (active || frame->time - state->start > TAP_TIME_MS) {
2187+ gin_gid_discard(ge, state->gid);
2188+ state->mintouch = ntouch;
2189+ state->maxtouch = ntouch;
2190+ state->active = 0;
2191+ }
2192+ return 0;
2193+}
2194+
2195+void gru_recognize(struct grail *ge,
2196+ const struct grail_frame *frame,
2197+ const struct utouch_frame *touch)
2198+{
2199+ struct gesture_recognizer *gru = ge->gru;
2200+
2201+ if (frame && frame->num_ongoing)
2202+ gru->slot = frame->ongoing[frame->num_ongoing - 1]->slot;
2203+
2204+ gru->move = frame->slots[gru->slot];
2205+
2206+ gru_touch_handler(ge, &gru->touch, touch);
2207+ gru_gesture_handler(ge, &gru->drag, touch);
2208+ gru_gesture_handler(ge, &gru->pinch, touch);
2209+ gru_gesture_handler(ge, &gru->rotate, touch);
2210+ gru_touch_handler(ge, &gru->wintouch, touch);
2211+ gru_gesture_handler(ge, &gru->windrag, touch);
2212+ gru_gesture_handler(ge, &gru->winpinch, touch);
2213+ gru_gesture_handler(ge, &gru->winrotate, touch);
2214+ gru_tap_handler(ge, &gru->tapping, touch);
2215+}
2216+
2217
2218=== modified file 'src/grail-recognizer.h'
2219--- src/grail-recognizer.h 2011-04-12 16:35:37 +0000
2220+++ src/grail-recognizer.h 2011-04-27 19:43:23 +0000
2221@@ -22,10 +22,26 @@
2222 #ifndef _GRAIL_RECOGNIZER_H
2223 #define _GRAIL_RECOGNIZER_H
2224
2225-#include "grail-gestures.h"
2226+#include "grail-inserter.h"
2227+
2228+#define PRIO_POINTER 1
2229+#define PRIO_GESTURE 2
2230+#define PRIO_ENV 3
2231+#define PRIO_META 4
2232+#define PRIO_TAP 5
2233+
2234+struct combo_model {
2235+ grail_time_t start;
2236+ int active, gid, tap;
2237+ int mintouch, maxtouch;
2238+ int nprop;
2239+ grail_prop_t prop[DIM_GRAIL_PROP];
2240+ const struct gesture_handler *handler;
2241+};
2242
2243 struct gesture_recognizer {
2244- struct move_model move;
2245+ int slot;
2246+ struct grail_element *move;
2247 struct combo_model touch;
2248 struct combo_model drag;
2249 struct combo_model pinch;
2250@@ -34,11 +50,30 @@
2251 struct combo_model windrag;
2252 struct combo_model winpinch;
2253 struct combo_model winrotate;
2254- struct tapping_model tapping;
2255+ struct combo_model tapping;
2256+};
2257+
2258+struct gesture_head {
2259+ int type;
2260+ int mintouch;
2261+ int maxtouch;
2262+ int priority;
2263+};
2264+
2265+struct gesture_handler {
2266+ int fm_mask;
2267+ struct gesture_head getype[DIM_TOUCH + 1];
2268+
2269+ void (*set_props)(const struct gesture_inserter *gin,
2270+ struct combo_model *state,
2271+ const struct grail_element *element,
2272+ const struct utouch_frame *frame);
2273 };
2274
2275 int gru_init(struct grail *ge);
2276-void gru_recognize(struct grail *ge, const struct utouch_frame *frame);
2277+void gru_recognize(struct grail *ge,
2278+ const struct grail_frame *frame,
2279+ const struct utouch_frame *touch);
2280 void gru_destroy(struct grail *ge);
2281
2282 #endif
2283
2284=== modified file 'tools/grail-test-mtdev.c'
2285--- tools/grail-test-mtdev.c 2011-04-12 16:35:37 +0000
2286+++ tools/grail-test-mtdev.c 2011-04-27 19:43:23 +0000
2287@@ -120,7 +120,6 @@
2288 slot->transform[4], slot->transform[5],
2289 slot->transform[6], slot->transform[7],
2290 slot->transform[8]);
2291- fprintf(stderr, " moveness: %f\n", slot->moveness);
2292 fprintf(stderr, " pivot.x: %f\n", slot->pivot.x);
2293 fprintf(stderr, " pivot.y: %f\n", slot->pivot.y);
2294 fprintf(stderr, " drag.x: %f\n", slot->drag.x);
2295
2296=== modified file 'tools/grail-transform.c'
2297--- tools/grail-transform.c 2011-04-12 16:35:37 +0000
2298+++ tools/grail-transform.c 2011-04-27 19:43:23 +0000
2299@@ -53,6 +53,7 @@
2300 int screen;
2301 float off_x, off_y;
2302 unsigned long white, black;
2303+ XColor red;
2304 };
2305
2306 static void clear_screen(struct appdata *w)
2307@@ -77,29 +78,29 @@
2308
2309 static void draw_object(struct appdata *w)
2310 {
2311- static const double frac = 0.01;
2312+ static const double frac = 0.04;
2313 const struct utouch_surface *s = utouch_frame_get_surface(w->fh);
2314 double d = frac * (s->mapped_max_x - s->mapped_min_x);
2315 int i;
2316
2317+ XSetForeground(w->dsp, w->gc, w->black);
2318 XDrawLines(w->dsp, w->win, w->gc, w->pts, 5, CoordModeOrigin);
2319
2320- if (w->scaling)
2321- XFillArc(w->dsp, w->win, w->gc,
2322- w->pivot.x - d / 2, w->pivot.y - d / 2,
2323- d, d, 0, 360 * 64);
2324-
2325- d *= 4;
2326 for (i = 0; i < w->ntouch; i++)
2327 XFillArc(w->dsp, w->win, w->gc,
2328 w->touch[i].x - d / 2, w->touch[i].y - d / 2,
2329 d, d, 0, 360 * 64);
2330+
2331+ d /= 4;
2332+ XSetForeground(w->dsp, w->gc, w->red.pixel);
2333+ XFillArc(w->dsp, w->win, w->gc,
2334+ w->pivot.x - d / 2, w->pivot.y - d / 2,
2335+ d, d, 0, 360 * 64);
2336 }
2337
2338 static void report_frame(struct appdata *w,
2339 const struct utouch_frame *touch)
2340 {
2341- const struct grail_control *ctl = grail_get_control(w->ge);
2342 const struct grail_frame *frame;
2343 const struct grail_element *slot;
2344 struct grail_coord tmp;
2345@@ -121,8 +122,7 @@
2346 w->pos[i] = tmp;
2347 }
2348
2349- XSetForeground(w->dsp, w->gc, w->white);
2350- draw_object(w);
2351+ clear_screen(w);
2352
2353 w->ntouch = touch->num_active;
2354 for (i = 0; i < w->ntouch; i++) {
2355@@ -130,7 +130,6 @@
2356 w->touch[i].y = touch->active[i]->y - w->off_y;
2357 }
2358
2359- w->scaling = slot->moveness < ctl->thresh_scale;
2360 w->pivot.x = slot->pivot.x - w->off_x;
2361 w->pivot.y = slot->pivot.y - w->off_y;
2362
2363@@ -148,6 +147,7 @@
2364 static int init_window(struct appdata *w)
2365 {
2366 int event, err;
2367+ Colormap colormap;
2368
2369 w->pos[0].x = 100;
2370 w->pos[0].y = 100;
2371@@ -169,6 +169,9 @@
2372 w->white = WhitePixel(w->dsp, w->screen);
2373 w->black = BlackPixel(w->dsp, w->screen);
2374
2375+ colormap = DefaultColormap(w->dsp, w->screen);
2376+ XAllocNamedColor(w->dsp, colormap, "red", &w->red, &w->red);
2377+
2378 w->win = XCreateSimpleWindow(w->dsp, XDefaultRootWindow(w->dsp),
2379 0, 0, 600, 600, 0, w->black, w->white);
2380 w->gc = DefaultGC(w->dsp, w->screen);
2381@@ -260,6 +263,7 @@
2382 grail_get_control(w->ge)->drop_y_ms = 1e8;
2383 grail_get_control(w->ge)->drop_scale_ms = 1e8;
2384 grail_get_control(w->ge)->drop_angle_ms = 1e8;
2385+ grail_get_control(w->ge)->pivot_type = GRAIL_CONVEX_HULL_RADIUS;
2386
2387 loop_device_mtdev(w);
2388
2389@@ -329,6 +333,8 @@
2390 if (!w->ge)
2391 return -1;
2392
2393+ grail_get_control(w->ge)->pivot_type = GRAIL_CONVEX_HULL_RADIUS;
2394+
2395 loop_device_xi2(w, id);
2396
2397 grail_delete(w->ge);
2398
2399=== modified file 'utouch-grail.sym.in'
2400--- utouch-grail.sym.in 2011-04-12 16:35:23 +0000
2401+++ utouch-grail.sym.in 2011-04-27 19:43:23 +0000
2402@@ -4,6 +4,7 @@
2403 grail_get_contact_frame
2404 grail_get_contacts
2405 grail_get_control
2406+grail_get_gesture_frame
2407 grail_get_units
2408 grail_get_version
2409 grail_idle
2410@@ -11,6 +12,7 @@
2411 grail_mask_count
2412 grail_mask_get_first
2413 grail_mask_get_next
2414+grail_mask_inner
2415 grail_mask_set_mask
2416 grail_new_raw
2417 grail_open

Subscribers

People subscribed via source and target branches