1 /* hgraph.c 1.4 83/05/05 2 * 3 * Copyright -C- 1982 Barry S. Roitblat 4 * 5 * This file contains the graphics routines for hard copy (gprint) 6 * production of gremlin files. 7 * 8 */ 9 10 #include "gprint.h" 11 #include <vfont.h> 12 13 14 /* line and character styles */ 15 16 int style[STYLES] = { DOTTED, DOTDASHED, SOLID, DASHED, SOLID, SOLID }; 17 int thick[STYLES] = { 1, 1, 5, 1, 1, 3 }; 18 char *tfont[FONTS] = { "R", "I", "B", "S" }; 19 char *tsize[SIZES] = { "10", "16", "24", "36" }; 20 21 22 /* variables used to print from font file */ 23 24 extern Orientation; 25 extern cfont; 26 extern csize; 27 extern struct header header; 28 extern struct dispatch dispatch[256]; 29 extern char *bits; 30 extern char *fontdir ; 31 32 /* imports from main.c */ 33 34 extern double scale; 35 extern point(); 36 extern int linethickness; 37 extern int linmod; 38 extern int lastx; 39 extern int lasty; 40 extern double orgx; 41 extern double orgy; 42 extern int DevRange; 43 44 45 line(x0, y0, x1, y1) 46 int x0, y0, x1, y1; 47 48 /* This routine is called to draw a line from the point at (x0, y0) to (x1, y1). 49 * The line is drawn using a variation of 50 */ 51 52 { 53 int dx, dy; 54 int xinc, yinc; 55 int res1; 56 int res2; 57 int slope; 58 59 xinc = 1; 60 yinc = 1; 61 if ((dx = x1-x0) < 0) 62 { 63 xinc = -1; 64 dx = -dx; 65 } 66 if ((dy = y1-y0) < 0) 67 { 68 yinc = -1; 69 dy = -dy; 70 } 71 slope = xinc*yinc; 72 res1 = 0; 73 res2 = 0; 74 if (dx >= dy) 75 while (x0 != x1) 76 { 77 if((x0+slope*y0)&linmod) point(x0, y0); 78 if (res1 > res2) 79 { 80 res2 += dx - res1; 81 res1 = 0; 82 y0 += yinc; 83 } 84 res1 += dy; 85 x0 += xinc; 86 } 87 else 88 while (y0 != y1) 89 { 90 if((x0+slope*y0)&linmod) point(x0, y0); 91 if (res1 > res2) 92 { 93 res2 += dy - res1; 94 res1 = 0; 95 x0 += xinc; 96 } 97 res1 += dx; 98 y0 += yinc; 99 } 100 if((x1+slope*y1)&linmod) point(x1, y1); 101 } 102 103 104 HGPrintElt(element) 105 ELT *element; 106 107 /* This routine examines the picture elements and calls the appropriate 108 * routine(s) to print them according to their type. 109 */ 110 111 { 112 POINT *p1, *p2, pt1, pt2; 113 int x1, y1, i, dx, dy; 114 char *txt, c; 115 116 if ( !DBNullelt(element) ) 117 { 118 if (TEXT(element->type)) 119 { 120 p1 = element->ptlist; 121 HGSetFont(element->brushf, element->size); 122 pt1.x = mapx(xorn(p1->x, p1->y)); 123 pt1.y = mapy(yorn(p1->x, p1->y)); 124 txt = element->textpt; 125 HGPutText(element->type, pt1, txt); 126 } 127 else 128 { 129 switch (element->type) 130 { 131 case ARC: p1 = element->ptlist; 132 p2 = PTNextPoint(p1); 133 HGSetBrush(element->brushf); 134 pt1.x = mapx(xorn(p1->x, p1->y)); 135 pt1.y = mapy(yorn(p1->x, p1->y)); 136 pt2.x = mapx(xorn(p2->x, p2->y)); 137 pt2.y = mapy(yorn(p2->x, p2->y)); 138 HGArc(&pt1, &pt2, element->size); 139 break; 140 141 case CURVE: HGSetBrush(element->brushf); 142 HGCurve(element->ptlist); 143 break; 144 145 case VECTOR: p1 = element->ptlist; 146 p2 = PTNextPoint(p1); 147 HGSetBrush(element->brushf); 148 while ( !Nullpoint(p2) ) 149 { 150 x1 = mapx(xorn(p1->x, p1->y)); 151 y1 = mapy(yorn(p1->x, p1->y)); 152 lastx = mapx(xorn(p2->x, p2->y)); 153 lasty = mapy(yorn(p2->x, p2->y)); 154 HGtline(x1, y1, lastx, lasty); 155 p1 = p2; 156 p2 = PTNextPoint(p2); 157 } /* end while */; 158 break; 159 } /* end switch */; 160 } /* end else Text */ 161 } /* end if */ 162 } /* end PrintElt */ 163 164 165 HGPutText(justify,pnt,string) 166 int justify; 167 POINT pnt; 168 char string[]; 169 170 /* This routine is used to calculate the proper starting position for a 171 * text string (based on justification, size and font), and prints it 172 * character by character. 173 */ 174 175 { 176 int length, height, nchars, i; 177 POINT pos; 178 179 height = dispatch['T'].up + dispatch['y'].down; 180 length = 0; 181 for (i=0; string[i] != '\0'; ++i) 182 length += dispatch[(string[i] == ' ') ? 'a' : string[i]].width; 183 nchars = i; 184 switch (justify) 185 { 186 case BOTLEFT: pos.x = pnt.x; 187 pos.y = pnt.y; 188 break; 189 case BOTCENT: if (Orientation == 0) 190 { 191 pos.x = pnt.x - (length/2); 192 pos.y = pnt.y; 193 } 194 else 195 { 196 pos.x = pnt.x; 197 pos.y = pnt.y - (length/2); 198 } 199 break; 200 case BOTRIGHT: if (Orientation == 0) 201 { 202 pos.x = pnt.x - length; 203 pos.y = pnt.y; 204 } 205 else 206 { 207 pos.x = pnt.x; 208 pos.y = pnt.y - length; 209 } 210 break; 211 case CENTLEFT: if (Orientation == 0) 212 { 213 pos.x = pnt.x; 214 pos.y = pnt.y + (height/2); 215 } 216 else 217 { 218 pos.x = pnt.x - (height/2); 219 pos.y = pnt.y; 220 } 221 break; 222 case CENTCENT: if (Orientation == 0) 223 { 224 pos.x = pnt.x - (length/2); 225 pos.y = pnt.y + (height/2); 226 } 227 else 228 { 229 pos.x = pnt.x - (height/2); 230 pos.y = pnt.y - (length/2); 231 } 232 break; 233 case CENTRIGHT: if (Orientation == 0) 234 { 235 pos.x = pnt.x - length; 236 pos.y = pnt.y + (height/2); 237 } 238 else 239 { 240 pos.x = pnt.x - (height/2); 241 pos.y = pnt.y - length; 242 } 243 break; 244 case TOPLEFT: if (Orientation == 0) 245 { 246 pos.x = pnt.x; 247 pos.y = pnt.y + height; 248 249 } 250 else 251 { 252 pos.x = pnt.x - height; 253 pos.y = pnt.y; 254 } 255 break; 256 case TOPCENT: if (Orientation == 0) 257 { 258 pos.x = pnt.x - (length/2); 259 pos.y = pnt.y + height; 260 } 261 else 262 { 263 pos.x = pnt.x - height; 264 pos.y = pnt.y - (length/2); 265 } 266 break; 267 case TOPRIGHT: if (Orientation == 0) 268 { 269 pos.x = pnt.x - length; 270 pos.y = pnt.y + height; 271 } 272 else 273 { 274 pos.x = pnt.x - height; 275 pos.y = pnt.y - length; 276 } 277 break; 278 } 279 280 HGMove(pos); 281 for ( i=0; i<nchars; ++i ) 282 { 283 HGplotch(string[i]); 284 } 285 } /* end HGPutText */; 286 287 288 #define pi 3.14159265357 289 #define log2_10 3.321915 290 291 HGArc(center,cpoint,angle) 292 POINT *center, *cpoint; 293 int angle; 294 295 /* This routine plots an arc centered about 'center' counter clockwise for 296 * the point 'cpoint' through 'angle' degrees. If angle is 0, a full circle 297 * is drawn. 298 */ 299 300 { 301 double xs, ys, resolution, epsalon, degreesperpoint, fullcircle; 302 double t1, t2; 303 int i, extent, nx, ny; 304 305 xs = cpoint->x - center->x; 306 ys = cpoint->y - center->y; 307 lastx = (int) cpoint->x; 308 lasty = (int) cpoint->y; 309 310 /* calculate drawing parameters */ 311 312 t1 = log10(sqrt( xs * xs + ys * ys)) * log2_10; 313 t1 = ceil(t1); 314 resolution = pow(2.0, t1); 315 epsalon = 1.0 / resolution; 316 fullcircle = 2 * pi * resolution; 317 fullcircle = ceil(fullcircle); 318 degreesperpoint = 360.0 / fullcircle; 319 320 if (angle == 0) extent = fullcircle; 321 else extent = angle/degreesperpoint; 322 323 for (i=0; i<extent; ++i) 324 { 325 xs += epsalon * ys; 326 nx = (int) (xs + center->x + 0.5); 327 ys -= epsalon * xs; 328 ny = (int) (ys + center->y + 0.5); 329 RoundEnd(nx, ny, (int) (linethickness/2), FALSE); 330 lastx = nx; 331 lasty = ny; 332 } /* end for */; 333 } /* end HGArc */; 334 335 336 RoundEnd(x, y, radius, filled) 337 int x, y, radius; 338 int filled; /* indicates whether the circle is filled */ 339 340 /* This routine plots a filled circle of the specified radius centered 341 * about (x, y). 342 */ 343 344 { 345 double xs, ys, epsalon; 346 int i, j, k, extent, nx, ny; 347 int cx, cy; 348 349 if (radius < 1) /* too small to notice */ 350 { 351 point(x, y); 352 return; 353 } 354 xs = 0; 355 ys = radius; 356 epsalon = 1.0 / radius; 357 extent = pi * radius / 2; /* 1/4 the circumference */ 358 359 /* Calculate the trajectory of the circle for 1/4 the circumference 360 * and mirror appropriately to get the other three quadrants. 361 */ 362 363 point(x, y+((int) ys)); /* take care if end of arc missed by */ 364 point(x, y-((int) ys)); /* below formulation */ 365 for (i=0; i<extent; ++i) 366 { 367 /* generate circumference */ 368 xs += epsalon * ys; 369 nx = (int) (xs + x + 0.5); 370 if (nx < x) nx = x; /* 1st quadrant, should be positive */ 371 ys -= epsalon * xs; 372 ny = (int) (ys + y + 0.5); 373 if (ny < y) ny = y; /* 1st quadrant, should be positive */ 374 375 if (filled == TRUE) 376 { /* fill from center */ 377 cx = x; 378 cy = y; 379 } 380 else 381 { /* fill from perimeter only (no fill) */ 382 cx = nx; 383 cy = ny; 384 } 385 for (j=cx; j<=nx; ++j) 386 { 387 for (k=cy; k<=ny; ++k) 388 { 389 point(j, k); 390 point(j, 2*y-k); 391 point(2*x-j, k); 392 point(2*x-j, 2*y-k); 393 } /* end for k */ 394 } /* end for j */; 395 } /* end for i */; 396 } /* end RoundEnd */; 397 398 399 #define MAXPOINTS 200 400 401 static Paramaterize(x, y, h, n) 402 float x[MAXPOINTS], y[MAXPOINTS], h[MAXPOINTS]; 403 int n; 404 /* This routine calculates parameteric values for use in calculating 405 * curves. The parametric values are returned in the array u. The values 406 * are an approximation of cumulative arc lengths of the curve (uses cord 407 * length). For additional information, see paper cited below. 408 */ 409 410 { 411 int i,j; 412 float u[MAXPOINTS]; 413 414 for (i=1; i<=n; ++i) 415 { 416 u[i] = 0; 417 for (j=1; j<i; ++j) 418 { 419 u[i] += sqrt(pow((double) (x[j+1] - x[j]),(double) 2.0) 420 + pow((double) (y[j+1] - y[j]), (double) 2.0)); 421 } 422 } 423 for (i=1; i<n; ++i) 424 h[i] = u[i+1] - u[i]; 425 } /* end Paramaterize */ 426 427 static PeriodicSpline(h, z, dz, d2z, d3z, npoints) 428 float h[MAXPOINTS], z[MAXPOINTS]; /* Point list and paramaterization */ 429 float dz[MAXPOINTS]; /* to return the 1st derivative */ 430 float d2z[MAXPOINTS], d3z[MAXPOINTS]; /* 2nd and 3rd derivatives */ 431 int npoints; /* number of valid points */ 432 /* 433 * This routine solves for the cubic polynomial to fit a spline 434 * curve to the the points specified by the list of values. 435 * The Curve generated is periodic. The alogrithms for this 436 * curve are from the "Spline Curve Techniques" paper cited below. 437 */ 438 439 { 440 float d[MAXPOINTS]; 441 float deltaz[MAXPOINTS], a[MAXPOINTS], b[MAXPOINTS]; 442 float c[MAXPOINTS], r[MAXPOINTS], s[MAXPOINTS]; 443 int i; 444 445 /* step 1 */ 446 for (i=1; i<npoints; ++i) 447 { 448 if (h[i] != 0) 449 deltaz[i] = (z[i+1] - z[i]) / h[i]; 450 else 451 deltaz[i] = 0; 452 } 453 h[0] = h[npoints-1]; 454 deltaz[0] = deltaz[npoints-1]; 455 456 /* step 2 */ 457 for (i=1; i<npoints-1; ++i) 458 { 459 d[i] = deltaz[i+1] - deltaz[i]; 460 } 461 d[0] = deltaz[1] - deltaz[0]; 462 463 /* step 3a */ 464 a[1] = 2 * (h[0] + h[1]); 465 b[1] = d[0]; 466 c[1] = h[0]; 467 for (i=2; i<npoints-1; ++i) 468 { 469 a[i] = 2 * (h[i-1] + h[i]) - pow((double) h[i-1], (double) 2.0) 470 / a[i-1]; 471 b[i] = d[i-1] - h[i-1] * b[i-1]/a[i-1]; 472 c[i] = -h[i-1] * c[i-1]/a[i-1]; 473 } 474 475 /* step 3b */ 476 r[npoints-1] = 1; 477 s[npoints-1] = 0; 478 for (i=npoints-2; i>0; --i) 479 { 480 r[i] = -(h[i] * r[i+1] + c[i])/a[i]; 481 s[i] = (6 * b[i] - h[i] * s[i+1])/a[i]; 482 } 483 484 /* step 4 */ 485 d2z[npoints-1] = (6 * d[npoints-2] - h[0] * s[1] 486 - h[npoints-1] * s[npoints-2]) 487 / (h[0] * r[1] + h[npoints-1] * r[npoints-2] 488 + 2 * (h[npoints-2] + h[0])); 489 for (i=1; i<npoints-1; ++i) 490 { 491 d2z[i] = r[i] * d2z[npoints-1] + s[i]; 492 } 493 d2z[npoints] = d2z[1]; 494 495 /* step 5 */ 496 for (i=1; i<npoints; ++i) 497 { 498 dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i+1])/6; 499 if (h[i] != 0) 500 d3z[i] = (d2z[i+1] - d2z[i])/h[i]; 501 else 502 d3z[i] = 0; 503 } 504 } /* end PeriodicSpline */ 505 506 507 static NaturalEndSpline(h, z, dz, d2z, d3z, npoints) 508 float h[MAXPOINTS], z[MAXPOINTS]; /* Point list and parameterization */ 509 float dz[MAXPOINTS]; /* to return the 1st derivative */ 510 float d2z[MAXPOINTS], d3z[MAXPOINTS]; /* 2nd and 3rd derivatives */ 511 int npoints; /* number of valid points */ 512 /* 513 * This routine solves for the cubic polynomial to fit a spline 514 * curve the the points specified by the list of values. The alogrithms for 515 * this curve are from the "Spline Curve Techniques" paper cited below. 516 */ 517 518 { 519 float d[MAXPOINTS]; 520 float deltaz[MAXPOINTS], a[MAXPOINTS], b[MAXPOINTS]; 521 int i; 522 523 /* step 1 */ 524 for (i=1; i<npoints; ++i) 525 { 526 if (h[i] != 0) 527 deltaz[i] = (z[i+1] - z[i]) / h[i]; 528 else 529 deltaz[i] = 0; 530 } 531 deltaz[0] = deltaz[npoints-1]; 532 533 /* step 2 */ 534 for (i=1; i<npoints-1; ++i) 535 { 536 d[i] = deltaz[i+1] - deltaz[i]; 537 } 538 d[0] = deltaz[1] - deltaz[0]; 539 540 /* step 3 */ 541 a[0] = 2 * (h[2] + h[1]); 542 b[0] = d[1]; 543 for (i=1; i<npoints-2; ++i) 544 { 545 a[i] = 2 * (h[i+1] + h[i+2]) - pow((double) h[i+1],(double) 2.0) 546 / a[i-1]; 547 b[i] = d[i+1] - h[i+1] * b[i-1]/a[i-1]; 548 } 549 550 /* step 4 */ 551 d2z[npoints] = d2z[1] = 0; 552 for (i=npoints-1; i>1; --i) 553 { 554 d2z[i] = (6 * b[i-2] - h[i] *d2z[i+1])/a[i-2]; 555 } 556 557 /* step 5 */ 558 for (i=1; i<npoints; ++i) 559 { 560 dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i+1])/6; 561 if (h[i] != 0) 562 d3z[i] = (d2z[i+1] - d2z[i])/h[i]; 563 else 564 d3z[i] = 0; 565 } 566 } /* end NaturalEndSpline */ 567 568 569 #define PointsPerInterval 32 570 571 HGCurve(pointlist,style) 572 POINT *pointlist; 573 int style; 574 /* 575 * This routine generates a smooth curve through a set of points. The 576 * method used is the parametric spline curve on unit knot mesh described 577 * in "Spline Curve Techniques" by Patrick Baudelaire, Robert Flegal, and 578 * Robert Sproull -- Xerox Parc. 579 */ 580 { 581 float h[MAXPOINTS]; 582 float x[MAXPOINTS], y[MAXPOINTS], dx[MAXPOINTS], dy[MAXPOINTS]; 583 float d2x[MAXPOINTS], d2y[MAXPOINTS], d3x[MAXPOINTS], d3y[MAXPOINTS]; 584 float t, t2, t3, xinter, yinter; 585 POINT *ptr; 586 int numpoints, i, j, k, lx, ly, nx, ny; 587 588 /* Copy point list to array for easier access */ 589 590 ptr = pointlist; 591 for (i=1; (!Nullpoint(ptr)); ++i) 592 { 593 x[i] = mapx(xorn(ptr->x, ptr->y)); 594 y[i] = mapy(yorn(ptr->x, ptr->y)); 595 if (i >= MAXPOINTS - 1) break; 596 ptr = PTNextPoint(ptr); 597 } 598 lx = (int) x[1]; 599 ly = (int) y[1]; 600 601 /* Solve for derivatives of the curve at each point 602 * separately for x and y (parametric). 603 */ 604 numpoints = i - 1; 605 Paramaterize(x, y, h, numpoints); 606 if ((x[1] == x[numpoints]) && (y[1] == y[numpoints]))/* closed curve */ 607 { 608 PeriodicSpline(h, x, dx, d2x, d3x, numpoints); 609 PeriodicSpline(h, y, dy, d2y, d3y, numpoints); 610 } 611 else 612 { 613 NaturalEndSpline(h, x, dx, d2x, d3x, numpoints); 614 NaturalEndSpline(h, y, dy, d2y, d3y, numpoints); 615 } 616 617 /* generate the curve using the above information and 618 * PointsPerInterval vectors between each specified knot. 619 */ 620 621 for (j=1; j<numpoints; ++j) 622 { 623 if ((x[j] == x[j+1]) && (y[j] == y[j+1])) continue; 624 for (k=0; k<=PointsPerInterval; ++k) 625 { 626 t = (float) k * h[j] / (float) PointsPerInterval; 627 t2 = t * t; 628 t3 = t * t * t; 629 xinter = x[j] + t * dx[j] + t2 * d2x[j]/2 630 + t3 * d3x[j]/6; 631 nx = (int) xinter; 632 yinter = y[j] + t * dy[j] + t2 * d2y[j]/2 633 + t3 * d3y[j]/6; 634 ny = (int) yinter; 635 HGtline(lx, ly, nx, ny); 636 lx = nx; 637 ly = ny; 638 } /* end for k */ 639 } /* end for j */ 640 } /* end HGCurve */ 641 642 643 644 HGplotch(ch) 645 char ch; 646 647 /* This routine prints a single character using the current (bit mapped) 648 * vtroff font 649 */ 650 651 { 652 int i,j,k; 653 char *ptr,c; 654 int nbytes; 655 656 ptr = bits + dispatch[ch].addr; 657 658 for(i = dispatch[ch].up; i > -dispatch[ch].down; --i) 659 { 660 nbytes = (dispatch[ch].right + dispatch[ch].left + 7)/8; 661 for(j = 0; j < nbytes; j++) 662 { 663 c = *ptr++; 664 for(k=7; k>=0; --k) 665 if((c>>k) & 1) 666 if (Orientation == 0 ) 667 point(lastx+7-k+j*8-dispatch[ch].left, lasty-i); 668 else 669 point(lastx+i, lasty+7-k+j*8-dispatch[ch].left); 670 } 671 } 672 if (Orientation == 0) 673 lastx += dispatch[ (ch == ' ') ? 'a' : ch ].width; 674 else 675 lasty += dispatch[ (ch == ' ') ? 'a' : ch ].width; 676 } 677 678 679 HGInitFont(fontFile) 680 char *fontFile; 681 682 /* This routine reads in the appropriate font file */ 683 684 { 685 char *s; 686 int fonts; 687 int i; 688 689 /* Get the font file */ 690 s = fontFile; 691 if((fonts = open(s,0)) == -1) 692 { 693 perror(s); 694 fprintf(stderr,"Can't get font file\n"); 695 exit(1); 696 } 697 /* Get the header and check magic number */ 698 if(read(fonts,&header,sizeof(header)) != sizeof(header)) 699 { 700 perror(s); 701 fprintf(stderr,"Bad read in font file\n"); 702 exit(1); 703 } 704 if(header.magic != 0436) 705 { 706 fprintf(stderr,"Bad magic numer in font file\n"); 707 exit(1); 708 } 709 /* Get dispatches */ 710 if(read(fonts,dispatch,sizeof(dispatch)) != sizeof(dispatch)) 711 { 712 perror(s); 713 fprintf(stderr,"Bad read in font file\n"); 714 exit(1); 715 } 716 /* Allocate space for bit map and read in bits */ 717 if (bits != NULL) free(bits); 718 bits = (char *) malloc(header.size); 719 720 if(read(fonts,bits,header.size) != header.size) 721 { 722 perror(s); 723 fprintf(stderr,"Can't read bit map in font file\n"); 724 exit(1); 725 } 726 /* Close font file */ 727 if(close(fonts) != 0) 728 { 729 perror(s); 730 fprintf(stderr,"Can't close font file\n"); 731 exit(1); 732 } 733 } 734 735 736 HGtline(x0, y0, x1, y1) 737 int x0, y0, x1, y1; 738 /* 739 * This routine calls line repeatedly until the line is 740 * of the proper thickness. 741 */ 742 743 { 744 double morelen, theta, wx, wy, xx, xy; 745 int xs, xe, ys, ye; 746 int addln, j, xdir, ydir, dx, dy; 747 748 xdir = ydir = 1; 749 dx = x1 - x0; /* calculate direction to move to */ 750 dy = y1 - y0; /* move to draw additional lines if needed */ 751 if (dx < 0 ) /* for extra thickness */ 752 { 753 dx = -dx; 754 xdir = -1; 755 } 756 if (dy < 0 ) 757 { 758 dy = -dy; 759 ydir = -1; 760 } 761 762 morelen = linethickness / 2; 763 addln = (int) morelen; 764 RoundEnd(x0, y0, (int) morelen, TRUE); /* add rounded end */ 765 for (j=(-addln); j<=addln; ++j) 766 { 767 if (dy == 0) 768 { 769 xs = x0; 770 xe = x1; 771 ys = ye = y0 + j; 772 } 773 if (dx == 0) 774 { 775 ys = y0; 776 ye = y1; 777 xs = xe = x0 + j; 778 } 779 if ((dx != 0) && (dy != 0)) 780 { 781 theta = pi / 2.0 - atan( ((double) dx)/((double) dy) ); 782 wx = j * sin(theta); 783 wy = j * cos(theta); 784 xs = x0 + wx * xdir; 785 ys = y0 - wy * ydir; 786 xe = x1 + wx * xdir; 787 ye = y1 - wy * ydir; 788 } 789 line(xs, ys, xe, ye); 790 } /* end for */ 791 RoundEnd(x1, y1, (int) morelen, TRUE); /* add rounded end */ 792 } /* end HGtline */ 793 794 795 HGMove(p) 796 POINT p; 797 { 798 lastx = p.x; 799 lasty = p.y; 800 } 801 802 HGSetFont(font, size) 803 int font, size; 804 { 805 int i; 806 char c, string[100]; 807 808 if ((font == cfont) && (size == csize)) return; 809 cfont = font; 810 csize = size; 811 strcpy(string, fontdir); 812 strcat(string, tfont[font-1]); 813 strcat(string, "."); 814 strcat(string, tsize[size-1]); 815 HGInitFont(string); 816 } 817 818 HGSetBrush(mode) 819 int mode; 820 { 821 linmod = style[mode - 1]; 822 linethickness = thick[mode - 1]; 823 824 } 825