a_path.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. /* This file is part of the GNU plotutils package. Copyright (C) 1995,
  2. 1996, 1997, 1998, 1999, 2000, 2005, 2008, Free Software Foundation, Inc.
  3. The GNU plotutils package is free software. You may redistribute it
  4. and/or modify it under the terms of the GNU General Public License as
  5. published by the Free Software foundation; either version 2, or (at your
  6. option) any later version.
  7. The GNU plotutils package is distributed in the hope that it will be
  8. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. General Public License for more details.
  11. You should have received a copy of the GNU General Public License along
  12. with the GNU plotutils package; see the file COPYING. If not, write to
  13. the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
  14. Boston, MA 02110-1301, USA. */
  15. /* This file contains the internal paint_path() and paint_paths() methods,
  16. which the public method endpath() is a wrapper around. */
  17. /* This version is for AIPlotters. By construction, for AIPlotters our
  18. path storage buffer may include only a segment list: a list of line
  19. segments and/or cubic Bezier segments. No primitives such as ellipses,
  20. circles, and boxes are allowed: any such primitive, if drawn, is
  21. replaced by a segment list at a higher level. */
  22. #include "sys-defines.h"
  23. #include "extern.h"
  24. /* Maximum value for squared sine of angle between two segments, if their
  25. juncture is to be a `smooth point' rather than a corner point. (In
  26. Illustrator, smooth points have only one direction handle; not two.) */
  27. #define MAX_SQUARED_SINE (1e-6)
  28. void
  29. _pl_a_paint_path (S___(Plotter *_plotter))
  30. {
  31. if (_plotter->drawstate->pen_type == 0
  32. && _plotter->drawstate->fill_type == 0)
  33. /* nothing to draw */
  34. return;
  35. switch ((int)_plotter->drawstate->path->type)
  36. {
  37. case (int)PATH_SEGMENT_LIST:
  38. {
  39. int i, numpoints;
  40. bool closed;
  41. double linewidth;
  42. /* sanity checks */
  43. if (_plotter->drawstate->path->num_segments == 0)/* nothing to do */
  44. break;
  45. if (_plotter->drawstate->path->num_segments == 1) /*shouldn't happen */
  46. break;
  47. if ((_plotter->drawstate->path->num_segments >= 3)/*check for closure*/
  48. && (_plotter->drawstate->path->segments[_plotter->drawstate->path->num_segments - 1].p.x == _plotter->drawstate->path->segments[0].p.x)
  49. && (_plotter->drawstate->path->segments[_plotter->drawstate->path->num_segments - 1].p.y == _plotter->drawstate->path->segments[0].p.y))
  50. closed = true;
  51. else
  52. closed = false; /* 2-point ones should be open */
  53. /* set fill color and pen color */
  54. if (_plotter->drawstate->fill_type)
  55. /* will be filling the path */
  56. _pl_a_set_fill_color (R___(_plotter) false);
  57. else
  58. /* won't be filling the path, but set AI's fill color anyway; in
  59. particular, to be the same as the pen color (this is a
  60. convenience for AI users who may wish e.g. to switch from
  61. stroking to filling) */
  62. _pl_a_set_fill_color (R___(_plotter) true);
  63. _pl_a_set_pen_color (S___(_plotter));
  64. /* update line attributes (cap style, join style, line width), if
  65. necessary */
  66. _pl_a_set_attributes (S___(_plotter));
  67. linewidth = _plotter->drawstate->line_width;
  68. numpoints = _plotter->drawstate->path->num_segments;
  69. /* loop over segments in path */
  70. for (i = 0; i < numpoints; i++)
  71. {
  72. bool smooth_join_point; /* if a path join point, a smooth one? */
  73. /* update bounding box to take into account the segment's
  74. terminal point (which is either a path join point or a path
  75. end point) */
  76. if (!closed && (i == 0 || i == numpoints - 1))
  77. /* for the path, an end rather than a join */
  78. {
  79. double xcurrent, ycurrent, xother, yother;
  80. smooth_join_point = false;
  81. /* compute path end point, and a nearby point, the vector
  82. to which will determine the shape of the path end */
  83. xcurrent = _plotter->drawstate->path->segments[i].p.x;
  84. ycurrent = _plotter->drawstate->path->segments[i].p.y;
  85. if (i == 0) /* i = 0, initial end point */
  86. {
  87. if (_plotter->drawstate->path->segments[i+1].type == S_CUBIC)
  88. {
  89. xother = _plotter->drawstate->path->segments[i+1].pc.x;
  90. yother = _plotter->drawstate->path->segments[i+1].pc.y;
  91. }
  92. else /* line segment */
  93. {
  94. xother = _plotter->drawstate->path->segments[i+1].p.x;
  95. yother = _plotter->drawstate->path->segments[i+1].p.y;
  96. }
  97. }
  98. else /* i = numpoints - 1, final end point */
  99. {
  100. if (_plotter->drawstate->path->segments[i].type == S_CUBIC)
  101. {
  102. xother = _plotter->drawstate->path->segments[i].pd.x;
  103. yother = _plotter->drawstate->path->segments[i].pd.y;
  104. }
  105. else /* line segment */
  106. {
  107. xother = _plotter->drawstate->path->segments[i-1].p.x;
  108. yother = _plotter->drawstate->path->segments[i-1].p.y;
  109. }
  110. }
  111. /* take path end into account: update bounding box */
  112. _set_line_end_bbox (_plotter->data->page,
  113. xcurrent, ycurrent, xother, yother,
  114. linewidth, _plotter->drawstate->cap_type,
  115. _plotter->drawstate->transform.m);
  116. }
  117. else
  118. /* for the path, a join rather than an end */
  119. {
  120. int a, b, c;
  121. double xcurrent, ycurrent, xleft, yleft, xright, yright;
  122. if (closed && (i == 0 || i == numpoints - 1)) /* wrap */
  123. {
  124. a = numpoints - 2;
  125. b = numpoints - 1;
  126. c = 1;
  127. }
  128. else /* normal join */
  129. {
  130. a = i - 1;
  131. b = i;
  132. c = i + 1;
  133. }
  134. xcurrent = _plotter->drawstate->path->segments[b].p.x;
  135. ycurrent = _plotter->drawstate->path->segments[b].p.y;
  136. /* compute points to left and right, vectors to which will
  137. determine the shape of the path join */
  138. switch ((int)_plotter->drawstate->path->segments[b].type)
  139. {
  140. case (int)S_LINE:
  141. default:
  142. xleft = _plotter->drawstate->path->segments[a].p.x;
  143. yleft = _plotter->drawstate->path->segments[a].p.y;
  144. break;
  145. case (int)S_CUBIC:
  146. xleft = _plotter->drawstate->path->segments[b].pd.x;
  147. yleft = _plotter->drawstate->path->segments[b].pd.y;
  148. break;
  149. }
  150. switch ((int)_plotter->drawstate->path->segments[c].type)
  151. {
  152. case (int)S_LINE:
  153. default:
  154. xright = _plotter->drawstate->path->segments[c].p.x;
  155. yright = _plotter->drawstate->path->segments[c].p.y;
  156. break;
  157. case (int)S_CUBIC:
  158. xright = _plotter->drawstate->path->segments[c].pc.x;
  159. yright = _plotter->drawstate->path->segments[c].pc.y;
  160. break;
  161. }
  162. /* take path join into account: update bounding box */
  163. _set_line_join_bbox(_plotter->data->page,
  164. xleft, yleft, xcurrent, ycurrent, xright, yright,
  165. linewidth,
  166. _plotter->drawstate->join_type,
  167. _plotter->drawstate->miter_limit,
  168. _plotter->drawstate->transform.m);
  169. /* is join smooth? */
  170. {
  171. double ux, uy, vx, vy, cross, dot, uselfdot, vselfdot;
  172. ux = xleft - xcurrent;
  173. uy = yleft - ycurrent;
  174. vx = xright - xcurrent;
  175. vy = yright - ycurrent;
  176. cross = ux * vy - uy * vx;
  177. dot = ux * vx + uy * vy;
  178. uselfdot = ux * ux + uy * uy;
  179. vselfdot = vx * vx + vy * vy;
  180. if (cross * cross < MAX_SQUARED_SINE * uselfdot * vselfdot
  181. && dot < 0.0)
  182. smooth_join_point = true;
  183. else
  184. smooth_join_point = false;
  185. }
  186. }
  187. /* output to Illustrator the points that define this segment */
  188. if (i != 0
  189. && (_plotter->drawstate->path->segments)[i].type == S_CUBIC)
  190. /* cubic Bezier segment, so output control points */
  191. {
  192. sprintf (_plotter->data->page->point,
  193. "%.4f %.4f %.4f %.4f ",
  194. XD(_plotter->drawstate->path->segments[i].pc.x,
  195. _plotter->drawstate->path->segments[i].pc.y),
  196. YD(_plotter->drawstate->path->segments[i].pc.x,
  197. _plotter->drawstate->path->segments[i].pc.y),
  198. XD(_plotter->drawstate->path->segments[i].pd.x,
  199. _plotter->drawstate->path->segments[i].pd.y),
  200. YD(_plotter->drawstate->path->segments[i].pd.x,
  201. _plotter->drawstate->path->segments[i].pd.y));
  202. _update_buffer (_plotter->data->page);
  203. /* update bounding box due to extremal x/y values in device
  204. frame */
  205. _set_bezier3_bbox (_plotter->data->page,
  206. _plotter->drawstate->path->segments[i-1].p.x,
  207. _plotter->drawstate->path->segments[i-1].p.y,
  208. _plotter->drawstate->path->segments[i].pc.x,
  209. _plotter->drawstate->path->segments[i].pc.y,
  210. _plotter->drawstate->path->segments[i].pd.x,
  211. _plotter->drawstate->path->segments[i].pd.y,
  212. _plotter->drawstate->path->segments[i].p.x,
  213. _plotter->drawstate->path->segments[i].p.y,
  214. _plotter->drawstate->device_line_width,
  215. _plotter->drawstate->transform.m);
  216. }
  217. /* output terminal point of segment */
  218. sprintf (_plotter->data->page->point,
  219. "%.4f %.4f ",
  220. XD(_plotter->drawstate->path->segments[i].p.x,
  221. _plotter->drawstate->path->segments[i].p.y),
  222. YD(_plotter->drawstate->path->segments[i].p.x,
  223. _plotter->drawstate->path->segments[i].p.y));
  224. _update_buffer (_plotter->data->page);
  225. /* tell Illustrator what sort of path segment this is */
  226. if (i == 0)
  227. /* start of path, so just move to point */
  228. sprintf (_plotter->data->page->point, "m\n");
  229. else
  230. /* append line segment or Bezier segment to path */
  231. switch ((int)_plotter->drawstate->path->segments[i].type)
  232. {
  233. case (int)S_LINE:
  234. default:
  235. sprintf (_plotter->data->page->point,
  236. smooth_join_point ? "l\n" : "L\n");
  237. break;
  238. case (int)S_CUBIC:
  239. sprintf (_plotter->data->page->point,
  240. smooth_join_point ? "c\n" : "C\n");
  241. break;
  242. }
  243. _update_buffer (_plotter->data->page);
  244. } /* end of loop over segments */
  245. if (_plotter->drawstate->pen_type)
  246. /* have a pen to draw with */
  247. {
  248. /* emit `closepath' if path is closed; stroke and maybe fill */
  249. if (_plotter->drawstate->fill_type)
  250. {
  251. if (closed)
  252. /* close path, fill and stroke */
  253. sprintf (_plotter->data->page->point, "b\n");
  254. else
  255. /* fill and stroke */
  256. sprintf (_plotter->data->page->point, "B\n");
  257. }
  258. else
  259. {
  260. if (closed)
  261. /* close path, stroke */
  262. sprintf (_plotter->data->page->point, "s\n");
  263. else
  264. /* stroke */
  265. sprintf (_plotter->data->page->point, "S\n");
  266. }
  267. }
  268. else
  269. /* no pen to draw with, but we may do filling */
  270. {
  271. /* emit `closepath' if path is closed; don't stroke */
  272. if (_plotter->drawstate->fill_type)
  273. {
  274. if (closed)
  275. /* close path, fill */
  276. sprintf (_plotter->data->page->point, "f\n");
  277. else
  278. /* fill */
  279. sprintf (_plotter->data->page->point, "F\n");
  280. }
  281. }
  282. _update_buffer (_plotter->data->page);
  283. }
  284. break;
  285. default: /* shouldn't happen */
  286. break;
  287. }
  288. }
  289. bool
  290. _pl_a_paint_paths (S___(Plotter *_plotter))
  291. {
  292. return false;
  293. }