1 /* @(#)psdit.c 1.4 04/17/88 */ 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 and polygon drawing */ 237 #define MAXPOINTS 200 238 double x[MAXPOINTS], y[MAXPOINTS]; 239 int numpoints; 240 241 main(argc, argv) 242 int argc; 243 char *argv[]; 244 { 245 FILE *fp; 246 int done(); 247 248 prog = argv[0]; 249 while (argc > 1 && argv[1][0] == '-') { 250 switch (argv[1][1]) { 251 case 'f': 252 case 'F': 253 if (argv[1][2]) 254 ditdir = &argv[1][2]; 255 else { 256 ditdir = argv[2]; 257 argv++; 258 argc--; 259 } 260 break; 261 case 'p': 262 if (argv[1][2]) 263 prologfile = &argv[1][2]; 264 break; 265 case 'o': 266 outlist(&argv[1][2]); 267 break; 268 case 'd': 269 #ifdef DEBUG 270 dbg = atoi(&argv[1][2]); 271 if (dbg == 0) 272 dbg = 1; 273 #endif DEBUG 274 break; 275 case 'b': /* ignore busy */ 276 break; 277 case 'w': /* ignore wait */ 278 break; 279 case 's': 280 spage = atoi(&argv[1][2]); 281 if (spage <= 0) 282 spage = 9999; 283 break; 284 } 285 argc--; 286 argv++; 287 } 288 289 if (signal(SIGINT, done) == SIG_IGN) { 290 signal(SIGINT, SIG_IGN); 291 signal(SIGQUIT, SIG_IGN); 292 signal(SIGHUP, SIG_IGN); 293 } else { 294 signal(SIGQUIT, done); 295 signal(SIGHUP, done); 296 } 297 signal(SIGTERM, done); 298 299 preface(); 300 301 if (argc <= 1) 302 conv(stdin); 303 else 304 while (--argc > 0) { 305 if (strcmp(*++argv, "-") == 0) 306 fp = stdin; 307 else if ((fp = fopen(*argv, "r")) == NULL) { 308 fprintf(stderr, "%s: can't open %s\n", 309 prog, *argv); 310 pexit(prog, 2); 311 } 312 infilename = *argv; 313 conv(fp); 314 (void) fclose(fp); 315 } 316 done(); 317 } 318 319 /* process list of page numbers to be printed */ 320 outlist(s) 321 register char *s; 322 { 323 int n1, n2, i; 324 325 nolist = 0; 326 while (*s) { 327 n1 = 0; 328 if (isdigit (*s)) 329 do 330 n1 = 10 * n1 + *s++ - '0'; 331 while (isdigit(*s)); 332 else 333 n1 = -9999; 334 n2 = n1; 335 if (*s == '-') { 336 s++; 337 n2 = 0; 338 if (isdigit(*s)) 339 do 340 n2 = 10 * n2 + *s++ - '0'; 341 while (isdigit(*s)); 342 else 343 n2 = 9999; 344 } 345 olist[nolist++] = n1; 346 olist[nolist++] = n2; 347 if (*s != '\0') 348 s++; 349 } 350 olist[nolist] = 0; 351 #ifdef DEBUG 352 if (dbg) 353 for (i = 0; i < nolist; i += 2) 354 printf("%3d %3d\n", olist[i], olist[i + 1]); 355 #endif 356 } 357 358 conv(fp) /* convert a file */ 359 register FILE *fp; 360 { 361 register int c, k; 362 int m, n, n1, m1; 363 char str[100], buf[300]; 364 365 while ((c = getc(fp)) != EOF) 366 switch (c) { 367 case '\n': case ' ': case '\0': 368 break; 369 case '{': /* push down current environment */ 370 t_push(); 371 break; 372 case '}': 373 t_pop(); 374 break; 375 case '0': case '1': case '2': case '3': case '4': 376 case '5': case '6': case '7': case '8': case '9': 377 /* two motion digits plus a character */ 378 hmot((c - '0') * 10 + getc(fp) - '0'); 379 lastcmd = HMOT; 380 put1(getc(fp), (char *) 0); 381 lastcmd = CPUT; 382 break; 383 case 'c': /* single ascii character */ 384 put1(getc(fp), (char *) 0); 385 lastcmd = CPUT; 386 break; 387 case 'C': 388 fscanf(fp, "%s", str); 389 put1s(str); 390 lastcmd = CPUT; 391 break; 392 case 't': /* straight text */ 393 fgets(buf, sizeof buf, fp); 394 t_text(buf); 395 lastcmd = CPUT; 396 break; 397 case 'D': /* draw function */ 398 fgets(buf, sizeof buf, fp); 399 switch (buf[0]) { 400 case 'l': /* draw a line */ 401 sscanf(buf + 1, "%d %d", &n, &m); 402 drawline(n, m); 403 break; 404 case 'c': /* circle */ 405 sscanf(buf + 1, "%d", &n); 406 drawcirc(n); 407 break; 408 case 'e': /* ellipse */ 409 sscanf(buf + 1, "%d %d", &m, &n); 410 drawellip(m, n); 411 break; 412 case 'a': /* arc */ 413 sscanf(buf + 1, "%d %d %d %d", 414 &n, &m, &n1, &m1); 415 drawarc(n, m, n1, m1); 416 break; 417 case '~': /* b-spline */ 418 case 'g': /* gremlin curve */ 419 case 'z': /* bezier cubic */ 420 drawcurve(buf); 421 break; 422 case 'p': /* filled polygon */ 423 case 'P': /* bordered filled polygon */ 424 drawpoly(buf); 425 break; 426 case 't': /* line thickness */ 427 case 's': /* line style */ 428 sscanf(buf + 1, "%d", &n); 429 printf("%d D%c\n", n, buf[0]); 430 break; 431 default: 432 fprintf(stderr, 433 "%s: unknown drawing function %s\n", 434 prog, buf); 435 exit(2); 436 } 437 break; 438 case 'i': 439 fscanf(fp, "%d", &n); 440 printf("%d Di\n", n); 441 break; 442 case 's': 443 fscanf(fp, "%d", &n); 444 t_size(n); 445 lastcmd = FNT; 446 break; 447 case 'f': 448 fscanf(fp, "%s", str); 449 setfont(t_font(str)); 450 lastcmd = FNT; 451 break; 452 case 'H': /* absolute horizontal motion */ 453 while ((c = getc(fp)) == ' ') 454 ; 455 k = 0; 456 do 457 k = 10 * k + c - '0'; 458 while (isdigit(c = getc(fp))); 459 ungetc(c, fp); 460 hgoto(k); 461 lastcmd = HMOT; 462 break; 463 case 'h': /* relative horizontal motion */ 464 while ((c = getc(fp)) == ' ') 465 ; 466 k = 0; 467 do 468 k = 10 * k + c - '0'; 469 while (isdigit(c = getc(fp))); 470 ungetc(c, fp); 471 hmot(k); 472 lastcmd = HMOT; 473 break; 474 case 'w': 475 FlushShow(1); 476 lastcmd = BRK; 477 break; 478 case 'V': 479 fscanf(fp, "%d", &n); 480 vgoto(n); 481 lastcmd = VMOT; 482 break; 483 case 'v': 484 fscanf(fp, "%d", &n); 485 vmot(n); 486 lastcmd = VMOT; 487 break; 488 case 'p': /* new page */ 489 fscanf(fp, "%d", &n); 490 t_page(n); 491 lastcmd = NONE; 492 break; 493 case 'n': /* end of line -- ignore */ 494 while (getc(fp) != '\n') 495 ; 496 FlushShow(1); 497 lastcmd = BRK; 498 break; 499 case '#': /* comment */ 500 /* maybe should pass through as a PS comment */ 501 while (getc(fp) != '\n') 502 ; 503 break; 504 case 'x': /* device control */ 505 devcntrl(fp); 506 break; 507 case '%': /* imbedded PostScript */ 508 /* copy everything up to but NOT including a line */ 509 /* with at single "." */ 510 FlushShow(0); 511 MoveTo(); 512 DoMove(); 513 printf("\n%% included PostScript\n"); 514 while (fgets(buf, sizeof buf, fp) != NULL) { 515 if (strcmp(".\n", buf) == 0) 516 break; 517 fputs(buf, stdout); 518 } 519 break; 520 default: 521 fprintf(stderr, "%s: bad input char \\%03o (%c)\n", 522 prog, c, c); 523 exit(2); 524 } 525 } 526 527 /* put in PostScript prolog */ 528 preface() 529 { 530 register FILE *prolog; 531 char hostname[256]; 532 char tempfile[512]; 533 struct passwd *pswd; 534 long clock; 535 char *libdir; 536 537 printf("%%!%s\n", COMMENTVERSION); 538 pswd = getpwuid(getuid()); 539 (void) gethostname(hostname, sizeof hostname); 540 printf("%%%%Creator: %s:%s (%s)\n", hostname, 541 pswd->pw_name, pswd->pw_gecos); 542 printf("%%%%Title: %s (ditroff)\n", infilename); 543 printf("%%%%CreationDate: %s", (time(&clock), ctime(&clock))); 544 printf("%%%%EndComments\n"); 545 if ((libdir = envget("PSLIBDIR")) == NULL) 546 libdir = LibDir; 547 mstrcat(tempfile, libdir, prologfile, sizeof tempfile); 548 if (copyfile(tempfile, stdout) != 0) { 549 fprintf(stderr, "%s: can't copy prolog file %s\n", 550 prog, tempfile); 551 exit(2); 552 } 553 printf("ditstart\n"); 554 } 555 556 devcntrl(fp) /* interpret device control functions */ 557 FILE *fp; 558 { 559 char str[20], str1[50], buf[50]; 560 int c, n, res, minh, minv; 561 562 fscanf(fp, "%s", str); 563 switch (str[0]) { /* crude for now */ 564 case 'i': /* initialize */ 565 fileinit(); 566 t_init(); 567 lastcmd = NONE; 568 break; 569 case 'T': /* device name */ 570 /* 571 fscanf(fp, "%s", devname); 572 if (strcmp(devname, "psc")) { 573 fprintf(stderr, "%s: device not psc\n", prog); 574 exit(2); 575 } 576 */ 577 printf("(%s)xT\n", devname); 578 lastcmd = NONE; 579 break; 580 case 't': /* trailer */ 581 t_trailer(); 582 lastcmd = NONE; 583 break; 584 case 'p': /* pause -- can restart */ 585 t_reset('p'); 586 lastcmd = NONE; 587 break; 588 case 's': /* stop */ 589 t_reset('s'); 590 lastcmd = NONE; 591 break; 592 case 'r': /* resolution assumed when prepared */ 593 fscanf(fp, "%d %d %d", &res, &minh, &minv); 594 t_res(res, minh, minv); 595 lastcmd = NONE; 596 break; 597 case 'f': /* font used */ 598 fscanf(fp, "%d %s", &n, str); 599 fgets(buf, sizeof buf, fp); /* in case theres a filename */ 600 ungetc('\n', fp); /* fgets goes too far */ 601 str1[0] = 0; /* in case there is nothing to come in */ 602 sscanf(buf, "%s", str1); 603 loadfont(n, str, str1); 604 lastcmd = FNT; 605 break; 606 case 'H': /* char height */ 607 fscanf(fp, "%d", &n); 608 t_charht(n); 609 lastcmd = FNT; 610 break; 611 case 'S': /* slant */ 612 fscanf(fp, "%d", &n); 613 t_slant(n); 614 lastcmd = FNT; 615 break; 616 #ifdef XMOD 617 case 'X': { /* \X command from ditroff */ 618 int last; 619 char largebuf[128]; 620 fscanf (fp, "%1s", str); 621 switch (str[0]) { 622 case 'p' : 623 FlushShow(0);MoveTo();DoMove(); 624 fgets(largebuf, sizeof(largebuf), fp); 625 last = strlen(largebuf) - 1; 626 if (last >= 0 && largebuf[last] == '\n') { 627 ungetc('\n', fp); 628 largebuf[last] = ' '; 629 } 630 puts(largebuf); 631 break; 632 case 'f' : 633 FlushShow(0);MoveTo();DoMove(); 634 if (fscanf(fp, "%s", largebuf) == 1) { 635 char *nl = (char *) index(largebuf, '\n'); 636 if (nl) *nl = '\0'; 637 includefile(largebuf); 638 } else 639 fprintf(stderr, "warning - include cmd w/o path.\n"); 640 break; 641 } 642 } 643 break; 644 #endif 645 } 646 /* skip rest of input line */ 647 while ((c = getc(fp)) != '\n' && c != EOF) 648 ; 649 } 650 651 #ifdef XMOD 652 includefile(filenm) 653 char *filenm; 654 { 655 FILE *inf; 656 int ch, c1, c2, firstch = 0; 657 658 if (!(inf = fopen(filenm, "r"))) { 659 fprintf(stderr, "psdit: fopen(%s): ", filenm); 660 perror(); 661 exit(1); 662 } 663 c1 = fgetc(inf); c2 = fgetc(inf); 664 if (c1 != '%' || c2 != '!') 665 fprintf(stderr, "psdit: %s not a postscript file.\n", filenm), 666 exit(1); 667 668 fputs("%!", stdout); 669 while ((ch = fgetc(inf)) != EOF) { 670 putchar(ch); 671 if (firstch && ch == '%') { 672 /* we have to double leading '%'s */ 673 putchar('%'); 674 } 675 firstch = (ch == '\n'); 676 } 677 fclose(inf); 678 } 679 #endif 680 681 fileinit() /* read in font and code files, etc. */ 682 { 683 int i, fin, nw; 684 char *filebase, *p; 685 char temp[60]; 686 unsigned msize; 687 688 /* 689 * Open table for device, 690 * read in resolution, size info, font info, etc., and set params. 691 */ 692 sprintf(temp, "%s/dev%s/DESC.out", ditdir, devname); 693 if ((fin = open(temp, 0)) < 0) { 694 fprintf(stderr, "%s: can't open %s - %s\n", 695 prog, devname, temp); 696 pexit(prog, 2); 697 } 698 if (read(fin, (char *) &dev, sizeof (struct dev)) != 699 sizeof (struct dev)) { 700 fprintf(stderr, "%s: can't read %s\n", prog, temp); 701 pexit(prog, 2); 702 } 703 dres = dev.res; 704 nfonts = dev.nfonts; 705 nsizes = dev.nsizes; 706 nchtab = dev.nchtab; 707 /* enough room for whole file */ 708 filebase = malloc((unsigned) dev.filesize); 709 if (read(fin, filebase, dev.filesize) != dev.filesize) { 710 fprintf(stderr, "%s: trouble reading %s\n", prog, temp); 711 pexit(prog, 2); 712 } 713 pstab = (short *) filebase; /* point size table */ 714 chtab = pstab + nsizes + 1; /* char index table */ 715 chname = (char *) (chtab + dev.nchtab); /* char name table */ 716 p = chname + dev.lchname; /* end of char name table */ 717 /* parse the preloaded font tables */ 718 for (i = 1; i <= nfonts; i++) { 719 fontdelta[i] = 0; 720 fontbase[i] = (struct font *) p; 721 nw = *p & BMASK; /* number of width entries */ 722 if ((smnt == 0) && (fontbase[i]->specfont == 1)) 723 smnt = i; /* first special font */ 724 p += sizeof (struct font); /* skip header */ 725 widthtab[i] = p; /* width table */ 726 /* kern table is next */ 727 codetab[i] = p + 2 * nw; /* device codes */ 728 fitab[i] = p + 3 * nw; /* font index table */ 729 p += 3 * nw + dev.nchtab + (128 - 32); /* next font */ 730 t_fp(i, fontbase[i]->namefont, fontbase[i]->intname); 731 loadpswidths(i, fontbase[i]->namefont); 732 sayload(i, fontbase[i]->namefont, (char *) 0); 733 #ifdef DEBUG 734 if (fdbg > 1) 735 fontprint(i); 736 #endif 737 } 738 fontdelta[0] = 0; 739 msize = 3*255 + dev.nchtab + (128 - 32) + sizeof (struct font); 740 fontbase[0] = (struct font *) malloc(msize); 741 widthtab[0] = (char *) fontbase[0] + sizeof (struct font); 742 fontbase[0]->nwfont = 255; 743 close(fin); 744 } 745 746 loadpswidths(i, name) 747 int i; 748 char *name; 749 { 750 char temp[60]; 751 register FILE *auxin; 752 register int j; 753 int cc, wid, funny; 754 755 sprintf(temp, "%s/dev%s/%s.aux", ditdir, devname, name); 756 auxin = fopen(temp, "r"); 757 /* allocate table */ 758 if (pswidths[i] == NULL) 759 pswidths[i] = (int *) malloc(256 * (sizeof (int))); 760 /* initialize to not-there */ 761 for (j = 0; j <= 255; pswidths[i][j++] = -1) 762 ; 763 /* read them in */ 764 while (fscanf(auxin, "%d %d %d", &cc, &wid, &funny) != EOF) 765 pswidths[i][cc] = wid | (funny << 12); 766 (void) fclose(auxin); 767 } 768 769 #ifdef DEBUG 770 fontprint(i) /* debugging print of font i (0, ...) */ 771 int i; 772 { 773 int j, n; 774 char *p; 775 776 printf("font %d:\n", i); 777 p = (char *) fontbase[i]; 778 n = fontbase[i]->nwfont & BMASK; 779 printf("base=0%o, nchars=%d, spec=%d, name=%s, widtab=0%o, fitab=0%o\n", 780 p, n, fontbase[i]->specfont, 781 fontbase[i]->namefont, widthtab[i], fitab[i]); 782 printf("widths:\n"); 783 for (j = 0; j <= n; j++) { 784 printf(" %2d", widthtab[i][j] & BMASK); 785 if (j % 20 == 19) 786 printf("\n"); 787 } 788 printf("\ncodetab:\n"); 789 for (j = 0; j <= n; j++) { 790 printf(" %2d", codetab[i][j] & BMASK); 791 if (j % 20 == 19) 792 printf("\n"); 793 } 794 printf("\nfitab:\n"); 795 for (j = 0; j <= dev.nchtab + 128 - 32; j++) { 796 printf(" %2d", fitab[i][j] & BMASK); 797 if (j % 20 == 19) 798 printf("\n"); 799 } 800 printf("\n"); 801 } 802 #endif 803 804 loadfont(n, s, s1) /* load font info for font s on position n */ 805 int n; 806 char *s, *s1; 807 { 808 char temp[60]; 809 int fin, nw, norig; 810 int bcount; 811 812 if (n < 0 || n > NFONT) { 813 fprintf(stderr, "%s: illegal fp command %d %s\n", prog, n, s); 814 exit(2); 815 } 816 if (strcmp(s, fontbase[n]->namefont) == 0) 817 return; 818 if (fontbase[n]->namefont != 0) 819 fontdelta[n] = 1; 820 if (s1 == NULL || s1[0] == '\0') 821 sprintf(temp, "%s/dev%s/%s.out", ditdir, devname, s); 822 else 823 sprintf(temp, "%s/%s.out", s1, s); 824 if ((fin = open(temp, 0)) < 0) { 825 fprintf(stderr, "%s: can't open font table %s\n", prog, temp); 826 pexit(prog, 2); 827 } 828 norig = fontbase[n]->nwfont & BMASK; 829 bcount = 3 * norig + nchtab + 128 - 32 + sizeof (struct font); 830 (void) read(fin, (char *) fontbase[n], bcount); 831 if ((fontbase[n]->nwfont & BMASK) > norig) { 832 fprintf(stderr, "%s: Font %s too big for position %d\n", 833 prog, s, n); 834 exit(2); 835 } 836 close(fin); 837 nw = fontbase[n]->nwfont & BMASK; 838 widthtab[n] = (char *) fontbase[n] + sizeof (struct font); 839 codetab[n] = (char *) widthtab[n] + 2 * nw; 840 fitab[n] = (char *) widthtab[n] + 3 * nw; 841 t_fp(n, fontbase[n]->namefont, fontbase[n]->intname); 842 loadpswidths(n, fontbase[n]->namefont); 843 sayload(n, s, s1); 844 fontbase[n]->nwfont = norig; /* so can later use full original size */ 845 #ifdef DEBUG 846 if (fdbg > 1) 847 fontprint(n); 848 #endif 849 } 850 851 sayload(n, s, s1) /* position n contains font s (internal s1) */ 852 int n; 853 char *s, *s1; 854 { 855 char pass[60]; 856 FILE *ptrfile; 857 char Adobefont[60]; 858 859 if (s1 == NULL || s1[0] == '\0') 860 sprintf(pass, "%s/dev%s/%s.map", ditdir, devname, s); 861 else 862 sprintf(pass, "%s/%s.map", s1, s); 863 if ((ptrfile = fopen(pass, "r")) == NULL) { 864 fprintf(stderr, "%s: can't open font map file %s\n", 865 prog, pass); 866 pexit(prog, 2); 867 } 868 fscanf(ptrfile, "%s", Adobefont); 869 FlushShow(0); 870 printf("%d(%s)xf %d f\n", n, Adobefont, n); 871 font = n; 872 (void) fclose(ptrfile); 873 } 874 875 done() 876 { 877 t_reset('s'); 878 exit(0); 879 } 880 881 t_init() /* "x i" - initialize device */ 882 { 883 movepending = NONE; 884 savex = savey = 0; 885 886 t_size(10); /* start somewhere */ 887 t_slant(0); 888 setfont(1); /* set font */ 889 printf("xi\n"); 890 printf("%%%%EndProlog\n"); 891 } 892 893 t_push() /* begin a new block */ 894 { 895 FlushShow(1); 896 MoveTo(); 897 DoMove(); 898 if (dlevel == DSTACK) { 899 fprintf(stderr, "%s: ditroff push/pop overflow!\n", prog); 900 exit(2); 901 } 902 ditstack[dlevel].hpos = hpos; 903 ditstack[dlevel].vpos = vpos; 904 ditstack[dlevel].fontsize = fontsize; 905 ditstack[dlevel].fontheight = fontheight; 906 ditstack[dlevel].fontslant = fontslant; 907 ditstack[dlevel].font = font; 908 dlevel++; 909 printf("\nditpush\n"); 910 } 911 912 t_pop() /* pop to previous state */ 913 { 914 FlushShow(1); 915 MoveTo(); 916 DoMove(); 917 if (dlevel == 0) { 918 fprintf(stderr, "%s: ditroff push/pop underflow!\n", prog); 919 exit(2); 920 } 921 dlevel--; 922 hpos = ditstack[dlevel].hpos; 923 vpos = ditstack[dlevel].vpos; 924 fontsize = ditstack[dlevel].fontsize; 925 fontheight = ditstack[dlevel].fontheight; 926 fontslant = ditstack[dlevel].fontslant; 927 font = ditstack[dlevel].font; 928 printf("%d s %d xH %d xS %d f\n", 929 fontsize, fontheight, fontslant, font); 930 startx = savex = hpos; 931 savey = vpos; 932 PSx = hpos * PSmag; 933 PSy = vpos * PSmag; 934 printf("%d %d MXY\n", savex, savey); 935 movepending = NONE; 936 printf("\nditpop\n"); 937 } 938 939 t_page(n) /* do whatever new page functions */ 940 { 941 register int i; 942 943 if (output && ++scount >= spage) { 944 t_reset('p'); 945 scount = 0; 946 } 947 output = 1; 948 FlushShow(0); 949 if (!firstpage) 950 printf("\n%d p", n); 951 firstpage = FALSE; 952 printf("\n%%%%Page: %d %d\n", n, ++pageno, n); 953 for (i = 0; i <= nfonts; i++) 954 if (fontdelta[i] != 0) 955 sayload(i, fontname[i].name, (char *) 0); 956 vpos = 0; 957 PSy = 0; 958 printf("%d s %d xH %d xS %d f\n", 959 fontsize, fontheight, fontslant, font); 960 if (nolist == 0) 961 return; 962 output = 0; 963 for (i = 0; i < nolist; i += 2) 964 if (n >= olist[i] && n <= olist[i + 1]) { 965 output = 1; 966 break; 967 } 968 } 969 970 t_size(n) /* convert integer to internal size number*/ 971 int n; 972 { 973 FlushShow(1); 974 if (fontsize != n) { 975 fontsize = n; 976 #ifdef XMOD 977 fontheight = n; 978 #endif 979 printf("%d s\n", fontsize); 980 } 981 } 982 983 t_charht(n) /* set character height to n */ 984 int n; 985 { 986 FlushShow(1); 987 if (fontheight != n) { 988 fontheight = n; 989 printf("%d xH\n", fontheight); 990 } 991 } 992 993 t_slant(n) /* set slant to n */ 994 int n; 995 { 996 FlushShow(1); 997 if (fontslant != n) { 998 fontslant = n; 999 printf("%d xS\n", fontslant); 1000 } 1001 } 1002 1003 t_font(s) /* convert string to internal font number */ 1004 char *s; 1005 { 1006 int n; 1007 1008 n = atoi(s); 1009 return n < 0 || n > nfonts ? 1 : n; 1010 } 1011 1012 t_text(s) /* print string s as text??? */ 1013 char *s; 1014 { 1015 fprintf(stderr, "%s: ditroff t <%s> unimplemented!\n", prog, s); 1016 } 1017 1018 t_reset(c) 1019 { 1020 output = 1; /* by God */ 1021 if (c == 'p') 1022 printf("\nxp\n"); 1023 else if (!stopped) { 1024 printf("\nxs\n"); 1025 stopped = 1; 1026 } 1027 fflush(stdout); 1028 } 1029 1030 t_res(res, minh, minv) 1031 int res, minh, minv; 1032 { 1033 resolution = res; 1034 minhoriz = minh; 1035 minvert = minv; 1036 printf("%d %d %d xr\n", res, minh, minv); 1037 } 1038 1039 t_trailer() 1040 { 1041 FlushShow(0); 1042 printf("\n%d p", pageno); 1043 printf("\n%%%%Trailer\n"); 1044 printf("xt\n"); 1045 } 1046 1047 put1s(s) /* s is a funny char name */ 1048 char *s; 1049 { 1050 int i; 1051 1052 if (!output) 1053 return; 1054 debugp(("%s ", s)); 1055 1056 /* search for s in the funny char name table */ 1057 for (i = 0; i < nchtab; i++) 1058 if (strcmp(&chname[chtab[i]], s) == 0) 1059 break; 1060 if (i < nchtab) 1061 put1(i + 128, s); 1062 else { 1063 debugp(("not found ")); 1064 putnf(0, s); 1065 } 1066 } 1067 1068 #define needsescape(c) ((c) == '\\' || (c) == '(' || (c) == ')') 1069 1070 put1(c, s) /* output char c */ 1071 int c; 1072 char *s; 1073 { 1074 char *pw; 1075 register char *p; 1076 register int i, k; 1077 register int cc; 1078 int ofont, code; 1079 int psinfo, pswid, tw; 1080 1081 if (!output) 1082 return; 1083 if (c == ' ') { 1084 thisw = 0; 1085 FlushShow(0); 1086 return; 1087 } 1088 if (c < ' ') { 1089 debugp(("non-exist 0%o\n", c)); 1090 return; 1091 } 1092 c -= 32; /* offset char code */ 1093 k = ofont = pfont = font; 1094 if (onspecial) 1095 pfont = prevfont; 1096 if ((i = fitab[pfont][c] & BMASK) != 0) { /* char on this font */ 1097 p = codetab[pfont]; 1098 pw = widthtab[pfont]; 1099 if (onspecial) { 1100 setfont(prevfont); 1101 thisw = 0; 1102 onspecial = 0; 1103 } 1104 } else if (smnt > 0) { /* on special (we hope) */ 1105 for (k = smnt; k <= nfonts; k += 1) 1106 if ((i = fitab[k][c] & BMASK) != 0) { 1107 p = codetab[k]; 1108 pw = widthtab[k]; 1109 prevfont = pfont; 1110 if (onspecial && k == specfont) 1111 break; 1112 setfont(k); 1113 thisw = 0; 1114 onspecial = 1; 1115 specfont = k; 1116 break; 1117 } 1118 } 1119 if (i == 0 || k > nfonts || (code = p[i] & BMASK) == 0) { 1120 debugp(("not found 0%o\n", c + 32)); 1121 putnf(c + 32, s); 1122 return; 1123 } 1124 /* 1125 * when we get here, 1126 * c == biased character code 1127 * k == font number 1128 * i == index into codetab and widthtab for this character 1129 * p == codetab for this font 1130 * pw == width tab for this font 1131 * code == character code for this char 1132 */ 1133 cc = c + 32; 1134 debugp(((isascii(cc) && isprint(cc)) ? "%c %d\n":"%03o %d\n", 1135 cc, code)); 1136 psinfo = pswidths[font][code]; /* PS specific char info */ 1137 pswid = psinfo & PSWID; /* PS character width */ 1138 thisw = pw[i] & BMASK; /* troff char width */ 1139 tw = thisw = (thisw * fontsize + dev.unitwidth / 2) / dev.unitwidth; 1140 1141 if (psinfo & ISPSPROC && psinfo != -1) { 1142 /* character is implemented by a PostScript proc */ 1143 showspecial(s, code, pswid); 1144 if (pswid > 0) 1145 PSx += PSscale(pswid * fontsize * dres); 1146 thisw = 0; 1147 } else { 1148 showchar(code); 1149 if (pswid > 0) 1150 PSshowlen += PSscale(pswid * fontsize * dres); 1151 } 1152 1153 /* 1154 if (font != ofont) { 1155 setfont(ofont); 1156 startx = hpos + tw; 1157 thisw = 0; 1158 lastcmd = FNT; 1159 } 1160 */ 1161 debugp(("...width (%d)\n", pw[i] & BMASK)); 1162 } 1163 1164 putnf(c, s) /* note that a character wasnt found */ 1165 int c; 1166 char *s; 1167 { 1168 FlushShow(0); 1169 thisw = 0; 1170 if (s == NULL || *s == '\0') 1171 printf("(\%3o)cb\n", c); 1172 else if (strcmp(s, "\\|") == 0 || strcmp(s, "\\^") == 0 || 1173 strcmp(s, "\\&") == 0) 1174 return; 1175 else 1176 printf("(%s)cb\n", s); 1177 } 1178 1179 t_fp(n, s, si) /* font position n now contains font s, intname si */ 1180 int n; /* position */ 1181 char *s; /* font (ditname) */ 1182 char *si; /* font (intname = number) */ 1183 { 1184 fontname[n].name = s; 1185 fontname[n].number = atoi(si); 1186 } 1187 1188 setfont(n) /* set font to n */ 1189 int n; 1190 { 1191 FlushShow(1); 1192 if (n < 0 || n > NFONT) 1193 fprintf(stderr, "%s: illegal font %d\n", prog, n); 1194 if (font != n) { 1195 font = n; 1196 printf("%d f\n", font); 1197 } 1198 onspecial = 0; 1199 } 1200 1201 drawline(dx, dy) /* draw line from here to dx, dy */ 1202 int dx, dy; 1203 { 1204 FlushShow(0); 1205 MoveTo(); 1206 DoMove(); 1207 printf("%d %d Dl\n", dx, dy); 1208 hpos += dx; 1209 PSx = hpos * PSmag; 1210 vpos += dy; 1211 PSy = vpos * PSmag; 1212 } 1213 1214 drawcurve(line) 1215 char *line; 1216 { 1217 FlushShow(0); 1218 MoveTo(); 1219 DoMove(); 1220 getpoints(line + 1); 1221 /* hpos and vpos won't be changed by curve drawing code */ 1222 hpos = x[numpoints]; 1223 vpos = y[numpoints]; 1224 switch (*line) { 1225 case 'g': 1226 IS_Initialize(); 1227 IS_Convert(); 1228 break; 1229 case '~': 1230 BS_Initialize(); 1231 BS_Convert(); 1232 break; 1233 case 'z': 1234 BZ_Offsets(); 1235 BZ_Convert(); 1236 break; 1237 } 1238 printf("Dstroke\n"); 1239 } 1240 1241 drawpoly(line) 1242 char *line; 1243 { 1244 int stipple; 1245 register i; 1246 register char *p; 1247 int minx, miny, maxx, maxy; 1248 1249 FlushShow(0); 1250 MoveTo(); 1251 DoMove(); 1252 for (p = line + 1; isspace(*p); p++) 1253 ; 1254 for (stipple = 0; isdigit(*p); 1255 stipple = stipple * 10 + *p++ - '0') 1256 ; 1257 getpoints(p); 1258 minx = maxx = hpos; 1259 miny = maxy = vpos; 1260 for (i = 1; i <= numpoints; i++) { 1261 printf(" %lg %lg lineto\n", x[i], y[i]); 1262 if (x[i] > maxx) 1263 maxx = x[i]; 1264 if (x[i] < minx) 1265 minx = x[i]; 1266 if (y[i] > maxy) 1267 maxy = y[i]; 1268 if (y[i] < miny) 1269 miny = y[i]; 1270 } 1271 printf("closepath %d %d %d %d %d D%c\n", 1272 stipple, minx, miny, maxx, maxy, *line); 1273 /* XXX, hpos and vpos not changed? */ 1274 PSx = x[numpoints] * PSmag; 1275 PSy = y[numpoints] * PSmag; 1276 } 1277 1278 getpoints(s) 1279 register char *s; 1280 { 1281 int h = hpos, v = vpos; 1282 1283 numpoints = 0; 1284 for (;;) { 1285 int dh, dv, neg; 1286 1287 numpoints++; 1288 x[numpoints] = h; 1289 y[numpoints] = v; 1290 if (numpoints >= MAXPOINTS - 2) /* -2 for good measure */ 1291 break; 1292 for (; isspace(*s); s++) 1293 ; 1294 if (neg = *s == '-') 1295 s++; 1296 if (!isdigit(*s)) 1297 break; 1298 for (dh = 0; isdigit(*s); dh = dh * 10 + *s++ - '0') 1299 ; 1300 if (neg) 1301 dh = - dh; 1302 for (; isspace(*s); s++) 1303 ; 1304 if (neg = *s == '-') 1305 s++; 1306 if (!isdigit(*s)) 1307 break; 1308 for (dv = 0; isdigit(*s); dv = dv * 10 + *s++ - '0') 1309 ; 1310 if (neg) 1311 dv = - dv; 1312 h += dh; 1313 v += dv; 1314 } 1315 } 1316 1317 drawcirc(d) 1318 int d; 1319 { 1320 FlushShow(0); 1321 MoveTo(); 1322 DoMove(); 1323 printf("%d Dc\n", d); 1324 hpos += d; 1325 PSx = hpos * PSmag; 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