h_path.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  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 HPGL and PCL Plotters. By construction, for these
  18. Plotters our path buffer always contains either a segment list, or a
  19. rectangle or circle object. If it's a segment list, it may include an
  20. arbitrary sequence of line, circular arc, and Bezier elements. (For
  21. circular arcs to be included, the map from user to device coordinates
  22. must be uniform, so that e.g. the angle subtended by the arc will be the
  23. same in user and device coordinates.) */
  24. #include "sys-defines.h"
  25. #include "extern.h"
  26. #define DIST(p0,p1) (sqrt( ((p0).x - (p1).x)*((p0).x - (p1).x) \
  27. + ((p0).y - (p1).y)*((p0).y - (p1).y)))
  28. void
  29. _pl_h_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. plIntPathSegment *xarray;
  40. plPoint p0, pp1, pc, savedpoint;
  41. bool closed, use_polygon_buffer;
  42. double last_x, last_y;
  43. int i, polyline_len;
  44. bool identical_user_coordinates = true;
  45. /* sanity checks */
  46. if (_plotter->drawstate->path->num_segments == 0)/* nothing to do */
  47. break;
  48. if (_plotter->drawstate->path->num_segments == 1) /* shouldn't happen*/
  49. break;
  50. if ((_plotter->drawstate->path->num_segments >= 3)/*check for closure*/
  51. && (_plotter->drawstate->path->segments[_plotter->drawstate->path->num_segments - 1].p.x == _plotter->drawstate->path->segments[0].p.x)
  52. && (_plotter->drawstate->path->segments[_plotter->drawstate->path->num_segments - 1].p.y == _plotter->drawstate->path->segments[0].p.y))
  53. closed = true;
  54. else
  55. closed = false; /* 2-point ones should be open */
  56. /* convert vertices to integer device coordinates, removing runs */
  57. /* array for points, with positions expressed in integer device coors*/
  58. xarray = (plIntPathSegment *)_pl_xmalloc (_plotter->drawstate->path->num_segments * sizeof(plIntPathSegment));
  59. /* add first point of path to xarray[] (type field is a moveto) */
  60. xarray[0].p.x = IROUND(XD(_plotter->drawstate->path->segments[0].p.x,
  61. _plotter->drawstate->path->segments[0].p.y));
  62. xarray[0].p.y = IROUND(YD(_plotter->drawstate->path->segments[0].p.x,
  63. _plotter->drawstate->path->segments[0].p.y));
  64. polyline_len = 1;
  65. /* save user coors of last point added to xarray[] */
  66. last_x = _plotter->drawstate->path->segments[0].p.x;
  67. last_y = _plotter->drawstate->path->segments[0].p.y;
  68. for (i = 1; i < _plotter->drawstate->path->num_segments; i++)
  69. {
  70. plPathSegment datapoint;
  71. double xuser, yuser, xdev, ydev;
  72. int device_x, device_y;
  73. datapoint = _plotter->drawstate->path->segments[i];
  74. xuser = datapoint.p.x;
  75. yuser = datapoint.p.y;
  76. if (xuser != last_x || yuser != last_y)
  77. /* in user space, not all points are the same */
  78. identical_user_coordinates = false;
  79. xdev = XD(xuser, yuser);
  80. ydev = YD(xuser, yuser);
  81. device_x = IROUND(xdev);
  82. device_y = IROUND(ydev);
  83. if (device_x != xarray[polyline_len-1].p.x
  84. || device_y != xarray[polyline_len-1].p.y)
  85. /* integer device coor(s) changed, so stash point (incl. type
  86. field) */
  87. {
  88. plPathSegmentType element_type;
  89. int device_xc, device_yc;
  90. xarray[polyline_len].p.x = device_x;
  91. xarray[polyline_len].p.y = device_y;
  92. element_type = datapoint.type;
  93. xarray[polyline_len].type = element_type;
  94. if (element_type == S_ARC)
  95. /* an arc element, so compute center, subtended angle too */
  96. {
  97. double angle;
  98. device_xc = IROUND(XD(datapoint.pc.x, datapoint.pc.y));
  99. device_yc = IROUND(YD(datapoint.pc.x, datapoint.pc.y));
  100. xarray[polyline_len].pc.x = device_xc;
  101. xarray[polyline_len].pc.y = device_yc;
  102. p0.x = last_x;
  103. p0.y = last_y;
  104. pp1 = datapoint.p;
  105. pc = datapoint.pc;
  106. angle = _angle_of_arc (p0, pp1, pc);
  107. /* if user coors -> device coors includes a reflection,
  108. flip sign */
  109. if (!_plotter->drawstate->transform.nonreflection)
  110. angle = -angle;
  111. xarray[polyline_len].angle = angle;
  112. }
  113. else if (element_type == S_CUBIC)
  114. /* a cubic Bezier element, so compute control points too */
  115. {
  116. xarray[polyline_len].pc.x
  117. = IROUND(XD(datapoint.pc.x, datapoint.pc.y));
  118. xarray[polyline_len].pc.y
  119. = IROUND(YD(datapoint.pc.x, datapoint.pc.y));
  120. xarray[polyline_len].pd.x
  121. = IROUND(XD(datapoint.pd.x, datapoint.pd.y));
  122. xarray[polyline_len].pd.y
  123. = IROUND(YD(datapoint.pd.x, datapoint.pd.y));
  124. }
  125. /* save user coors of last point added to xarray[] */
  126. last_x = datapoint.p.x;
  127. last_y = datapoint.p.y;
  128. polyline_len++;
  129. }
  130. }
  131. /* Check first for special subcase: all user-space juncture points
  132. in the polyline were mapped to a single integer HP-GL
  133. pseudo-pixel. If (1) they weren't all the same to begin with,
  134. or (2) they were all the same to begin with and the cap mode is
  135. "round", then draw as a filled circle, of diameter equal to the
  136. line width; otherwise draw nothing. */
  137. if (_plotter->drawstate->path->num_segments > 1 && polyline_len == 1)
  138. /* all points mapped to a single integer pseudo-pixel */
  139. {
  140. if (identical_user_coordinates == false
  141. || _plotter->drawstate->cap_type == PL_CAP_ROUND)
  142. {
  143. double r = 0.5 * _plotter->drawstate->line_width;
  144. double device_frame_radius;
  145. /* draw single filled circle, using HP-GL's native
  146. circle-drawing facility */
  147. /* move to center of circle */
  148. savedpoint = _plotter->drawstate->pos;
  149. _plotter->drawstate->pos =
  150. _plotter->drawstate->path->segments[0].p;
  151. _pl_h_set_position (S___(_plotter));
  152. _plotter->drawstate->pos = savedpoint;
  153. /* set fill color to pen color, arrange to do filling; sync
  154. attributes too, incl. pen width */
  155. {
  156. /* emit HP-GL directives; select a fill color that's
  157. actually the pen color */
  158. _pl_h_set_fill_color (R___(_plotter) true);
  159. _pl_h_set_attributes (S___(_plotter));
  160. }
  161. /* compute radius in device frame */
  162. device_frame_radius =
  163. sqrt(XDV(r,0)*XDV(r,0)+YDV(r,0)*YDV(r,0));
  164. /* Syncing the fill color may have set the
  165. _plotter->hpgl_bad_pen flag (e.g. if optimal pen is #0
  166. [white] and we're not allowed to use pen #0 to draw
  167. with). So we test _plotter->hpgl_bad_pen before using
  168. the pen. */
  169. if (_plotter->hpgl_bad_pen == false)
  170. /* fill the circle (360 degree wedge) */
  171. {
  172. sprintf (_plotter->data->page->point, "WG%d,0,360;",
  173. IROUND(device_frame_radius));
  174. _update_buffer (_plotter->data->page);
  175. }
  176. /* KLUDGE: in pre-HP-GL/2, our `set_fill_color' function
  177. may alter the line type, since it may request *solid*
  178. crosshatching; so reset the line type */
  179. if (_plotter->hpgl_version < 2)
  180. _pl_h_set_attributes (S___(_plotter));
  181. }
  182. /* free our temporary array and depart */
  183. free (xarray);
  184. break;
  185. }
  186. /* At this point, we know we have a nondegenerate path in our
  187. pseudo-integer device space. */
  188. /* will draw vectors (or arcs) into polygon buffer if appropriate */
  189. use_polygon_buffer = (_plotter->hpgl_version == 2
  190. || (_plotter->hpgl_version == 1 /* i.e. "1.5" */
  191. && (polyline_len > 2
  192. || _plotter->drawstate->fill_type)) ? true : false);
  193. /* Sync pen color. This is needed here only if HPGL_VERSION is 1,
  194. but we always do it here so that HP-GL/2 output that draws a
  195. polyline, if sent erroneously to a generic HP-GL device, will
  196. yield a polyline in the correct color, so long as the color
  197. isn't white. */
  198. _pl_h_set_pen_color (R___(_plotter) HPGL_OBJECT_PATH);
  199. /* set_pen_color() sets the advisory bad_pen flag if white pen (pen
  200. #0) would have been selected, and we can't use pen #0 to draw
  201. with. Such a situation isn't fatal if HPGL_VERSION is "1.5" or
  202. "2", since we may be filling the polyline with a nonwhite color,
  203. as well as using a white pen to draw it. But if HPGL_VERSION is
  204. "1", we don't fill polylines, so we might as well punt right
  205. now. */
  206. if (_plotter->hpgl_bad_pen && _plotter->hpgl_version == 1)
  207. {
  208. /* free integer storage buffer and depart */
  209. free (xarray);
  210. break;
  211. }
  212. /* sync attributes, incl. pen width if possible; move pen to p0 */
  213. _pl_h_set_attributes (S___(_plotter));
  214. savedpoint = _plotter->drawstate->pos;
  215. _plotter->drawstate->pos = _plotter->drawstate->path->segments[0].p;
  216. _pl_h_set_position (S___(_plotter));
  217. _plotter->drawstate->pos = savedpoint;
  218. if (use_polygon_buffer)
  219. /* have a polygon buffer, and can use it to fill polyline */
  220. {
  221. /* enter polygon mode */
  222. strcpy (_plotter->data->page->point, "PM0;");
  223. _update_buffer (_plotter->data->page);
  224. }
  225. if (use_polygon_buffer || _plotter->drawstate->pen_type)
  226. /* either (1) we'll be drawing into a polygon buffer, and will be
  227. using it for at least one of (a) filling and (b) edging, or
  228. (2) we won't be drawing into a polygon buffer, so we won't be
  229. filling, but we'll be edging (because pen_type isn't zero) */
  230. {
  231. /* ensure that pen is down for drawing */
  232. if (_plotter->hpgl_pendown == false)
  233. {
  234. strcpy (_plotter->data->page->point, "PD;");
  235. _update_buffer (_plotter->data->page);
  236. _plotter->hpgl_pendown = true;
  237. }
  238. /* loop through points in xarray[], emitting HP-GL instructions */
  239. i = 1;
  240. while (i < polyline_len)
  241. {
  242. switch ((int)xarray[i].type)
  243. {
  244. case (int)S_LINE:
  245. /* emit one or more pen advances */
  246. strcpy (_plotter->data->page->point, "PA");
  247. _update_buffer (_plotter->data->page);
  248. sprintf (_plotter->data->page->point, "%d,%d",
  249. xarray[i].p.x, xarray[i].p.y);
  250. _update_buffer (_plotter->data->page);
  251. i++;
  252. while (i < polyline_len && xarray[i].type == S_LINE)
  253. {
  254. sprintf (_plotter->data->page->point,
  255. ",%d,%d", xarray[i].p.x, xarray[i].p.y);
  256. _update_buffer (_plotter->data->page);
  257. i++;
  258. }
  259. sprintf (_plotter->data->page->point, ";");
  260. _update_buffer (_plotter->data->page);
  261. break;
  262. case (int)S_CUBIC:
  263. /* emit one or more cubic Bezier segments */
  264. strcpy (_plotter->data->page->point, "BZ");
  265. _update_buffer (_plotter->data->page);
  266. sprintf (_plotter->data->page->point, "%d,%d,%d,%d,%d,%d",
  267. xarray[i].pc.x, xarray[i].pc.y,
  268. xarray[i].pd.x, xarray[i].pd.y,
  269. xarray[i].p.x, xarray[i].p.y);
  270. _update_buffer (_plotter->data->page);
  271. i++;
  272. while (i < polyline_len && xarray[i].type == S_CUBIC)
  273. {
  274. sprintf (_plotter->data->page->point, ",%d,%d,%d,%d,%d,%d",
  275. xarray[i].pc.x, xarray[i].pc.y,
  276. xarray[i].pd.x, xarray[i].pd.y,
  277. xarray[i].p.x, xarray[i].p.y);
  278. _update_buffer (_plotter->data->page);
  279. i++;
  280. }
  281. sprintf (_plotter->data->page->point, ";");
  282. _update_buffer (_plotter->data->page);
  283. break;
  284. case (int)S_ARC:
  285. {
  286. double degrees;
  287. int int_degrees;
  288. /* emit an arc, using integer sweep angle if possible */
  289. degrees = 180.0 * xarray[i].angle / M_PI;
  290. int_degrees = IROUND (degrees);
  291. if (_plotter->hpgl_version > 0)
  292. /* HPGL_VERSION = 1.5 or 2 */
  293. {
  294. if (degrees == (double)int_degrees)
  295. sprintf (_plotter->data->page->point, "AA%d,%d,%d;",
  296. xarray[i].pc.x, xarray[i].pc.y,
  297. int_degrees);
  298. else
  299. sprintf (_plotter->data->page->point, "AA%d,%d,%.3f;",
  300. xarray[i].pc.x, xarray[i].pc.y,
  301. degrees);
  302. }
  303. else
  304. /* HPGL_VERSION = 1, i.e. generic HP-GL */
  305. /* note: generic HP-GL can only handle integer
  306. sweep angles */
  307. sprintf (_plotter->data->page->point, "AA%d,%d,%d;",
  308. xarray[i].pc.x, xarray[i].pc.y,
  309. int_degrees);
  310. _update_buffer (_plotter->data->page);
  311. i++;
  312. }
  313. break;
  314. default:
  315. /* shouldn't happen: unknown type for path segment,
  316. ignore */
  317. i++;
  318. break;
  319. }
  320. }
  321. }
  322. if (use_polygon_buffer)
  323. /* using polygon mode; will now employ polygon buffer to do
  324. filling (possibly) and edging */
  325. {
  326. if (!closed)
  327. /* polyline is open, so lift pen and exit polygon mode */
  328. {
  329. strcpy (_plotter->data->page->point, "PU;");
  330. _update_buffer (_plotter->data->page);
  331. _plotter->hpgl_pendown = false;
  332. strcpy (_plotter->data->page->point, "PM2;");
  333. _update_buffer (_plotter->data->page);
  334. }
  335. else
  336. /* polyline is closed, so exit polygon mode and then lift pen */
  337. {
  338. strcpy (_plotter->data->page->point, "PM2;");
  339. _update_buffer (_plotter->data->page);
  340. strcpy (_plotter->data->page->point, "PU;");
  341. _update_buffer (_plotter->data->page);
  342. _plotter->hpgl_pendown = false;
  343. }
  344. if (_plotter->drawstate->fill_type)
  345. /* polyline should be filled */
  346. {
  347. /* Sync fill color. This may set the
  348. _plotter->hpgl_bad_pen flag (if optimal pen is #0
  349. [white] and we're not allowed to use pen #0 to draw
  350. with). So we test _plotter->hpgl_bad_pen before using
  351. the pen to fill with. */
  352. _pl_h_set_fill_color (R___(_plotter) false);
  353. if (_plotter->hpgl_bad_pen == false)
  354. /* fill polyline, specifying nonzero winding rule if
  355. necessary */
  356. {
  357. switch (_plotter->drawstate->fill_rule_type)
  358. {
  359. case PL_FILL_ODD_WINDING:
  360. default:
  361. strcpy (_plotter->data->page->point, "FP;");
  362. break;
  363. case PL_FILL_NONZERO_WINDING:
  364. if (_plotter->hpgl_version == 2)
  365. strcpy (_plotter->data->page->point, "FP1;");
  366. else /* pre-HP-GL/2 doesn't support nonzero rule */
  367. strcpy (_plotter->data->page->point, "FP;");
  368. break;
  369. }
  370. _update_buffer (_plotter->data->page);
  371. }
  372. /* KLUDGE: in pre-HP-GL/2, our `set_fill_color' function may
  373. alter the line type, since it may request *solid*
  374. crosshatching; so reset the line type */
  375. if (_plotter->hpgl_version < 2)
  376. _pl_h_set_attributes (S___(_plotter));
  377. }
  378. if (_plotter->drawstate->pen_type)
  379. /* polyline should be edged */
  380. {
  381. /* Sync pen color. This may set the _plotter->hpgl_bad_pen
  382. flag (if optimal pen is #0 and we're not allowed to use
  383. pen #0 to draw with). So we test _plotter->hpgl_bad_pen
  384. before using the pen. */
  385. _pl_h_set_pen_color (R___(_plotter) HPGL_OBJECT_PATH);
  386. if (_plotter->hpgl_bad_pen == false)
  387. /* select appropriate pen for edging, and edge the
  388. polyline */
  389. {
  390. _pl_h_set_pen_color (R___(_plotter) HPGL_OBJECT_PATH);
  391. strcpy (_plotter->data->page->point, "EP;");
  392. _update_buffer (_plotter->data->page);
  393. }
  394. }
  395. }
  396. /* We know where the pen now is: if we used a polygon buffer, then
  397. _plotter->hpgl_pos is now xarray[0].p. If we didn't (as would
  398. be the case if we're outputting generic HP-GL), then
  399. _plotter->hpgl_pos is now xarray[polyline_len - 1].p.
  400. Unfortunately we can't simply update _plotter->hpgl_pos, because
  401. we want the generated HP-GL[/2] code to work properly on both
  402. HP-GL and HP-GL/2 devices. So we punt. */
  403. _plotter->hpgl_position_is_unknown = true;
  404. /* free integer storage buffer and depart */
  405. free (xarray);
  406. }
  407. break;
  408. case (int)PATH_BOX:
  409. {
  410. plPoint p0, p1, savedpoint;
  411. p0 = _plotter->drawstate->path->p0;
  412. p1 = _plotter->drawstate->path->p1;
  413. /* sync line attributes, incl. pen width */
  414. _pl_h_set_attributes (S___(_plotter));
  415. /* move HP-GL pen to first vertex */
  416. savedpoint = _plotter->drawstate->pos;
  417. _plotter->drawstate->pos = p0;
  418. _pl_h_set_position (S___(_plotter));
  419. _plotter->drawstate->pos = savedpoint;
  420. if (_plotter->drawstate->fill_type)
  421. /* rectangle should be filled */
  422. {
  423. /* Sync fill color. This may set the _plotter->hpgl_bad_pen
  424. flag (e.g. if optimal pen is #0 [white] and we're not
  425. allowed to use pen #0 to draw with). So we test
  426. _plotter->hpgl_bad_pen before using the pen. */
  427. _pl_h_set_fill_color (R___(_plotter) false);
  428. if (_plotter->hpgl_bad_pen == false)
  429. /* fill the rectangle */
  430. {
  431. sprintf (_plotter->data->page->point, "RA%d,%d;",
  432. IROUND(XD(p1.x,p1.y)), IROUND(YD(p1.x,p1.y)));
  433. _update_buffer (_plotter->data->page);
  434. }
  435. /* KLUDGE: in pre-HP-GL/2, our `set_fill_color' function may
  436. alter the line type, since it may request *solid*
  437. crosshatching; so reset it */
  438. if (_plotter->hpgl_version < 2)
  439. _pl_h_set_attributes (S___(_plotter));
  440. }
  441. if (_plotter->drawstate->pen_type)
  442. /* rectangle should be edged */
  443. {
  444. /* Sync pen color. This may set the _plotter->hpgl_bad_pen
  445. flag (e.g. if optimal pen is #0 [white] and we're not
  446. allowed to use pen #0 to draw with). So we test
  447. _plotter->hpgl_bad_pen before using the pen. */
  448. _pl_h_set_pen_color (R___(_plotter) HPGL_OBJECT_PATH);
  449. if (_plotter->hpgl_bad_pen == false)
  450. /* edge the rectangle */
  451. {
  452. sprintf (_plotter->data->page->point, "EA%d,%d;",
  453. IROUND(XD(p1.x,p1.y)), IROUND(YD(p1.x,p1.y)));
  454. _update_buffer (_plotter->data->page);
  455. }
  456. }
  457. }
  458. break;
  459. case (int)PATH_CIRCLE:
  460. {
  461. plPoint pc, savedpoint;
  462. double r = _plotter->drawstate->path->radius;
  463. double radius = sqrt(XDV(r,0)*XDV(r,0)+YDV(r,0)*YDV(r,0));
  464. pc = _plotter->drawstate->path->pc;
  465. /* sync attributes, incl. pen width; move to center of circle */
  466. _pl_h_set_attributes (S___(_plotter));
  467. savedpoint = _plotter->drawstate->pos;
  468. _plotter->drawstate->pos = pc;
  469. _pl_h_set_position (S___(_plotter));
  470. _plotter->drawstate->pos = savedpoint;
  471. if (_plotter->drawstate->fill_type)
  472. /* circle should be filled */
  473. {
  474. /* Sync fill color. This may set the _plotter->hpgl_bad_pen
  475. flag (e.g. if optimal pen is #0 [white] and we're not
  476. allowed to use pen #0 to draw with). So we test
  477. _plotter->hpgl_bad_pen before using the pen. */
  478. _pl_h_set_fill_color (R___(_plotter) false);
  479. if (_plotter->hpgl_bad_pen == false)
  480. /* fill the circle (360 degree wedge) */
  481. {
  482. sprintf (_plotter->data->page->point, "WG%d,0,360;",
  483. IROUND(radius));
  484. _update_buffer (_plotter->data->page);
  485. }
  486. /* KLUDGE: in pre-HP-GL/2, our `set_fill_color' function may
  487. alter the line type, since it may request *solid*
  488. crosshatching; so reset it */
  489. if (_plotter->hpgl_version < 2)
  490. _pl_h_set_attributes (S___(_plotter));
  491. }
  492. if (_plotter->drawstate->pen_type)
  493. /* circle should be edged */
  494. {
  495. /* Sync pen color. This may set the _plotter->hpgl_bad_pen
  496. flag (e.g. if optimal pen is #0 [white] and we're not
  497. allowed to use pen #0 to draw with). So we test
  498. _plotter->hpgl_bad_pen before using the pen. */
  499. _pl_h_set_pen_color (R___(_plotter) HPGL_OBJECT_PATH);
  500. if (_plotter->hpgl_bad_pen == false)
  501. /* do the edging */
  502. {
  503. sprintf (_plotter->data->page->point, "CI%d;", IROUND(radius));
  504. _update_buffer (_plotter->data->page);
  505. }
  506. }
  507. }
  508. break;
  509. default: /* unrecognized path type, shouldn't happen */
  510. break;
  511. }
  512. }
  513. /* A low-level method for moving the pen position of an HP-GL pen plotter
  514. to agree with the Plotter's notion of what the graphics cursor position
  515. should be. The state of the pen (up vs. down) after calling this
  516. function is not uniquely determined. */
  517. void
  518. _pl_h_set_position (S___(Plotter *_plotter))
  519. {
  520. int xnew, ynew;
  521. /* if plotter's pen position doesn't agree with what it should be,
  522. adjust it */
  523. xnew = IROUND(XD(_plotter->drawstate->pos.x, _plotter->drawstate->pos.y));
  524. ynew = IROUND(YD(_plotter->drawstate->pos.x, _plotter->drawstate->pos.y));
  525. if (_plotter->hpgl_position_is_unknown == true
  526. || xnew != _plotter->hpgl_pos.x || ynew != _plotter->hpgl_pos.y)
  527. {
  528. if (_plotter->hpgl_pendown == true)
  529. {
  530. sprintf (_plotter->data->page->point, "PU;PA%d,%d;", xnew, ynew);
  531. _plotter->hpgl_pendown = false;
  532. }
  533. else
  534. sprintf (_plotter->data->page->point, "PA%d,%d;", xnew, ynew);
  535. _update_buffer (_plotter->data->page);
  536. /* update our knowledge of pen position */
  537. _plotter->hpgl_position_is_unknown = false;
  538. _plotter->hpgl_pos.x = xnew;
  539. _plotter->hpgl_pos.y = ynew;
  540. }
  541. }
  542. bool
  543. _pl_h_paint_paths (S___(Plotter *_plotter))
  544. {
  545. return false;
  546. }