1 /* draw.c 1.3 83/11/01 2 * 3 * This file contains the functions for producing the graphics 4 * images in the canon/imagen driver for ditroff. 5 */ 6 7 8 #include <stdio.h> 9 #include <ctype.h> 10 #include <math.h> 11 #include "canon.h" 12 13 14 #define TRUE 1 15 #define FALSE 0 16 /* imports from dip.c */ 17 #define hmot(n) hpos += n; 18 #define hgoto(n) hpos = n; 19 #define vmot(n) vpos += n; 20 #define vgoto(n) vpos = n; 21 22 extern int hpos; 23 extern int vpos; 24 extern int MAXX; 25 extern int MAXY; 26 extern FILE *tf; 27 extern putint(); 28 29 #define word(x) putint(x,tf) 30 #define byte(x) putc(x,tf) 31 #define MAXPOINTS 200 /* number of points legal for a curve */ 32 33 #define SOLID -1 /* line styles: these are used as bit masks to */ 34 #define DOTTED 004 /* create the right style lines. */ 35 #define DASHED 020 36 #define DOTDASHED 024 37 #define LONGDASHED 074 38 /* constants... */ 39 #define pi 3.14159265358979324 40 #define log2_10 3.3219280948873623 41 42 #define START 1 43 #define POINT 0 44 /* the imagen complains if a path is drawn at < 1, or > limit, so truncate. */ 45 #define xbound(x) (x < 1 ? 1 : x > MAXX ? MAXX : x) 46 #define ybound(y) (y < 1 ? 1 : y > MAXY ? MAXY : y) 47 48 49 int linethickness = -1; /* number of pixels wide to make lines */ 50 int linmod = SOLID; /* type of line (SOLID, DOTTED, DASHED...) */ 51 52 53 54 /*---------------------------------------------------------------------------- 55 | Routine: drawline (horizontal_motion, vertical_motion) 56 | 57 | Results: Draws a line of "linethickness" width and "linmod" style 58 | from current (hpos, vpos) to (hpos + dh, vpos + dv). 59 | 60 | Side Efct: Resulting position is at end of line (hpos + dh, vpos + dv) 61 *----------------------------------------------------------------------------*/ 62 63 drawline(dh, dv) 64 register int dh; 65 register int dv; 66 { 67 HGtline (hpos, vpos, hpos + dh, vpos + dv); 68 hmot (dh); /* new position is at */ 69 vmot (dv); /* the end of the line */ 70 } 71 72 73 /*---------------------------------------------------------------------------- 74 | Routine: drawcirc (diameter) 75 | 76 | Results: Draws a circle with leftmost point at current (hpos, vpos) 77 | with the given diameter d. 78 | 79 | Side Efct: Resulting position is at (hpos + diameter, vpos) 80 *----------------------------------------------------------------------------*/ 81 82 drawcirc(d) 83 register int d; 84 { /* 0.0 is the angle to sweep the arc: = full circle */ 85 HGArc (hpos + d/2, vpos, hpos, vpos, 0.0); 86 hmot (d); /* new postion is the right of the circle */ 87 } 88 89 90 /*---------------------------------------------------------------------------- 91 | Routine: drawellip (horizontal_diameter, vertical_diameter) 92 | 93 | Results: Draws regular ellipses given the major "diameters." It does 94 | so by drawing many small lines, every other pixel. The ellipse 95 | formula: ((x-x0)/hrad)**2 + ((y-y0)/vrad)**2 = 1 is used, 96 | converting to: y = y0 +- vrad * sqrt(1 - ((x-x0)/hrad)**2). 97 | The line segments are duplicated (mirrored) on either side of 98 | the horizontal "diameter". 99 | 100 | Side Efct: Resulting position is at (hpos + hd, vpos). 101 | 102 | Bugs: Odd numbered horizontal axes are rounded up to even numbers. 103 *----------------------------------------------------------------------------*/ 104 105 drawellip(hd, vd) 106 register int hd; 107 int vd; 108 { 109 register int bx; /* multiplicative x factor */ 110 register int x; /* x position drawing to */ 111 register int k2; /* the square-root term */ 112 register int y; /* y position drawing to */ 113 double k1; /* k? are constants depending on parameters */ 114 int bxsave, xsave, hdsave; /* places to save things to be used over */ 115 116 117 hd = 2 * ((hd + 1) / 2); /* don't accept odd diameters */ 118 if (hd < 2) hd = 2; /* or dinky ones */ 119 120 bx = 4 * (hpos + hd); 121 x = hpos; 122 k1 = vd / (2.0 * hd); 123 k2 = hd * hd - 4 * (hpos + hd/2) * (hpos + hd/2); 124 125 bxsave = bx; /* remember the parameters that will change through */ 126 xsave = x; /* the top half of the elipse, so the bottom half */ 127 hdsave = hd; /* can be drawn later. */ 128 129 byte(ASPATH); /* define drawing path */ 130 word(hd / 2 + 1); 131 word(xbound(hpos)); /* start out at current position */ 132 word(ybound(vpos)); 133 do { 134 x += 2; 135 word(xbound(x)); 136 y = vpos + (int) (k1 * sqrt((double) (k2 + (bx -= 8) * x))); 137 word(ybound(y)); 138 } while (hd -= 2); 139 byte(ADRAW); /* now draw the top half */ 140 byte(15); 141 142 bx = bxsave; /* get back the parameters for bottom half */ 143 x = xsave; 144 hd = hdsave; 145 146 byte(ASPATH); /* define drawing path */ 147 word(hd / 2 + 1); 148 word(xbound(hpos)); /* start out at current position */ 149 word(ybound(vpos)); 150 do { 151 x += 2; 152 word(xbound(x)); 153 y = vpos - (int) (k1 * sqrt((double) (k2 + (bx -= 8) * x))); 154 word(ybound(y)); 155 } while (hd -= 2); 156 byte(ADRAW); /* now draw the bottom half */ 157 byte(15); 158 159 hmot (hdsave); /* end position is the right-hand side of the ellipse */ 160 } 161 162 163 /*---------------------------------------------------------------------------- 164 | Routine: drawarc (xcenter, ycenter, xpoint, ypoint) 165 | 166 | Results: Draws an arc starting at current (hpos, vpos). Center is 167 | at (hpos + cdh, vpos + cdv) and the terminating point is 168 | at <center> + (pdh, pdv). The angle between the lines 169 | formed by the starting, ending, and center points is figured 170 | first, then the points and angle are sent to HGArc for the 171 | drawing. 172 | 173 | Side Efct: Resulting position is at the last point of the arc. 174 *----------------------------------------------------------------------------*/ 175 176 drawarc (cdh, cdv, pdh, pdv) 177 register int cdh; 178 register int cdv; 179 register int pdh; 180 register int pdv; 181 { 182 register double angle; 183 /* figure angle from the three points...*/ 184 /* and convert (and round) to degrees */ 185 angle = (atan2((double) pdh, (double) pdv) 186 - atan2 ((double) -cdh, (double) -cdv)) * 180.0 / pi; 187 /* "normalize" and round */ 188 angle += (angle < 0.0) ? 360.5 : 0.5; 189 190 HGArc(hpos + cdh, vpos + cdv, hpos, vpos, (int) angle); 191 hmot(cdh + pdh); 192 vmot(cdv + pdv); 193 } 194 195 196 /*---------------------------------------------------------------------------- 197 | Routine: drawwig (character_buffer, file_pointer, type_flag) 198 | 199 | Results: Given the starting position, the motion list in buf, and any 200 | extra characters from fp (terminated by a \n), drawwig sets 201 | up a point list to make a spline from. If "pic" is set picurve 202 | is called to draw the curve in pic style; else it calls HGCurve 203 | for the gremlin-style curve. 204 | 205 | Side Efct: Resulting position is reached from adding successive motions 206 | to the current position. 207 *----------------------------------------------------------------------------*/ 208 209 drawwig (buf, fp, pic) 210 char *buf; 211 FILE *fp; 212 int pic; 213 { 214 register int len = strlen(buf); /* length of the string in "buf" */ 215 register int npts = 2; /* point list index */ 216 register char *ptr = buf; /* "walking" pointer into buf */ 217 int x[MAXPOINTS], y[MAXPOINTS]; /* point list */ 218 219 while (*ptr == ' ') ptr++; /* skip any leading spaces */ 220 x[1] = hpos; /* the curve starts at the */ 221 y[1] = vpos; /* current position */ 222 223 while (*ptr != '\n') { /* curve commands end with a '\n' */ 224 hmot(atoi(ptr)); /* convert motion to curve points */ 225 x[npts] = hpos; /* and remember them */ 226 while (isdigit(*++ptr)); /* skip number*/ 227 while (*++ptr == ' '); /* skip spaces 'tween numbers */ 228 vmot(atoi(ptr)); 229 y[npts] = vpos; 230 while (isdigit(*++ptr)); 231 while (*ptr == ' ') ptr++; 232 /* if the amount we read wasn't the */ 233 /* whole thing, read some more in */ 234 if (len - (ptr - buf) < 15 && *(buf + len - 1) != '\n') { 235 char *cop = buf; 236 237 while (*cop++ = *ptr++); /* copy what's left to the beginning */ 238 fgets ((cop - 1), len - (cop - buf), fp); 239 ptr = buf; 240 } 241 if (npts < MAXPOINTS - 1) /* if too many points, forget some */ 242 npts++; 243 } 244 npts--; /* npts must point to the last coordinate in x and y */ 245 /* now, actually DO the curve */ 246 if (pic) 247 picurve(x, y, npts); 248 else 249 HGCurve(x, y, npts); 250 } 251 252 253 /*----------------------------------------------------------------------------* 254 | Routine: drawthick (thickness) 255 | 256 | Results: sets the variable "linethickness" to the given size. If this 257 | is different than previous thiknesses, informs Imagen of the 258 | change. NO motion is involved. 259 *----------------------------------------------------------------------------*/ 260 261 drawthick(s) 262 int s; 263 { 264 if (linethickness != s) { 265 byte(ASPEN); 266 byte((linethickness = s) < 1 ? 1 : linethickness > MAXPENW ? 267 MAXPENW : linethickness); 268 } 269 } 270 271 272 /*----------------------------------------------------------------------------* 273 | Routine: drawstyle (style_bit_map) 274 | 275 | Results: sets the variable "linmod" to the given bit map. 276 | NO motion is involved. 277 *----------------------------------------------------------------------------*/ 278 279 drawstyle(s) 280 int s; 281 { 282 linmod = s; 283 } 284 285 286 /*---------------------------------------------------------------------------- 287 | Routine: picurve (xpoints, ypoints, num_of_points) 288 | 289 | Results: Draws a curve delimited by (not through) the line segments 290 | traced by (xpoints, ypoints) point list. This is the "Pic" 291 | style curve. 292 *----------------------------------------------------------------------------*/ 293 294 picurve (x, y, npts) 295 int x[MAXPOINTS]; 296 int y[MAXPOINTS]; 297 int npts; 298 { 299 register int i; /* line segment traverser */ 300 register float w; /* position factor */ 301 register int xp; /* current point (and intermediary) */ 302 register int yp; 303 register int j; /* inner curve segment traverser */ 304 register int nseg; /* effective resolution for each curve */ 305 float t1, t2, t3; /* calculation temps */ 306 307 308 if (x[1] == x[npts] && y[1] == y[npts]) { 309 x[0] = x[npts - 1]; /* if the lines' ends meet, make */ 310 y[0] = y[npts - 1]; /* sure the curve meets */ 311 x[npts + 1] = x[2]; 312 y[npts + 1] = y[2]; 313 } else { /* otherwise, make the ends of the */ 314 x[0] = x[1]; /* curve touch the ending points of */ 315 y[0] = y[1]; /* the line segments */ 316 x[npts + 1] = x[npts]; 317 y[npts + 1] = y[npts]; 318 } 319 320 for (i = 0; i < npts; i++) { /* traverse the line segments */ 321 xp = x[i] - x[i+1]; 322 yp = y[i] - y[i+1]; 323 nseg = (int) sqrt((double)(xp * xp + yp * yp)); 324 xp = x[i+1] - x[i+2]; 325 yp = y[i+1] - y[i+2]; /* "nseg" is the number of line */ 326 /* segments that will be drawn for */ 327 /* each curve segment. ">> 3" is */ 328 /* dropping the resolution ( == / 8) */ 329 nseg = (nseg + (int) sqrt((double)(xp * xp + yp * yp))) >> 3; 330 331 byte(ASPATH); 332 if (nseg) 333 word(nseg + 1); 334 else 335 word(2); 336 for (j = 0; j <= nseg; j++) { 337 w = (float) j / (float) nseg; 338 t1 = 0.5 * w * w; 339 w -= 0.5; 340 t2 = 0.75 - w * w ; 341 w -= 0.5; 342 t3 = 0.5 * w * w; 343 xp = t1 * x[i+2] + t2 * x[i+1] + t3 * x[i] + 0.5; 344 yp = t1 * y[i+2] + t2 * y[i+1] + t3 * y[i] + 0.5; 345 word(xbound(xp)); 346 word(ybound(yp)); 347 } 348 if (nseg == 0) { 349 word(xbound(xp)); 350 word(ybound(yp)); 351 } 352 byte(ADRAW); 353 byte(15); 354 } 355 } 356 357 358 /*---------------------------------------------------------------------------- 359 | Routine: HGArc (xcenter, ycenter, xstart, ystart, angle) 360 | 361 | Results: This routine plots an arc centered about (cx, cy) counter 362 | clockwise starting from the point (px, py) through 'angle' 363 | degrees. If angle is 0, a full circle is drawn. It does so 364 | by creating a draw-path around the arc whose density of 365 | points depends on the size of the arc. 366 *----------------------------------------------------------------------------*/ 367 368 HGArc(cx,cy,px,py,angle) 369 int cx, cy, px, py, angle; 370 { 371 double xs, ys, resolution, fullcircle; 372 register int i; 373 register int extent; 374 register int nx; 375 register int ny; 376 register double epsilon; 377 378 xs = px - cx; 379 ys = py - cy; 380 381 /* calculate drawing parameters */ 382 383 resolution = pow(2.0, floor(log10(sqrt(xs * xs + ys * ys)) * log2_10)); 384 epsilon = 1.0 / resolution; 385 fullcircle = ceil(2 * pi * resolution); 386 if (angle == 0) 387 extent = fullcircle; 388 else 389 extent = angle * fullcircle / 360.0; 390 391 byte(ASPATH); /* start path definition */ 392 if (extent > 1) { 393 word(extent); /* number of points */ 394 for (i=0; i<extent; ++i) { 395 xs += epsilon * ys; 396 nx = (int) (xs + cx + 0.5); 397 ys -= epsilon * xs; 398 ny = (int) (ys + cy + 0.5); 399 word(xbound(nx)); /* put out a point on circle */ 400 word(ybound(ny)); 401 } /* end for */ 402 } else { /* arc is too small: put out point */ 403 word(2); 404 word(xbound(cx)); 405 word(ybound(cy)); 406 word(xbound(cx)); 407 word(ybound(cy)); 408 } 409 byte(ADRAW); /* now draw the arc */ 410 byte(15); 411 } /* end HGArc */ 412 413 414 /*---------------------------------------------------------------------------- 415 | Routine: Paramaterize (xpoints, ypoints, hparams, num_points) 416 | 417 | Results: This routine calculates parameteric values for use in 418 | calculating curves. The parametric values are returned 419 | in the array h. The values are an approximation of 420 | cumulative arc lengths of the curve (uses cord length). 421 | For additional information, see paper cited below. 422 *----------------------------------------------------------------------------*/ 423 424 static Paramaterize(x, y, h, n) 425 int x[MAXPOINTS]; 426 int y[MAXPOINTS]; 427 float h[MAXPOINTS]; 428 int n; 429 { 430 register int dx; 431 register int dy; 432 register int i; 433 register int j; 434 float u[MAXPOINTS]; 435 436 437 for (i=1; i<=n; ++i) { 438 u[i] = 0; 439 for (j=1; j<i; j++) { 440 dx = x[j+1] - x[j]; 441 dy = y[j+1] - y[j]; 442 u[i] += sqrt ((double) (dx * dx + dy * dy)); 443 } 444 } 445 for (i=1; i<n; ++i) h[i] = u[i+1] - u[i]; 446 } /* end Paramaterize */ 447 448 449 /*---------------------------------------------------------------------------- 450 | Routine: PeriodicSpline (h, z, dz, d2z, d3z, npoints) 451 | 452 | Results: This routine solves for the cubic polynomial to fit a 453 | spline curve to the the points specified by the list 454 | of values. The Curve generated is periodic. The algorithms 455 | for this curve are from the "Spline Curve Techniques" paper 456 | cited below. 457 *----------------------------------------------------------------------------*/ 458 459 static PeriodicSpline(h, z, dz, d2z, d3z, npoints) 460 float h[MAXPOINTS]; /* paramaterization */ 461 int z[MAXPOINTS]; /* point list */ 462 float dz[MAXPOINTS]; /* to return the 1st derivative */ 463 float d2z[MAXPOINTS], d3z[MAXPOINTS]; /* 2nd and 3rd derivatives */ 464 int npoints; /* number of valid points */ 465 { 466 float d[MAXPOINTS]; 467 float deltaz[MAXPOINTS], a[MAXPOINTS], b[MAXPOINTS]; 468 float c[MAXPOINTS], r[MAXPOINTS], s[MAXPOINTS]; 469 int i; 470 471 /* step 1 */ 472 for (i=1; i<npoints; ++i) { 473 deltaz[i] = h[i] ? ((double) (z[i+1] - z[i])) / h[i] : 0; 474 } 475 h[0] = h[npoints-1]; 476 deltaz[0] = deltaz[npoints-1]; 477 478 /* step 2 */ 479 for (i=1; i<npoints-1; ++i) { 480 d[i] = deltaz[i+1] - deltaz[i]; 481 } 482 d[0] = deltaz[1] - deltaz[0]; 483 484 /* step 3a */ 485 a[1] = 2 * (h[0] + h[1]); 486 b[1] = d[0]; 487 c[1] = h[0]; 488 for (i=2; i<npoints-1; ++i) { 489 a[i] = 2*(h[i-1]+h[i]) - pow ((double) h[i-1],(double)2.0) / a[i-1]; 490 b[i] = d[i-1] - h[i-1] * b[i-1]/a[i-1]; 491 c[i] = -h[i-1] * c[i-1]/a[i-1]; 492 } 493 494 /* step 3b */ 495 r[npoints-1] = 1; 496 s[npoints-1] = 0; 497 for (i=npoints-2; i>0; --i) { 498 r[i] = -(h[i] * r[i+1] + c[i])/a[i]; 499 s[i] = (6 * b[i] - h[i] * s[i+1])/a[i]; 500 } 501 502 /* step 4 */ 503 d2z[npoints-1] = (6 * d[npoints-2] - h[0] * s[1] 504 - h[npoints-1] * s[npoints-2]) 505 / (h[0] * r[1] + h[npoints-1] * r[npoints-2] 506 + 2 * (h[npoints-2] + h[0])); 507 for (i=1; i<npoints-1; ++i) { 508 d2z[i] = r[i] * d2z[npoints-1] + s[i]; 509 } 510 d2z[npoints] = d2z[1]; 511 512 /* step 5 */ 513 for (i=1; i<npoints; ++i) { 514 dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i+1])/6; 515 d3z[i] = h[i] ? (d2z[i+1] - d2z[i])/h[i] : 0; 516 } 517 } /* end PeriodicSpline */ 518 519 520 /*---------------------------------------------------------------------------- 521 | Routine: NaturalEndSpline (h, z, dz, d2z, d3z, npoints) 522 | 523 | Results: This routine solves for the cubic polynomial to fit a 524 | spline curve the the points specified by the list of 525 | values. The alogrithms for this curve are from the 526 | "Spline Curve Techniques" paper cited below. 527 *----------------------------------------------------------------------------*/ 528 529 static NaturalEndSpline(h, z, dz, d2z, d3z, npoints) 530 float h[MAXPOINTS]; /* parameterization */ 531 int z[MAXPOINTS]; /* Point list */ 532 float dz[MAXPOINTS]; /* to return the 1st derivative */ 533 float d2z[MAXPOINTS], d3z[MAXPOINTS]; /* 2nd and 3rd derivatives */ 534 int npoints; /* number of valid points */ 535 { 536 float d[MAXPOINTS]; 537 float deltaz[MAXPOINTS], a[MAXPOINTS], b[MAXPOINTS]; 538 int i; 539 540 /* step 1 */ 541 for (i=1; i<npoints; ++i) { 542 deltaz[i] = h[i] ? ((double) (z[i+1] - z[i])) / h[i] : 0; 543 } 544 deltaz[0] = deltaz[npoints-1]; 545 546 /* step 2 */ 547 for (i=1; i<npoints-1; ++i) { 548 d[i] = deltaz[i+1] - deltaz[i]; 549 } 550 d[0] = deltaz[1] - deltaz[0]; 551 552 /* step 3 */ 553 a[0] = 2 * (h[2] + h[1]); 554 b[0] = d[1]; 555 for (i=1; i<npoints-2; ++i) { 556 a[i] = 2*(h[i+1]+h[i+2]) - pow((double) h[i+1],(double) 2.0)/a[i-1]; 557 b[i] = d[i+1] - h[i+1] * b[i-1]/a[i-1]; 558 } 559 560 /* step 4 */ 561 d2z[npoints] = d2z[1] = 0; 562 for (i=npoints-1; i>1; --i) { 563 d2z[i] = (6 * b[i-2] - h[i] *d2z[i+1])/a[i-2]; 564 } 565 566 /* step 5 */ 567 for (i=1; i<npoints; ++i) { 568 dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i+1])/6; 569 d3z[i] = h[i] ? (d2z[i+1] - d2z[i])/h[i] : 0; 570 } 571 } /* end NaturalEndSpline */ 572 573 574 /*---------------------------------------------------------------------------- 575 | Routine: HGCurve(xpoints, ypoints, num_points) 576 | 577 | Results: This routine generates a smooth curve through a set of points. 578 | The method used is the parametric spline curve on unit knot 579 | mesh described in "Spline Curve Techniques" by Patrick 580 | Baudelaire, Robert Flegal, and Robert Sproull -- Xerox Parc. 581 *----------------------------------------------------------------------------*/ 582 583 #define PointsPerInterval 32 584 585 HGCurve(x, y, numpoints) 586 int x[MAXPOINTS]; 587 int y[MAXPOINTS]; 588 int numpoints; 589 { 590 float h[MAXPOINTS], dx[MAXPOINTS], dy[MAXPOINTS]; 591 float d2x[MAXPOINTS], d2y[MAXPOINTS], d3x[MAXPOINTS], d3y[MAXPOINTS]; 592 float t, t2, t3; 593 register int j; 594 register int k; 595 register int nx; 596 register int ny; 597 int lx, ly; 598 599 600 lx = x[1]; 601 ly = y[1]; 602 603 /* Solve for derivatives of the curve at each point 604 * separately for x and y (parametric). 605 */ 606 Paramaterize(x, y, h, numpoints); 607 /* closed curve */ 608 if ((x[1] == x[numpoints]) && (y[1] == y[numpoints])) { 609 PeriodicSpline(h, x, dx, d2x, d3x, numpoints); 610 PeriodicSpline(h, y, dy, d2y, d3y, numpoints); 611 } else { 612 NaturalEndSpline(h, x, dx, d2x, d3x, numpoints); 613 NaturalEndSpline(h, y, dy, d2y, d3y, numpoints); 614 } 615 616 /* generate the curve using the above information and 617 * PointsPerInterval vectors between each specified knot. 618 */ 619 620 for (j=1; j<numpoints; ++j) { 621 if ((x[j] == x[j+1]) && (y[j] == y[j+1])) continue; 622 for (k=0; k<=PointsPerInterval; ++k) { 623 t = (float) k * h[j] / (float) PointsPerInterval; 624 t2 = t * t; 625 t3 = t * t * t; 626 nx = x[j] + (int) (t * dx[j] + t2 * d2x[j]/2 + t3 * d3x[j]/6); 627 ny = y[j] + (int) (t * dy[j] + t2 * d2y[j]/2 + t3 * d3y[j]/6); 628 HGtline(lx, ly, nx, ny); 629 lx = nx; 630 ly = ny; 631 } /* end for k */ 632 } /* end for j */ 633 } /* end HGCurve */ 634 635 636 /*---------------------------------------------------------------------------- 637 | Routine: line(xstart, ystart, xend, yend) 638 | 639 | Results: Creates a drawing path and draws the line. If the line falls 640 | off the end of the page, a crude clipping is done: truncating 641 | the offending ordinate. 642 *----------------------------------------------------------------------------*/ 643 644 line(x0, y0, x1, y1) 645 int x0, y0, x1, y1; 646 { 647 byte(ASPATH); /* send the coordinates first */ 648 word(2); /* only two */ 649 word(xbound(x0)); 650 word(ybound(y0)); 651 word(xbound(x1)); 652 word(ybound(y1)); 653 byte(ADRAW); /* now draw it */ 654 byte(15); /* black */ 655 } /* end line */ 656 657 658 /*----------------------------------------------------------------------------* 659 | Routine: change (x_position, y_position, visible_flag) 660 | 661 | Results: As HGtline passes from the invisible to visible (or vice 662 | versa) portion of a line, change is called to either draw 663 | the line, or initialize the beginning of the next one. 664 | Change calls line to draw segments if visible_flag is set 665 | (which means we're leaving a visible area). 666 *----------------------------------------------------------------------------*/ 667 668 change (x, y, vis) 669 register int x; 670 register int y; 671 register int vis; 672 { 673 static int xorg; 674 static int yorg; 675 676 if (vis) /* leaving a visible area, draw it. */ 677 line (xorg, yorg, x, y); 678 else { /* otherwise, we're entering one, remember beginning */ 679 xorg = x; 680 yorg = y; 681 } 682 } 683 684 685 /*---------------------------------------------------------------------------- 686 | Routine: HGtline (xstart, ystart, xend, yend) 687 | 688 | Results: Draws a line from (x0,y0) to (x1,y1) using line(x0,y0,x1,y1) 689 | to place individual segments of dotted or dashed lines. 690 *----------------------------------------------------------------------------*/ 691 692 HGtline(x0, y0, x1, y1) 693 register int x0; 694 register int y0; 695 int x1; 696 int y1; 697 { 698 register int dx; 699 register int dy; 700 register int res1; 701 register int visible; 702 int res2; 703 int xinc; 704 int yinc; 705 int slope; 706 707 708 if (linmod == -1) { 709 line(x0, y0, x1, y1); 710 return; 711 } 712 xinc = 1; 713 yinc = 1; 714 if ((dx = x1-x0) < 0) { 715 xinc = -1; 716 dx = -dx; 717 } 718 if ((dy = y1-y0) < 0) { 719 yinc = -1; 720 dy = -dy; 721 } 722 slope = xinc*yinc; 723 res1 = 0; 724 res2 = 0; 725 visible = 0; 726 if (dx >= dy) 727 while (x0 != x1) { 728 if((((x0+slope*y0)&linmod)&&1)^visible) { 729 change(x0, y0, visible); 730 visible = !visible; 731 } 732 if (res1 > res2) { 733 res2 += dx - res1; 734 res1 = 0; 735 y0 += yinc; 736 } 737 res1 += dy; 738 x0 += xinc; 739 } 740 else 741 while (y0 != y1) { 742 if((((x0+slope*y0)&linmod)&&1)^visible) { 743 change(x0, y0, visible); 744 visible = !visible; 745 } 746 if (res1 > res2) { 747 res2 += dy - res1; 748 res1 = 0; 749 x0 += xinc; 750 } 751 res1 += dx; 752 y0 += yinc; 753 } 754 if(visible) change(x1, y1, 1); 755 } 756