5 #include "recognize_stroke.h"
7 float dist(GdkPoint *pt0, GdkPoint *pt1)
9 return sqrt(pow(pt1->x - pt0->x, 2) + pow(pt1->y - pt0->y, 2));
12 static float angle(GdkPoint *pt0, GdkPoint *pt, GdkPoint *pt2)
14 float d0 = dist(pt0, pt);
15 float d2 = dist(pt, pt2);
16 float d = dist(pt0, pt2);
17 return acos((pow(d0, 2) + pow(d2, 2) - pow(d, 2))/(2*d0*d2));
20 gchar get_stroke_char(GdkPoint *p0, GdkPoint *p1)
22 float x = p1->x - p0->x;
23 float y = p1->y - p0->y;
24 float a = acos(x/dist(p0, p1));
29 if((M_PI/8 < a) && (a < M_PI/2))
34 if((5*M_PI/8 < a) && (a < 7*M_PI/8))
36 if((3*M_PI/8 <= a) && (a <= 5*M_PI/8))
38 if((M_PI/8 < a) && (a < 3*M_PI/8))
44 static float find_largest_angle(GList *s, GList **out)
49 if(g_list_length(s) < 3)
51 for(s0 = s; s0 != g_list_last(s0); s0 = g_list_next(s0))
53 for(s1 = g_list_next(s0); s1 && (s1 != g_list_last(s1)); s1 = g_list_next(s1))
55 for(s2 = g_list_next(s1); s2 && (s2 != g_list_last(s2)); s2 = g_list_next(s2))
57 GdkPoint *pt0 = (GdkPoint*)s0->data;
58 GdkPoint *pt = (GdkPoint*)s1->data;
59 GdkPoint *pt2 = (GdkPoint*)s2->data;
60 a1 = angle(pt0, pt, pt2);
72 static GList* filter_equal_points(GList *s)
75 for(;s != g_list_last(s); s = g_list_next(s))
77 p = (GdkPoint*)s->data;
78 p2 = (GdkPoint*)g_list_next(s)->data;
79 if((p->x == p2->x) && (p->y == p2->y))
81 s = g_list_delete_link(s, s);
84 return g_list_first(s);
87 /* let A, B, C be consecutive points
88 * if angle ABC larger then predefined value
90 static GList* filter_points_by_angle(GList *s)
92 const float MIN_MAX_ANGLE = 170*M_PI/180;
95 if(g_list_length(s) < 3)
96 return g_list_first(s);
98 if(find_largest_angle(s, &pt) > MIN_MAX_ANGLE)
99 s = g_list_delete_link(s, pt);
103 if(g_list_length(s) < 3)
104 return g_list_first(s);
105 GdkPoint *p0, *p, *p2;
106 for(s = g_list_next(s); s != g_list_last(s); s = g_list_next(s))
108 if(g_list_length(s) < 3)
109 return g_list_first(s);
110 p0 = (GdkPoint*)g_list_previous(s)->data;
111 p = (GdkPoint*)s->data;
112 p2 = (GdkPoint*)g_list_next(s)->data;
113 gchar ch0 = get_stroke_char(p0, p);
114 gchar ch1 = get_stroke_char(p, p2);
116 s = g_list_delete_link(s, s);
118 return g_list_first(s);
121 static float find_average_and_smallest_dist(GList *s, GList **pt0, GList **pt1, float *pdmin)
123 float d = 0, dt, dmin = -1;
125 for(; s != g_list_last(s); s = g_list_next(s), i++)
127 GdkPoint *p0 = (GdkPoint*)s->data;
128 GdkPoint *p1 = (GdkPoint*)g_list_next(s)->data;
130 if((dmin < 0) || (dmin > dt))
134 *pt1 = g_list_next(s);
142 /* let A, B be consecutive points
143 * if dist(A,B) less than a certain percentage of average dist
145 static GList* filter_points_by_dist(GList *s)
147 const float MAX_MIN_DIST = 0.3;
149 GList *pt0 = 0, *pt1 = 0;
152 if(g_list_length(s) < 3)
153 return g_list_first(s);
154 d0 = MAX_MIN_DIST*find_average_and_smallest_dist(s, &pt0, &pt1, &dmin);
160 else if(pt1 == g_list_last(s))
164 GdkPoint *p0 = (GdkPoint*)pt0->data;
165 GdkPoint *p01 = (GdkPoint*)g_list_previous(pt0)->data;
166 GdkPoint *p1 = (GdkPoint*)pt1->data;
167 GdkPoint *p11 = (GdkPoint*)g_list_next(pt1)->data;
168 float d0 = dist(p0, p01);
169 float d1 = dist(p1, p11);
175 s = g_list_delete_link(s, del);
183 gchar *get_stroke_str(GList *s)
185 gchar *ret = calloc(g_list_length(s), sizeof(gchar));
188 for(;s != g_list_last(s); s = g_list_next(s))
190 GdkPoint *p0 = (GdkPoint*)s->data;
191 GdkPoint *p1 = (GdkPoint*)g_list_next(s)->data;
192 gchar ch = get_stroke_char(p0, p1);
198 ch = g_ascii_tolower(ch);
206 gchar* recognize_stroke(GList *stroke, GList **out)
208 *out = g_list_copy(stroke);
209 *out = filter_equal_points(*out);
210 *out = filter_points_by_angle(*out);
211 *out = filter_points_by_dist(*out);
212 return get_stroke_str(*out);