linegen.c 5.5 KB

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