1 /* @(#)dterm.c 1.4 (Berkeley) 08/15/83" 2 * 3 * Converts ditroff output to text on a terminal. It is NOT meant to 4 * produce readable output, but is to show one how one's paper is (in 5 * general) formatted - what will go where on which page. 6 * 7 * options: 8 * 9 * -hn set horizontal resolution to n (in characters per inch; 10 * default is 10.0). 11 * 12 * -vn set vertical resolution (default is 6.0). 13 * 14 * -ln set maximum output line-length to n (default is 79). 15 * 16 * -olist output page list - as in troff. 17 * 18 * -c continue at end of page. Default is to stop at the end 19 * of each page, print "dterm:" and wait for a command. 20 * Type ? to get a list of available commands. 21 * 22 * -w sets h = 20, v = 12, l = 131, also sets -c to allow for 23 * extra-wide printouts on the printer. 24 * 25 * -fxxx get special character definition file "xxx". Default is 26 * /usr/lib/font/devter/specfile. 27 */ 28 29 30 #include <stdio.h> 31 #include <ctype.h> 32 #include <math.h> 33 34 35 #define FATAL 1 36 #define PGWIDTH 133 37 #define PGHEIGHT 110 38 #define LINELEN 78 39 #define SPECFILE "/usr/lib/font/devter/specfile" 40 41 #define hgoto(n) hpos = n 42 #define vgoto(n) vpos = n 43 #define hmot(n) hpos += n 44 #define vmot(n) vpos += n 45 46 #define sgn(n) ((n > 0) ? 1 : ((n < 0) ? -1 : 0)) 47 #define abs(n) ((n) >= 0 ? (n) : -(n)) 48 #define max(x,y) ((x) > (y) ? (x) : (y)) 49 #define min(x,y) ((x) < (y) ? (x) : (y)) 50 #define arcmove(x,y) { hgoto(x); vmot(-vpos-(y)); } 51 #define sqr(x) (long int)(x)*(x) 52 53 54 char SccsId [] = "@(#)dterm.c 1.4 (Berkeley) 08/15/83"; 55 56 char **spectab; /* here go the special characters */ 57 char *specfile = SPECFILE; /* place to look up special characters */ 58 char *malloc(); 59 60 int keepon = 0; /* flag: Don't stop at the end of each page? */ 61 int output = 0; /* do we do output at all? */ 62 int nolist = 0; /* output page list if > 0 */ 63 int olist[20]; /* pairs of page numbers */ 64 65 float hscale = 10.0; /* characters and lines per inch for output */ 66 float vscale = 6.0; /* device (defaults are for printer) */ 67 FILE *fp = stdin; /* input file pointer */ 68 69 char pagebuf[PGHEIGHT][PGWIDTH]; 70 int minh = PGWIDTH; 71 int maxh = 0; 72 int minv = PGHEIGHT; 73 int maxv = 0; 74 int linelen = LINELEN; 75 76 int hpos; /* horizontal position to be next (left = 0) */ 77 int vpos; /* current vertical position (down positive) */ 78 79 int np; /* number of pages seen */ 80 int npmax; /* high-water mark of np */ 81 int pgnum[40]; /* their actual numbers */ 82 long pgadr[40]; /* their seek addresses */ 83 84 int DP; /* step size for drawing */ 85 int drawdot = '.'; /* draw with this character */ 86 int maxdots = 32000; /* maximum number of dots in an object */ 87 88 89 90 main(argc, argv) 91 int argc; 92 char **argv; 93 { 94 argv++; 95 while (argc > 1 && **argv == '-') { 96 switch (*(++*argv)) { 97 case 'f': /* special character filepath */ 98 specfile = ++*argv; 99 break; 100 case 'l': /* output line length */ 101 linelen = atoi(++*argv) - 1; 102 break; 103 case 'h': /* horizontal scale (char/inch) */ 104 hscale = atof(++*argv); 105 break; 106 case 'v': /* vertical scale (char/inch) */ 107 vscale = atof(++*argv); 108 break; 109 case 'o': /* output list */ 110 outlist(++*argv); 111 break; 112 case 'c': /* continue (^L too) at endofpage */ 113 keepon = 1; 114 break; 115 case 'w': /* "wide" format */ 116 hscale = 16.0; 117 vscale = 9.6; 118 linelen = 131; 119 keepon = 1; 120 break; 121 } 122 argc--; 123 argv++; 124 } 125 126 if (argc <= 1) 127 conv(stdin); 128 else 129 while (--argc) { 130 if (strcmp(*argv, "-") == 0) 131 fp = stdin; 132 else if ((fp = fopen(*argv, "r")) == NULL) 133 error(FATAL, "can't open %s", *argv); 134 conv(fp); 135 fclose(fp); 136 argv++; 137 } 138 done(); 139 } 140 141 142 outlist(s) /* process list of page numbers to be printed */ 143 char *s; 144 { 145 int n1, n2, i; 146 147 nolist = 0; 148 while (*s) { 149 n1 = 0; 150 if (isdigit(*s)) 151 do 152 n1 = 10 * n1 + *s++ - '0'; 153 while (isdigit(*s)); 154 else 155 n1 = -9999; 156 n2 = n1; 157 if (*s == '-') { 158 s++; 159 n2 = 0; 160 if (isdigit(*s)) 161 do 162 n2 = 10 * n2 + *s++ - '0'; 163 while (isdigit(*s)); 164 else 165 n2 = 9999; 166 } 167 olist[nolist++] = n1; 168 olist[nolist++] = n2; 169 if (*s != '\0') 170 s++; 171 } 172 olist[nolist] = 0; 173 } 174 175 176 in_olist(n) /* is n in olist? */ 177 int n; 178 { 179 int i; 180 181 if (nolist == 0) 182 return(1); /* everything is included */ 183 for (i = 0; i < nolist; i += 2) 184 if (n >= olist[i] && n <= olist[i+1]) 185 return(1); 186 return(0); 187 } 188 189 190 conv(fp) 191 register FILE *fp; 192 { 193 register int c; 194 int m, n, i, n1, m1; 195 char str[100], buf[300]; 196 197 while ((c = getc(fp)) != EOF) { 198 switch (c) { 199 case '\n': /* when input is text */ 200 case '\t': 201 case ' ': 202 case 0: 203 break; 204 205 case '0': case '1': case '2': case '3': case '4': 206 case '5': case '6': case '7': case '8': case '9': 207 /* two motion digits plus a character */ 208 hmot((c-'0')*10 + getc(fp)-'0'); 209 put1(getc(fp)); 210 break; 211 212 case 'c': /* single ascii character */ 213 put1(getc(fp)); 214 break; 215 216 case 'C': /* funny character */ 217 fscanf(fp, "%s", str); 218 put1s(str); 219 break; 220 221 case 't': /* straight text */ 222 fgets(buf, sizeof(buf), fp); 223 t_text(buf); 224 break; 225 226 case 'D': /* draw function */ 227 fgets(buf, sizeof(buf), fp); 228 switch (buf[0]) { 229 case 'l': /* draw a line */ 230 sscanf(buf+1, "%d %d", &n, &m); 231 drawline(n, m, "."); 232 break; 233 case 'c': /* circle */ 234 sscanf(buf+1, "%d", &n); 235 drawcirc(n); 236 break; 237 case 'e': /* ellipse */ 238 sscanf(buf+1, "%d %d", &m, &n); 239 drawellip(m, n); 240 break; 241 case 'a': /* arc */ 242 sscanf(buf+1, "%d %d %d %d", &n, &m, &n1, &m1); 243 drawarc(n, m, n1, m1); 244 break; 245 case 'g': /* "gremlin" curve */ 246 case '~': /* wiggly line */ 247 drawwig(buf+1); 248 break; 249 case 't': /* thickness - not important */ 250 case 's': /* style - not important */ 251 break; 252 default: 253 error(FATAL,"unknown drawing command %s\n",buf); 254 break; 255 } 256 break; 257 case 's': /* point size - ignored */ 258 fscanf(fp, "%d", &n); 259 break; 260 261 case 'f': /* font request - ignored */ 262 fscanf(fp, "%s", str); 263 break; 264 265 case 'H': /* absolute horizontal motion */ 266 fscanf(fp, "%d", &n); 267 hgoto(n); 268 break; 269 270 case 'h': /* relative horizontal motion */ 271 fscanf(fp, "%d", &n); 272 hmot(n); 273 break; 274 275 case 'w': /* word space */ 276 break; 277 278 case 'V': /* absolute vertical motion */ 279 fscanf(fp, "%d", &n); 280 vgoto(n); 281 break; 282 283 case 'v': /* relative vertical motion */ 284 fscanf(fp, "%d", &n); 285 vmot(n); 286 break; 287 288 case 'p': /* new page */ 289 fscanf(fp, "%d", &n); 290 t_page(n); 291 break; 292 293 case 'n': /* end of line */ 294 hpos = 0; 295 case '#': /* comment */ 296 while (getc(fp) != '\n') 297 ; 298 break; 299 300 case 'x': /* device control */ 301 devcntrl(fp); 302 break; 303 304 default: 305 error(!FATAL, "unknown input character %o %c\n", c, c); 306 done(); 307 } 308 } 309 } 310 311 312 devcntrl(fp) /* interpret device control functions */ 313 FILE *fp; 314 { 315 int c, n; 316 char str[20]; 317 318 fscanf(fp, "%s", str); 319 switch (str[0]) { /* crude for now */ 320 case 'i': /* initialize */ 321 t_init(0); 322 break; 323 case 'r': /* resolution assumed when prepared */ 324 fscanf(fp, "%d", &n); 325 hscale = (float) n / hscale; 326 vscale = (float) n / vscale; 327 if((DP = n / 10 - 6) < 1) DP = 1; /* guess the drawing */ 328 break; /* resolution */ 329 case 'f': /* font used */ 330 case 'T': /* device name */ 331 case 't': /* trailer */ 332 case 'p': /* pause -- can restart */ 333 case 's': /* stop */ 334 break; 335 } 336 while (getc(fp) != '\n') /* skip rest of input line */ 337 ; 338 } 339 340 /* error printing routine - first argument is a "fatal" flag */ 341 error(f, s, a1, a2, a3, a4, a5, a6, a7) { 342 fprintf(stderr, "dterm: "); 343 fprintf(stderr, s, a1, a2, a3, a4, a5, a6, a7); 344 fprintf(stderr, "\n"); 345 if (f) exit(1); 346 } 347 348 349 t_init(reinit) /* initialize device */ 350 int reinit; 351 { 352 register int i; 353 register int j; 354 register FILE *fp; /* file to look up special characters */ 355 register char *charptr; /* string pointer to step through specials */ 356 register char *tabptr; /* string pointer for spectab setting */ 357 char specials[5000]; /* intermediate input buffer (made bigger */ 358 /* than we'll EVER use... */ 359 360 361 fflush(stdout); 362 hpos = vpos = 0; 363 for (i = 0; i < PGHEIGHT; i++) 364 for (j = 0; j < PGWIDTH; j++) 365 pagebuf[i][j] = ' '; 366 minh = PGWIDTH; 367 maxh = 0; 368 minv = PGHEIGHT; 369 maxv = 0; 370 371 if (reinit) return; /* if this is the first time, read */ 372 /* special character table file. */ 373 if ((fp = fopen (specfile, "r")) != NULL) { 374 charptr = &specials[0]; 375 for (i = 2; fscanf(fp, "%s", charptr) != EOF; i += 2) { 376 charptr += strlen(charptr) + 1; 377 } 378 fclose(fp); 379 *charptr++ = '\0'; /* ending strings */ 380 *charptr++ = '\0'; 381 /* allocate table */ 382 spectab = (char **) malloc(i * sizeof(char*)); 383 spectab[0] = tabptr = malloc(j = (int) (charptr - &specials[0])); 384 385 /* copy whole table */ 386 for (charptr = &specials[0]; j--; *tabptr++ = *charptr++); 387 388 tabptr = spectab[j]; /* set up pointers to table */ 389 for (j = 0; i--; j++) { 390 spectab[j] = tabptr; 391 tabptr += strlen(tabptr) + 1; 392 } 393 394 } else { /* didn't find table - allocate a null one */ 395 396 error (!FATAL, "Can't open special character file: %s", specfile); 397 spectab = (char **) malloc(2 * sizeof(char*)); 398 spectab[0] = malloc (2); 399 spectab[1] = spectab[0] + 1; 400 *spectab[0] = '\0'; 401 *spectab[1] = '\0'; 402 } 403 } 404 405 406 /* just got "p#" command. print the current page and */ 407 t_page(n) /* do whatever new page functions */ 408 { 409 long ftell(); 410 int c, m, i; 411 char buf[100], *bp; 412 413 pgnum[np++] = n; 414 pgadr[np] = ftell(fp); 415 if (np > npmax) 416 npmax = np; 417 if (output == 0) { 418 output = in_olist(n); 419 t_init(1); 420 return; 421 } 422 423 putpage(); 424 fflush(stdout); 425 426 if (keepon) { 427 putchar(''); 428 t_init(1); 429 return; 430 } 431 next: 432 for (bp = buf; (*bp = readch()); ) 433 if (*bp++ == '\n') 434 break; 435 *bp = 0; 436 switch (buf[0]) { 437 case 0: 438 done(); 439 break; 440 case '\n': 441 output = in_olist(n); 442 t_init(1); 443 return; 444 case '-': 445 case 'p': 446 m = atoi(&buf[1]) + 1; 447 if (fp == stdin) { 448 fputs("you can't; it's not a file\n", stderr); 449 break; 450 } 451 if (np - m <= 0) { 452 fputs("too far back\n", stderr); 453 break; 454 } 455 np -= m; 456 fseek(fp, pgadr[np], 0); 457 output = 1; 458 t_init(1); 459 return; 460 case '0': case '1': case '2': case '3': case '4': 461 case '5': case '6': case '7': case '8': case '9': 462 m = atoi(&buf[0]); 463 for (i = 0; i < npmax; i++) 464 if (m == pgnum[i]) 465 break; 466 if (i >= npmax || fp == stdin) { 467 fputs("you can't\n", stderr); 468 break; 469 } 470 np = i + 1; 471 fseek(fp, pgadr[np], 0); 472 output = 1; 473 t_init(1); 474 return; 475 case 'o': 476 outlist(&buf[1]); 477 output = 0; 478 t_init(1); 479 return; 480 case '?': 481 fputs("p print this page again\n", stderr); 482 fputs("-n go back n pages\n", stderr); 483 fputs("n print page n (previously printed)\n", stderr); 484 fputs("o... set the -o output list to ...\n", stderr); 485 break; 486 default: 487 fputs("?\n", stderr); 488 break; 489 } 490 goto next; 491 } 492 493 /* print the contents of the current page. puts out */ 494 putpage() /* only the part of the page that's been written on */ 495 { 496 int i, j, k; 497 498 fflush(stdout); 499 for (i = minv; i <= maxv; i++) { 500 for (k = maxh; pagebuf[i][k] == ' '; k--) 501 ; 502 if (k > minh + linelen) 503 k = minh + linelen; 504 for (j = minh; j <= k; j++) 505 putchar(pagebuf[i][j]); 506 putchar('\n'); 507 } 508 fflush(stdout); 509 } 510 511 512 t_text(s) /* print string s as text */ 513 char *s; 514 { 515 int c; 516 char str[100]; 517 518 if (!output) 519 return; 520 while ((c = *s++) != '\n') { 521 if (c == '\\') { 522 switch (c = *s++) { 523 case '\\': 524 case 'e': 525 put1('\\'); 526 break; 527 case '(': 528 str[0] = *s++; 529 str[1] = *s++; 530 str[2] = '\0'; 531 put1s(str); 532 break; 533 } 534 } else { 535 put1(c); 536 } 537 hmot(1); 538 } 539 } 540 541 542 put1s(s) /* s is a funny char name */ 543 char *s; 544 { 545 int i; 546 char *p; 547 static char prev[10] = ""; 548 static int previ; 549 550 if (!output) 551 return; 552 if (strcmp(s, prev) != 0) { 553 previ = -1; 554 for (i = 0; *spectab[i] != '\0'; i += 2) 555 if (strcmp(spectab[i], s) == 0) { 556 strcpy(prev, s); 557 previ = i; 558 break; 559 } 560 } 561 if (previ >= 0) { 562 for (p = spectab[previ+1]; *p; p++) 563 store(*p); 564 } else 565 prev[0] = '\0'; 566 } 567 568 569 put1(c) /* output char c */ 570 int c; 571 { 572 if (!output) 573 return; 574 store(c); 575 } 576 577 578 done() 579 { 580 output = 1; 581 putpage(); 582 fflush(stdout); 583 exit(0); 584 } 585 586 587 readch () 588 { 589 int c; 590 static FILE *rcf; 591 static nbol; /* 0 if at beginning of a line */ 592 593 if (rcf == NULL) { 594 rcf = fopen ("/dev/tty", "r"); 595 setbuf (rcf, NULL); 596 } 597 598 if (!nbol) 599 fprintf (stderr, "dterm: "); /* issue prompt */ 600 if ((c = getc (rcf)) == EOF) 601 return 0; 602 nbol = (c != '\n'); 603 return c; 604 } 605 606 607 store(c) /* put 'c' in the page at (hpos, vpos) */ 608 { 609 register int i; 610 register int j; 611 612 613 i = hpos / hscale; /* scale the position to page coordinates */ 614 j = vpos / vscale; 615 616 if (i >= PGWIDTH) i = PGWIDTH - 1; /* don't go over the edge */ 617 else if (i < 0) i = 0; 618 if (j >= PGHEIGHT) j = PGHEIGHT - 1; 619 else if (j < 0) j = 0; 620 621 pagebuf[j][i] = c; /* write the character */ 622 623 if (i > maxh) maxh = i; /* update the page bounds */ 624 if (i < minh) minh = i; 625 if (j > maxv) maxv = j; 626 if (j < minv) minv = j; 627 } 628 629 630 drawline(dx, dy, s) /* draw line from here to dx, dy using s */ 631 int dx, dy; 632 char *s; 633 { 634 register int xd; 635 register int yd; 636 register int i; 637 register int numdots; 638 int dirmot, perp; 639 int motincr, perpincr; 640 int ohpos, ovpos; 641 float val, slope; 642 float incrway; 643 644 ohpos = hpos; 645 ovpos = vpos; 646 xd = dx / DP; 647 yd = dy / DP; 648 if (xd == 0) { 649 numdots = abs (yd); 650 numdots = min(numdots, maxdots); 651 motincr = DP * sgn (yd); 652 for (i = 0; i < numdots; i++) { 653 vmot(motincr); 654 put1(drawdot); 655 } 656 } else 657 if (yd == 0) { 658 numdots = abs (xd); 659 motincr = DP * sgn (xd); 660 for (i = 0; i < numdots; i++) { 661 hmot(motincr); 662 put1(drawdot); 663 } 664 } else { 665 if (abs (xd) > abs (yd)) { 666 val = slope = (float) xd/yd; 667 numdots = abs (xd); 668 dirmot = 'h'; 669 perp = 'v'; 670 motincr = DP * sgn (xd); 671 perpincr = DP * sgn (yd); 672 } else { 673 val = slope = (float) yd/xd; 674 numdots = abs (yd); 675 dirmot = 'v'; 676 perp = 'h'; 677 motincr = DP * sgn (yd); 678 perpincr = DP * sgn (xd); 679 } 680 numdots = min(numdots, maxdots); 681 incrway = sgn ((int) slope); 682 for (i = 0; i < numdots; i++) { 683 val -= incrway; 684 if (dirmot == 'h') 685 hmot(motincr); 686 else 687 vmot(motincr); 688 if (val * slope < 0) { 689 if (perp == 'h') 690 hmot(perpincr); 691 else 692 vmot(perpincr); 693 val += slope; 694 } 695 put1(drawdot); 696 } 697 } 698 hgoto(ohpos + dx); 699 vgoto(ovpos + dy); 700 } 701 702 703 drawwig(s) /* draw wiggly line */ 704 char *s; 705 { 706 int x[50], y[50], xp, yp, pxp, pyp; 707 float t1, t2, t3, w; 708 int i, j, numdots, N; 709 char temp[50], *p, *getstr(); 710 711 p = s; 712 for (N = 2; (p=getstr(p,temp)) != NULL && N < sizeof(x)/sizeof(x[0]);) { 713 x[N] = atoi(temp); 714 p = getstr(p, temp); 715 y[N++] = atoi(temp); 716 } 717 x[0] = x[1] = hpos; 718 y[0] = y[1] = vpos; 719 for (i = 1; i < N; i++) { 720 x[i+1] += x[i]; 721 y[i+1] += y[i]; 722 } 723 x[N] = x[N-1]; 724 y[N] = y[N-1]; 725 pxp = pyp = -9999; 726 for (i = 0; i < N-1; i++) { /* interval */ 727 numdots = (dist(x[i], y[i], x[i+1], y[i+1]) 728 + dist(x[i+1], y[i+1], x[i+2], y[i+2])) / 2; 729 numdots /= DP; 730 numdots = min(numdots, maxdots); 731 for (j = 0; j < numdots; j++) { /* points within */ 732 w = (float) j / numdots; 733 t1 = 0.5 * w * w; 734 w = w - 0.5; 735 t2 = 0.75 - w * w; 736 w = w - 0.5; 737 t3 = 0.5 * w * w; 738 xp = t1 * x[i+2] + t2 * x[i+1] + t3 * x[i] + 0.5; 739 yp = t1 * y[i+2] + t2 * y[i+1] + t3 * y[i] + 0.5; 740 if (xp != pxp || yp != pyp) { 741 hgoto(xp); 742 vgoto(yp); 743 put1(drawdot); 744 pxp = xp; 745 pyp = yp; 746 } 747 } 748 } 749 } 750 751 752 /* copy next non-blank string from p to temp, update p */ 753 754 char *getstr(p, temp) 755 char *p, *temp; 756 { 757 while (*p == ' ' || *p == '\t' || *p == '\n') 758 p++; 759 if (*p == '\0') { 760 temp[0] = 0; 761 return(NULL); 762 } 763 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 764 *temp++ = *p++; 765 *temp = '\0'; 766 return(p); 767 } 768 769 770 drawcirc(d) 771 { 772 int xc, yc; 773 774 xc = hpos; 775 yc = vpos; 776 conicarc(hpos + d/2, -vpos, hpos, -vpos, hpos, -vpos, d/2, d/2); 777 hgoto(xc + d); /* circle goes to right side */ 778 vgoto(yc); 779 } 780 781 782 dist(x1, y1, x2, y2) /* integer distance from x1,y1 to x2,y2 */ 783 { 784 float dx, dy; 785 786 dx = x2 - x1; 787 dy = y2 - y1; 788 return sqrt(dx*dx + dy*dy) + 0.5; 789 } 790 791 792 drawarc(dx1, dy1, dx2, dy2) 793 { 794 int x0, y0, x2, y2, r; 795 796 x0 = hpos + dx1; /* center */ 797 y0 = vpos + dy1; 798 x2 = x0 + dx2; /* "to" */ 799 y2 = y0 + dy2; 800 r = sqrt((float) dx1 * dx1 + (float) dy1 * dy1) + 0.5; 801 conicarc(x0, -y0, hpos, -vpos, x2, -y2, r, r); 802 } 803 804 805 drawellip(a, b) 806 { 807 int xc, yc; 808 809 xc = hpos; 810 yc = vpos; 811 conicarc(hpos + a/2, -vpos, hpos, -vpos, hpos, -vpos, a/2, b/2); 812 hgoto(xc + a); 813 vgoto(yc); 814 } 815 816 817 conicarc(x, y, x0, y0, x1, y1, a, b) 818 { 819 /* based on Bresenham, CACM Feb 77, pp 102-3 by Chris Van Wyk */ 820 /* capitalized vars are an internal reference frame */ 821 long dotcount = 0; 822 int xs, ys, xt, yt, Xs, Ys, qs, Xt, Yt, qt, 823 M1x, M1y, M2x, M2y, M3x, M3y, 824 Q, move, Xc, Yc; 825 int ox1, oy1; 826 long delta; 827 float xc, yc; 828 float radius, slope; 829 float xstep, ystep; 830 831 ox1 = x1; 832 oy1 = y1; 833 if (a != b) /* an arc of an ellipse; internally, think of circle */ 834 if (a > b) { 835 xstep = (float)a / b; 836 ystep = 1; 837 radius = b; 838 } else { 839 xstep = 1; 840 ystep = (float)b / a; 841 radius = a; 842 } 843 else { 844 /* a circular arc; radius computed from center and first point */ 845 xstep = ystep = 1; 846 radius = sqrt((float)(sqr(x0 - x) + sqr(y0 - y))); 847 } 848 849 xc = x0; 850 yc = y0; 851 /* now, use start and end point locations to figure out 852 the angle at which start and end happen; use these 853 angles with known radius to figure out where start 854 and end should be 855 */ 856 slope = atan2((double)(y0 - y), (double)(x0 - x) ); 857 if (slope == 0.0 && x0 < x) 858 slope = 3.14159265; 859 x0 = x + radius * cos(slope) + 0.5; 860 y0 = y + radius * sin(slope) + 0.5; 861 slope = atan2((double)(y1 - y), (double)(x1 - x)); 862 if (slope == 0.0 && x1 < x) 863 slope = 3.14159265; 864 x1 = x + radius * cos(slope) + 0.5; 865 y1 = y + radius * sin(slope) + 0.5; 866 /* step 2: translate to zero-centered circle */ 867 xs = x0 - x; 868 ys = y0 - y; 869 xt = x1 - x; 870 yt = y1 - y; 871 /* step 3: normalize to first quadrant */ 872 if (xs < 0) 873 if (ys < 0) { 874 Xs = abs(ys); 875 Ys = abs(xs); 876 qs = 3; 877 M1x = 0; 878 M1y = -1; 879 M2x = 1; 880 M2y = -1; 881 M3x = 1; 882 M3y = 0; 883 } else { 884 Xs = abs(xs); 885 Ys = abs(ys); 886 qs = 2; 887 M1x = -1; 888 M1y = 0; 889 M2x = -1; 890 M2y = -1; 891 M3x = 0; 892 M3y = -1; 893 } 894 else if (ys < 0) { 895 Xs = abs(xs); 896 Ys = abs(ys); 897 qs = 0; 898 M1x = 1; 899 M1y = 0; 900 M2x = 1; 901 M2y = 1; 902 M3x = 0; 903 M3y = 1; 904 } else { 905 Xs = abs(ys); 906 Ys = abs(xs); 907 qs = 1; 908 M1x = 0; 909 M1y = 1; 910 M2x = -1; 911 M2y = 1; 912 M3x = -1; 913 M3y = 0; 914 } 915 916 Xc = Xs; 917 Yc = Ys; 918 if (xt < 0) 919 if (yt < 0) { 920 Xt = abs(yt); 921 Yt = abs(xt); 922 qt = 3; 923 } else { 924 Xt = abs(xt); 925 Yt = abs(yt); 926 qt = 2; 927 } 928 else if (yt < 0) { 929 Xt = abs(xt); 930 Yt = abs(yt); 931 qt = 0; 932 } else { 933 Xt = abs(yt); 934 Yt = abs(xt); 935 qt = 1; 936 } 937 938 /* step 4: calculate number of quadrant crossings */ 939 if (((4 + qt - qs) % 4 == 0) && (Xt <= Xs) && (Yt >= Ys)) 940 Q = 3; 941 else 942 Q = (4 + qt - qs) % 4 - 1; 943 /* step 5: calculate initial decision difference */ 944 delta = sqr(Xs + 1) + sqr(Ys - 1) - sqr(xs) - sqr(ys); 945 /* here begins the work of drawing. */ 946 while ((Q >= 0) || ((Q > -2) && ((Xt > Xc) && (Yt < Yc)))) { 947 if (dotcount++ % DP == 0) 948 putdot((int)xc, (int)yc); 949 if (Yc < 0.5) { 950 /* reinitialize */ 951 Xs = Xc = 0; 952 Ys = Yc = sqrt((float)(sqr(xs) + sqr(ys))); 953 delta = sqr(Xs + 1) + sqr(Ys - 1) - sqr(xs) - sqr(ys); 954 Q--; 955 M1x = M3x; 956 M1y = M3y; 957 { 958 int T; 959 T = M2y; 960 M2y = M2x; 961 M2x = -T; 962 T = M3y; 963 M3y = M3x; 964 M3x = -T; 965 } 966 } else { 967 if (delta <= 0) 968 if (2 * delta + 2 * Yc - 1 <= 0) 969 move = 1; 970 else 971 move = 2; 972 else if (2 * delta - 2 * Xc - 1 <= 0) 973 move = 2; 974 else 975 move = 3; 976 switch (move) { 977 case 1: 978 Xc++; 979 delta += 2 * Xc + 1; 980 xc += M1x * xstep; 981 yc += M1y * ystep; 982 break; 983 case 2: 984 Xc++; 985 Yc--; 986 delta += 2 * Xc - 2 * Yc + 2; 987 xc += M2x * xstep; 988 yc += M2y * ystep; 989 break; 990 case 3: 991 Yc--; 992 delta -= 2 * Yc + 1; 993 xc += M3x * xstep; 994 yc += M3y * ystep; 995 break; 996 } 997 } 998 } 999 drawline((int)xc-ox1,(int)yc-oy1,"."); 1000 } 1001 1002 1003 putdot(x, y) 1004 { 1005 arcmove(x, y); 1006 put1(drawdot); 1007 } 1008