|
|
1.1 ! root 1: #include <stdio.h> ! 2: #include <math.h> ! 3: #include "pic.h" ! 4: #include "y.tab.h" ! 5: ! 6: void arc_extreme(double, double, double, double, double, double); ! 7: int quadrant(double x, double y); ! 8: ! 9: obj *arcgen(int type) /* handles circular and (eventually) elliptical arcs */ ! 10: { ! 11: static double prevw = HT10; ! 12: static double prevh = HT5; ! 13: static double prevrad = HT2; ! 14: static int dtox[2][4] ={ 1, -1, -1, 1, 1, 1, -1, -1 }; ! 15: static int dtoy[2][4] ={ 1, 1, -1, -1, -1, 1, 1, -1 }; ! 16: static int dctrx[2][4] ={ 0, -1, 0, 1, 0, 1, 0, -1 }; ! 17: static int dctry[2][4] ={ 1, 0, -1, 0, -1, 0, 1, 0 }; ! 18: static int nexthv[2][4] ={ U_DIR, L_DIR, D_DIR, R_DIR, D_DIR, R_DIR, U_DIR, L_DIR }; ! 19: double dx2, dy2, ht, phi, r, d; ! 20: int i, head, to, at, cw, invis, ddtype, battr; ! 21: obj *p, *ppos; ! 22: double fromx, fromy, tox, toy, fillval = 0; ! 23: Attr *ap; ! 24: ! 25: prevrad = getfval("arcrad"); ! 26: prevh = getfval("arrowht"); ! 27: prevw = getfval("arrowwid"); ! 28: fromx = curx; ! 29: fromy = cury; ! 30: head = to = at = cw = invis = ddtype = battr = 0; ! 31: for (i = 0; i < nattr; i++) { ! 32: ap = &attr[i]; ! 33: switch (ap->a_type) { ! 34: case TEXTATTR: ! 35: savetext(ap->a_sub, ap->a_val.p); ! 36: break; ! 37: case HEAD: ! 38: head += ap->a_val.i; ! 39: break; ! 40: case INVIS: ! 41: invis = INVIS; ! 42: break; ! 43: case HEIGHT: /* length of arrowhead */ ! 44: prevh = ap->a_val.f; ! 45: break; ! 46: case WIDTH: /* width of arrowhead */ ! 47: prevw = ap->a_val.f; ! 48: break; ! 49: case RADIUS: ! 50: prevrad = ap->a_val.f; ! 51: break; ! 52: case DIAMETER: ! 53: prevrad = ap->a_val.f / 2; ! 54: break; ! 55: case CW: ! 56: cw = 1; ! 57: break; ! 58: case FROM: /* start point of arc */ ! 59: ppos = ap->a_val.o; ! 60: fromx = ppos->o_x; ! 61: fromy = ppos->o_y; ! 62: break; ! 63: case TO: /* end point of arc */ ! 64: ppos = ap->a_val.o; ! 65: tox = ppos->o_x; ! 66: toy = ppos->o_y; ! 67: to++; ! 68: break; ! 69: case AT: /* center of arc */ ! 70: ppos = ap->a_val.o; ! 71: curx = ppos->o_x; ! 72: cury = ppos->o_y; ! 73: at = 1; ! 74: break; ! 75: case UP: ! 76: hvmode = U_DIR; ! 77: break; ! 78: case DOWN: ! 79: hvmode = D_DIR; ! 80: break; ! 81: case RIGHT: ! 82: hvmode = R_DIR; ! 83: break; ! 84: case LEFT: ! 85: hvmode = L_DIR; ! 86: break; ! 87: case FILL: ! 88: battr |= FILLBIT; ! 89: if (ap->a_sub == DEFAULT) ! 90: fillval = getfval("fillval"); ! 91: else ! 92: fillval = ap->a_val.f; ! 93: break; ! 94: } ! 95: } ! 96: if (!at && !to) { /* the defaults are mostly OK */ ! 97: curx = fromx + prevrad * dctrx[cw][hvmode]; ! 98: cury = fromy + prevrad * dctry[cw][hvmode]; ! 99: tox = fromx + prevrad * dtox[cw][hvmode]; ! 100: toy = fromy + prevrad * dtoy[cw][hvmode]; ! 101: hvmode = nexthv[cw][hvmode]; ! 102: } ! 103: else if (!at) { ! 104: dx2 = (tox - fromx) / 2; ! 105: dy2 = (toy - fromy) / 2; ! 106: phi = atan2(dy2, dx2) + (cw ? -PI/2 : PI/2); ! 107: if (prevrad <= 0.0) ! 108: prevrad = dx2*dx2+dy2*dy2; ! 109: for (r=prevrad; (d = r*r - (dx2*dx2+dy2*dy2)) <= 0.0; r *= 2) ! 110: ; /* this kludge gets around too-small radii */ ! 111: prevrad = r; ! 112: ht = sqrt(d); ! 113: curx = fromx + dx2 + ht * cos(phi); ! 114: cury = fromy + dy2 + ht * sin(phi); ! 115: dprintf("dx2,dy2=%g,%g, phi=%g, r,ht=%g,%g\n", ! 116: dx2, dy2, phi, r, ht); ! 117: } ! 118: else if (at && !to) { /* do we have all the cases??? */ ! 119: tox = fromx + prevrad * dtox[cw][hvmode]; ! 120: toy = fromy + prevrad * dtoy[cw][hvmode]; ! 121: hvmode = nexthv[cw][hvmode]; ! 122: } ! 123: if (cw) { /* interchange roles of from-to and heads */ ! 124: double temp; ! 125: temp = fromx; fromx = tox; tox = temp; ! 126: temp = fromy; fromy = toy; toy = temp; ! 127: if (head == HEAD1) ! 128: head = HEAD2; ! 129: else if (head == HEAD2) ! 130: head = HEAD1; ! 131: } ! 132: p = makenode(type, 7); ! 133: arc_extreme(fromx, fromy, tox, toy, curx, cury); ! 134: p->o_val[0] = fromx; ! 135: p->o_val[1] = fromy; ! 136: p->o_val[2] = tox; ! 137: p->o_val[3] = toy; ! 138: if (cw) { ! 139: curx = fromx; ! 140: cury = fromy; ! 141: } else { ! 142: curx = tox; ! 143: cury = toy; ! 144: } ! 145: p->o_val[4] = prevw; ! 146: p->o_val[5] = prevh; ! 147: p->o_val[6] = prevrad; ! 148: p->o_attr = head | (cw ? CW_ARC : 0) | invis | ddtype | battr; ! 149: p->o_fillval = fillval; ! 150: if (head) ! 151: p->o_nhead = getfval("arrowhead"); ! 152: dprintf("arc rad %g at %g %g from %g %g to %g %g head %g %g\n", ! 153: prevrad, p->o_x, p->o_y, ! 154: p->o_val[0], p->o_val[1], p->o_val[2], p->o_val[3], p->o_val[4], p->o_val[5]); ! 155: return(p); ! 156: } ! 157: ! 158: /*************************************************************************** ! 159: bounding box of a circular arc Eric Grosse 24 May 84 ! 160: ! 161: Conceptually, this routine generates a list consisting of the start, ! 162: end, and whichever north, east, south, and west points lie on the arc. ! 163: The bounding box is then the range of this list. ! 164: list = {start,end} ! 165: j = quadrant(start) ! 166: k = quadrant(end) ! 167: if( j==k && long way 'round ) append north,west,south,east ! 168: else ! 169: while( j != k ) ! 170: append center+radius*[j-th of north,west,south,east unit vectors] ! 171: j += 1 (mod 4) ! 172: return( bounding box of list ) ! 173: The following code implements this, with simple optimizations. ! 174: ***********************************************************************/ ! 175: ! 176: ! 177: void arc_extreme(double x0, double y0, double x1, double y1, double xc, double yc) ! 178: /* start, end, center */ ! 179: { ! 180: /* assumes center isn't too far out */ ! 181: double r, xmin, ymin, xmax, ymax; ! 182: int j, k; ! 183: x0 -= xc; y0 -= yc; /* move to center */ ! 184: x1 -= xc; y1 -= yc; ! 185: xmin = (x0<x1)?x0:x1; ymin = (y0<y1)?y0:y1; ! 186: xmax = (x0>x1)?x0:x1; ymax = (y0>y1)?y0:y1; ! 187: r = sqrt(x0*x0 + y0*y0); ! 188: if (r > 0.0) { ! 189: j = quadrant(x0,y0); ! 190: k = quadrant(x1,y1); ! 191: if (j == k && y1*x0 < x1*y0) { ! 192: /* viewed as complex numbers, if Im(z1/z0)<0, arc is big */ ! 193: if( xmin > -r) xmin = -r; if( ymin > -r) ymin = -r; ! 194: if( xmax < r) xmax = r; if( ymax < r) ymax = r; ! 195: } else { ! 196: while (j != k) { ! 197: switch (j) { ! 198: case 1: if( ymax < r) ymax = r; break; /* north */ ! 199: case 2: if( xmin > -r) xmin = -r; break; /* west */ ! 200: case 3: if( ymin > -r) ymin = -r; break; /* south */ ! 201: case 4: if( xmax < r) xmax = r; break; /* east */ ! 202: } ! 203: j = j%4 + 1; ! 204: } ! 205: } ! 206: } ! 207: xmin += xc; ymin += yc; ! 208: xmax += xc; ymax += yc; ! 209: extreme(xmin, ymin); ! 210: extreme(xmax, ymax); ! 211: } ! 212: ! 213: quadrant(double x, double y) ! 214: { ! 215: if ( x>=0.0 && y> 0.0) return(1); ! 216: else if( x< 0.0 && y>=0.0) return(2); ! 217: else if( x<=0.0 && y< 0.0) return(3); ! 218: else if( x> 0.0 && y<=0.0) return(4); ! 219: else return 0; /* shut up lint */ ! 220: } ! 221:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.