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