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 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[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 */ 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 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 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 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 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 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 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 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 876 done() 877 { 878 t_reset('s'); 879 exit(0); 880 } 881 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 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 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 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 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 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 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 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 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 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 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 1041 t_trailer() 1042 { 1043 FlushShow(0); 1044 printf("\n%d p", pageno); 1045 printf("\n%%%%Trailer\n"); 1046 printf("xt\n"); 1047 } 1048 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 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 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 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 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 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 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 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 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 1319 drawcirc(d) 1320 int d; 1321 { 1322 FlushShow(0); 1323 MoveTo(); 1324 DoMove(); 1325 printf("%d Dc\n", d); 1326 } 1327 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 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 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 1364 hgoto(a) /* absolute horizontal motion */ 1365 int a; 1366 { 1367 FlushShow(1); 1368 startx = hpos = a; 1369 thisw = 0; 1370 } 1371 1372 vmot(a) /* relative vertical motion */ 1373 int a; 1374 { 1375 FlushShow(1); 1376 vpos += a; 1377 thisw = 0; 1378 } 1379 1380 vgoto(a) /* absolute vertical motion */ 1381 int a; 1382 { 1383 FlushShow(1); 1384 vpos = a; 1385 thisw = 0; 1386 } 1387 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 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 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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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