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