1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <math.h> 5 #include "pic.h" 6 #include "y.tab.h" 7 8 obj *linegen(int type) 9 { 10 static double prevdx = HT; 11 static double prevdy = 0; 12 static double prevw = HT10; 13 static double prevh = HT5; 14 int i, j, some, head, ddtype, invis, chop, battr, with; 15 double ddval, chop1, chop2, x0, y0, x1, y1; 16 double fillval = 0; 17 double theta; 18 double defx, defy, xwith, ywith; 19 obj *p, *ppos; 20 static int xtab[] = { 1, 0, -1, 0 }; /* R=0, U=1, L=2, D=3 */ 21 static int ytab[] = { 0, 1, 0, -1 }; 22 double dx[500], dy[500]; 23 int ndxy; 24 double nx, ny; 25 Attr *ap, *chop_ap[4]; 26 27 nx = curx; 28 ny = cury; 29 defx = getfval("linewid"); 30 defy = getfval("lineht"); 31 prevh = getfval("arrowht"); 32 prevw = getfval("arrowwid"); 33 dx[0] = dy[0] = ndxy = some = head = invis = battr = with = 0; 34 chop = chop1 = chop2 = 0; 35 ddtype = ddval = xwith = ywith = 0; 36 for (i = 0; i < nattr; i++) { 37 ap = &attr[i]; 38 switch (ap->a_type) { 39 case TEXTATTR: 40 savetext(ap->a_sub, ap->a_val.p); 41 break; 42 case HEAD: 43 head += ap->a_val.i; 44 break; 45 case INVIS: 46 invis = INVIS; 47 break; 48 case NOEDGE: 49 battr |= NOEDGEBIT; 50 break; 51 case DOT: 52 case DASH: 53 ddtype = ap->a_type==DOT ? DOTBIT : DASHBIT; 54 if (ap->a_sub == DEFAULT) 55 ddval = getfval("dashwid"); 56 else 57 ddval = ap->a_val.f; 58 break; 59 case SAME: 60 dx[ndxy] = prevdx; 61 dy[ndxy] = prevdy; 62 some++; 63 break; 64 case LEFT: 65 dx[ndxy] -= (ap->a_sub==DEFAULT) ? defx : ap->a_val.f; 66 some++; 67 hvmode = L_DIR; 68 break; 69 case RIGHT: 70 dx[ndxy] += (ap->a_sub==DEFAULT) ? defx : ap->a_val.f; 71 some++; 72 hvmode = R_DIR; 73 break; 74 case UP: 75 dy[ndxy] += (ap->a_sub==DEFAULT) ? defy : ap->a_val.f; 76 some++; 77 hvmode = U_DIR; 78 break; 79 case DOWN: 80 dy[ndxy] -= (ap->a_sub==DEFAULT) ? defy : ap->a_val.f; 81 some++; 82 hvmode = D_DIR; 83 break; 84 case HEIGHT: /* length of arrowhead */ 85 prevh = ap->a_val.f; 86 break; 87 case WIDTH: /* width of arrowhead */ 88 prevw = ap->a_val.f; 89 break; 90 case TO: 91 if (some) { 92 nx += dx[ndxy]; 93 ny += dy[ndxy]; 94 ndxy++; 95 dx[ndxy] = dy[ndxy] = some = 0; 96 } 97 ppos = attr[i].a_val.o; 98 if (ppos == NULL) 99 ERROR "no tag defined for `to'" FATAL; 100 dx[ndxy] = ppos->o_x - nx; 101 dy[ndxy] = ppos->o_y - ny; 102 some++; 103 break; 104 case BY: 105 if (some) { 106 nx += dx[ndxy]; 107 ny += dy[ndxy]; 108 ndxy++; 109 dx[ndxy] = dy[ndxy] = some = 0; 110 } 111 ppos = ap->a_val.o; 112 if (ppos == NULL) 113 ERROR "no tag defined for `by'" FATAL; 114 dx[ndxy] = ppos->o_x; 115 dy[ndxy] = ppos->o_y; 116 some++; 117 break; 118 case THEN: /* turn off any previous accumulation */ 119 if (some) { 120 nx += dx[ndxy]; 121 ny += dy[ndxy]; 122 ndxy++; 123 dx[ndxy] = dy[ndxy] = some = 0; 124 } 125 break; 126 case FROM: 127 case AT: 128 ppos = ap->a_val.o; 129 if (ppos == NULL) 130 ERROR "no tag defined for `from' or `at'" FATAL; 131 nx = curx = ppos->o_x; 132 ny = cury = ppos->o_y; 133 break; 134 case WITH: 135 with = ap->a_val.i; 136 break; 137 case CHOP: 138 if (ap->a_sub != PLACENAME) { 139 if( chop == 0) 140 chop1 = chop2 = ap->a_val.f; 141 else 142 chop2 = ap->a_val.f; 143 } 144 chop_ap[chop++] = ap; 145 break; 146 case FILL: 147 battr |= FILLBIT; 148 if (ap->a_sub == DEFAULT) 149 fillval = getfval("fillval"); 150 else 151 fillval = ap->a_val.f; 152 break; 153 } 154 } 155 if (with) { /* this doesn't work at all */ 156 switch (with) { 157 case CENTER: 158 xwith = (dx[1] - dx[0]) / 2; ywith = (dy[1] - dy[0]) / 2; break; 159 } 160 for (i = 0; i < ndxy; i++) { 161 dx[i] -= xwith; 162 dy[i] -= ywith; 163 } 164 curx += xwith; 165 cury += ywith; 166 } 167 if (some) { 168 nx += dx[ndxy]; 169 ny += dy[ndxy]; 170 ndxy++; 171 defx = dx[ndxy-1]; 172 defy = dy[ndxy-1]; 173 } else { 174 defx *= xtab[hvmode]; 175 defy *= ytab[hvmode]; 176 dx[ndxy] = defx; 177 dy[ndxy] = defy; 178 ndxy++; 179 nx += defx; 180 ny += defy; 181 } 182 prevdx = defx; 183 prevdy = defy; 184 if (chop) { 185 if (chop == 1 && chop1 == 0) /* just said "chop", so use default */ 186 chop1 = chop2 = getfval("circlerad"); 187 theta = atan2(dy[0], dx[0]); 188 x0 = chop1 * cos(theta); 189 y0 = chop1 * sin(theta); 190 curx += x0; 191 cury += y0; 192 dx[0] -= x0; 193 dy[0] -= y0; 194 195 theta = atan2(dy[ndxy-1], dx[ndxy-1]); 196 x1 = chop2 * cos(theta); 197 y1 = chop2 * sin(theta); 198 nx -= x1; 199 ny -= y1; 200 dx[ndxy-1] -= x1; 201 dy[ndxy-1] -= y1; 202 dprintf("chopping %g %g %g %g; cur=%g,%g end=%g,%g\n", 203 x0, y0, x1, y1, curx, cury, nx, ny); 204 } 205 p = makenode(type, 5 + 2 * ndxy); 206 curx = p->o_val[0] = nx; 207 cury = p->o_val[1] = ny; 208 if (head || type == ARROW) { 209 p->o_nhead = getfval("arrowhead"); 210 p->o_val[2] = prevw; 211 p->o_val[3] = prevh; 212 if (head == 0) 213 head = HEAD2; /* default arrow head */ 214 } 215 p->o_attr = head | invis | ddtype | battr; 216 p->o_fillval = fillval; 217 p->o_val[4] = ndxy; 218 nx = p->o_x; 219 ny = p->o_y; 220 for (i = 0, j = 5; i < ndxy; i++, j += 2) { 221 p->o_val[j] = dx[i]; 222 p->o_val[j+1] = dy[i]; 223 if (type == LINE || type == ARROW) 224 extreme(nx += dx[i], ny += dy[i]); 225 else if (type == SPLINE && i < ndxy-1) { 226 /* to compute approx extreme of spline at p, 227 /* compute midway between p-1 and p+1, 228 /* then go 3/4 from there to p */ 229 double ex, ey, xi, yi, xi1, yi1; 230 xi = nx + dx[i]; yi = ny + dy[i]; /* p */ 231 xi1 = xi + dx[i+1]; yi1 = yi + dy[i+1]; /* p+1 */ 232 ex = (nx+xi1)/2; ey = (ny+yi1)/2; /* midway */ 233 ex += 0.75*(xi-ex); ey += 0.75*(yi-ey); 234 extreme(ex, ey); 235 nx = xi; ny = yi; 236 } 237 238 } 239 p->o_ddval = ddval; 240 if (dbg) { 241 printf("S or L from %g %g to %g %g with %d elements:\n", p->o_x, p->o_y, curx, cury, ndxy); 242 for (i = 0, j = 5; i < ndxy; i++, j += 2) 243 printf("%g %g\n", p->o_val[j], p->o_val[j+1]); 244 } 245 extreme(p->o_x, p->o_y); 246 extreme(curx, cury); 247 return(p); 248 } 249