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));
31 if((5*M_PI/8 < a) && (a < 7*M_PI/8))
33 if((3*M_PI/8 <= a) && (a <= 5*M_PI/8))
35 if((M_PI/8 < a) && (a < 3*M_PI/8))
40 if((5*M_PI/8 < a) && (a < 7*M_PI/8))
42 if((3*M_PI/8 <= a) && (a <= 5*M_PI/8))
44 if((M_PI/8 < a) && (a < 3*M_PI/8))
50 static float find_largest_angle(GList *s, GList **out)
55 if(g_list_length(s) < 3)
57 for(s0 = s; s0 != g_list_last(s0); s0 = g_list_next(s0))
59 for(s1 = g_list_next(s0); s1 && (s1 != g_list_last(s1)); s1 = g_list_next(s1))
61 for(s2 = g_list_next(s1); s2 && (s2 != g_list_last(s2)); s2 = g_list_next(s2))
63 GdkPoint *pt0 = (GdkPoint*)s0->data;
64 GdkPoint *pt = (GdkPoint*)s1->data;
65 GdkPoint *pt2 = (GdkPoint*)s2->data;
66 a1 = angle(pt0, pt, pt2);
78 static GList* filter_equal_points(GList *s)
81 for(;s != g_list_last(s); s = g_list_next(s))
83 p = (GdkPoint*)s->data;
84 p2 = (GdkPoint*)g_list_next(s)->data;
85 if((p->x == p2->x) && (p->y == p2->y))
87 s = g_list_delete_link(g_list_first(s), s);
90 return g_list_first(s);
93 /* let A, B, C be consecutive points
94 * if angle ABC larger then predefined value
96 static GList* filter_points_by_angle(GList *s)
98 if(g_list_length(s) < 3)
101 GdkPoint *p0, *p, *p2;
102 for(s = g_list_next(s); s != g_list_last(s); s = g_list_next(s))
104 if(g_list_length(s) < 3)
106 p0 = (GdkPoint*)g_list_previous(s)->data;
107 p = (GdkPoint*)s->data;
108 p2 = (GdkPoint*)g_list_next(s)->data;
109 ch0 = get_stroke_char(p0, p);
110 ch1 = get_stroke_char(p, p2);
112 s = g_list_delete_link(s, s);
114 return g_list_first(s);
117 static GList* filter_points_by_angle2(GList *s)
119 if(g_list_length(s) < 3)
121 const float MIN_MAX_ANGLE = 170*M_PI/180;
124 if(g_list_length(s) < 3)
127 if(find_largest_angle(s, &pt) > MIN_MAX_ANGLE)
128 s = g_list_delete_link(s, pt);
132 return g_list_first(s);
135 static GList* filter_points_by_angle3(GList *s)
137 if(g_list_length(s) < 4)
142 GdkPoint *p0 = (GdkPoint*)s->data;
143 GList *s1 = g_list_next(s);
145 GdkPoint *p1 = (GdkPoint*)s1->data;
146 GList *s2 = g_list_next(s1);
148 GdkPoint *p2 = (GdkPoint*)s2->data;
149 GList *s3 = g_list_next(s2);
151 GdkPoint *p3 = (GdkPoint*)s3->data;
152 gchar ch1 = get_stroke_char(p0, p1);
153 gchar ch3 = get_stroke_char(p2, p3);
156 if((angle(p0, p1, p2) > 3*M_PI/4) && (angle(p1, p2, p3) > 3*M_PI/4))
158 s = g_list_delete_link(s, s1);
159 s = g_list_delete_link(s, s2);
164 return g_list_first(s);
167 static float find_average_and_smallest_dist(GList *s, GList **pt0, GList **pt1, float *pdmin)
169 float d = 0, dt, dmin = -1;
171 for(; s != g_list_last(s); s = g_list_next(s), i++)
173 GdkPoint *p0 = (GdkPoint*)s->data;
174 GdkPoint *p1 = (GdkPoint*)g_list_next(s)->data;
176 if((dmin < 0) || (dmin > dt))
180 *pt1 = g_list_next(s);
188 /* let A, B be consecutive points
189 * if dist(A,B) less than a certain percentage of average dist
191 static GList* filter_points_by_dist(GList *s)
193 if(g_list_length(s) < 3)
195 const float MAX_MIN_DIST = 0.2;
197 GList *pt0 = 0, *pt1 = 0;
200 if(g_list_length(s) < 3)
202 d0 = MAX_MIN_DIST*find_average_and_smallest_dist(s, &pt0, &pt1, &dmin);
208 else if(pt1 == g_list_last(s))
212 GdkPoint *p0 = (GdkPoint*)pt0->data;
213 GdkPoint *p01 = (GdkPoint*)g_list_previous(pt0)->data;
214 GdkPoint *p1 = (GdkPoint*)pt1->data;
215 GdkPoint *p11 = (GdkPoint*)g_list_next(pt1)->data;
216 float d0 = dist(p0, p01);
217 float d1 = dist(p1, p11);
223 s = g_list_delete_link(s, del);
228 return g_list_first(s);
231 gchar *get_stroke_str(GList *s)
233 gchar *ret = calloc(g_list_length(s), sizeof(gchar));
236 for(;s != g_list_last(s); s = g_list_next(s))
238 GdkPoint *p0 = (GdkPoint*)s->data;
239 GdkPoint *p1 = (GdkPoint*)g_list_next(s)->data;
240 gchar ch = get_stroke_char(p0, p1);
243 if(g_ascii_tolower(ch) != g_ascii_tolower(prev))
246 ch = g_ascii_tolower(ch);
254 gchar* recognize_stroke(GList *stroke, GList **out)
256 *out = g_list_copy(stroke);
260 len1 = g_list_length(*out);
261 //g_printf("len_orig: %d\n", g_list_length(*out));
262 *out = filter_points_by_angle(*out);
263 //g_printf("len_angle_filtered: %d\n", g_list_length(*out));
264 *out = filter_points_by_dist(*out);
265 //g_printf("len_dist_filtered: %d\n", g_list_length(*out));
266 len2 = g_list_length(*out);
269 *out = filter_points_by_angle2(*out);
270 //g_printf("len_angle2_filtered: %d\n", g_list_length(*out));
271 *out = filter_points_by_angle3(*out);
272 //g_printf("len_angle3_filtered: %d\n", g_list_length(*out));
273 len2 = g_list_length(*out);
277 return get_stroke_str(*out);