summaryrefslogtreecommitdiff
path: root/appl/lib/strokes/readstrokes.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/lib/strokes/readstrokes.b')
-rw-r--r--appl/lib/strokes/readstrokes.b205
1 files changed, 205 insertions, 0 deletions
diff --git a/appl/lib/strokes/readstrokes.b b/appl/lib/strokes/readstrokes.b
new file mode 100644
index 00000000..c42bd48c
--- /dev/null
+++ b/appl/lib/strokes/readstrokes.b
@@ -0,0 +1,205 @@
+implement Readstrokes;
+
+#
+# read structures from stroke classifier files
+#
+
+include "sys.m";
+ sys: Sys;
+
+include "bufio.m";
+ bufio: Bufio;
+ Iobuf: import bufio;
+
+include "strokes.m";
+ strokes: Strokes;
+ Classifier, Penpoint, Stroke, Region: import strokes;
+ buildstrokes: Buildstrokes;
+
+init(s: Strokes)
+{
+ sys = load Sys Sys->PATH;
+ bufio = load Bufio Bufio->PATH;
+ strokes = s;
+}
+
+getint(fp: ref Iobuf): (int, int)
+{
+ while((c := fp.getc()) == ' ' || c == '\t' || c == '\n')
+ ;
+ if(c < 0)
+ return (c, 0);
+ sign := 1;
+ if(c == '-')
+ sign = -1;
+ else if(c == '+')
+ ;
+ else
+ fp.ungetc();
+ rc := 0;
+ n := 0;
+ while((c = fp.getc()) >= '0' && c <= '9'){
+ n = n*10 + (c-'0');
+ rc = 1;
+ }
+ return (rc, n*sign);
+}
+
+getstr(fp: ref Iobuf): (int, string)
+{
+ while((c := fp.getc()) == ' ' || c == '\t' || c == '\n')
+ ;
+ if(c < 0)
+ return (c, nil);
+ fp.ungetc();
+ s := "";
+ while((c = fp.getc()) != ' ' && c != '\t' && c != '\n')
+ s[len s] = c;
+ return (0, s);
+}
+
+getpoint(fp: ref Iobuf): (int, Penpoint)
+{
+ (okx, x) := getint(fp);
+ (oky, y) := getint(fp);
+ if(okx <= 0 || oky <= 0)
+ return (-1, (0,0,0));
+ return (0, (x,y,0));
+}
+
+getpoints(fp: ref Iobuf): ref Stroke
+{
+ (ok, npts) := getint(fp);
+ if(ok <= 0 || npts < 0 || npts > 4000)
+ return nil;
+ pts := array[npts] of Penpoint;
+ for(i := 0; i < npts; i++){
+ (ok, pts[i]) = getpoint(fp);
+ if(ok < 0)
+ return nil;
+ }
+ return ref Stroke(npts, pts, 0, 0);
+}
+
+read_classifier_points(fp: ref Iobuf, nclass: int): (int, array of string, array of list of ref Stroke)
+{
+ names := array[nclass] of string;
+ examples := array[nclass] of list of ref Stroke;
+ for(k := 0; k < nclass; k++){
+ # read class name and number of examples
+ (ok, nex) := getint(fp);
+ if(ok <= 0)
+ return (-1, nil, nil);
+ (ok, names[k]) = getstr(fp);
+ if(ok < 0)
+ return (ok, nil, nil);
+
+ # read examples
+ for(i := 0; i < nex; i++){
+ pts := getpoints(fp);
+ if(pts == nil)
+ return (-1, nil, nil);
+ examples[k] = pts :: examples[k];
+ }
+ }
+ return (0, names, examples);
+}
+
+#
+# read a classifier, using its digest if that exists
+#
+read_classifier(file: string, build: int, needex: int): (string, ref Classifier)
+{
+ rc := ref Classifier;
+ l := len file;
+ digestfile: string;
+ if(l >= 4 && file[l-4:]==".clx")
+ digestfile = file;
+ else if(!needex && l >= 3 && file[l-3:]==".cl")
+ digestfile = file[0:l-3]+".clx"; # try the digest file first
+ err: string;
+ if(digestfile != nil){
+ fd := sys->open(digestfile, Sys->OREAD);
+ if(fd != nil){
+ (err, rc.cnames, rc.dompts) = read_digest(fd);
+ rc.nclasses = len rc.cnames;
+ if(rc.cnames == nil)
+ err = "empty digest file";
+ if(err == nil)
+ return (nil, rc);
+ }else
+ err = sys->sprint("%r");
+ if(!build)
+ return (sys->sprint("digest file: %s", err), nil);
+ }
+
+ if(buildstrokes == nil){
+ buildstrokes = load Buildstrokes Buildstrokes->PATH;
+ if(buildstrokes == nil)
+ return (sys->sprint("module %s: %r", Buildstrokes->PATH), nil);
+ buildstrokes->init(strokes);
+ }
+
+ fd := sys->open(file, Sys->OREAD);
+ if(fd == nil)
+ return (sys->sprint("%r"), nil);
+ (emsg, cnames, examples) := read_examples(fd);
+ if(emsg != nil)
+ return (emsg, nil);
+ rc.nclasses = len cnames;
+ (err, rc.canonex, rc.dompts) = buildstrokes->canonical_example(rc.nclasses, cnames, examples);
+ if(err != nil)
+ return ("failed to calculate canonical examples", nil);
+ rc.cnames = cnames;
+ if(needex)
+ rc.examples = examples;
+
+ return (nil, rc);
+}
+
+read_examples(fd: ref Sys->FD): (string, array of string, array of list of ref Strokes->Stroke)
+{
+ fp := bufio->fopen(fd, Bufio->OREAD);
+ (ok, nclasses) := getint(fp);
+ if(ok <= 0)
+ return ("missing number of classes", nil, nil);
+ (okc, cnames, examples) := read_classifier_points(fp, nclasses);
+ if(okc < 0)
+ return ("couldn't read examples", nil, nil);
+ return (nil, cnames, examples);
+}
+
+#
+# attempt to read the digest of a classifier,
+# and return its contents if successful;
+# return a diagnostic if not
+#
+read_digest(fd: ref Sys->FD): (string, array of string, array of ref Stroke)
+{
+ # Read-in the name and dominant points for each class.
+ fp := bufio->fopen(fd, Bufio->OREAD);
+ cnames := array[32] of string;
+ dompts := array[32] of ref Stroke;
+ for(nclasses := 0;; nclasses++){
+ if(nclasses >= len cnames){
+ a := array[nclasses+32] of string;
+ a[0:] = cnames;
+ cnames = a;
+ b := array[nclasses+32] of ref Stroke;
+ b[0:] = dompts;
+ dompts = b;
+ }
+ (okn, class) := getstr(fp);
+ if(okn == Bufio->EOF)
+ break;
+ if(class == nil)
+ return ("expected class name", nil, nil);
+ cnames[nclasses] = class;
+ dpts := getpoints(fp);
+ if(dpts == nil)
+ return ("bad points list", nil, nil);
+ strokes->compute_chain_code(dpts);
+ dompts[nclasses] = dpts;
+ }
+ return (nil, cnames[0:nclasses], dompts[0:nclasses]);
+}