2 libstroke - a stroke interface library
3 Copyright (c) 1996,1997,1998,1999,2000 Mark F. Willey, ETLA Technical
5 Permission is hereby granted, free of charge, to any person obtaining
6 a copy of this software and associated documentation files (the
7 "Software"), to deal in the Software, including the rights to use, copy,
8 modify, merge, publish, and distribute copies of the Software, and to
9 permit persons to whom the Software is furnished to do so, subject to
10 the following conditions:
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 as published by the Free Software Foundation; version 2.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 The above copyright notice and this permission notice shall be included
26 in all copies or substantial portions of the Software.
28 See the file "LICENSE" for a copy of the GNU GPL terms.
30 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
31 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
33 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
34 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
35 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
36 OTHER DEALINGS IN THE SOFTWARE.
38 Except as contained in this notice, the name of the author shall
39 name be used in advertising or otherwise to promote the sale, use or
40 other dealings in this Software without prior written authorization
43 Non-GPL commercial use licenses are available - contact copyright holder.
45 Author: Mark F. Willey -- willey@etla.net
64 /* structure for holding point data */
65 typedef struct s_point
*p_point
;
73 /* point list head and tail */
74 static p_point point_list_head
;
75 static p_point point_list_tail
;
79 /* determine which bin a point falls in */
80 static int stroke_bin (p_point point_p
, int bound_x_1
, int bound_x_2
,
81 int bound_y_1
, int bound_y_2
);
85 /* point list head and tail */
86 static p_point point_list_head
=NULL
;
87 static p_point point_list_tail
=NULL
;
89 /* metrics fo input stroke */
90 static int min_x
= 10000;
91 static int min_y
= 10000;
92 static int max_x
= -1;
93 static int max_y
= -1;
94 static int point_count
= 0;
96 static void init_stroke_data (void)
98 while (point_list_head
!= NULL
) {
99 point_list_tail
= point_list_head
;
100 point_list_head
= point_list_head
->next
;
101 free (point_list_tail
);
103 point_list_tail
= NULL
;
106 void stroke_init (void)
113 int stroke_trans (char *sequence
)
115 /* number of bins recorded in the stroke */
116 int sequence_count
= 0;
118 /* points-->sequence translation scratch variables */
123 /* flag indicating the start of a stroke - always count it in the sequence */
124 int first_bin
= TRUE
;
126 /* bin boundary and size variables */
127 int delta_x
, delta_y
;
128 int bound_x_1
, bound_x_2
;
129 int bound_y_1
, bound_y_2
;
131 /* determine size of grid */
132 delta_x
= max_x
- min_x
;
133 delta_y
= max_y
- min_y
;
135 /* calculate bin boundary positions */
136 bound_x_1
= min_x
+ (delta_x
/ 3);
137 bound_x_2
= min_x
+ 2 * (delta_x
/ 3);
139 bound_y_1
= min_y
+ (delta_y
/ 3);
140 bound_y_2
= min_y
+ 2 * (delta_y
/ 3);
142 if (delta_x
> STROKE_SCALE_RATIO
* delta_y
) {
143 bound_y_1
= (max_y
+ min_y
- delta_x
) / 2 + (delta_x
/ 3);
144 bound_y_2
= (max_y
+ min_y
- delta_x
) / 2 + 2 * (delta_x
/ 3);
145 } else if (delta_y
> STROKE_SCALE_RATIO
* delta_x
) {
146 bound_x_1
= (max_x
+ min_x
- delta_y
) / 2 + (delta_y
/ 3);
147 bound_x_2
= (max_x
+ min_x
- delta_y
) / 2 + 2 * (delta_y
/ 3);
151 printf ("DEBUG:: point count: %d\n",point_count);
152 printf ("DEBUG:: min_x: %d\n",min_x);
153 printf ("DEBUG:: max_x: %d\n",max_x);
154 printf ("DEBUG:: min_y: %d\n",min_y);
155 printf ("DEBUG:: max_y: %d\n",max_y);
156 printf ("DEBUG:: delta_x: %d\n",delta_x);
157 printf ("DEBUG:: delta_y: %d\n",delta_y);
158 printf ("DEBUG:: bound_x_1: %d\n",bound_x_1);
159 printf ("DEBUG:: bound_x_2: %d\n",bound_x_2);
160 printf ("DEBUG:: bound_y_1: %d\n",bound_y_1);
161 printf ("DEBUG:: bound_y_2: %d\n",bound_y_2);
165 build string by placing points in bins, collapsing bins and
166 discarding those with too few points...
169 while (point_list_head
!= NULL
) {
171 /* figure out which bin the point falls in */
172 current_bin
= stroke_bin(point_list_head
,bound_x_1
, bound_x_2
,
173 bound_y_1
, bound_y_2
);
174 /* if this is the first point, consider it the previous bin,
176 prev_bin
= (prev_bin
== 0) ? current_bin
: prev_bin
;
177 /* printf ("DEBUG:: current bin: %d\n",current_bin); */
179 if (prev_bin
== current_bin
)
181 else { /* we are moving to a new bin -- consider adding to the
183 if ((bin_count
> (point_count
* STROKE_BIN_COUNT_PERCENT
))
184 || (first_bin
== TRUE
)) {
186 sequence
[sequence_count
++] = '0' + prev_bin
;
187 /* printf ("DEBUG:: adding sequence: %d\n",prev_bin);
191 /* restart counting points in the new bin */
193 prev_bin
= current_bin
;
196 /* move to next point, freeing current point from list */
197 point_list_tail
= point_list_head
;
198 point_list_head
= point_list_head
->next
;
199 free (point_list_tail
);
201 point_list_tail
= NULL
;
203 /* add the last run of points to the sequence */
204 sequence
[sequence_count
++] = '0' + current_bin
;
205 /* printf ("DEBUG:: adding final sequence: %d\n",current_bin); */
207 /* bail out on error cases */
208 if ((point_count
< STROKE_MIN_POINTS
)
209 || (sequence_count
> STROKE_MAX_SEQUENCE
)) {
211 strcpy (sequence
,"0");
215 /* add null termination and leave */
217 sequence
[sequence_count
] = '\0';
221 /* figure out which bin the point falls in */
222 static int stroke_bin (p_point point_p
, int bound_x_1
, int bound_x_2
,
223 int bound_y_1
, int bound_y_2
)
226 if (point_p
->x
> bound_x_1
) bin_num
+= 1;
227 if (point_p
->x
> bound_x_2
) bin_num
+= 1;
228 if (point_p
->y
> bound_y_1
) bin_num
+= 3;
229 if (point_p
->y
> bound_y_2
) bin_num
+= 3;
234 void stroke_record (int x
, int y
)
240 if (point_count
< STROKE_MAX_POINTS
) {
241 new_point_p
= (p_point
) malloc (sizeof(struct s_point
));
243 if (point_list_tail
== NULL
) {
245 /* first point in list - initialize list and metrics */
246 point_list_head
= point_list_tail
= new_point_p
;
254 /* interpolate between last and current point */
255 delx
= x
- point_list_tail
->x
;
256 dely
= y
- point_list_tail
->y
;
258 /* step by the greatest delta direction */
259 if (abs(delx
) > abs(dely
)) {
260 iy
= point_list_tail
->y
;
262 /* go from the last point to the current, whatever direction it
264 for (ix
= point_list_tail
->x
;
265 (delx
> 0) ? (ix
< x
) : (ix
> x
);
266 ix
+= (delx
> 0) ? 1 : -1) {
268 /* step the other axis by the correct increment */
269 iy
+= fabs(((float) dely
270 / (float) delx
)) * (float) ((dely
< 0) ? -1.0 : 1.0);
272 /* add the interpolated point */
273 point_list_tail
->next
= new_point_p
;
274 point_list_tail
= new_point_p
;
277 new_point_p
->next
= NULL
;
280 if (((int) ix
) < min_x
) min_x
= (int) ix
;
281 if (((int) ix
) > max_x
) max_x
= (int) ix
;
282 if (((int) iy
) < min_y
) min_y
= (int) iy
;
283 if (((int) iy
) > max_y
) max_y
= (int) iy
;
286 new_point_p
= (p_point
) malloc (sizeof(struct s_point
));
288 } else { /* same thing, but for dely larger than delx case... */
289 ix
= point_list_tail
->x
;
291 /* go from the last point to the current, whatever direction
293 for (iy
= point_list_tail
->y
; (dely
> 0) ? (iy
< y
) : (iy
> y
);
294 iy
+= (dely
> 0) ? 1 : -1) {
296 /* step the other axis by the correct increment */
297 ix
+= fabs(((float) delx
/ (float) dely
))
298 * (float) ((delx
< 0) ? -1.0 : 1.0);
300 /* add the interpolated point */
301 point_list_tail
->next
= new_point_p
;
302 point_list_tail
= new_point_p
;
305 new_point_p
->next
= NULL
;
308 if (((int) ix
) < min_x
) min_x
= (int) ix
;
309 if (((int) ix
) > max_x
) max_x
= (int) ix
;
310 if (((int) iy
) < min_y
) min_y
= (int) iy
;
311 if (((int) iy
) > max_y
) max_y
= (int) iy
;
314 new_point_p
= (p_point
) malloc (sizeof(struct s_point
));
318 /* add the sampled point */
319 point_list_tail
->next
= new_point_p
;
320 point_list_tail
= new_point_p
;
323 /* record the sampled point values */
326 new_point_p
->next
= NULL
;