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