Merge lp:~chasedouglas/grail/pivot_type into lp:~oif-team/grail/grail2
- pivot_type
- Merge into grail2
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Henrik Rydberg (community) | Disapprove | ||
Review via email: mp+59272@code.launchpad.net |
Commit message
Description of the change
RFC for this changeset that adds configuration of where the pivot should be determined.
- 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
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 |
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.