1 /* @(#)psdit.c 1.6 04/03/89 */
2 #ifndef lint
3 static char Notice[] = "Copyright (c) 1984, 1985 Adobe Systems Incorporated";
4 static char *RCSID = "$Header: psdit.c,v 2.1 85/11/24 11:50:41 shore Rel $";
5 #endif
6 # define XMOD
7 /*
8 * Changed by Edward Wang (edward@ucbarpa.berkeley.edu) to handle graphics,
9 * 17 Feb, 87, with code provided by John Coker (john@renoir.berkeley.edu)
10 * and Peehong Chen (phc@renoir.berkeley.edu).
11 */
12 /* psdit.c
13 *
14 * Copyright (c) 1984, 1985 Adobe Systems Incorporated
15 *
16 * ditroff intermediate file to PostScript translator
17 *
18 * Original Version: Barry Hayes spring/summer 1984
19 * Edit History:
20 * Andrew Shore: Sat Nov 23 20:05:26 1985
21 * End Edit History.
22 *
23 * RCSLOG:
24 * $Log: psdit.c,v $
25 * Revision 2.1 85/11/24 11:50:41 shore
26 * Product Release 2.0
27 *
28 * Revision 1.8 85/11/23 20:09:44 shore
29 * test for termination of included PostScript was bad
30 *
31 * Revision 1.7 85/11/21 14:23:56 shore
32 * added envget check for PSLIBDIR
33 *
34 * Revision 1.6 85/11/20 00:43:43 shore
35 * support for included PostScript
36 * big rework on FlushShow, word "breaks"
37 * removed FlushFont and made them instant
38 * Still no Gremlin support yet
39 *
40 * Revision 1.5 85/10/03 10:48:09 shore
41 * added FlushShow to xf fix !
42 *
43 * Revision 1.4 85/10/02 16:20:32 shore
44 * fixed xf bug
45 * mounting a font causes a font switch!
46 *
47 * Revision 1.3 85/07/09 13:10:20 shore
48 * added fclose on map file
49 *
50 * Revision 1.2 85/05/14 11:24:23 shore
51 * added flush to trailer
52 * fixed read bug when mounting fonts
53 */
54
55 /*
56 output language from troff:
57 all numbers are character strings
58
59 sn size in points
60 fn font as number from 1-n
61 cx ascii character x
62 Cxyz funny char xyz. terminated by white space
63 Hn go to absolute horizontal position n
64 Vn go to absolute vertical position n (down is positive)
65 hn go n units horizontally (relative)
66 vn ditto vertically
67 nnc move right nn, then print c (exactly 2 digits!)
68 (this wart is an optimization that shrinks output file size
69 about 35% and run-time about 15% while preserving ascii-ness)
70 Dt ...\n draw operation 't':
71 Dl x y line from here by x,y
72 Dc d circle of diameter d with left side here
73 De x y ellipse of axes x,y with left side here
74 Da x y r arc counter-clockwise by x,y of radius r
75 Dp ... bordered polygon
76 DP ... unbordered polygon
77 D~ x y x y ... b-spline by x,y then x,y ...
78 Dg ... gremlin curve
79 Dz ... bezier curve
80 nb a end of line (information only -- no action needed)
81 a = space before line, a = after
82 w paddable word space -- no action needed
83 pn new page begins -- set v to 0
84 { push current environment (font info & location)
85 } pop a saved environment
86 txxxx print string xxxx using natural widths
87 #...\n comment
88 x ...\n device control functions:
89 x i[nit] init
90 x T s name of device is s
91 x r[es] n h v resolution is n/inch
92 h = min horizontal motion, v = min vert
93 x p[ause] pause (can restart)
94 x s[top] stop -- done for ever
95 x t[railer] generate trailer
96 x f[font] n s font position n contains font s
97 x H[eight] n set character height to n
98 x S[slant] n set slant to N
99
100 Adobe Extension for included PostScript:
101 %
102 (raw postscript...)
103 .\n
104
105 */
106
107 #include <stdio.h>
108 #include <ctype.h>
109 #include <signal.h>
110 #include <pwd.h>
111 #ifdef SYSV
112 extern struct passwd *getpwuid();
113 #endif
114 #include "transcript.h"
115
116 #include "dev.h"
117
118 char *malloc();
119
120 #define NFONT 10
121
122 /* DIT state consists of: */
123 int hpos; /* current horizontal position */
124 int vpos; /* current vertical position */
125 int fontsize; /* current font size */
126 int fontheight; /* current character height */
127 int fontslant; /* current font slant */
128 int font; /* current font */
129 int resolution; /* device resolution */
130 int minhoriz; /* minimum horizontal motion */
131 int minvert; /* minimum vertical motion */
132 int stipplefont; /* current stipple font */
133
134 int onspecial;
135 int specfont;
136 int prevfont;
137 int pfont;
138
139 /* {} push/pop stack */
140 #define DSTACK 10
141 struct ditstack {
142 int hpos, vpos, fontsize, fontheight, fontslant, font;
143 } ditstack[DSTACK];
144 int dlevel = 0;
145
146 #define ErrorTolerance 48
147 #define PSWID 0x00000FFF
148 #define ISPSPROC 0x000FF000
149
150 /* PSscale is equivalent to (x * PSmag / 72000) + 0.5 */
151 #define PSmag 16
152 #define PSscale(x) (((x) + 2250) / 4500)
153
154 /* we maintain PS coords with PSmag times the precision */
155 /* current PS state is: */
156
157 int PSx; /* current horizontal position */
158 int PSy; /* current vertical position */
159 int savex, savey; /* position of start of current show string */
160
161 /* ps move types -- note that XMOVE|YMOVE == XYMOVE ! */
162 #define NONE 0
163 #define XMOVE 1
164 #define YMOVE 2
165 #define XYMOVE 3
166
167 int movepending = NONE;
168
169 /* buffer string for show -- save up adjacent chars */
170 #define SHOWSIZE 400
171 char showbuf[SHOWSIZE + 3]; /* extras are for quoting */
172 int showind = 0; /* index into string of next available byte */
173 int PSshowlen = 0; /* size in big units of buffered string */
174 int nshow = 0; /* actual number of show chars in showbuf */
175 int startx; /* troff starting pos of current string */
176 int thisw;
177
178 /* #define NONE 0 */
179 #define HMOT 1
180 #define VMOT 2
181 #define CPUT 4
182 #define BRK 8
183 #define FNT 16
184 int lastcmd;
185
186 int output = 0; /* do we do output at all? */
187 int nolist = 0; /* output page list if > 0 */
188 int olist[20]; /* pairs of page numbers */
189 int spage = 9999; /* stop every spage pages */
190 int scount = 0;
191 int stopped = 0;
192 int pageno = 0;
193 int firstpage = TRUE;
194
195 struct dev dev;
196 struct font *fontbase[NFONT+1];
197 short *pstab;
198 int dres; /* resolution from DESC */
199 int nsizes; /* number of point sizes from DESC */
200 int nfonts; /* number of fonts from DESC */
201 int smnt; /* index of first special font */
202 int nchtab;
203 char *chname;
204 short *chtab;
205 char *fitab[NFONT+1];
206 char *widthtab[NFONT+1]; /* widtab would be a better name */
207 char *codetab[NFONT+1]; /* device codes */
208
209 int *pswidths[NFONT+1]; /* ps width tables */
210 int fontdelta[NFONT+1]; /* nonzero if xf overwrites font i */
211
212 /* font position info: */
213 struct {
214 char *name;
215 int number;
216 } fontname[NFONT+1];
217
218 #define FATAL 1
219 #define BMASK 0377
220
221 #ifdef DEBUG
222 int dbg = 0;
223 int fdbg = 0;
224 #define debugp(xxx) (dbg != 0 ? (dbg--, printf xxx, fflush(stdout)) : 0)
225 #else
226 #define debugp(x)
227 #endif
228
229 char devname[20] = "psc";
230
231 char *infilename = "stdin"; /* input file name */
232 char *prologfile = PSDITPRO;
233 char *ditdir = DitDir;
234
235 char *prog; /* argv[0] - program name */
236
237 /* for curve and polygon drawing */
238 #define MAXPOINTS 200
239 double x[MAXPOINTS], y[MAXPOINTS];
240 int numpoints;
241
main(argc,argv)242 main(argc, argv)
243 int argc;
244 char *argv[];
245 {
246 FILE *fp;
247 int done();
248
249 prog = argv[0];
250 while (argc > 1 && argv[1][0] == '-') {
251 switch (argv[1][1]) {
252 case 'f':
253 case 'F':
254 if (argv[1][2])
255 ditdir = &argv[1][2];
256 else {
257 ditdir = argv[2];
258 argv++;
259 argc--;
260 }
261 break;
262 case 'p':
263 if (argv[1][2])
264 prologfile = &argv[1][2];
265 break;
266 case 'o':
267 outlist(&argv[1][2]);
268 break;
269 case 'd':
270 #ifdef DEBUG
271 dbg = atoi(&argv[1][2]);
272 if (dbg == 0)
273 dbg = 1;
274 #endif DEBUG
275 break;
276 case 'b': /* ignore busy */
277 break;
278 case 'w': /* ignore wait */
279 break;
280 case 's':
281 spage = atoi(&argv[1][2]);
282 if (spage <= 0)
283 spage = 9999;
284 break;
285 }
286 argc--;
287 argv++;
288 }
289
290 if (signal(SIGINT, done) == SIG_IGN) {
291 signal(SIGINT, SIG_IGN);
292 signal(SIGQUIT, SIG_IGN);
293 signal(SIGHUP, SIG_IGN);
294 } else {
295 signal(SIGQUIT, done);
296 signal(SIGHUP, done);
297 }
298 signal(SIGTERM, done);
299
300 preface();
301
302 if (argc <= 1)
303 conv(stdin);
304 else
305 while (--argc > 0) {
306 if (strcmp(*++argv, "-") == 0)
307 fp = stdin;
308 else if ((fp = fopen(*argv, "r")) == NULL) {
309 fprintf(stderr, "%s: can't open %s\n",
310 prog, *argv);
311 pexit(prog, 2);
312 }
313 infilename = *argv;
314 conv(fp);
315 (void) fclose(fp);
316 }
317 done();
318 }
319
320 /* process list of page numbers to be printed */
outlist(s)321 outlist(s)
322 register char *s;
323 {
324 int n1, n2, i;
325
326 nolist = 0;
327 while (*s) {
328 n1 = 0;
329 if (isdigit (*s))
330 do
331 n1 = 10 * n1 + *s++ - '0';
332 while (isdigit(*s));
333 else
334 n1 = -9999;
335 n2 = n1;
336 if (*s == '-') {
337 s++;
338 n2 = 0;
339 if (isdigit(*s))
340 do
341 n2 = 10 * n2 + *s++ - '0';
342 while (isdigit(*s));
343 else
344 n2 = 9999;
345 }
346 olist[nolist++] = n1;
347 olist[nolist++] = n2;
348 if (*s != '\0')
349 s++;
350 }
351 olist[nolist] = 0;
352 #ifdef DEBUG
353 if (dbg)
354 for (i = 0; i < nolist; i += 2)
355 printf("%3d %3d\n", olist[i], olist[i + 1]);
356 #endif
357 }
358
conv(fp)359 conv(fp) /* convert a file */
360 register FILE *fp;
361 {
362 register int c, k;
363 int m, n, n1, m1;
364 char str[100], buf[1024];
365
366 while ((c = getc(fp)) != EOF)
367 switch (c) {
368 case '\n': case ' ': case '\0':
369 break;
370 case '{': /* push down current environment */
371 t_push();
372 break;
373 case '}':
374 t_pop();
375 break;
376 case '0': case '1': case '2': case '3': case '4':
377 case '5': case '6': case '7': case '8': case '9':
378 /* two motion digits plus a character */
379 hmot((c - '0') * 10 + getc(fp) - '0');
380 lastcmd = HMOT;
381 put1(getc(fp), (char *) 0);
382 lastcmd = CPUT;
383 break;
384 case 'c': /* single ascii character */
385 put1(getc(fp), (char *) 0);
386 lastcmd = CPUT;
387 break;
388 case 'C':
389 fscanf(fp, "%s", str);
390 put1s(str);
391 lastcmd = CPUT;
392 break;
393 case 't': /* straight text */
394 fgets(buf, sizeof buf, fp);
395 t_text(buf);
396 lastcmd = CPUT;
397 break;
398 case 'D': /* draw function */
399 fgets(buf, sizeof buf, fp);
400 switch (buf[0]) {
401 case 'l': /* draw a line */
402 sscanf(buf + 1, "%d %d", &n, &m);
403 drawline(n, m);
404 break;
405 case 'c': /* circle */
406 sscanf(buf + 1, "%d", &n);
407 drawcirc(n);
408 break;
409 case 'e': /* ellipse */
410 sscanf(buf + 1, "%d %d", &m, &n);
411 drawellip(m, n);
412 break;
413 case 'a': /* arc */
414 sscanf(buf + 1, "%d %d %d %d",
415 &n, &m, &n1, &m1);
416 drawarc(n, m, n1, m1);
417 break;
418 case '~': /* b-spline */
419 case 'g': /* gremlin curve */
420 case 'z': /* bezier cubic */
421 drawcurve(buf);
422 break;
423 case 'p': /* filled polygon */
424 case 'P': /* bordered filled polygon */
425 drawpoly(buf);
426 break;
427 case 't': /* line thickness */
428 case 's': /* line style */
429 sscanf(buf + 1, "%d", &n);
430 printf("%d D%c\n", n, buf[0]);
431 break;
432 default:
433 fprintf(stderr,
434 "%s: unknown drawing function %s\n",
435 prog, buf);
436 exit(2);
437 }
438 break;
439 case 'i':
440 fscanf(fp, "%d", &stipplefont);
441 printf("%d i\n", stipplefont);
442 break;
443 case 's':
444 fscanf(fp, "%d", &n);
445 t_size(n);
446 lastcmd = FNT;
447 break;
448 case 'f':
449 fscanf(fp, "%s", str);
450 setfont(t_font(str));
451 lastcmd = FNT;
452 break;
453 case 'H': /* absolute horizontal motion */
454 while ((c = getc(fp)) == ' ')
455 ;
456 k = 0;
457 do
458 k = 10 * k + c - '0';
459 while (isdigit(c = getc(fp)));
460 ungetc(c, fp);
461 hgoto(k);
462 lastcmd = HMOT;
463 break;
464 case 'h': /* relative horizontal motion */
465 while ((c = getc(fp)) == ' ')
466 ;
467 k = 0;
468 do
469 k = 10 * k + c - '0';
470 while (isdigit(c = getc(fp)));
471 ungetc(c, fp);
472 hmot(k);
473 lastcmd = HMOT;
474 break;
475 case 'w':
476 FlushShow(1);
477 lastcmd = BRK;
478 break;
479 case 'V':
480 fscanf(fp, "%d", &n);
481 vgoto(n);
482 lastcmd = VMOT;
483 break;
484 case 'v':
485 fscanf(fp, "%d", &n);
486 vmot(n);
487 lastcmd = VMOT;
488 break;
489 case 'p': /* new page */
490 fscanf(fp, "%d", &n);
491 t_page(n);
492 lastcmd = NONE;
493 break;
494 case 'n': /* end of line -- ignore */
495 while (getc(fp) != '\n')
496 ;
497 FlushShow(1);
498 lastcmd = BRK;
499 break;
500 case '#': /* comment */
501 /* maybe should pass through as a PS comment */
502 while (getc(fp) != '\n')
503 ;
504 break;
505 case 'x': /* device control */
506 devcntrl(fp);
507 break;
508 case '%': /* imbedded PostScript */
509 /* copy everything up to but NOT including a line */
510 /* with at single "." */
511 FlushShow(0);
512 MoveTo();
513 DoMove();
514 printf("\n%% included PostScript\n");
515 while (fgets(buf, sizeof buf, fp) != NULL) {
516 if (strcmp(".\n", buf) == 0)
517 break;
518 fputs(buf, stdout);
519 }
520 break;
521 default:
522 fprintf(stderr, "%s: bad input char \\%03o (%c)\n",
523 prog, c, c);
524 exit(2);
525 }
526 }
527
528 /* put in PostScript prolog */
preface()529 preface()
530 {
531 register FILE *prolog;
532 char hostname[256];
533 char tempfile[512];
534 struct passwd *pswd;
535 long clock;
536 char *libdir;
537
538 printf("%%!%s\n", COMMENTVERSION);
539 pswd = getpwuid(getuid());
540 (void) gethostname(hostname, sizeof hostname);
541 printf("%%%%Creator: %s:%s (%s)\n", hostname,
542 pswd->pw_name, pswd->pw_gecos);
543 printf("%%%%Title: %s (ditroff)\n", infilename);
544 printf("%%%%CreationDate: %s", (time(&clock), ctime(&clock)));
545 printf("%%%%EndComments\n");
546 if ((libdir = envget("PSLIBDIR")) == NULL)
547 libdir = LibDir;
548 mstrcat(tempfile, libdir, prologfile, sizeof tempfile);
549 if (copyfile(tempfile, stdout) != 0) {
550 fprintf(stderr, "%s: can't copy prolog file %s\n",
551 prog, tempfile);
552 exit(2);
553 }
554 printf("ditstart\n");
555 }
556
devcntrl(fp)557 devcntrl(fp) /* interpret device control functions */
558 FILE *fp;
559 {
560 char str[20], str1[50], buf[50];
561 int c, n, res, minh, minv;
562
563 fscanf(fp, "%s", str);
564 switch (str[0]) { /* crude for now */
565 case 'i': /* initialize */
566 fileinit();
567 t_init();
568 lastcmd = NONE;
569 break;
570 case 'T': /* device name */
571 /*
572 fscanf(fp, "%s", devname);
573 if (strcmp(devname, "psc")) {
574 fprintf(stderr, "%s: device not psc\n", prog);
575 exit(2);
576 }
577 */
578 printf("(%s)xT\n", devname);
579 lastcmd = NONE;
580 break;
581 case 't': /* trailer */
582 t_trailer();
583 lastcmd = NONE;
584 break;
585 case 'p': /* pause -- can restart */
586 t_reset('p');
587 lastcmd = NONE;
588 break;
589 case 's': /* stop */
590 t_reset('s');
591 lastcmd = NONE;
592 break;
593 case 'r': /* resolution assumed when prepared */
594 fscanf(fp, "%d %d %d", &res, &minh, &minv);
595 t_res(res, minh, minv);
596 lastcmd = NONE;
597 break;
598 case 'f': /* font used */
599 fscanf(fp, "%d %s", &n, str);
600 fgets(buf, sizeof buf, fp); /* in case theres a filename */
601 ungetc('\n', fp); /* fgets goes too far */
602 str1[0] = 0; /* in case there is nothing to come in */
603 sscanf(buf, "%s", str1);
604 loadfont(n, str, str1);
605 lastcmd = FNT;
606 break;
607 case 'H': /* char height */
608 fscanf(fp, "%d", &n);
609 t_charht(n);
610 lastcmd = FNT;
611 break;
612 case 'S': /* slant */
613 fscanf(fp, "%d", &n);
614 t_slant(n);
615 lastcmd = FNT;
616 break;
617 #ifdef XMOD
618 case 'X': { /* \X command from ditroff */
619 int last;
620 char largebuf[128];
621 fscanf (fp, "%1s", str);
622 switch (str[0]) {
623 case 'p' :
624 FlushShow(0);MoveTo();DoMove();
625 fgets(largebuf, sizeof(largebuf), fp);
626 last = strlen(largebuf) - 1;
627 if (last >= 0 && largebuf[last] == '\n') {
628 ungetc('\n', fp);
629 largebuf[last] = ' ';
630 }
631 puts(largebuf);
632 break;
633 case 'f' :
634 FlushShow(0);MoveTo();DoMove();
635 if (fscanf(fp, "%s", largebuf) == 1) {
636 char *nl = (char *) index(largebuf, '\n');
637 if (nl) *nl = '\0';
638 includefile(largebuf);
639 } else
640 fprintf(stderr, "warning - include cmd w/o path.\n");
641 break;
642 }
643 }
644 break;
645 #endif
646 }
647 /* skip rest of input line */
648 while ((c = getc(fp)) != '\n' && c != EOF)
649 ;
650 }
651
652 #ifdef XMOD
includefile(filenm)653 includefile(filenm)
654 char *filenm;
655 {
656 FILE *inf;
657 int ch, c1, c2, firstch = 0;
658
659 if (!(inf = fopen(filenm, "r"))) {
660 fprintf(stderr, "psdit: fopen(%s): ", filenm);
661 perror();
662 exit(1);
663 }
664 c1 = fgetc(inf); c2 = fgetc(inf);
665 if (c1 != '%' || c2 != '!')
666 fprintf(stderr, "psdit: %s not a postscript file.\n", filenm),
667 exit(1);
668
669 fputs("%!", stdout);
670 while ((ch = fgetc(inf)) != EOF) {
671 putchar(ch);
672 if (firstch && ch == '%') {
673 /* we have to double leading '%'s */
674 putchar('%');
675 }
676 firstch = (ch == '\n');
677 }
678 fclose(inf);
679 }
680 #endif
681
fileinit()682 fileinit() /* read in font and code files, etc. */
683 {
684 int i, fin, nw;
685 char *filebase, *p;
686 char temp[60];
687 unsigned msize;
688
689 /*
690 * Open table for device,
691 * read in resolution, size info, font info, etc., and set params.
692 */
693 sprintf(temp, "%s/dev%s/DESC.out", ditdir, devname);
694 if ((fin = open(temp, 0)) < 0) {
695 fprintf(stderr, "%s: can't open %s - %s\n",
696 prog, devname, temp);
697 pexit(prog, 2);
698 }
699 if (read(fin, (char *) &dev, sizeof (struct dev)) !=
700 sizeof (struct dev)) {
701 fprintf(stderr, "%s: can't read %s\n", prog, temp);
702 pexit(prog, 2);
703 }
704 dres = dev.res;
705 nfonts = dev.nfonts;
706 nsizes = dev.nsizes;
707 nchtab = dev.nchtab;
708 /* enough room for whole file */
709 filebase = malloc((unsigned) dev.filesize);
710 if (read(fin, filebase, dev.filesize) != dev.filesize) {
711 fprintf(stderr, "%s: trouble reading %s\n", prog, temp);
712 pexit(prog, 2);
713 }
714 pstab = (short *) filebase; /* point size table */
715 chtab = pstab + nsizes + 1; /* char index table */
716 chname = (char *) (chtab + dev.nchtab); /* char name table */
717 p = chname + dev.lchname; /* end of char name table */
718 /* parse the preloaded font tables */
719 for (i = 1; i <= nfonts; i++) {
720 fontdelta[i] = 0;
721 fontbase[i] = (struct font *) p;
722 nw = *p & BMASK; /* number of width entries */
723 if ((smnt == 0) && (fontbase[i]->specfont == 1))
724 smnt = i; /* first special font */
725 p += sizeof (struct font); /* skip header */
726 widthtab[i] = p; /* width table */
727 /* kern table is next */
728 codetab[i] = p + 2 * nw; /* device codes */
729 fitab[i] = p + 3 * nw; /* font index table */
730 p += 3 * nw + dev.nchtab + (128 - 32); /* next font */
731 t_fp(i, fontbase[i]->namefont, fontbase[i]->intname);
732 loadpswidths(i, fontbase[i]->namefont);
733 sayload(i, fontbase[i]->namefont, (char *) 0);
734 #ifdef DEBUG
735 if (fdbg > 1)
736 fontprint(i);
737 #endif
738 }
739 fontdelta[0] = 0;
740 msize = 3*255 + dev.nchtab + (128 - 32) + sizeof (struct font);
741 fontbase[0] = (struct font *) malloc(msize);
742 widthtab[0] = (char *) fontbase[0] + sizeof (struct font);
743 fontbase[0]->nwfont = 255;
744 close(fin);
745 }
746
loadpswidths(i,name)747 loadpswidths(i, name)
748 int i;
749 char *name;
750 {
751 char temp[60];
752 register FILE *auxin;
753 register int j;
754 int cc, wid, funny;
755
756 sprintf(temp, "%s/dev%s/%s.aux", ditdir, devname, name);
757 auxin = fopen(temp, "r");
758 /* allocate table */
759 if (pswidths[i] == NULL)
760 pswidths[i] = (int *) malloc(256 * (sizeof (int)));
761 /* initialize to not-there */
762 for (j = 0; j <= 255; pswidths[i][j++] = -1)
763 ;
764 /* read them in */
765 while (fscanf(auxin, "%d %d %d", &cc, &wid, &funny) != EOF)
766 pswidths[i][cc] = wid | (funny << 12);
767 (void) fclose(auxin);
768 }
769
770 #ifdef DEBUG
fontprint(i)771 fontprint(i) /* debugging print of font i (0, ...) */
772 int i;
773 {
774 int j, n;
775 char *p;
776
777 printf("font %d:\n", i);
778 p = (char *) fontbase[i];
779 n = fontbase[i]->nwfont & BMASK;
780 printf("base=0%o, nchars=%d, spec=%d, name=%s, widtab=0%o, fitab=0%o\n",
781 p, n, fontbase[i]->specfont,
782 fontbase[i]->namefont, widthtab[i], fitab[i]);
783 printf("widths:\n");
784 for (j = 0; j <= n; j++) {
785 printf(" %2d", widthtab[i][j] & BMASK);
786 if (j % 20 == 19)
787 printf("\n");
788 }
789 printf("\ncodetab:\n");
790 for (j = 0; j <= n; j++) {
791 printf(" %2d", codetab[i][j] & BMASK);
792 if (j % 20 == 19)
793 printf("\n");
794 }
795 printf("\nfitab:\n");
796 for (j = 0; j <= dev.nchtab + 128 - 32; j++) {
797 printf(" %2d", fitab[i][j] & BMASK);
798 if (j % 20 == 19)
799 printf("\n");
800 }
801 printf("\n");
802 }
803 #endif
804
loadfont(n,s,s1)805 loadfont(n, s, s1) /* load font info for font s on position n */
806 int n;
807 char *s, *s1;
808 {
809 char temp[60];
810 int fin, nw, norig;
811 int bcount;
812
813 if (n < 0 || n > NFONT) {
814 fprintf(stderr, "%s: illegal fp command %d %s\n", prog, n, s);
815 exit(2);
816 }
817 if (strcmp(s, fontbase[n]->namefont) == 0)
818 return;
819 if (fontbase[n]->namefont != 0)
820 fontdelta[n] = 1;
821 if (s1 == NULL || s1[0] == '\0')
822 sprintf(temp, "%s/dev%s/%s.out", ditdir, devname, s);
823 else
824 sprintf(temp, "%s/%s.out", s1, s);
825 if ((fin = open(temp, 0)) < 0) {
826 fprintf(stderr, "%s: can't open font table %s\n", prog, temp);
827 pexit(prog, 2);
828 }
829 norig = fontbase[n]->nwfont & BMASK;
830 bcount = 3 * norig + nchtab + 128 - 32 + sizeof (struct font);
831 (void) read(fin, (char *) fontbase[n], bcount);
832 if ((fontbase[n]->nwfont & BMASK) > norig) {
833 fprintf(stderr, "%s: Font %s too big for position %d\n",
834 prog, s, n);
835 exit(2);
836 }
837 close(fin);
838 nw = fontbase[n]->nwfont & BMASK;
839 widthtab[n] = (char *) fontbase[n] + sizeof (struct font);
840 codetab[n] = (char *) widthtab[n] + 2 * nw;
841 fitab[n] = (char *) widthtab[n] + 3 * nw;
842 t_fp(n, fontbase[n]->namefont, fontbase[n]->intname);
843 loadpswidths(n, fontbase[n]->namefont);
844 sayload(n, s, s1);
845 fontbase[n]->nwfont = norig; /* so can later use full original size */
846 #ifdef DEBUG
847 if (fdbg > 1)
848 fontprint(n);
849 #endif
850 }
851
sayload(n,s,s1)852 sayload(n, s, s1) /* position n contains font s (internal s1) */
853 int n;
854 char *s, *s1;
855 {
856 char pass[60];
857 FILE *ptrfile;
858 char Adobefont[60];
859
860 if (s1 == NULL || s1[0] == '\0')
861 sprintf(pass, "%s/dev%s/%s.map", ditdir, devname, s);
862 else
863 sprintf(pass, "%s/%s.map", s1, s);
864 if ((ptrfile = fopen(pass, "r")) == NULL) {
865 fprintf(stderr, "%s: can't open font map file %s\n",
866 prog, pass);
867 pexit(prog, 2);
868 }
869 fscanf(ptrfile, "%s", Adobefont);
870 FlushShow(0);
871 printf("%d(%s)xf %d f\n", n, Adobefont, n);
872 font = n;
873 (void) fclose(ptrfile);
874 }
875
done()876 done()
877 {
878 t_reset('s');
879 exit(0);
880 }
881
t_init()882 t_init() /* "x i" - initialize device */
883 {
884 movepending = NONE;
885 savex = savey = 0;
886
887 t_size(10); /* start somewhere */
888 t_slant(0);
889 setfont(1); /* set font */
890 stipplefont = 1;
891 printf("xi\n");
892 printf("%%%%EndProlog\n");
893 }
894
t_push()895 t_push() /* begin a new block */
896 {
897 FlushShow(1);
898 MoveTo();
899 DoMove();
900 if (dlevel == DSTACK) {
901 fprintf(stderr, "%s: ditroff push/pop overflow!\n", prog);
902 exit(2);
903 }
904 ditstack[dlevel].hpos = hpos;
905 ditstack[dlevel].vpos = vpos;
906 ditstack[dlevel].fontsize = fontsize;
907 ditstack[dlevel].fontheight = fontheight;
908 ditstack[dlevel].fontslant = fontslant;
909 ditstack[dlevel].font = font;
910 dlevel++;
911 printf("\nditpush\n");
912 }
913
t_pop()914 t_pop() /* pop to previous state */
915 {
916 FlushShow(1);
917 MoveTo();
918 DoMove();
919 if (dlevel == 0) {
920 fprintf(stderr, "%s: ditroff push/pop underflow!\n", prog);
921 exit(2);
922 }
923 dlevel--;
924 hpos = ditstack[dlevel].hpos;
925 vpos = ditstack[dlevel].vpos;
926 fontsize = ditstack[dlevel].fontsize;
927 fontheight = ditstack[dlevel].fontheight;
928 fontslant = ditstack[dlevel].fontslant;
929 font = ditstack[dlevel].font;
930 printf("%d s %d xH %d xS %d f\n",
931 fontsize, fontheight, fontslant, font);
932 startx = savex = hpos;
933 savey = vpos;
934 PSx = hpos * PSmag;
935 PSy = vpos * PSmag;
936 printf("%d %d MXY\n", savex, savey);
937 movepending = NONE;
938 printf("\nditpop\n");
939 }
940
t_page(n)941 t_page(n) /* do whatever new page functions */
942 {
943 register int i;
944
945 if (output && ++scount >= spage) {
946 t_reset('p');
947 scount = 0;
948 }
949 output = 1;
950 FlushShow(0);
951 if (!firstpage)
952 printf("\n%d p", n);
953 firstpage = FALSE;
954 printf("\n%%%%Page: %d %d\n", n, ++pageno, n);
955 for (i = 0; i <= nfonts; i++)
956 if (fontdelta[i] != 0)
957 sayload(i, fontname[i].name, (char *) 0);
958 vpos = 0;
959 PSy = 0;
960 printf("%d s %d xH %d xS %d f %d i\n",
961 fontsize, fontheight, fontslant, font, stipplefont);
962 if (nolist == 0)
963 return;
964 output = 0;
965 for (i = 0; i < nolist; i += 2)
966 if (n >= olist[i] && n <= olist[i + 1]) {
967 output = 1;
968 break;
969 }
970 }
971
t_size(n)972 t_size(n) /* convert integer to internal size number*/
973 int n;
974 {
975 FlushShow(1);
976 if (fontsize != n) {
977 fontsize = n;
978 #ifdef XMOD
979 fontheight = n;
980 #endif
981 printf("%d s\n", fontsize);
982 }
983 }
984
t_charht(n)985 t_charht(n) /* set character height to n */
986 int n;
987 {
988 FlushShow(1);
989 if (fontheight != n) {
990 fontheight = n;
991 printf("%d xH\n", fontheight);
992 }
993 }
994
t_slant(n)995 t_slant(n) /* set slant to n */
996 int n;
997 {
998 FlushShow(1);
999 if (fontslant != n) {
1000 fontslant = n;
1001 printf("%d xS\n", fontslant);
1002 }
1003 }
1004
t_font(s)1005 t_font(s) /* convert string to internal font number */
1006 char *s;
1007 {
1008 int n;
1009
1010 n = atoi(s);
1011 return n < 0 || n > nfonts ? 1 : n;
1012 }
1013
t_text(s)1014 t_text(s) /* print string s as text??? */
1015 char *s;
1016 {
1017 fprintf(stderr, "%s: ditroff t <%s> unimplemented!\n", prog, s);
1018 }
1019
t_reset(c)1020 t_reset(c)
1021 {
1022 output = 1; /* by God */
1023 if (c == 'p')
1024 printf("\nxp\n");
1025 else if (!stopped) {
1026 printf("\nxs\n");
1027 stopped = 1;
1028 }
1029 fflush(stdout);
1030 }
1031
t_res(res,minh,minv)1032 t_res(res, minh, minv)
1033 int res, minh, minv;
1034 {
1035 resolution = res;
1036 minhoriz = minh;
1037 minvert = minv;
1038 printf("%d %d %d xr\n", res, minh, minv);
1039 }
1040
t_trailer()1041 t_trailer()
1042 {
1043 FlushShow(0);
1044 printf("\n%d p", pageno);
1045 printf("\n%%%%Trailer\n");
1046 printf("xt\n");
1047 }
1048
put1s(s)1049 put1s(s) /* s is a funny char name */
1050 char *s;
1051 {
1052 int i;
1053
1054 if (!output)
1055 return;
1056 debugp(("%s ", s));
1057
1058 /* search for s in the funny char name table */
1059 for (i = 0; i < nchtab; i++)
1060 if (strcmp(&chname[chtab[i]], s) == 0)
1061 break;
1062 if (i < nchtab)
1063 put1(i + 128, s);
1064 else {
1065 debugp(("not found "));
1066 putnf(0, s);
1067 }
1068 }
1069
1070 #define needsescape(c) ((c) == '\\' || (c) == '(' || (c) == ')')
1071
put1(c,s)1072 put1(c, s) /* output char c */
1073 int c;
1074 char *s;
1075 {
1076 char *pw;
1077 register char *p;
1078 register int i, k;
1079 register int cc;
1080 int ofont, code;
1081 int psinfo, pswid, tw;
1082
1083 if (!output)
1084 return;
1085 if (c == ' ') {
1086 thisw = 0;
1087 FlushShow(0);
1088 return;
1089 }
1090 if (c < ' ') {
1091 debugp(("non-exist 0%o\n", c));
1092 return;
1093 }
1094 c -= 32; /* offset char code */
1095 k = ofont = pfont = font;
1096 if (onspecial)
1097 pfont = prevfont;
1098 if ((i = fitab[pfont][c] & BMASK) != 0) { /* char on this font */
1099 p = codetab[pfont];
1100 pw = widthtab[pfont];
1101 if (onspecial) {
1102 setfont(prevfont);
1103 thisw = 0;
1104 onspecial = 0;
1105 }
1106 } else if (smnt > 0) { /* on special (we hope) */
1107 for (k = smnt; k <= nfonts; k += 1)
1108 if ((i = fitab[k][c] & BMASK) != 0) {
1109 p = codetab[k];
1110 pw = widthtab[k];
1111 prevfont = pfont;
1112 if (onspecial && k == specfont)
1113 break;
1114 setfont(k);
1115 thisw = 0;
1116 onspecial = 1;
1117 specfont = k;
1118 break;
1119 }
1120 }
1121 if (i == 0 || k > nfonts || (code = p[i] & BMASK) == 0) {
1122 debugp(("not found 0%o\n", c + 32));
1123 putnf(c + 32, s);
1124 return;
1125 }
1126 /*
1127 * when we get here,
1128 * c == biased character code
1129 * k == font number
1130 * i == index into codetab and widthtab for this character
1131 * p == codetab for this font
1132 * pw == width tab for this font
1133 * code == character code for this char
1134 */
1135 cc = c + 32;
1136 debugp(((isascii(cc) && isprint(cc)) ? "%c %d\n":"%03o %d\n",
1137 cc, code));
1138 psinfo = pswidths[font][code]; /* PS specific char info */
1139 pswid = psinfo & PSWID; /* PS character width */
1140 thisw = pw[i] & BMASK; /* troff char width */
1141 tw = thisw = (thisw * fontsize + dev.unitwidth / 2) / dev.unitwidth;
1142
1143 if (psinfo & ISPSPROC && psinfo != -1) {
1144 /* character is implemented by a PostScript proc */
1145 showspecial(s, code, pswid);
1146 if (pswid > 0)
1147 PSx += PSscale(pswid * fontsize * dres);
1148 thisw = 0;
1149 } else {
1150 showchar(code);
1151 if (pswid > 0)
1152 PSshowlen += PSscale(pswid * fontsize * dres);
1153 }
1154
1155 /*
1156 if (font != ofont) {
1157 setfont(ofont);
1158 startx = hpos + tw;
1159 thisw = 0;
1160 lastcmd = FNT;
1161 }
1162 */
1163 debugp(("...width (%d)\n", pw[i] & BMASK));
1164 }
1165
putnf(c,s)1166 putnf(c, s) /* note that a character wasnt found */
1167 int c;
1168 char *s;
1169 {
1170 FlushShow(0);
1171 thisw = 0;
1172 if (s == NULL || *s == '\0')
1173 printf("(%3o)cb\n", c);
1174 else if (strcmp(s, "\\|") == 0 || strcmp(s, "\\^") == 0 ||
1175 strcmp(s, "\\&") == 0)
1176 return;
1177 else
1178 printf("(%s)cb\n", s);
1179 }
1180
t_fp(n,s,si)1181 t_fp(n, s, si) /* font position n now contains font s, intname si */
1182 int n; /* position */
1183 char *s; /* font (ditname) */
1184 char *si; /* font (intname = number) */
1185 {
1186 fontname[n].name = s;
1187 fontname[n].number = atoi(si);
1188 }
1189
setfont(n)1190 setfont(n) /* set font to n */
1191 int n;
1192 {
1193 FlushShow(1);
1194 if (n < 0 || n > NFONT)
1195 fprintf(stderr, "%s: illegal font %d\n", prog, n);
1196 if (font != n) {
1197 font = n;
1198 printf("%d f\n", font);
1199 }
1200 onspecial = 0;
1201 }
1202
drawline(dx,dy)1203 drawline(dx, dy) /* draw line from here to dx, dy */
1204 int dx, dy;
1205 {
1206 FlushShow(0);
1207 MoveTo();
1208 DoMove();
1209 printf("%d %d Dl\n", dx, dy);
1210 hpos += dx;
1211 PSx = hpos * PSmag;
1212 vpos += dy;
1213 PSy = vpos * PSmag;
1214 }
1215
drawcurve(line)1216 drawcurve(line)
1217 char *line;
1218 {
1219 FlushShow(0);
1220 MoveTo();
1221 DoMove();
1222 getpoints(line + 1);
1223 /* hpos and vpos won't be changed by curve drawing code */
1224 hpos = x[numpoints];
1225 vpos = y[numpoints];
1226 switch (*line) {
1227 case 'g':
1228 IS_Initialize();
1229 IS_Convert();
1230 break;
1231 case '~':
1232 BS_Initialize();
1233 BS_Convert();
1234 break;
1235 case 'z':
1236 BZ_Offsets();
1237 BZ_Convert();
1238 break;
1239 }
1240 printf("Dstroke\n");
1241 }
1242
drawpoly(line)1243 drawpoly(line)
1244 char *line;
1245 {
1246 int stipple;
1247 register i;
1248 register char *p;
1249 int minx, miny, maxx, maxy;
1250
1251 FlushShow(0);
1252 MoveTo();
1253 DoMove();
1254 for (p = line + 1; isspace(*p); p++)
1255 ;
1256 for (stipple = 0; isdigit(*p);
1257 stipple = stipple * 10 + *p++ - '0')
1258 ;
1259 getpoints(p);
1260 minx = maxx = hpos;
1261 miny = maxy = vpos;
1262 for (i = 1; i <= numpoints; i++) {
1263 printf(" %lg %lg lineto\n", x[i], y[i]);
1264 if (x[i] > maxx)
1265 maxx = x[i];
1266 if (x[i] < minx)
1267 minx = x[i];
1268 if (y[i] > maxy)
1269 maxy = y[i];
1270 if (y[i] < miny)
1271 miny = y[i];
1272 }
1273 printf("closepath %d %d %d %d %d D%c\n",
1274 stipple, minx, miny, maxx, maxy, *line);
1275 /* XXX, hpos and vpos not changed? */
1276 PSx = x[numpoints] * PSmag;
1277 PSy = y[numpoints] * PSmag;
1278 }
1279
getpoints(s)1280 getpoints(s)
1281 register char *s;
1282 {
1283 int h = hpos, v = vpos;
1284
1285 numpoints = 0;
1286 for (;;) {
1287 int dh, dv, neg;
1288
1289 numpoints++;
1290 x[numpoints] = h;
1291 y[numpoints] = v;
1292 if (numpoints >= MAXPOINTS - 2) /* -2 for good measure */
1293 break;
1294 for (; isspace(*s); s++)
1295 ;
1296 if (neg = *s == '-')
1297 s++;
1298 if (!isdigit(*s))
1299 break;
1300 for (dh = 0; isdigit(*s); dh = dh * 10 + *s++ - '0')
1301 ;
1302 if (neg)
1303 dh = - dh;
1304 for (; isspace(*s); s++)
1305 ;
1306 if (neg = *s == '-')
1307 s++;
1308 if (!isdigit(*s))
1309 break;
1310 for (dv = 0; isdigit(*s); dv = dv * 10 + *s++ - '0')
1311 ;
1312 if (neg)
1313 dv = - dv;
1314 h += dh;
1315 v += dv;
1316 }
1317 }
1318
drawcirc(d)1319 drawcirc(d)
1320 int d;
1321 {
1322 FlushShow(0);
1323 MoveTo();
1324 DoMove();
1325 printf("%d Dc\n", d);
1326 }
1327
drawarc(dx1,dy1,dx2,dy2)1328 drawarc(dx1, dy1, dx2, dy2)
1329 int dx1, dy1, dx2, dy2;
1330 {
1331 FlushShow(0);
1332 MoveTo();
1333 DoMove();
1334 printf("%d %d %d %d Da\n", dx1, dy1, dx2, dy2);
1335 hpos += dx1 + dx2;
1336 PSx = hpos * PSmag;
1337 vpos += dy1 + dy2;
1338 PSy = vpos * PSmag;
1339 }
1340
drawellip(a,b)1341 drawellip(a, b)
1342 int a, b;
1343 {
1344 FlushShow(0);
1345 MoveTo();
1346 DoMove();
1347 printf("%d %d De\n", a, b);
1348 }
1349
hmot(a)1350 hmot(a) /* relative horizontal motion */
1351 int a;
1352 {
1353 register int aa;
1354
1355 aa = abs(a);
1356 if (aa < 8 || aa > 10 * thisw || a >= 100 ||
1357 thisw != 0 && abs(thisw - a) > 4)
1358 FlushShow(1);
1359 hpos += a;
1360 if (lastcmd != CPUT)
1361 startx = hpos;
1362 }
1363
hgoto(a)1364 hgoto(a) /* absolute horizontal motion */
1365 int a;
1366 {
1367 FlushShow(1);
1368 startx = hpos = a;
1369 thisw = 0;
1370 }
1371
vmot(a)1372 vmot(a) /* relative vertical motion */
1373 int a;
1374 {
1375 FlushShow(1);
1376 vpos += a;
1377 thisw = 0;
1378 }
1379
vgoto(a)1380 vgoto(a) /* absolute vertical motion */
1381 int a;
1382 {
1383 FlushShow(1);
1384 vpos = a;
1385 thisw = 0;
1386 }
1387
showspecial(s,cc,wid)1388 showspecial(s, cc, wid)
1389 char *s;
1390 int cc;
1391 int wid;
1392 {
1393 char *sp;
1394
1395 FlushShow(0);
1396 MoveTo();
1397 DoMove();
1398 putchar('(');
1399 for (sp = s; *sp != '\0'; sp++) {
1400 if (needsescape(*sp))
1401 putchar('\\');
1402 putchar(*sp);
1403 }
1404 printf(")%d %d oc\n", cc, wid);
1405 }
1406
showchar(c)1407 showchar(c)
1408 int c;
1409 {
1410 if (showind == 0)
1411 MoveTo();
1412 else if (vpos * PSmag != PSy) {
1413 FlushShow(0);
1414 MoveTo();
1415 }
1416 if (showind >= SHOWSIZE)
1417 FlushShow(0);
1418 if (isascii(c) && isprint(c))
1419 switch (c) {
1420 case '\\':
1421 case '(':
1422 case ')':
1423 showbuf[showind++] = '\\';
1424 /* fall through */
1425 default:
1426 showbuf[showind++] = c;
1427 }
1428 else {
1429 showbuf[showind++] = '\\';
1430 showbuf[showind++] = ((c >> 6) & 03) + '0';
1431 showbuf[showind++] = ((c >> 3) & 07) + '0';
1432 showbuf[showind++] = (c & 07) + '0';
1433 }
1434 showbuf[showind] = '\0';
1435 nshow++;
1436 }
1437
MoveTo()1438 MoveTo()
1439 {
1440 int x, y;
1441
1442 x = hpos * PSmag;
1443 y = vpos * PSmag;
1444 if (x != PSx) {
1445 startx = savex = hpos;
1446 PSx = x;
1447 movepending |= XMOVE;
1448 }
1449 if (y != PSy) {
1450 savey = vpos;
1451 PSy = y;
1452 movepending |= YMOVE;
1453 }
1454 }
1455
FlushMove()1456 FlushMove()
1457 {
1458 switch (movepending) {
1459 case NONE:
1460 break;
1461 case XMOVE:
1462 printf("%d", savex);
1463 break;
1464 case YMOVE:
1465 printf("%d", savey);
1466 break;
1467 case XYMOVE:
1468 printf("%d %d", savex, savey);
1469 break;
1470 default:
1471 fprintf(stderr, "%s: invalid move code %d\n",
1472 prog, movepending);
1473 exit(2);
1474 }
1475 }
1476
1477 char *movecmds[] = { "MX", "MY", "MXY" };
1478
DoMove()1479 DoMove()
1480 {
1481 FlushMove();
1482 if (movepending != NONE) {
1483 printf(" %s\n", movecmds[movepending - 1]);
1484 movepending = NONE;
1485 }
1486 }
1487
1488 char showops[] = "SXYN";
1489
FlushShow(t)1490 FlushShow(t)
1491 int t;
1492 {
1493 long err, tlen;
1494 float cerror;
1495
1496 if (showind == 0) {
1497 thisw = 0;
1498 return;
1499 }
1500 if (movepending != NONE)
1501 FlushMove();
1502 tlen = hpos - startx;
1503 if (lastcmd == CPUT)
1504 tlen += thisw;
1505 err = tlen * PSmag - PSshowlen;
1506 if (nshow != 1 && abs(err) > ErrorTolerance) {
1507 cerror = (float) err / ((nshow - 1) * PSmag);
1508 #ifdef DEBUG
1509 fprintf(stderr, "F%d lc %d thisw %d ", t, lastcmd, thisw);
1510 fprintf(stderr, "x %ld h %ld tn %ld %ld ",
1511 startx, hpos, tlen*PSmag, PSshowlen);
1512 fprintf(stderr, "error %d %.4f %s\n", nshow, cerror, showbuf);
1513 fflush(stderr);
1514 #endif
1515 printf(" %.4f(%s)A%c\n", cerror, showbuf, showops[movepending]);
1516 } else
1517 printf("(%s)%c\n", showbuf, showops[movepending]);
1518 showind = 0;
1519 nshow = 0;
1520 showbuf[showind] = '\0';
1521 PSx += PSshowlen;
1522 PSshowlen = 0;
1523 startx = hpos;
1524 if (lastcmd == CPUT)
1525 startx += thisw;
1526 thisw = 0;
1527 movepending = NONE;
1528 }
1529
1530 /* The following stolen (with modifications) from ... */
1531 /*
1532 * This program is part of gr2ps. It converts Gremlin's curve output to
1533 * control vertices of Bezier Cubics, as supported by PostScript.
1534 * Gremlin currently supports three kinds of curves:
1535 * (1) cubic interpolated spline with
1536 * i) periodic end condition, if two end points coincide
1537 * ii) natural end condition, otherwise
1538 * (2) uniform cubic B-spline with
1539 * i) closed curve (no vertex interpolated), if end vertices coincide
1540 * ii) end vertex interpolation, otherwise
1541 * (3) Bezier cubics
1542 *
1543 * The basic idea of the conversion algorithm for the first two is
1544 * (1) take each curve segment's two end points as Bezier end vertices.
1545 * (2) find two intermediate points in the orginal curve segment
1546 * (with u=1/4 and u=1/2, for example).
1547 * (3) solve for the two intermediate control vertices.
1548 * The conversion between Bezier Cubics of Gremlin and that of PostScript
1549 * is straightforward.
1550 *
1551 * Author: Peehong Chen (phc@renoir.berkeley.edu)
1552 * Date: 9/17/1986
1553 */
1554 #include <math.h>
1555
1556 #define BezierMax 5
1557 #define BC1 1.0/9 /* coefficient of Bezier conversion */
1558 #define BC2 4*BC1
1559 #define BC3 3*BC2
1560 #define BC4 8*BC2
1561
1562 double Qx, Qy, h[MAXPOINTS], dx[MAXPOINTS],
1563 dy[MAXPOINTS], d2x[MAXPOINTS], d2y[MAXPOINTS], d3x[MAXPOINTS],
1564 d3y[MAXPOINTS];
1565
1566 /*
1567 * This routine converts each segment of a curve, P1, P2, P3, and P4
1568 * to a set of two intermediate control vertices, V2 and V3, in a Bezier
1569 * segment, plus a third vertex of the end point P4 (assuming the current
1570 * position is P1), and then writes a PostScript command "V2 V3 V4 curveto"
1571 * to the output file.
1572 * The two intermediate vertices are obtained using
1573 * Q(u) = V1 * (1-u)^3 + V2 * 3u(1-u)^2 + V3 * 3(1-u)u^2 + V4 * u^3
1574 * with u=1/4, and u=1/2,
1575 * Q(1/4) = Q2 = (x2, y2)
1576 * Q(1/2) = Q3 = (x3, y3)
1577 * V1 = P1
1578 * V4 = P4
1579 * and
1580 * V2 = (32/9)*Q2 - (4/3)*(Q3 + V1) + (1/9)*V4
1581 * V3 = -(32/9)*Q2 + 4*Q3 + V1 - (4/9)*V4
1582 */
BezierSegment(x1,y1,x2,y2,x3,y3,x4,y4)1583 BezierSegment(x1, y1, x2, y2, x3, y3, x4, y4)
1584 double x1, y1, x2, y2, x3, y3, x4, y4;
1585 {
1586 double V2x, V2y, V3x, V3y;
1587
1588 V2x = BC4 * x2 - BC3 * (x3 + x1) + BC1 * x4;
1589 V2y = BC4 * y2 - BC3 * (y3 + y1) + BC1 * y4;
1590 V3x = -BC4 * x2 + 4 * x3 + x1 - BC2 * x4;
1591 V3y = -BC4 * y2 + 4 * y3 + y1 - BC2 * y4;
1592
1593 printf(" %lg %lg %lg %lg %lg %lg curveto\n",
1594 V2x, V2y, V3x, V3y, x4, y4);
1595 PSx = x4 * PSmag;
1596 PSy = y4 * PSmag;
1597 } /* end BezierSegment */
1598
1599 /*
1600 * This routine calculates parameteric values for use in calculating
1601 * curves. The values are an approximation of cumulative arc lengths
1602 * of the curve (uses cord * length). For additional information,
1603 * see paper cited below.
1604 *
1605 * This is from Gremlin (called Paramaterize in gremlin),
1606 * with minor modifications (elimination of param list)
1607 */
IS_Parameterize()1608 IS_Parameterize()
1609 {
1610 register i, j;
1611 double t1, t2;
1612 double u[MAXPOINTS];
1613
1614 for (i = 1; i <= numpoints; i++) {
1615 u[i] = 0.0;
1616 for (j = 1; j < i; j++) {
1617 t1 = x[j + 1] - x[j];
1618 t2 = y[j + 1] - y[j];
1619 u[i] += sqrt(t1 * t1 + t2 * t2);
1620 }
1621 }
1622 for (i = 1; i < numpoints; i++)
1623 h[i] = u[i + 1] - u[i];
1624 } /* end IS_Parameterize */
1625
1626 /*
1627 * This routine solves for the cubic polynomial to fit a spline
1628 * curve to the the points specified by the list of values.
1629 * The curve generated is periodic. The alogrithms for this
1630 * curve are from the "Spline Curve Techniques" paper cited below.
1631 *
1632 * This is from Gremlin (called PeriodicSpline in gremlin)
1633 *
1634 */
IS_PeriodicEnd(h,z,dz,d2z,d3z)1635 IS_PeriodicEnd(h, z, dz, d2z, d3z)
1636 double h[MAXPOINTS]; /* Parameterizeaterization */
1637 double z[MAXPOINTS]; /* point list */
1638 double dz[MAXPOINTS]; /* to return the 1st derivative */
1639 double d2z[MAXPOINTS]; /* 2nd derivative */
1640 double d3z[MAXPOINTS]; /* and 3rd derivative */
1641 {
1642 double a[MAXPOINTS];
1643 double b[MAXPOINTS];
1644 double c[MAXPOINTS];
1645 double d[MAXPOINTS];
1646 double deltaz[MAXPOINTS];
1647 double r[MAXPOINTS];
1648 double s[MAXPOINTS];
1649 double ftmp;
1650 register i;
1651
1652 /* step 1 */
1653 for (i = 1; i < numpoints; i++)
1654 if (h[i] != 0)
1655 deltaz[i] = (z[i + 1] - z[i]) / h[i];
1656 else
1657 deltaz[i] = 0;
1658 h[0] = h[numpoints - 1];
1659 deltaz[0] = deltaz[numpoints - 1];
1660
1661 /* step 2 */
1662 for (i = 1; i < numpoints - 1; i++)
1663 d[i] = deltaz[i + 1] - deltaz[i];
1664 d[0] = deltaz[1] - deltaz[0];
1665
1666 /* step 3a */
1667 a[1] = 2 * (h[0] + h[1]);
1668 if (a[1] == 0)
1669 return (-1); /* 3 consecutive knots at same point */
1670 b[1] = d[0];
1671 c[1] = h[0];
1672
1673 for (i = 2; i < numpoints - 1; i++) {
1674 ftmp = h[i - 1];
1675 a[i] = ftmp + ftmp + h[i] + h[i] - ftmp * ftmp / a[i - 1];
1676 if (a[i] == 0)
1677 return (-1); /* 3 consec knots at same point */
1678 b[i] = d[i - 1] - ftmp * b[i - 1] / a[i - 1];
1679 c[i] = - ftmp * c[i - 1]/a[i - 1];
1680 }
1681
1682 /* step 3b */
1683 r[numpoints - 1] = 1;
1684 s[numpoints - 1] = 0;
1685 for (i = numpoints - 2; i > 0; i--) {
1686 r[i] = - (h[i] * r[i + 1] + c[i]) / a[i];
1687 s[i] = (6 * b[i] - h[i] * s[i + 1]) / a[i];
1688 }
1689
1690 /* step 4 */
1691 d2z[numpoints - 1] = (6 * d[numpoints - 2] - h[0] * s[1]
1692 - h[numpoints - 1] * s[numpoints - 2])
1693 / (h[0] * r[1] + h[numpoints - 1] * r[numpoints - 2]
1694 + 2 * (h[numpoints - 2] + h[0]));
1695 for (i = 1; i < numpoints - 1; i++)
1696 d2z[i] = r[i] * d2z[numpoints - 1] + s[i];
1697 d2z[numpoints] = d2z[1];
1698
1699 /* step 5 */
1700 for (i = 1; i < numpoints; i++) {
1701 dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i + 1]) / 6;
1702 if (h[i] != 0)
1703 d3z[i] = (d2z[i + 1] - d2z[i]) / h[i];
1704 else
1705 d3z[i] = 0;
1706 }
1707
1708 return (0);
1709 } /* end IS_PeriodicEnd */
1710
1711 /*
1712 * This routine solves for the cubic polynomial to fit a spline
1713 * curve from the points specified by the list of values. The alogrithms for
1714 * this curve are from the "Spline Curve Techniques" paper cited below.
1715 *
1716 * This is from Gremlin (called NaturalEndSpline in gremlin)
1717 */
IS_NaturalEnd(h,z,dz,d2z,d3z)1718 IS_NaturalEnd(h, z, dz, d2z, d3z)
1719 double h[MAXPOINTS]; /* parameterization */
1720 double z[MAXPOINTS]; /* point list */
1721 double dz[MAXPOINTS]; /* to return the 1st derivative */
1722 double d2z[MAXPOINTS]; /* 2nd derivative */
1723 double d3z[MAXPOINTS]; /* and 3rd derivative */
1724 {
1725 double a[MAXPOINTS];
1726 double b[MAXPOINTS];
1727 double d[MAXPOINTS];
1728 double deltaz[MAXPOINTS];
1729 double ftmp;
1730 register i;
1731
1732 /* step 1 */
1733 for (i = 1; i < numpoints; i++)
1734 if (h[i] != 0)
1735 deltaz[i] = (z[i + 1] - z[i]) / h[i];
1736 else
1737 deltaz[i] = 0;
1738 deltaz[0] = deltaz[numpoints - 1];
1739
1740 /* step 2 */
1741 for (i = 1; i < numpoints - 1; i++)
1742 d[i] = deltaz[i + 1] - deltaz[i];
1743 d[0] = deltaz[1] - deltaz[0];
1744
1745 /* step 3 */
1746 a[0] = 2 * (h[2] + h[1]);
1747 if (a[0] == 0) /* 3 consec knots at same point */
1748 return (-1);
1749 b[0] = d[1];
1750
1751 for (i = 1; i < numpoints - 2; i++) {
1752 ftmp = h[i + 1];
1753 a[i] = ftmp + ftmp + h[i + 2] + h[i + 2] -
1754 (ftmp * ftmp) / a[i - 1];
1755 if (a[i] == 0) /* 3 consec knots at same point */
1756 return (-1);
1757 b[i] = d[i + 1] - ftmp * b[i - 1] / a[i - 1];
1758 }
1759
1760 /* step 4 */
1761 d2z[numpoints] = d2z[1] = 0;
1762 for (i = numpoints - 1; i > 1; i--)
1763 d2z[i] = (6 * b[i - 2] - h[i] * d2z[i + 1]) / a[i - 2];
1764
1765 /* step 5 */
1766 for (i = 1; i < numpoints; i++) {
1767 dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i + 1]) / 6;
1768 if (h[i] != 0)
1769 d3z[i] = (d2z[i + 1] - d2z[i]) / h[i];
1770 else
1771 d3z[i] = 0;
1772 }
1773
1774 return (0);
1775 } /* end IS_NaturalEnd */
1776
1777 /*
1778 * Use the same algorithm Gremlin uses to interpolate a given
1779 * set of points, as described in ``Spline Curve Techniques,''
1780 * by Pattrick Baudelaire, Robert M. Flegal, and Robert F. Sproull,
1781 * Xerox PARC Tech Report No. 78CSL-059.
1782 */
IS_Initialize()1783 IS_Initialize()
1784 {
1785 IS_Parameterize();
1786
1787 /* Solve for derivatives of the curve at each point
1788 separately for x and y (parametric). */
1789
1790 if (x[1] == x[numpoints] && y[1] == y[numpoints]) { /* closed curve */
1791 IS_PeriodicEnd(h, x, dx, d2x, d3x);
1792 IS_PeriodicEnd(h, y, dy, d2y, d3y);
1793 } else {
1794 IS_NaturalEnd(h, x, dx, d2x, d3x);
1795 IS_NaturalEnd(h, y, dy, d2y, d3y);
1796 }
1797 }
1798
1799 /*
1800 * This routine converts cubic interpolatory spline to Bezier control vertices
1801 */
IS_Convert()1802 IS_Convert()
1803 {
1804 double t, t2, t3, x2, y2, x3, y3;
1805 register j, j1;
1806
1807 for (j = 1; j < numpoints; j++) {
1808 t = .25 * h[j];
1809 t2 = t * t;
1810 t3 = t2 * t;
1811 x2 = x[j] + t * dx[j] + t2 * d2x[j] / 2.0 + t3 * d3x[j] / 6.0;
1812 y2 = y[j] + t * dy[j] + t2 * d2y[j] / 2.0 + t3 * d3y[j] / 6.0;
1813
1814 t = 2 * t;
1815 t2 = t * t;
1816 t3 = t2 * t;
1817 x3 = x[j] + t * dx[j] + t2 * d2x[j] / 2.0 + t3 * d3x[j] / 6.0;
1818 y3 = y[j] + t * dy[j] + t2 * d2y[j] / 2.0 + t3 * d3y[j] / 6.0;
1819
1820 j1 = j + 1;
1821 BezierSegment(x[j], y[j], x2, y2, x3, y3, x[j1], y[j1]);
1822 }
1823 } /* end IS_Convert */
1824
1825 /*
1826 * This routine computes a point in B-spline segment, given i, and u.
1827 * Details of this algorithm can be found in the tech. report cited below.
1828 */
BS_ComputePoint(i,u,xp,yp)1829 BS_ComputePoint(i, u, xp, yp)
1830 int i;
1831 float u;
1832 double *xp, *yp;
1833 {
1834 float u2, u3, b_2, b_1, b0, b1;
1835 register i1, i_2, i_1;
1836
1837 i1 = i + 1;
1838 i_1 = i - 1;
1839 i_2 = i - 2;
1840
1841 u2 = u * u;
1842 u3 = u2 * u;
1843 b_2 = (1 - 3 * u + 3 * u2 - u3) / 6.0;
1844 b_1 = (4 - 6 * u2 + 3 * u3) / 6.0;
1845 b0 = (1 + 3 * u + 3 * u2 - 3 * u3) / 6.0;
1846 b1 = u3 / 6.0;
1847
1848 *xp = b_2 * x[i_2] + b_1 * x[i_1] + b0 * x[i] + b1 * x[i1];
1849 *yp = b_2 * y[i_2] + b_1 * y[i_1] + b0 * y[i] + b1 * y[i1];
1850 } /* end BS_ComputePoint */
1851
1852 /*
1853 * This routine initializes the array of control vertices
1854 * We consider two end conditions here:
1855 * (1) closed curve -- C2 continuation and end vertex not interpolated, i.e.
1856 * V[0] = V[n-1], and
1857 * V[n+1] = V[2].
1858 * (2) open curve -- end vertex interpolation, i.e.
1859 * V[0] = 2*V[1] - V[2], and
1860 * V[n+1] = 2*V[n] - V[n-1].
1861 * Details of uniform cubic B-splines, including other end conditions
1862 * and important properties can be found in Chapters 4-5 of
1863 * Richard H. Bartels and Brian A. Barsky,
1864 * "An Introduction to the Use of Splines in Computer Graphics",
1865 * Tech. Report CS-83-136, Computer Science Division,
1866 * University of California, Berkeley, 1984.
1867 */
BS_Initialize()1868 BS_Initialize()
1869 {
1870 register n_1, n1;
1871
1872 n_1 = numpoints - 1;
1873 n1 = numpoints + 1;
1874 if (x[1] == x[numpoints] && y[1] == y[numpoints]) { /* closed curve */
1875 x[0] = x[n_1]; /* V[0] */
1876 y[0] = y[n_1];
1877 x[n1] = x[2]; /* V[n+1] */
1878 y[n1] = y[2];
1879 } else { /* end vertex interpolation */
1880 x[0] = 2 * x[1] - x[2]; /* V[0] */
1881 y[0] = 2 * y[1] - y[2];
1882 x[n1] = 2 * x[numpoints] - x[n_1]; /* V[n+1] */
1883 y[n1] = 2 * y[numpoints] - y[n_1];
1884 }
1885 } /* end BS_Initialize */
1886
1887 /*
1888 * This routine converts uniform cubic B-spline to Bezier control vertices
1889 */
BS_Convert()1890 BS_Convert()
1891 {
1892 double x1, y1, x2, y2, x3, y3, x4, y4;
1893 register i;
1894
1895 for (i = 2; i <= numpoints; i++) {
1896 BS_ComputePoint(i, 0.0, &x1, &y1);
1897 BS_ComputePoint(i, 0.25, &x2, &y2);
1898 BS_ComputePoint(i, 0.5, &x3, &y3);
1899 BS_ComputePoint(i, 1.0, &x4, &y4);
1900 if (i == 2)
1901 printf("%lg %lg moveto\n", x1, y1);
1902 BezierSegment(x1, y1, x2, y2, x3, y3, x4, y4);
1903 }
1904 } /* end BS_Convert */
1905
1906 /*
1907 * This routine copies the offset between two consecutive control points
1908 * into an array. That is,
1909 * O[i] = (x[i], y[i]) = V[i+1] - V[i],
1910 * for i=1 to N-1, where N is the number of points given.
1911 * The starting end point (V[1]) is saved in (Qx, Qy).
1912 */
BZ_Offsets()1913 BZ_Offsets()
1914 {
1915 register i;
1916
1917 /* Assign offsets btwn points to array for convenience of processing */
1918 Qx = x[1];
1919 Qy = y[1];
1920 for (i = 1; i < numpoints; i++) {
1921 x[i] = x[i + 1] - x[i];
1922 y[i] = y[i + 1] - y[i];
1923 }
1924 }
1925
1926 /*
1927 * This routine contructs paths of piecewise continuous Bezier cubics
1928 * in PostScript based on the given set of control vertices.
1929 * Given 2 points, a straight line is drawn.
1930 * Given 3 points V[1], V[2], and V[3], a Bezier cubic segment
1931 * of (V[1], (V[1]+V[2])/2, (V[2]+V[3])/2, V[3]) is drawn.
1932 * In the case when N (N >= 4) points are given, N-2 Bezier segments will
1933 * be drawn, each of which (for i=1 to N-2) is translated to PostScript as
1934 * Q+O[i]/3 Q+(3*O[i]+O[i+1])/6 K+O[i+1]/2 curveto,
1935 * where
1936 * Q is the current point,
1937 * K is the continuation offset = Qinitial + Sigma(1, i)(O[i])
1938 * Note that when i is 1, the initial point
1939 * Q = V[1].
1940 * and when i is N-2, the terminating point
1941 * K+O[i+1]/2 = V[N].
1942 */
BZ_Convert()1943 BZ_Convert()
1944 {
1945 register i, i1;
1946 double x1, y1, x2, y2, x3, y3, Kx, Ky;
1947
1948 if (numpoints == 2) {
1949 printf(" %lg %lg rlineto\n", x[1], y[1]);
1950 PSx += x[1] * PSmag;
1951 PSy += y[1] * PSmag;
1952 return;
1953 }
1954 if (numpoints == 3) {
1955 x1 = Qx + x[1];
1956 y1 = Qy + y[1];
1957 x2 = x1 + x[2];
1958 y2 = y1 + y[2];
1959 printf(" %lg %lg %lg %lg %lg %lg curveto\n",
1960 (Qx + x1) / 2.0, (Qy + y1) / 2.0, (x1 + x2) / 2.0,
1961 (y1 + y2) / 2.0, x2, y2);
1962 PSx = x2 * PSmag;
1963 PSy = y2 * PSmag;
1964 return;
1965 }
1966 /* numpoints >= 4 */
1967 Kx = Qx + x[1];
1968 Ky = Qy + y[1];
1969 x[1] *= 2;
1970 y[1] *= 2;
1971 x[numpoints - 1] *= 2;
1972 y[numpoints - 1] *= 2;
1973 for (i = 1; i <= numpoints - 2; i++) {
1974 i1 = i + 1;
1975 x1 = Qx + x[i] / 3;
1976 y1 = Qy + y[i] / 3;
1977 x2 = Qx + (3 * x[i] + x[i1]) / 6;
1978 y2 = Qy + (3 * y[i] + y[i1]) / 6;
1979 x3 = Kx + x[i1] / 2;
1980 y3 = Ky + y[i1] / 2;
1981 printf(" %lg %lg %lg %lg %lg %lg curveto\n",
1982 x1, y1, x2, y2, x3, y3);
1983 Qx = x3;
1984 Qy = y3;
1985 Kx += x[i1];
1986 Ky += y[i1];
1987 }
1988 PSx = x3 * PSmag;
1989 PSy = y3 * PSmag;
1990 } /* end BZ_Convert */
1991