1 /* pltroff.c (Berkeley) 1.5 83/10/07 2 * This version has code generators to drive the old-style troff 3 * that produces output for the Graphic Systems C/A/T. 4 * Very few people actually have a C/A/T; they instead typically 5 * use some other typesetter that simulates it. This is slow and 6 * rather silly, but compatibility with the past is important. 7 * Or so they say. Anyway ... 8 9 * The code generator can be turned on to old-style troff by setting 10 * the constant OLDTROFF with a #define statement; this will also 11 * have the effect of setting the default typesetter to the C/A/T 12 * in a consistent manner. 13 */ 14 15 #include <stdio.h> 16 #include <math.h> 17 extern int dbg; 18 19 /* this is the place to define OLDTROFF if you're going to */ 20 #ifdef OLDTROFF 21 # define OLDSTYLE 1 22 # define MAXMOT 8192 23 #else 24 # define OLDSTYLE 0 25 # define MAXMOT 32768 26 #endif 27 28 #define abs(n) (n >= 0 ? n : -(n)) 29 #define max(x,y) ((x)>(y) ? (x) : (y)) 30 #define PI 3.141592654 31 #define PI2 PI/2 32 33 extern int res; 34 extern int DX; /* step size in x */ 35 extern int DY; /* step size in y */ 36 37 int minline = 245; /* draw lines shorter than this with dots on 202 */ 38 /* ought to be point-size dependent, but what's that? */ 39 /* this is big enough to handle 202 up to 36 points */ 40 int drawdot = '.'; /* character to use when drawing */ 41 42 int useDline = 1; /* if set, produce \D for all lines */ 43 extern float hshift; /* how much to move left by for text */ 44 extern float vshift; /* how much down */ 45 46 /* scaling stuff, specific to typesetter */ 47 /* defined by s command as X0,Y0 to X1,Y1 */ 48 /* output dimensions set by -l,-w options to 0,0 to hmax, vmax */ 49 /* default output is 6x6 inches */ 50 51 52 float xscale; 53 float yscale; 54 55 int hpos = 0; /* current horizontal position in output coordinate system */ 56 int vpos = 0; /* current vertical position; 0 is top of page */ 57 58 int htrue = 0; /* where we really are */ 59 int vtrue = 0; 60 61 float X0, Y0; /* left bottom of input */ 62 float X1, Y1; /* right top of input */ 63 64 int hmax; /* right end of output */ 65 int vmax; /* top of output (down is positive) */ 66 67 extern float deltx; 68 extern float delty; 69 extern float xbound; 70 extern float ybound; 71 extern float xmin, ymin, xmax, ymax, sxmin, symin, sxmax, symax; 72 extern int crop; 73 74 openpl(s) /* initialize device */ 75 char *s; /* residue of .PS invocation line */ 76 { 77 float maxdelt; 78 79 hpos = vpos = 0; 80 hmax = vmax = 6 * res; /* default = 6 x 6 */ 81 if (deltx > xbound) { /* default 8 inches */ 82 fprintf(stderr, "pic: %g X %g picture shrunk to", deltx, delty); 83 deltx *= xbound/deltx; 84 delty *= xbound/deltx; 85 fprintf(stderr, " %g X %g\n", deltx, delty); 86 } 87 if (delty > ybound) { /* default 10 inches */ 88 fprintf(stderr, "pic: %g X %g picture shrunk to", deltx, delty); 89 deltx *= ybound/delty; 90 delty *= ybound/delty; 91 fprintf(stderr, " %g X %g\n", deltx, delty); 92 } 93 if (deltx > 0 && delty > 0) { /* have to change default size */ 94 hmax = res * deltx; 95 vmax = res * delty; 96 } 97 if (crop) { 98 if (xmax == xmin) 99 space(xmin, ymin, xmin + ymax-ymin, ymax); 100 else 101 space(xmin, ymin, xmax, ymin + xmax-xmin); /* assumes 1:1 aspect ratio */ 102 } 103 else 104 space(sxmin, symin, sxmax, symax); 105 printf("... %g %g %g %g %g %g %g %g\n", 106 xmin, ymin, xmax, ymax, sxmin, symin, sxmax, symax); 107 printf("... %du %du %du %du %du %du %du %du\n", 108 xconv(xmin), yconv(ymin), xconv(xmax), yconv(ymax), 109 xconv(sxmin), yconv(symin), xconv(sxmax), yconv(symax)); 110 printf(".PS %d %d %s", yconv(ymin), xconv(xmax), s); 111 /* assumes \n comes as part of s */ 112 if (xconv(xmax) >= MAXMOT || yconv(ymax) >= MAXMOT) { /* internal troff limit: 15 bits for motion */ 113 fprintf(stderr, "picture too high or wide"); 114 exit(1); 115 } 116 printf(".br\n"); 117 } 118 119 closepl(type) /* clean up after finished */ 120 { 121 movehv(0, 0); /* get back to where we started */ 122 if (type == 'F') 123 printf(".PF\n"); 124 else { 125 printf(".sp 1+%du\n", yconv(ymin)); 126 printf(".PE\n"); 127 } 128 } 129 130 move(x, y) /* go to position x, y in external coords */ 131 float x, y; 132 { 133 hgoto(xconv(x)); 134 vgoto(yconv(y)); 135 } 136 137 movehv(h, v) /* go to internal position h, v */ 138 int h, v; 139 { 140 hgoto(h); 141 vgoto(v); 142 } 143 144 hmot(n) /* generate n units of horizontal motion */ 145 int n; 146 { 147 hpos += n; 148 } 149 150 vmot(n) /* generate n units of vertical motion */ 151 int n; 152 { 153 vpos += n; 154 } 155 156 hgoto(n) 157 { 158 hpos = n; 159 } 160 161 vgoto(n) 162 { 163 vpos = n; 164 } 165 166 hvflush() /* get to proper point for output */ 167 { 168 if (hpos != htrue) { 169 printf("\\h'%du'", hpos - htrue); 170 htrue = hpos; 171 } 172 if (vpos != vtrue) { 173 printf("\\v'%du'", vpos - vtrue); 174 vtrue = vpos; 175 } 176 } 177 178 flyback() /* return to upper left corner (entry point) */ 179 { 180 printf(".sp -1\n"); 181 htrue = vtrue = 0; 182 } 183 184 troff(s) /* output troff right here */ 185 char *s; 186 { 187 printf("%s\n", s); 188 } 189 190 label(s, t, nh) /* text s of type t nh half-lines up */ 191 char *s; 192 int t, nh; 193 { 194 int q; 195 char *p; 196 197 hvflush(); 198 printf("\\h'-%.1fm'\\v'%.1fm'", hshift, vshift); /* shift down and left */ 199 /* .3 .3 is best for PO in circuit diagrams */ 200 if (t == 'A') 201 nh++; 202 else if (t == 'B') 203 nh--; 204 if (nh) 205 printf("\\v'%du*\\n(.vu/2u'", -nh); 206 /* just in case the text contains a quote: */ 207 q = 0; 208 for (p = s; *p; p++) 209 if (*p == '\'') { 210 q = 1; 211 break; 212 } 213 switch (t) { 214 case 'L': 215 default: 216 printf("%s", s); 217 break; 218 case 'C': 219 case 'A': 220 case 'B': 221 if (q) 222 printf("\\h\\(ts-\\w\\(ts%s\\(tsu/2u\\(ts%s\\h\\(ts-\\w\\(ts%s\\(tsu/2u\\(ts", s, s, s); 223 else 224 printf("\\h'-\\w'%s'u/2u'%s\\h'-\\w'%s'u/2u'", s, s, s); 225 break; 226 case 'R': 227 if (q) 228 printf("\\h\\(ts-\\w\\(ts%s\\(tsu\\(ts%s", s, s); 229 else 230 printf("\\h'-\\w'%s'u'%s", s, s); 231 break; 232 } 233 /* don't need these if flyback called immediately */ 234 printf("\n"); 235 flyback(); 236 } 237 238 line(x0, y0, x1, y1) /* draw line from x0,y0 to x1,y1 */ 239 float x0, y0, x1, y1; 240 { 241 move(x0, y0); 242 cont(x1, y1); 243 } 244 245 arrow(x0, y0, x1, y1, w, h) /* draw arrow (without line), head wid w & len h */ 246 float x0, y0, x1, y1, w, h; 247 { 248 double alpha, rot, hyp; 249 float dx, dy; 250 251 rot = atan2( w / 2, h ); 252 hyp = sqrt(w/2 * w/2 + h * h); 253 alpha = atan2(y1-y0, x1-x0); 254 if (dbg) 255 printf("rot=%f, hyp=%f, alpha=%f\n", rot, hyp, alpha); 256 dx = hyp * cos(alpha + PI + rot); 257 dy = hyp * sin(alpha + PI + rot); 258 if (dbg) printf("dx,dy = %g,%g\n", dx, dy); 259 line(x1+dx, y1+dy, x1, y1); 260 dx = hyp * cos(alpha + PI - rot); 261 dy = hyp * sin(alpha + PI - rot); 262 if (dbg) printf("dx,dy = %g,%g\n", dx, dy); 263 line(x1+dx, y1+dy, x1, y1); 264 } 265 266 box(x0, y0, x1, y1) 267 float x0, y0, x1, y1; 268 { 269 move(x0, y0); 270 cont(x0, y1); 271 cont(x1, y1); 272 cont(x1, y0); 273 cont(x0, y0); 274 } 275 276 cont(x, y) /* continue line from here to x,y */ 277 float x, y; 278 { 279 int h1, v1; 280 int dh, dv; 281 282 h1 = xconv(x); 283 v1 = yconv(y); 284 dh = h1 - hpos; 285 dv = v1 - vpos; 286 downsize(); 287 hvflush(); 288 if (!useDline && dv == 0 && abs(dh) > minline) /* horizontal */ 289 printf("\\l'%du'\n", dh); 290 else if (!useDline && dh == 0 && abs(dv) > minline) { /* vertical */ 291 printf("\\v'-.25m'\\L'%du\\(br'\\v'.25m'\n", dv); 292 /* add -.25m correction if use \(br */ 293 } else { 294 if (OLDSTYLE) 295 drawline(dh, dv); 296 else 297 printf("\\D'l%du %du'\n", dh, dv); 298 } 299 upsize(); 300 flyback(); /* expensive */ 301 hpos = h1; 302 vpos = v1; 303 } 304 305 circle(x, y, r) 306 float x, y, r; 307 { 308 int d; 309 310 downsize(); 311 d = xsc(2 * r); 312 move(x-r, y); 313 hvflush(); 314 if (OLDSTYLE) 315 drawcircle(d); 316 else 317 printf("\\D'c%du'\n", d); 318 upsize(); 319 flyback(); 320 } 321 322 spline(x, y, n, p) 323 float x, y, *p; 324 float n; 325 { 326 int i, j, dx, dy; 327 char temp[1000]; 328 329 downsize(); 330 move(x, y); 331 hvflush(); 332 if (OLDSTYLE) { 333 temp[0] = 0; 334 for (i = 0; i < 2 * n; i += 2) { 335 dx = xsc(p[i]); 336 dy = ysc(p[i+1]); 337 sprintf(&temp[strlen(temp)], " %d %d", dx, dy); 338 } 339 drawspline(temp); 340 } 341 else { 342 printf("\\D'~"); 343 for (i = 0; i < 2 * n; i += 2) { 344 dx = xsc(p[i]); 345 dy = ysc(p[i+1]); 346 printf(" %du %du", dx, dy); 347 } 348 printf("'\n"); 349 } 350 upsize(); 351 flyback(); 352 } 353 354 ellipse(x, y, r1, r2) 355 float x, y, r1, r2; 356 { 357 int ir1, ir2; 358 359 downsize(); 360 move(x-r1, y); 361 hvflush(); 362 ir1 = xsc(r1); 363 ir2 = ysc(r2); 364 if (OLDSTYLE) 365 drawellipse(2 * ir1, 2 * abs(ir2)); 366 else 367 printf("\\D'e%du %du'\n", 2 * ir1, 2 * abs(ir2)); 368 upsize(); 369 flyback(); 370 } 371 372 arc(x, y, x0, y0, x1, y1, r) /* draw arc with center x,y */ 373 float x, y, x0, y0, x1, y1, r; 374 { 375 376 downsize(); 377 move(x0, y0); 378 hvflush(); 379 if (OLDSTYLE) { 380 drawarc(xsc(x1-x0), ysc(y1-y0), xsc(r)); 381 } else { 382 printf("\\D'a%du %du %du %du'\n", 383 xsc(x-x0), ysc(y-y0), xsc(x1-x), ysc(y1-y)); 384 } 385 upsize(); 386 flyback(); 387 } 388 389 erase() /* get to bottom of frame */ 390 { 391 return; /* for now, ignore them */ 392 } 393 394 point(x, y) /* put point at x,y */ 395 float x, y; 396 { 397 static char *temp = "."; 398 399 move(x, y); 400 label(temp, 'L'); 401 } 402 403 space(x0, y0, x1, y1) /* set limits of page */ 404 float x0, y0, x1, y1; 405 { 406 if (x0 == x1) 407 x1 = x0 + 1; 408 if (y0 == y1) 409 y1 = y0 - 1; /* kludge */ 410 X0 = x0; 411 Y0 = y0; 412 X1 = x1; 413 Y1 = y1; 414 xscale = hmax / (X1-X0); 415 yscale = vmax / (Y0-Y1); 416 } 417 418 xconv(x) /* convert x from external to internal form */ 419 float x; 420 { 421 int v; 422 423 v = (x-X0) * xscale + 0.5; 424 if (OLDSTYLE) { 425 v = (v + DX - 1) / DX; 426 v *= DX; 427 } 428 return v; 429 } 430 431 xsc(x) /* convert x from external to internal form, scaling only */ 432 float x; 433 { 434 int v; 435 436 v = (x) * xscale + 0.5; 437 if (OLDSTYLE) { 438 v = (v + DX - 1) / DX; 439 v *= DX; 440 } 441 return v; 442 } 443 444 yconv(y) /* convert y from external to internal form */ 445 float y; 446 { 447 int v; 448 449 y += Y1 - ymax; 450 v = (y-Y1) * yscale + 0.5; 451 if (OLDSTYLE) { 452 v = (v + DY - 1) / DY; 453 v *= DY; 454 } 455 return v; 456 } 457 458 ysc(y) /* convert y from external to internal form, scaling only */ 459 float y; 460 { 461 int v; 462 463 v = (y) * yscale + 0.5; 464 if (OLDSTYLE) { 465 v = (v + DY - 1) / DY; 466 v *= DY; 467 } 468 return v; 469 } 470 471 linemod(s) 472 char *s; 473 { 474 } 475 476 dot() { 477 hvflush(); 478 if (OLDSTYLE) printf("\\&.\n"); 479 else printf("\\D'l 0 0'\n"); 480 flyback(); 481 } 482 483 #ifndef OLDTROFF 484 485 /* satisfy the loader... */ 486 487 drawline(){;} 488 drawcircle(){;} 489 drawspline(){;} 490 drawellipse(){;} 491 drawarc(){;} 492 upsize(){;} 493 downsize(){;} 494 495 #endif 496 497 #ifdef OLDTROFF 498 499 /* these are for real */ 500 501 int drawsize = 2; /* shrink point size by this factor */ 502 503 #define sgn(n) ((n > 0) ? 1 : ((n < 0) ? -1 : 0)) 504 #define arcmove(x,y) { hgoto(x); vmot(-vpos-(y)); } 505 506 put1(c) /* output one character, usually a dot */ 507 { 508 static int nput = 0; 509 510 if (nput++ > 100) { /* crude approx: troff input buffer ~ 400 */ 511 nput = 0; 512 printf("\n"); /* someday this will give a spurious break */ 513 flyback(); 514 printf("\\\&"); 515 } 516 hvflush(); /* crude! */ 517 printf("\\z%c", c); 518 } 519 520 downsize() /* set size lower to make it lighter */ 521 { 522 if (drawsize != 1) { 523 printf(".nr .. \\n(.s/%d\n", drawsize); 524 printf(".ps \\n(..\n"); 525 } 526 } 527 528 upsize() /* undo downsize */ 529 { 530 printf(".ps\n"); /* God help anyone who fiddles .ps */ 531 } 532 533 drawline(dx, dy) /* draw line from here to dx, dy */ 534 int dx, dy; 535 { 536 int xd, yd; 537 float val, slope; 538 int i, numdots; 539 int dirmot, perp; 540 int motincr, perpincr; 541 int ohpos, ovpos, osize; 542 float incrway; 543 544 ohpos = hpos; 545 ovpos = vpos; 546 xd = dx / DX; 547 yd = dy / DX; 548 printf("\\\&"); 549 put1(drawdot); 550 if (xd == 0) { 551 numdots = abs (yd); 552 motincr = DX * sgn (yd); 553 for (i = 0; i < numdots; i++) { 554 vmot(motincr); 555 put1(drawdot); 556 } 557 vgoto(ovpos + dy); 558 printf("\n"); 559 return; 560 } 561 if (yd == 0) { 562 numdots = abs (xd); 563 motincr = DX * sgn (xd); 564 for (i = 0; i < numdots; i++) { 565 hmot(motincr); 566 put1(drawdot); 567 } 568 hgoto(ohpos + dx); 569 printf("\n"); 570 return; 571 } 572 if (abs (xd) > abs (yd)) { 573 val = slope = (float) xd/yd; 574 numdots = abs (xd); 575 dirmot = 'h'; 576 perp = 'v'; 577 motincr = DX * sgn (xd); 578 perpincr = DX * sgn (yd); 579 } 580 else { 581 val = slope = (float) yd/xd; 582 numdots = abs (yd); 583 dirmot = 'v'; 584 perp = 'h'; 585 motincr = DX * sgn (yd); 586 perpincr = DX * sgn (xd); 587 } 588 incrway = sgn ((int) slope); 589 for (i = 0; i < numdots; i++) { 590 val -= incrway; 591 if (dirmot == 'h') 592 hmot(motincr); 593 else 594 vmot(motincr); 595 if (val * slope < 0) { 596 if (perp == 'h') 597 hmot(perpincr); 598 else 599 vmot(perpincr); 600 val += slope; 601 } 602 put1(drawdot); 603 } 604 hgoto(ohpos + dx); 605 vgoto(ovpos + dy); 606 printf("\n"); 607 } 608 609 drawspline(s) /* draw spline curve */ 610 char *s; 611 { 612 int x[50], y[50], xp, yp, pxp, pyp; 613 float t1, t2, t3, w; 614 int i, j, steps, N, prevsteps; 615 616 N = sscanf(s, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d ", 617 &x[2], &y[2], &x[3], &y[3], &x[4], &y[4], &x[5], &y[5], &x[6], &y[6], &x[7], &y[7], &x[8], &y[8], &x[9], &y[9], &x[10], &y[10], &x[11], &y[11], &x[12], &y[12], 618 &x[13], &y[13], &x[14], &y[14], &x[15], &y[15], &x[16], &y[16], &x[17], &y[17], &x[18], &y[18], &x[19], &y[19], &x[20], &y[20], &x[21], &y[21], &x[22], &y[22], &x[23], &y[23], &x[24], &y[24], 619 &x[25], &y[25], &x[26], &y[26], &x[27], &y[27], &x[28], &y[28], &x[29], &y[29], &x[30], &y[30], &x[31], &y[31], &x[32], &y[32], &x[33], &y[33], &x[34], &y[34], &x[35], &y[35], &x[36], &y[36], 620 &x[37], &y[37]); 621 N = N/2 + 2; 622 x[0] = x[1] = hpos; 623 y[0] = y[1] = vpos; 624 for (i = 1; i < N; i++) { 625 x[i+1] += x[i]; 626 y[i+1] += y[i]; 627 } 628 x[N] = x[N-1]; 629 y[N] = y[N-1]; 630 prevsteps = 0; 631 pxp = pyp = -9999; 632 printf("\\\&"); 633 for (i = 0; i < N-1; i++) { /* interval */ 634 steps = (dist(x[i],y[i], x[i+1],y[i+1]) + dist(x[i+1],y[i+1], x[i+2],y[i+2])) / 2; 635 steps /= DX; 636 for (j = 0; j < steps; j++) { /* points within */ 637 w = (float) j / steps; 638 t1 = 0.5 * w * w; 639 w = w - 0.5; 640 t2 = 0.75 - w * w; 641 w = w - 0.5; 642 t3 = 0.5 * w * w; 643 xp = t1 * x[i+2] + t2 * x[i+1] + t3 * x[i] + 0.5; 644 yp = t1 * y[i+2] + t2 * y[i+1] + t3 * y[i] + 0.5; 645 xp = round(xp, DX); 646 yp = round(yp, DY); 647 if (xp != pxp || yp != pyp) { 648 hgoto(xp); 649 vgoto(yp); 650 put1(drawdot); 651 pxp = xp; 652 pyp = yp; 653 } 654 } 655 } 656 printf("\n"); 657 } 658 659 drawcirc(d) 660 { 661 int xc, yc; 662 663 xc = hpos; 664 yc = vpos; 665 printf("\\\&"); 666 conicarc(hpos + d/2, -vpos, hpos, -vpos, hpos, -vpos, d/2, d/2); 667 hgoto(xc + d); /* circle goes to right side */ 668 vgoto(yc); 669 printf("\n"); 670 } 671 672 dist(x1, y1, x2, y2) /* integer distance from x1,y1 to x2,y2 */ 673 { 674 float dx, dy; 675 676 dx = x2 - x1; 677 dy = y2 - y1; 678 return sqrt(dx*dx + dy*dy) + 0.5; 679 } 680 681 drawarc(x, y, r) 682 { 683 int x0, y0; 684 float dx, dy, phi, d, ht, ang; 685 686 if (r == 0) 687 r = 1; 688 if (r < 0) 689 ang = PI / 2; 690 else 691 ang = -(PI / 2); 692 dx = x / 2; 693 dy = y / 2; 694 phi = atan2(dy, dx) + ang; 695 while ((d = (float)r * r - (dx*dx + dy*dy)) < 0.0) 696 r *= 2; 697 ht = sqrt(d); 698 x0 = hpos + dx + ht * cos(phi) + 0.5; 699 y0 = vpos + dy + ht * sin(phi) + 0.5; 700 printf("\\\&"); 701 conicarc(x0, -y0, hpos, -vpos, hpos+x, -vpos-y, r, r); 702 printf("\n"); 703 } 704 705 drawellip(a, b) 706 { 707 int xc, yc; 708 709 xc = hpos; 710 yc = vpos; 711 printf("\\\&"); 712 conicarc(hpos + a/2, -vpos, hpos, -vpos, hpos, -vpos, a/2, b/2); 713 hgoto(xc + a); 714 vgoto(yc); 715 printf("\n"); 716 } 717 718 #define sqr(x) (long int)(x)*(x) 719 720 conicarc(x, y, x0, y0, x1, y1, a, b) 721 { 722 /* based on Bresenham, CACM, Feb 77, pp 102-3 */ 723 /* by Chris Van Wyk */ 724 /* capitalized vars are an internal reference frame */ 725 long dotcount = 0; 726 int xs, ys, xt, yt, Xs, Ys, qs, Xt, Yt, qt, 727 M1x, M1y, M2x, M2y, M3x, M3y, 728 Q, move, Xc, Yc; 729 int delta; 730 float xc, yc; 731 float radius, slope; 732 float xstep, ystep; 733 if (a != b) /* an arc of an ellipse; internally, will still think of circle */ 734 if (a > b) { 735 xstep = (float)a / b; 736 ystep = 1; 737 radius = b; 738 } 739 else 740 { 741 xstep = 1; 742 ystep = (float)b / a; 743 radius = a; 744 } 745 else /* a circular arc; radius is computed from center and first point */ { 746 xstep = ystep = 1; 747 radius = sqrt((float)(sqr(x0 - x) + sqr(y0 - y))); 748 } 749 750 751 xc = x0; 752 yc = y0; 753 /* now, use start and end point locations to figure out 754 the angle at which start and end happen; use these 755 angles with known radius to figure out where start 756 and end should be */ 757 slope = atan2((double)(y0 - y), (double)(x0 - x) 758 ); 759 if ((slope == 0.0) 760 && (x0 < x) 761 ) 762 slope = 3.14159265; 763 x0 = x + radius * cos(slope) 764 + 0.5; 765 y0 = y + radius * sin(slope) 766 + 0.5; 767 slope = atan2((double)(y1 - y), (double)(x1 - x) 768 ); 769 if ((slope == 0.0) 770 && (x1 < x) 771 ) 772 slope = 3.14159265; 773 x1 = x + radius * cos(slope) 774 + 0.5; 775 y1 = y + radius * sin(slope) 776 + 0.5; 777 /* step 2: translate to zero-centered circle */ 778 xs = x0 - x; 779 ys = y0 - y; 780 xt = x1 - x; 781 yt = y1 - y; 782 /* step 3: normalize to first quadrant */ 783 if (xs < 0) 784 if (ys < 0) { 785 Xs = abs(ys); 786 Ys = abs(xs); 787 qs = 3; 788 M1x = 0; 789 M1y = -1; 790 M2x = 1; 791 M2y = -1; 792 M3x = 1; 793 M3y = 0; 794 } 795 else { 796 Xs = abs(xs); 797 Ys = abs(ys); 798 qs = 2; 799 M1x = -1; 800 M1y = 0; 801 M2x = -1; 802 M2y = -1; 803 M3x = 0; 804 M3y = -1; 805 } 806 else if (ys < 0) { 807 Xs = abs(xs); 808 Ys = abs(ys); 809 qs = 0; 810 M1x = 1; 811 M1y = 0; 812 M2x = 1; 813 M2y = 1; 814 M3x = 0; 815 M3y = 1; 816 } else { 817 Xs = abs(ys); 818 Ys = abs(xs); 819 qs = 1; 820 M1x = 0; 821 M1y = 1; 822 M2x = -1; 823 M2y = 1; 824 M3x = -1; 825 M3y = 0; 826 } 827 828 829 Xc = Xs; 830 Yc = Ys; 831 if (xt < 0) 832 if (yt < 0) { 833 Xt = abs(yt); 834 Yt = abs(xt); 835 qt = 3; 836 } 837 else { 838 Xt = abs(xt); 839 Yt = abs(yt); 840 qt = 2; 841 } 842 else if (yt < 0) { 843 Xt = abs(xt); 844 Yt = abs(yt); 845 qt = 0; 846 } else { 847 Xt = abs(yt); 848 Yt = abs(xt); 849 qt = 1; 850 } 851 852 853 /* step 4: calculate number of quadrant crossings */ 854 if (((4 + qt - qs) 855 % 4 == 0) 856 && (Xt <= Xs) 857 && (Yt >= Ys) 858 ) 859 Q = 3; 860 else 861 Q = (4 + qt - qs) % 4 - 1; 862 /* step 5: calculate initial decision difference */ 863 delta = sqr(Xs + 1) 864 + sqr(Ys - 1) 865 -sqr(xs) 866 -sqr(ys); 867 /* here begins the work of drawing 868 we hope it ends here too */ 869 while ((Q >= 0) 870 || ((Q > -2) 871 && ((Xt > Xc) 872 || (Yt < Yc) 873 ) 874 ) 875 ) { 876 if (dotcount++ % DX == 0) 877 putdot(round((int) xc, DX), round((int) yc, DY)); 878 if (Yc < 0.5) { 879 /* reinitialize */ 880 Xs = Xc = 0; 881 Ys = Yc = sqrt((float)(sqr(xs) + sqr(ys))); 882 delta = sqr(Xs + 1) + sqr(Ys - 1) - sqr(xs) - sqr(ys); 883 Q--; 884 M1x = M3x; 885 M1y = M3y; 886 { 887 int T; 888 T = M2y; 889 M2y = M2x; 890 M2x = -T; 891 T = M3y; 892 M3y = M3x; 893 M3x = -T; 894 } 895 } else { 896 if (delta <= 0) 897 if (2 * delta + 2 * Yc - 1 <= 0) 898 move = 1; 899 else 900 move = 2; 901 else if (2 * delta - 2 * Xc - 1 <= 0) 902 move = 2; 903 else 904 move = 3; 905 switch (move) { 906 case 1: 907 Xc++; 908 delta += 2 * Xc + 1; 909 xc += M1x * xstep; 910 yc += M1y * ystep; 911 break; 912 case 2: 913 Xc++; 914 Yc--; 915 delta += 2 * Xc - 2 * Yc + 2; 916 xc += M2x * xstep; 917 yc += M2y * ystep; 918 break; 919 case 3: 920 Yc--; 921 delta -= 2 * Yc + 1; 922 xc += M3x * xstep; 923 yc += M3y * ystep; 924 break; 925 } 926 } 927 } 928 929 930 } 931 932 putdot(x, y) 933 { 934 arcmove(x, y); 935 put1(drawdot); 936 } 937 938 round(x, dx) /* round x relative to dx */ 939 { 940 x = (x + dx - 1) / dx; 941 return x * dx; 942 } 943 #endif 944