summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile15
-rw-r--r--match/match.c326
-rw-r--r--match/match.h25
-rw-r--r--match/test.c40
-rw-r--r--src/common.h3
-rw-r--r--src/hwdata.h1
-rw-r--r--src/multitouch.c2
-rw-r--r--src/state.c72
-rw-r--r--src/state.h3
9 files changed, 473 insertions, 14 deletions
diff --git a/Makefile b/Makefile
index bc5cc02..c805140 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,8 @@
1LIBRARY = multitouch.so 1LIBRARY = multitouch.so
2FDIS = 11-multitouch.fdi 2FDIS = 11-multitouch.fdi
3MODULES = src 3MODULES = match src
4
5o_match = match
4 6
5o_src = capabilities \ 7o_src = capabilities \
6 iobuffer \ 8 iobuffer \
@@ -31,13 +33,11 @@ OPTS = -O3
31.PHONY: all clean 33.PHONY: all clean
32.PRECIOUS: obj/%.o 34.PRECIOUS: obj/%.o
33 35
34all: $(OBJS) $(TLIB) $(TOBJ) 36all: $(OBJS) $(TLIB) $(TOBJ) $(TBIN)
35
36test: $(TBIN)
37 37
38bin/%: obj/%.o 38bin/%: obj/%.o
39 @mkdir -p $(@D) 39 @mkdir -p $(@D)
40 gcc $< $(OBJS) $(LIBS) -o $@ 40 gcc $< -o $@
41 41
42$(TLIB): $(OBJS) 42$(TLIB): $(OBJS)
43 @rm -f $(TLIB) 43 @rm -f $(TLIB)
@@ -62,3 +62,8 @@ install: $(TLIB) $(TFDI)
62 install -d "$(DESTDIR)/$(DFDI)" 62 install -d "$(DESTDIR)/$(DFDI)"
63 install -m 755 $(TLIB) "$(DESTDIR)/$(DLIB)" 63 install -m 755 $(TLIB) "$(DESTDIR)/$(DLIB)"
64 install -m 644 $(TFDI) "$(DESTDIR)/$(DFDI)" 64 install -m 644 $(TFDI) "$(DESTDIR)/$(DFDI)"
65
66test:
67 gcc $< $(OBJS) -o LINKTEST
68
69obj/match/test.o: match/match.c
diff --git a/match/match.c b/match/match.c
new file mode 100644
index 0000000..604faaf
--- /dev/null
+++ b/match/match.c
@@ -0,0 +1,326 @@
1#include "match.h"
2#include <string.h>
3#include <stdio.h>
4
5/**
6 * MATLAB implementation of the hungarian algorithm (2008)
7 *
8 * modified by Henrik Rydberg (2008)
9 */
10
11const float BIG_VALUE = 1e20;
12
13typedef unsigned short col_t;
14
15#define GETBIT2(m, row, col) ((m[col]>>row)&1U)
16#define SETBIT2(m, row, col) (m[col]|=(1U<<row))
17#define CLEARBIT2(m, row, col) (m[col]&=~(1U<<row))
18
19#define GETBIT(m, x) ((m>>x)&1U)
20#define SETBIT(m, x) (m|=(1U<<x))
21#define CLEARBIT(m, x) (m&=~(1U<<x))
22
23/********************************************************/
24
25static void buildixvector(int *ix, col_t *mstar, int nrows, int ncols)
26{
27 int row, col;
28 for (row = 0; row < nrows; row++) {
29 for (col = 0; col < ncols; col++) {
30 if (GETBIT2(mstar, row, col)) {
31 ix[row] = col;
32 break;
33 }
34 }
35 }
36}
37
38
39/********************************************************/
40
41static void step2a(int *ix, float *mdist, col_t *mstar, col_t *nmstar, col_t *mprime, col_t ccol, col_t crow, int nrows, int ncols, int dmin);
42static void step2b(int *ix, float *mdist, col_t *mstar, col_t *nmstar, col_t *mprime, col_t ccol, col_t crow, int nrows, int ncols, int dmin);
43static void step3 (int *ix, float *mdist, col_t *mstar, col_t *nmstar, col_t *mprime, col_t ccol, col_t crow, int nrows, int ncols, int dmin);
44static void step4 (int *ix, float *mdist, col_t *mstar, col_t *nmstar, col_t *mprime, col_t ccol, col_t crow, int nrows, int ncols, int dmin, int row, int col);
45static void step5 (int *ix, float *mdist, col_t *mstar, col_t *nmstar, col_t *mprime, col_t ccol, col_t crow, int nrows, int ncols, int dmin);
46
47static void ixoptimal(int *ix, float *mdist, int nrows, int ncols)
48{
49 float *mdistTemp, *mdistEnd, *columnEnd, value, minValue;
50 int nelem, dmin, row, col;
51 col_t ccol,crow, mstar[DIM_FINGER],mprime[DIM_FINGER],nmstar[DIM_FINGER];
52
53 ccol = crow = 0;
54 memset(mstar, 0, sizeof(mstar));
55 memset(mprime, 0, sizeof(mprime));
56 memset(nmstar, 0, sizeof(nmstar));
57
58
59 /* initialization */
60 for(row=0; row<nrows; row++)
61 ix[row] = -1;
62
63 nelem = nrows * ncols;
64 mdistEnd = mdist + nelem;
65
66 /* preliminary steps */
67 if(nrows <= ncols) {
68 dmin = nrows;
69
70 for(row=0; row<nrows; row++) {
71 /* find the smallest element in the row */
72 mdistTemp = mdist + row;
73 minValue = *mdistTemp;
74 mdistTemp += nrows;
75 while(mdistTemp < mdistEnd) {
76 value = *mdistTemp;
77 if(value < minValue)
78 minValue = value;
79 mdistTemp += nrows;
80 }
81
82 /* subtract the smallest element from each element of the row */
83 mdistTemp = mdist + row;
84 while(mdistTemp < mdistEnd) {
85 *mdistTemp -= minValue;
86 mdistTemp += nrows;
87 }
88 }
89
90 /* Steps 1 and 2a */
91 for(row=0; row<nrows; row++)
92 for(col=0; col<ncols; col++)
93 if(mdist[row + nrows*col] == 0)
94 if(!GETBIT(ccol, col)) {
95 SETBIT2(mstar, row, col);
96 SETBIT(ccol, col);
97 break;
98 }
99 }
100 else /* if(nrows > ncols) */
101 {
102 dmin = ncols;
103
104 for(col=0; col<ncols; col++)
105 {
106 /* find the smallest element in the column */
107 mdistTemp = mdist + nrows*col;
108 columnEnd = mdistTemp + nrows;
109
110 minValue = *mdistTemp++;
111 while(mdistTemp < columnEnd)
112 {
113 value = *mdistTemp++;
114 if(value < minValue)
115 minValue = value;
116 }
117
118 /* subtract the smallest element from each element of the column */
119 mdistTemp = mdist + nrows*col;
120 while(mdistTemp < columnEnd)
121 *mdistTemp++ -= minValue;
122 }
123
124 /* Steps 1 and 2a */
125 for(col=0; col<ncols; col++)
126 for(row=0; row<nrows; row++)
127 if(mdist[row + nrows*col] == 0)
128 if(!GETBIT(crow, row))
129 {
130 SETBIT2(mstar, row, col);
131 SETBIT(ccol, col);
132 SETBIT(crow, row);
133 break;
134 }
135 for(row=0; row<nrows; row++)
136 CLEARBIT(crow, row);
137
138 }
139
140 /* move to step 2b */
141 step2b(ix, mdist, mstar, nmstar, mprime, ccol, crow, nrows, ncols, dmin);
142}
143
144/********************************************************/
145static void step2a(int *ix, float *mdist, col_t *mstar, col_t *nmstar, col_t *mprime, col_t ccol, col_t crow, int nrows, int ncols, int dmin)
146{
147 int col, row;
148
149 /* cover every column containing a starred zero */
150 for(col=0; col<ncols; col++) {
151 for(row=col;row<nrows;row++) {
152 if(GETBIT2(mstar, row, col)) {
153 SETBIT(ccol, col);
154 break;
155 }
156 }
157 }
158
159 /* move to step 3 */
160 step2b(ix, mdist, mstar, nmstar, mprime, ccol, crow, nrows, ncols, dmin);
161}
162
163/********************************************************/
164static void step2b(int *ix, float *mdist, col_t *mstar, col_t *nmstar, col_t *mprime, col_t ccol, col_t crow, int nrows, int ncols, int dmin)
165{
166 int col, ncc;
167
168 /* count covered columns */
169 ncc = 0;
170 for(col=0; col<ncols; col++)
171 if(GETBIT(ccol, col))
172 ncc++;
173
174 if(ncc == dmin)
175 {
176 /* algorithm finished */
177 buildixvector(ix, mstar, nrows, ncols);
178 }
179 else
180 {
181 /* move to step 3 */
182 step3(ix, mdist, mstar, nmstar, mprime, ccol, crow, nrows, ncols, dmin);
183 }
184
185}
186
187/********************************************************/
188static void step3(int *ix, float *mdist, col_t *mstar, col_t *nmstar, col_t *mprime, col_t ccol, col_t crow, int nrows, int ncols, int dmin)
189{
190 bool zerosFound;
191 int row, col, cstar;
192
193 zerosFound = 1;
194 while(zerosFound)
195 {
196 zerosFound = 0;
197 for(col=0; col<ncols; col++)
198 if(!GETBIT(ccol,col))
199 for(row=0; row<nrows; row++)
200 if((!GETBIT(crow,row)) && (mdist[row + nrows*col] == 0))
201 {
202 /* prime zero */
203 SETBIT2(mprime, row, col);
204
205 /* find starred zero in current row */
206 for(cstar=0; cstar<ncols; cstar++)
207 if(GETBIT2(mstar, row, cstar))
208 break;
209
210 if(cstar == ncols) /* no starred zero found */
211 {
212 /* move to step 4 */
213 step4(ix, mdist, mstar, nmstar, mprime, ccol, crow, nrows, ncols, dmin, row, col);
214 return;
215 }
216 else
217 {
218 SETBIT(crow, row);
219 CLEARBIT(ccol,cstar);
220 zerosFound = 1;
221 break;
222 }
223 }
224 }
225
226 /* move to step 5 */
227 step5(ix, mdist, mstar, nmstar, mprime, ccol, crow, nrows, ncols, dmin);
228}
229
230/********************************************************/
231static void step4(int *ix, float *mdist, col_t *mstar, col_t *nmstar, col_t *mprime, col_t ccol, col_t crow, int nrows, int ncols, int dmin, int row, int col)
232{
233 int n, rstar, cstar, primeRow, primeCol;
234 int nelem = nrows*ncols;
235
236 /* generate temporary copy of mstar */
237 for(n=0; n<nelem; n++)
238 nmstar[n] = mstar[n];
239
240 /* star current zero */
241 SETBIT2(nmstar, row, col);
242
243 /* find starred zero in current column */
244 cstar = col;
245 for(rstar=0; rstar<nrows; rstar++)
246 if(GETBIT2(mstar, rstar, cstar))
247 break;
248
249 while(rstar<nrows)
250 {
251 /* unstar the starred zero */
252 CLEARBIT2(nmstar, rstar, cstar);
253
254 /* find primed zero in current row */
255 primeRow = rstar;
256 for(primeCol=0; primeCol<ncols; primeCol++)
257 if(GETBIT2(mprime, primeRow, primeCol))
258 break;
259
260 /* star the primed zero */
261 SETBIT2(nmstar, primeRow, primeCol);
262
263 /* find starred zero in current column */
264 cstar = primeCol;
265 for(rstar=0; rstar<nrows; rstar++)
266 if(GETBIT2(mstar, rstar, cstar))
267 break;
268 }
269
270 /* use temporary copy as new mstar */
271 /* delete all primes, uncover all rows */
272 for(n=0; n<nelem; n++)
273 {
274 mprime[n] = 0;
275 mstar[n] = nmstar[n];
276 }
277 for(n=0; n<nrows; n++)
278 CLEARBIT(crow, n);
279
280 /* move to step 2a */
281 step2a(ix, mdist, mstar, nmstar, mprime, ccol, crow, nrows, ncols, dmin);
282}
283
284/********************************************************/
285static void step5(int *ix, float *mdist, col_t *mstar, col_t *nmstar, col_t *mprime, col_t ccol, col_t crow, int nrows, int ncols, int dmin)
286{
287 float h, value;
288 int row, col;
289
290 /* find smallest uncovered element h */
291 h = BIG_VALUE;
292 for(row=0; row<nrows; row++)
293 if(!GETBIT(crow, row))
294 for(col=0; col<ncols; col++)
295 if(!GETBIT(ccol,col))
296 {
297 value = mdist[row + nrows*col];
298 if(value < h)
299 h = value;
300 }
301
302 /* add h to each covered row */
303 for(row=0; row<nrows; row++)
304 if(GETBIT(crow, row))
305 for(col=0; col<ncols; col++)
306 mdist[row + nrows*col] += h;
307
308 /* subtract h from each uncovered column */
309 for(col=0; col<ncols; col++)
310 if(!GETBIT(ccol,col))
311 for(row=0; row<nrows; row++)
312 mdist[row + nrows*col] -= h;
313
314 /* move to step 3 */
315 step3(ix, mdist, mstar, nmstar, mprime, ccol, crow, nrows, ncols, dmin);
316}
317
318////////////////////////////////////////////////////////
319
320void match_fingers(int ix[DIM_FINGER], float A[DIM2_FINGER], int nrow, int ncol)
321{
322 ixoptimal(ix, A, nrow, ncol);
323}
324
325////////////////////////////////////////////////////////
326
diff --git a/match/match.h b/match/match.h
new file mode 100644
index 0000000..8936de4
--- /dev/null
+++ b/match/match.h
@@ -0,0 +1,25 @@
1#ifndef MATCHER_H
2#define MATCHER_H
3
4/**
5 * Special implementation of the hungarian algorithm.
6 * The maximum number of fingers matches a uint32.
7 * Bitmasks are used extensively.
8 */
9
10#define DIM_FINGER 16
11#define DIM2_FINGER (DIM_FINGER * DIM_FINGER)
12
13#define MIN(a, b) ((a) < (b) ? (a) : (b))
14#define MAX(a, b) ((a) < (b) ? (b) : (a))
15
16typedef int bool;
17
18////////////////////////////////////////////////////////
19
20void match_fingers(int index[DIM_FINGER], float A[DIM2_FINGER],
21 int nrow, int ncol);
22
23////////////////////////////////////////////////////////
24
25#endif
diff --git a/match/test.c b/match/test.c
new file mode 100644
index 0000000..1544765
--- /dev/null
+++ b/match/test.c
@@ -0,0 +1,40 @@
1#include <stdio.h>
2#include <time.h>
3#include "match.c"
4
5#define ITS 1000000
6
7int main(int argc,char* argv[])
8{
9 // column-by-column matrix
10 float A[DIM2_FINGER];
11 float x1[DIM_FINGER]={1,5,2,3,4,5,6,7,8};
12 float y1[DIM_FINGER]={1,5,2,3,4,5.1,6,7,8};
13 float x2[DIM_FINGER]={1.1,3,2,4,5,6,7,8};
14 float y2[DIM_FINGER]={1,3,2,4,5,6,7,8};
15 int index[DIM_FINGER];
16 int n1 = 4;
17 int n2 = 7;
18
19 int i, j;
20
21 for (i = 0; i < n1; i++) {
22 for (j = 0; j < n2; j++) {
23 A[i + n1 * j] =
24 (x1[i] - x2[j]) * (x1[i] - x2[j]) +
25 (y1[i] - y2[j]) * (y1[i] - y2[j]);
26 }
27 }
28
29 clock_t t1 = clock();
30 for (i = 0; i < ITS; i++)
31 match_fingers(index, A, n1, n2);
32 clock_t t2 = clock();
33
34 printf("%lf matches per second\n", ITS * ((float)CLOCKS_PER_SEC / (t2 - t1)));
35
36 for (i = 0; i < n1; i++)
37 printf("match[%d] = %d\n", i, index[i]);
38
39 return 0;
40}
diff --git a/src/common.h b/src/common.h
index 5a83f95..c57ae1a 100644
--- a/src/common.h
+++ b/src/common.h
@@ -7,6 +7,7 @@
7#include <xf86Xinput.h> 7#include <xf86Xinput.h>
8#include <linux/input.h> 8#include <linux/input.h>
9#include <errno.h> 9#include <errno.h>
10#include <match/match.h>
10//#include <exevents.h> 11//#include <exevents.h>
11 12
12//////////////////////////////////////////////////////// 13////////////////////////////////////////////////////////
@@ -27,8 +28,6 @@
27#define ABS_MT_POSITION_X 0x35 28#define ABS_MT_POSITION_X 0x35
28#define ABS_MT_POSITION_Y 0x36 29#define ABS_MT_POSITION_Y 0x36
29 30
30typedef int bool;
31
32#define SYSCALL(call) while (((call) == -1) && (errno == EINTR)) 31#define SYSCALL(call) while (((call) == -1) && (errno == EINTR))
33 32
34//////////////////////////////////////////////////////// 33////////////////////////////////////////////////////////
diff --git a/src/hwdata.h b/src/hwdata.h
index 239e022..59cff0d 100644
--- a/src/hwdata.h
+++ b/src/hwdata.h
@@ -3,7 +3,6 @@
3 3
4#include "common.h" 4#include "common.h"
5 5
6#define DIM_FINGER 16
7#define DIM_BUTTON 3 6#define DIM_BUTTON 3
8 7
9#define MT_BUTTON_LEFT 0 8#define MT_BUTTON_LEFT 0
diff --git a/src/multitouch.c b/src/multitouch.c
index f6e3d05..21f3e1e 100644
--- a/src/multitouch.c
+++ b/src/multitouch.c
@@ -82,7 +82,7 @@ static void read_input(LocalDevicePtr local)
82 if (local->fd >= 0) { 82 if (local->fd >= 0) {
83 while (read_synchronized_event(mt, local->fd)) { 83 while (read_synchronized_event(mt, local->fd)) {
84 modify_state(&mt->ns, &mt->hw); 84 modify_state(&mt->ns, &mt->hw);
85 // and something in between here 85 output_state(&mt->ns);
86 mt->os = mt->ns; 86 mt->os = mt->ns;
87 } 87 }
88 } 88 }
diff --git a/src/state.c b/src/state.c
index 46b7fef..fc3580d 100644
--- a/src/state.c
+++ b/src/state.c
@@ -1,4 +1,5 @@
1#include "state.h" 1#include "state.h"
2#include <stdlib.h>
2 3
3/******************************************************/ 4/******************************************************/
4 5
@@ -9,11 +10,58 @@ void init_state(struct State *s)
9 10
10/******************************************************/ 11/******************************************************/
11 12
13inline int fincomp(const struct FingerState* a,const struct FingerState* b)
14{
15 return a->id - b->id;
16}
17
18inline float dist2(const struct FingerData* a,const struct FingerData* b)
19{
20 float dx = a->position_x - b->position_x;
21 float dy = a->position_y - b->position_y;
22
23 return dx * dx + dy * dy;
24}
25
12void modify_state(struct State *s, const struct HWData* hw) 26void modify_state(struct State *s, const struct HWData* hw)
13{ 27{
14 int i; 28 float A[DIM2_FINGER], *row;
15 if (s->button[0] != hw->button[0]) 29 int id[DIM_FINGER], index[DIM_FINGER], i, j;
16 xf86Msg(X_INFO, "multitouch: button changed\n"); 30
31 for (j = 0; j < s->nfinger; j++) {
32 id[j] = s->finger[j].id;
33 row = A + hw->nfinger * j;
34 for (i = 0; i < hw->nfinger; i++)
35 row[i] = dist2(&hw->finger[i], &s->finger[j].hw);
36 }
37
38 match_fingers(index, A, hw->nfinger, s->nfinger);
39
40 s->nfinger = 0;
41
42 /* update matched fingers */
43 for (i = 0; i < hw->nfinger; i++) {
44 if ((j = index[i]) >= 0) {
45 s->finger[s->nfinger].id = id[j];
46 s->finger[s->nfinger].hw = hw->finger[i];
47 s->nfinger++;
48 }
49 }
50
51 /* create new fingers */
52 for (i = 0; i < hw->nfinger; i++) {
53 if (index[i] < 0) {
54 s->finger[s->nfinger].id = ++s->lastid;
55 s->finger[s->nfinger].hw = hw->finger[i];
56 s->nfinger++;
57 }
58 }
59
60 /* sort fingers in touching order */
61 qsort(s->finger, s->nfinger, sizeof(struct FingerState),
62 (int (*)(const void*,const void*))fincomp);
63
64 /* copy buttons */
17 for (i = 0; i < DIM_BUTTON; i++) 65 for (i = 0; i < DIM_BUTTON; i++)
18 s->button[i] = hw->button[i]; 66 s->button[i] = hw->button[i];
19} 67}
@@ -23,9 +71,11 @@ void modify_state(struct State *s, const struct HWData* hw)
23const struct FingerState *find_finger(const struct State *s, int id) 71const struct FingerState *find_finger(const struct State *s, int id)
24{ 72{
25 int i; 73 int i;
74
26 for (i = 0; i < s->nfinger; i++) 75 for (i = 0; i < s->nfinger; i++)
27 if (s->finger[i].id == id) 76 if (s->finger[i].id == id)
28 return s->finger+i; 77 return s->finger + i;
78
29 return NULL; 79 return NULL;
30} 80}
31 81
@@ -33,6 +83,20 @@ const struct FingerState *find_finger(const struct State *s, int id)
33 83
34void output_state(const struct State *s) 84void output_state(const struct State *s)
35{ 85{
86 int i;
87 printf("buttons: %d%d%d\n", s->button[0], s->button[1], s->button[2]);
88 printf("fingers: %d\n", s->nfinger);
89 for (i = 0; i < s->nfinger; i++) {
90 printf(" %+02d %+05d:%+05d +%05d:%+05d %+05d %+05d:%+05d\n",
91 s->finger[i].id,
92 s->finger[i].hw.touch_major,
93 s->finger[i].hw.touch_minor,
94 s->finger[i].hw.width_major,
95 s->finger[i].hw.width_minor,
96 s->finger[i].hw.orientation,
97 s->finger[i].hw.position_x,
98 s->finger[i].hw.position_y);
99 }
36} 100}
37 101
38/******************************************************/ 102/******************************************************/
diff --git a/src/state.h b/src/state.h
index 9c36617..8b41920 100644
--- a/src/state.h
+++ b/src/state.h
@@ -14,7 +14,8 @@ struct FingerState {
14 14
15struct State { 15struct State {
16 struct FingerState finger[DIM_FINGER]; 16 struct FingerState finger[DIM_FINGER];
17 int nfinger, button[DIM_BUTTON]; 17 int button[DIM_BUTTON];
18 int nfinger, lastid;
18}; 19};
19 20
20//////////////////////////////////////////////////////// 21////////////////////////////////////////////////////////