h_color.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806
  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. #include "sys-defines.h"
  16. #include "extern.h"
  17. #define ONEBYTE (0xff)
  18. #define USE_PEN_ZERO (_plotter->hpgl_version == 2 && (_plotter->hpgl_use_opaque_mode || _plotter->hpgl_can_assign_colors))
  19. /* _h_set_pen_color() sets the pen color used by the HP-GL[/2] device to
  20. match the pen color in our current drawing state. It's invoked just
  21. before any drawing operation.
  22. If the device's palette contains a matching color, the corresponding pen
  23. is selected. Otherwise, we do one of several things.
  24. 1. If we can add colors to the palette, we add the specified color, and
  25. then select the corresponding pen.
  26. 2. If we can't add colors to the palette, but we can specify a shading
  27. level, i.e., a desaturation level, we find the closest point in the RGB
  28. cube to the specified color that's a shaded version of one of the colors
  29. in the palette. Then we select it, by both selecting the appropriate
  30. pen, and selecting a shading level.
  31. There are two subcases to case #2: either the drawing operation to
  32. follow this invocation of set_pen_color will draw a path, or it will
  33. draw a text string using a font native to the HP-GL interpreter. In the
  34. former case, we use the `SV' (screened vector) instruction to set the
  35. shading level; in the latter, we use the `CF' (character fill)
  36. instruction to set the shading level. The two sub-cases are
  37. distinguished by a hint that's passed to us, by being placed in the
  38. HP-GL-specific part of the drawing state before this function is called.
  39. 3. If we can't do either (1) or (2), then we search the palette for the
  40. closest match, and the corresponding `quantized' pen is selected. We
  41. adopt a convention: nonwhite pen colors are never quantized to white.
  42. Pen #0 is the canonical white pen. But on pen plotters, drawing with
  43. pen #0 isn't meaningful. So we won't actually use pen #0 to draw with,
  44. unless HPGL_VERSION==2 and HPGL_OPAQUE_MODE=yes (or
  45. HPGL_ASSIGN_COLORS=yes, which presumably means the output is directed to
  46. a DesignJet). If the closest match in case #3 is pen #0 and we won't be
  47. using pen #0 to draw with, we set the advisory `hpgl_bad_pen' flag in
  48. the Plotter to `true'; otherwise we set it to `false'. */
  49. void
  50. _pl_h_set_pen_color(R___(Plotter *_plotter) int hpgl_object_type)
  51. {
  52. bool found;
  53. int longred, longgreen, longblue;
  54. int red, green, blue;
  55. int i;
  56. plColor color;
  57. color = _plotter->drawstate->fgcolor;
  58. longred = color.red;
  59. longgreen = color.green;
  60. longblue = color.blue;
  61. /* truncate to 24-bit color */
  62. red = (longred >> 8) & ONEBYTE;
  63. green = (longgreen >> 8) & ONEBYTE;
  64. blue = (longblue >> 8) & ONEBYTE;
  65. /* Check whether color is in the palette, in which case all we need to do
  66. is select it. */
  67. found = false;
  68. for (i = 0; i < HPGL2_MAX_NUM_PENS; i++)
  69. {
  70. if (_plotter->hpgl_pen_defined[i] != 0 /* i.e. defined (hard or soft) */
  71. && _plotter->hpgl_pen_color[i].red == red
  72. && _plotter->hpgl_pen_color[i].green == green
  73. && _plotter->hpgl_pen_color[i].blue == blue)
  74. {
  75. found = true;
  76. break;
  77. }
  78. }
  79. if (found)
  80. /* Color is in palette: the simplest case. Besides selecting the
  81. corresponding pen, must set pen type to solid, if there's support
  82. for altering the pen type via `screening of vectors'; since in that
  83. case the pen type could have been set to `shaded' previously. If a
  84. label is to be drawn rather than a path, we must similarly update
  85. the character rendition type to `solid fill' rather than `shaded'. */
  86. {
  87. if (i != 0 || (i == 0 && USE_PEN_ZERO))
  88. /* can be selected */
  89. {
  90. /* select the pen */
  91. _pl_h_set_hpgl_pen (R___(_plotter) i);
  92. /* in HP-GL/2 case, be sure that `solid' vector screening or
  93. character filling is used (one or the other, depending on a
  94. hint as to which type of object is to be drawn) */
  95. switch (hpgl_object_type)
  96. {
  97. case HPGL_OBJECT_PATH:
  98. if (_plotter->hpgl_version == 2
  99. && _plotter->hpgl_have_screened_vectors == true)
  100. /* set pen type to solid */
  101. _pl_h_set_hpgl_pen_type (R___(_plotter) HPGL_PEN_SOLID,
  102. /* options ignored */
  103. 0.0, 0.0);
  104. break;
  105. case HPGL_OBJECT_LABEL:
  106. if (_plotter->hpgl_version == 2
  107. && _plotter->hpgl_have_char_fill == true)
  108. /* if necessary, emit `CF' instruction: specify that
  109. characters are to be rendered by being filled solid with
  110. the current pen color without edging, which is the
  111. default */
  112. if (_plotter->hpgl_char_rendering_type !=
  113. HPGL_CHAR_FILL_SOLID_AND_MAYBE_EDGE)
  114. {
  115. sprintf (_plotter->data->page->point, "CF;");
  116. _update_buffer (_plotter->data->page);
  117. _plotter->hpgl_char_rendering_type =
  118. HPGL_CHAR_FILL_SOLID_AND_MAYBE_EDGE;
  119. }
  120. break;
  121. default:
  122. break;
  123. }
  124. _plotter->hpgl_bad_pen = false;
  125. }
  126. else
  127. /* won't use pen #0, so set advisory flag */
  128. _plotter->hpgl_bad_pen = true;
  129. }
  130. else
  131. /* color not in palette, must do something */
  132. if (_plotter->hpgl_version == 2 && _plotter->hpgl_can_assign_colors)
  133. /* CASE #1: can soft-define pen colors (HP-GL/2, presumably a
  134. DesignJet) */
  135. {
  136. /* assign current `free pen' to be the new color */
  137. sprintf (_plotter->data->page->point, "PC%d,%d,%d,%d;",
  138. _plotter->hpgl_free_pen, red, green, blue);
  139. _update_buffer (_plotter->data->page);
  140. _plotter->hpgl_pen_color[_plotter->hpgl_free_pen].red = red;
  141. _plotter->hpgl_pen_color[_plotter->hpgl_free_pen].green = green;
  142. _plotter->hpgl_pen_color[_plotter->hpgl_free_pen].blue = blue;
  143. _plotter->hpgl_pen_defined[_plotter->hpgl_free_pen] = 1; /* soft-def */
  144. /* select pen */
  145. _pl_h_set_hpgl_pen (R___(_plotter) _plotter->hpgl_free_pen);
  146. /* update free pen, i.e. choose next non-hard-defined pen */
  147. do
  148. _plotter->hpgl_free_pen = (_plotter->hpgl_free_pen + 1) % HPGL2_MAX_NUM_PENS;
  149. while (_plotter->hpgl_pen_defined[_plotter->hpgl_free_pen] == 2);
  150. /* in HP-GL/2 case, be sure that `solid' vector screening or
  151. character filling is used (one or the other, depending on a hint
  152. as to which type of object is to be drawn) */
  153. switch (hpgl_object_type)
  154. {
  155. case HPGL_OBJECT_PATH:
  156. if (_plotter->hpgl_version == 2
  157. && _plotter->hpgl_have_screened_vectors == true)
  158. /* set pen type to solid */
  159. _pl_h_set_hpgl_pen_type (R___(_plotter) HPGL_PEN_SOLID,
  160. /* options ignored */
  161. 0.0, 0.0);
  162. break;
  163. case HPGL_OBJECT_LABEL:
  164. if (_plotter->hpgl_version == 2
  165. && _plotter->hpgl_have_char_fill == true)
  166. /* if necessary, emit `CF' instruction: specify that
  167. characters are to be rendered by being filled solid with
  168. the current pen color without edging, which is the default */
  169. if (_plotter->hpgl_char_rendering_type !=
  170. HPGL_CHAR_FILL_SOLID_AND_MAYBE_EDGE)
  171. {
  172. sprintf (_plotter->data->page->point, "CF;");
  173. _update_buffer (_plotter->data->page);
  174. _plotter->hpgl_char_rendering_type =
  175. HPGL_CHAR_FILL_SOLID_AND_MAYBE_EDGE;
  176. }
  177. break;
  178. default:
  179. break;
  180. }
  181. _plotter->hpgl_bad_pen = false;
  182. }
  183. else if (_plotter->hpgl_version == 2
  184. && _plotter->hpgl_have_screened_vectors == true
  185. && hpgl_object_type == HPGL_OBJECT_PATH)
  186. /* CASE #2a: HP-GL/2, and we have a path to draw, according to the
  187. passed hint; can't soft-define pen colors, but can set a pen
  188. shading level via the `SV' instruction. So locate closest point
  189. in RGB cube that is a desaturated version of one of the defined
  190. pen colors, and shade at the appropriate level. */
  191. {
  192. double shading;
  193. _pl_h_hpgl_shaded_pseudocolor (R___(_plotter)
  194. red, green, blue, &i, &shading);
  195. if (i != 0 || (i == 0 && USE_PEN_ZERO))
  196. /* can be selected */
  197. {
  198. /* select the pen */
  199. _pl_h_set_hpgl_pen (R___(_plotter) i);
  200. /* set shading level, as a percentage */
  201. _pl_h_set_hpgl_pen_type (R___(_plotter) HPGL_PEN_SHADED,
  202. /* 2nd option ignored for HPGL_PEN_SHADED */
  203. 100.0 * shading, 0.0);
  204. _plotter->hpgl_bad_pen = false;
  205. }
  206. else
  207. /* won't use pen #0, so set advisory flag */
  208. _plotter->hpgl_bad_pen = true;
  209. }
  210. else if (_plotter->hpgl_version == 2
  211. && _plotter->hpgl_have_char_fill == true
  212. && hpgl_object_type == HPGL_OBJECT_LABEL)
  213. /* CASE #2b: HP-GL/2, and we have a label to draw, according to the
  214. passed hint; can't soft-define pen colors, but can set a character
  215. shading level via the `CF' instruction. So locate closest point
  216. in RGB cube that is a desaturated version of one of the defined
  217. pen colors, and shade at the appropriate level. */
  218. {
  219. double shading;
  220. _pl_h_hpgl_shaded_pseudocolor (R___(_plotter)
  221. red, green, blue, &i, &shading);
  222. if (i != 0 || (i == 0 && USE_PEN_ZERO))
  223. /* can be selected */
  224. {
  225. /* select the pen */
  226. _pl_h_set_hpgl_pen (R___(_plotter) i);
  227. /* if necessary, emit `CF' instruction: specify that characters
  228. are to be rendered in a non-default way, by being filled
  229. with the current fill type (without edging) */
  230. if (_plotter->hpgl_char_rendering_type != HPGL_CHAR_FILL)
  231. {
  232. sprintf (_plotter->data->page->point, "CF%d;", HPGL_CHAR_FILL);
  233. _update_buffer (_plotter->data->page);
  234. _plotter->hpgl_char_rendering_type = HPGL_CHAR_FILL;
  235. }
  236. /* set the fill type to be a shading level (expressed as a
  237. percentage) */
  238. _pl_h_set_hpgl_fill_type (R___(_plotter) HPGL_FILL_SHADED,
  239. 100.0 * shading, 0.0); /* 2nd option ignord */
  240. _plotter->hpgl_bad_pen = false;
  241. }
  242. else
  243. /* won't use pen #0, so set advisory flag */
  244. _plotter->hpgl_bad_pen = true;
  245. }
  246. else
  247. /* CASE #3: we're stuck with a fixed set of pen colors, from which we
  248. need to choose. [HPGL_VERSION may be "1" (i.e. generic HP-GL) or
  249. "1.5" (i.e. HP7550A), or "2" (i.e. modern HP-GL/2, but without the
  250. ability to define a palette).] So select closest defined pen in
  251. RGB cube, using Euclidean distance as metric. Final arg here is
  252. `true' on account of our convention that a non-white pen color
  253. [unlike a fill color] is never quantized to white (i.e. to pen
  254. #0). */
  255. {
  256. i = _pl_h_hpgl_pseudocolor (R___(_plotter) red, green, blue, true);
  257. if (i != 0 || (i == 0 && USE_PEN_ZERO))
  258. /* can be selected */
  259. {
  260. /* select the pen */
  261. _pl_h_set_hpgl_pen (R___(_plotter) i);
  262. /* do some updating, based on the type of object to be drawn */
  263. switch (hpgl_object_type)
  264. {
  265. case HPGL_OBJECT_PATH:
  266. if (_plotter->hpgl_version == 2
  267. && _plotter->hpgl_have_screened_vectors == true)
  268. /* set pen type to solid */
  269. _pl_h_set_hpgl_pen_type (R___(_plotter) HPGL_PEN_SOLID,
  270. /* options ignored */
  271. 0.0, 0.0);
  272. break;
  273. case HPGL_OBJECT_LABEL:
  274. if (_plotter->hpgl_version == 2
  275. && _plotter->hpgl_have_char_fill == true)
  276. /* if necessary, emit `CF' instruction: specify that
  277. characters are to be rendered by being filled solid with
  278. the current pen color without edging, which is the
  279. default */
  280. if (_plotter->hpgl_char_rendering_type !=
  281. HPGL_CHAR_FILL_SOLID_AND_MAYBE_EDGE)
  282. {
  283. sprintf (_plotter->data->page->point, "CF;");
  284. _update_buffer (_plotter->data->page);
  285. _plotter->hpgl_char_rendering_type =
  286. HPGL_CHAR_FILL_SOLID_AND_MAYBE_EDGE;
  287. }
  288. break;
  289. default:
  290. break;
  291. }
  292. _plotter->hpgl_bad_pen = false;
  293. }
  294. else
  295. /* won't use pen #0, so set advisory flag */
  296. _plotter->hpgl_bad_pen = true;
  297. }
  298. }
  299. /* _pl_h_set_fill_color() is similar to _pl_h_set_pen_color: it sets the
  300. HP-GL pen color (and fill type, if appropriate) to match the fill color
  301. in our current drawing state. It's invoked before any filling
  302. operation.
  303. (Note that all filling operations will use the polygon buffer, except
  304. when we're emitting generic HP-GL [i.e., HPGL_VERSION="1"], which has no
  305. polygon buffer and no support for general filling operations. In that
  306. case the only filling operations we perform are the filling of circles
  307. and rectangles aligned with the coordinate axes.)
  308. There are three cases.
  309. (1) An HP-GL/2 device supporting modification of the palette,
  310. i.e. `soft-definition' of pen colors. I.e., HPGL_VERSION="2" and
  311. HPGL_ASSIGN_COLORS="yes". We use solid filling, after defining the fill
  312. color as a new pen color if necessary.
  313. (2) An HP-GL/2 device not supporting modification of the palette, but
  314. which do support shading at any specified intensity. I.e.,
  315. HPGL_VERSION="2" and HPGL_ASSIGN_COLORS="no". We determine which shade
  316. of which defined pen is closest to the fill color in the sense of
  317. Euclidean distance within the RGB cube. `Shades' are really
  318. desaturations (interpolations between a pen color, and white).
  319. (3) An HP7550A-like device or generic HP-GL device, neither of which has
  320. firmware support for shading. I.e., HPGL_VERSION="1.5" or "1". Such
  321. devices do support cross-hatching, though. So we (a) determine which
  322. shade of which defined pen is closest to the fill color in the sense of
  323. Euclidean distance within the RGB cube, and (b) select a cross-hatch
  324. distance that will emulate this shade. For this, we use the algorithm
  325. that the HP-GL/2 counterpart of the HP7550A, the HP7550B, uses.
  326. (WARNING: our selection of cross-hatching includes the setting of the
  327. line type to `solid'. As a consequence, if HPGL_VERSION="1.5" or "1",
  328. then `_pl_h_set_fill_color' does not commute with
  329. `_pl_h_set_attributes'. This is taken into account in several places in
  330. h_path.c; grep for KLUDGE.)
  331. Pen #0 is the canonical white pen. But on pen plotters, filling with
  332. pen #0 isn't meaningful. So we won't actually use pen #0 to fill with
  333. unless HPGL_VERSION==2 and HPGL_OPAQUE_MODE=yes (or
  334. HPGL_ASSIGN_COLORS=yes, which presumably means the output is directed to
  335. a DesignJet). Accordingly if the closest match here is pen #0, we set
  336. the advisory `hpgl_bad_pen' flag in the Plotter to `true'; otherwise we
  337. set it to `false'. This is just as in set_pen_color() above. */
  338. void
  339. _pl_h_set_fill_color(R___(Plotter *_plotter) bool force_pen_color)
  340. {
  341. bool found;
  342. int longred, longgreen, longblue;
  343. int red, green, blue;
  344. int i;
  345. if (force_pen_color == false && _plotter->drawstate->fill_type == 0)
  346. /* won't be doing filling, so punt */
  347. return;
  348. /* get 48-bit color; if force_pen_color is set, use pen color
  349. instead of fill color */
  350. if (force_pen_color)
  351. {
  352. longred = _plotter->drawstate->fgcolor.red;
  353. longgreen = _plotter->drawstate->fgcolor.green;
  354. longblue = _plotter->drawstate->fgcolor.blue;
  355. }
  356. else
  357. {
  358. longred = _plotter->drawstate->fillcolor.red;
  359. longgreen = _plotter->drawstate->fillcolor.green;
  360. longblue = _plotter->drawstate->fillcolor.blue;
  361. }
  362. /* truncate to 24-bit color */
  363. red = (longred >> 8) & ONEBYTE;
  364. green = (longgreen >> 8) & ONEBYTE;
  365. blue = (longblue >> 8) & ONEBYTE;
  366. /* check whether color is already in palette, in which case all we need
  367. to do is select it (and set fill type to solid) */
  368. found = false;
  369. for (i = 0; i < HPGL2_MAX_NUM_PENS; i++)
  370. {
  371. if (_plotter->hpgl_pen_defined[i] != 0 /* i.e. defined (hard or soft) */
  372. && _plotter->hpgl_pen_color[i].red == red
  373. && _plotter->hpgl_pen_color[i].green == green
  374. && _plotter->hpgl_pen_color[i].blue == blue)
  375. {
  376. found = true;
  377. break;
  378. }
  379. }
  380. if (found)
  381. /* color is in palette */
  382. {
  383. if (i != 0 || (i == 0 && USE_PEN_ZERO))
  384. /* can be selected */
  385. {
  386. /* select it */
  387. _pl_h_set_hpgl_pen (R___(_plotter) i);
  388. /* set fill type to solid, unidirectional */
  389. _pl_h_set_hpgl_fill_type (R___(_plotter) HPGL_FILL_SOLID_UNI,
  390. 0.0, 0.0); /* options ignored */
  391. _plotter->hpgl_bad_pen = false;
  392. }
  393. else
  394. /* aren't using pen #0, so set advisory flag */
  395. _plotter->hpgl_bad_pen = true;
  396. }
  397. else
  398. /* color not in palette, must do something */
  399. if (_plotter->hpgl_version == 2 && _plotter->hpgl_can_assign_colors)
  400. /* CASE #1: HP-GL/2 and can soft-define pen colors */
  401. {
  402. /* assign current `free pen' to be the new color */
  403. sprintf (_plotter->data->page->point, "PC%d,%d,%d,%d;",
  404. _plotter->hpgl_free_pen, red, green, blue);
  405. _update_buffer (_plotter->data->page);
  406. _plotter->hpgl_pen_color[_plotter->hpgl_free_pen].red = red;
  407. _plotter->hpgl_pen_color[_plotter->hpgl_free_pen].green = green;
  408. _plotter->hpgl_pen_color[_plotter->hpgl_free_pen].blue = blue;
  409. _plotter->hpgl_pen_defined[_plotter->hpgl_free_pen] = 1; /* soft-def */
  410. /* select pen */
  411. _pl_h_set_hpgl_pen (R___(_plotter) _plotter->hpgl_free_pen);
  412. /* update free pen, i.e. choose next non-hard-defined pen */
  413. do
  414. _plotter->hpgl_free_pen = (_plotter->hpgl_free_pen + 1) % HPGL2_MAX_NUM_PENS;
  415. while (_plotter->hpgl_pen_defined[_plotter->hpgl_free_pen] == 2);
  416. /* set fill type to solid, unidirectional */
  417. _pl_h_set_hpgl_fill_type (R___(_plotter) HPGL_FILL_SOLID_UNI,
  418. 0.0, 0.0); /* options ignored */
  419. _plotter->hpgl_bad_pen = false;
  420. }
  421. else if (_plotter->hpgl_version == 2
  422. && _plotter->hpgl_can_assign_colors == false)
  423. /* CASE #2: HP-GL/2, but can't soft-define pen colors; locate closest
  424. point in RGB cube that is a desaturated version of one of the
  425. defined pen colors, and fill by shading at the appropriate level */
  426. {
  427. double shading;
  428. _pl_h_hpgl_shaded_pseudocolor (R___(_plotter)
  429. red, green, blue, &i, &shading);
  430. if (i != 0 || (i == 0 && USE_PEN_ZERO))
  431. /* can be selected */
  432. {
  433. _pl_h_set_hpgl_pen (R___(_plotter) i);
  434. /* shading level in HP-GL/2 is expressed as a percentage */
  435. _pl_h_set_hpgl_fill_type (R___(_plotter) HPGL_FILL_SHADED,
  436. 100.0 * shading, 0.0); /* 2nd option ignord */
  437. _plotter->hpgl_bad_pen = false;
  438. }
  439. else
  440. /* aren't using pen #0, so set advisory flag */
  441. _plotter->hpgl_bad_pen = true;
  442. }
  443. else
  444. /* CASE #3: HPGL_VERSION must be "1" (i.e. generic HP-GL) or "1.5"
  445. (i.e. HP7550A), so (a) determine which shade of which defined pen
  446. is closest to the fill color in the sense of Euclidean distance
  447. within the RGB cube, and (b) select a cross-hatch distance that
  448. will emulate this shade. For this, we use the algorithm that the
  449. HP-GL/2 counterpart of the HP7550A, the HP7550B, uses. As with
  450. the HP7550B, we use a cross-hatch angle of 45 degrees. */
  451. {
  452. double shading;
  453. _pl_h_hpgl_shaded_pseudocolor (R___(_plotter)
  454. red, green, blue, &i, &shading);
  455. if (i != 0 && shading > 0.01)
  456. /* pen can be selected; note that we insist that shading level be
  457. at least 1%, to avoid silly huge inter-line spacings, and also
  458. division by zero */
  459. {
  460. double interline_distance;
  461. _pl_h_set_hpgl_pen (R___(_plotter) i);
  462. /* convert shading fraction to cross-hatch distance */
  463. /* If w=width of pen, d=distance between lines, and f=fraction,
  464. then f = (2wd - w^2)/(d^2). I.e., fd^2 - 2wd +w^2 = 0.
  465. Relevant solution is d = (w/f) [1 + sqrt(1-f)].
  466. HP7550B algorithm assume that w = 0.3mm = 12 plotter units,
  467. which is a standard width for plotter pens. So that's what
  468. we use for w also; we call it HPGL_NOMINAL_PEN_WIDTH.
  469. We specify spacing in native plotter units because that's
  470. what the HP7550B does. Its interpretation of shading level
  471. as crosshatching is entirely independent of the definition
  472. of user units, the locations of the scaling points, etc. */
  473. interline_distance
  474. = HPGL_NOMINAL_PEN_WIDTH * (1.0 + sqrt (1.0 - shading)) /shading;
  475. _pl_h_set_hpgl_fill_type (R___(_plotter) HPGL_FILL_CROSSHATCHED_LINES,
  476. interline_distance, 45.0); /* 45 degrees */
  477. _plotter->hpgl_bad_pen = false;
  478. }
  479. else
  480. /* aren't doing any filling (which would be white or near-white),
  481. so set advisory flag */
  482. _plotter->hpgl_bad_pen = true;
  483. }
  484. }
  485. /* Low-level routine that emits the HP-GL `SP' instruction to set the pen
  486. color by selecting a pen in the palette, by number. */
  487. void
  488. _pl_h_set_hpgl_pen (R___(Plotter *_plotter) int new_pen)
  489. {
  490. if (new_pen != _plotter->hpgl_pen) /* need to select new pen */
  491. {
  492. if (_plotter->hpgl_pendown)
  493. {
  494. sprintf (_plotter->data->page->point, "PU;");
  495. _update_buffer (_plotter->data->page);
  496. _plotter->hpgl_pendown = false;
  497. }
  498. sprintf (_plotter->data->page->point, "SP%d;", new_pen);
  499. _update_buffer (_plotter->data->page);
  500. _plotter->hpgl_pen = new_pen;
  501. }
  502. }
  503. /* Low-level routine for HP-GL/2 only, which emits an `SV' instruction to
  504. select not a pen, but rather a `screening type', i.e. an area fill type
  505. such as a shading, that will be applied to all pen strokes. (Nearly all
  506. HP-GL/2 devices that aren't pen plotters support `screened vectors'.)
  507. This permits accurate matching of user-specified pen colors; see
  508. above. */
  509. void
  510. _pl_h_set_hpgl_pen_type (R___(Plotter *_plotter) int new_hpgl_pen_type, double option1, double option2)
  511. {
  512. if (new_hpgl_pen_type != _plotter->hpgl_pen_type
  513. /* in shading case, we store the current shading level in the option1
  514. field */
  515. || (new_hpgl_pen_type == HPGL_PEN_SHADED
  516. && _plotter->hpgl_pen_option1 != option1)
  517. /* in predefined pattern case (there are six cross-hatch patterns
  518. that are imported from PCL or RTL, each of which has line width 4
  519. dots and cell size 32x32 dots on a 600dpi printer), we store the
  520. current pattern type in the option1 field */
  521. || (new_hpgl_pen_type == HPGL_PEN_PREDEFINED_CROSSHATCH
  522. && _plotter->hpgl_pen_option1 != option1))
  523. /* need to emit `SV' instruction to change vector screening */
  524. {
  525. switch (new_hpgl_pen_type)
  526. {
  527. case HPGL_PEN_SOLID:
  528. default:
  529. /* options ignored */
  530. sprintf (_plotter->data->page->point, "SV;");
  531. break;
  532. case HPGL_PEN_SHADED:
  533. /* option1 is shading level in percent */
  534. sprintf (_plotter->data->page->point, "SV%d,%.1f;",
  535. new_hpgl_pen_type, option1);
  536. /* stash shading level */
  537. _plotter->hpgl_pen_option1 = option1;
  538. break;
  539. case HPGL_PEN_PREDEFINED_CROSSHATCH: /* imported from PCL or RTL */
  540. /* option1 is pattern type, in range 1..6 */
  541. sprintf (_plotter->data->page->point, "SV%d,%d;",
  542. new_hpgl_pen_type, IROUND(option1));
  543. /* stash pattern type */
  544. _plotter->hpgl_pen_option1 = option1;
  545. break;
  546. }
  547. _update_buffer (_plotter->data->page);
  548. _plotter->hpgl_pen_type = new_hpgl_pen_type;
  549. }
  550. }
  551. /* Low-level routine, which emits the HP-GL `FT' instruction to set a `fill
  552. type', e.g., a shading or a cross-hatching, that will be applied when
  553. doing filling operations. WARNING: in the case of filling with
  554. cross-hatched or parallel lines, this monkeys with the line type (it
  555. sets it to `solid'). */
  556. void
  557. _pl_h_set_hpgl_fill_type (R___(Plotter *_plotter) int new_hpgl_fill_type, double option1, double option2)
  558. {
  559. if (new_hpgl_fill_type != _plotter->hpgl_fill_type
  560. /* in shading case, we store the current shading level in the option1
  561. field */
  562. || (new_hpgl_fill_type == HPGL_FILL_SHADED
  563. && _plotter->hpgl_fill_option1 != option1)
  564. /* in cross-hatched or parallel line case, we store the current
  565. inter-line distance (in plotter units) in the option1 field, and
  566. and the line angle in the option2 field */
  567. || ((new_hpgl_fill_type == HPGL_FILL_CROSSHATCHED_LINES
  568. || new_hpgl_fill_type == HPGL_FILL_PARALLEL_LINES)
  569. && (_plotter->hpgl_fill_option1 != option1
  570. || _plotter->hpgl_fill_option2 != option2))
  571. /* in predefined fill pattern case (there are six cross-hatch
  572. patterns that are imported from PCL or RTL, each of which has line
  573. width 4 dots and cell size 32x32 dots on a 600dpi printer), we
  574. store the current pattern type in the option1 field */
  575. || (new_hpgl_fill_type == HPGL_FILL_PREDEFINED_CROSSHATCH
  576. && _plotter->hpgl_fill_option1 != option1))
  577. /* need to emit `FT' instruction to change fill type */
  578. {
  579. switch (new_hpgl_fill_type)
  580. {
  581. case HPGL_FILL_SOLID_BI: /* bidirectional solid fill */
  582. case HPGL_FILL_SOLID_UNI: /* unidirectional solid fill */
  583. default:
  584. /* options ignored */
  585. sprintf (_plotter->data->page->point, "FT%d;", new_hpgl_fill_type);
  586. break;
  587. case HPGL_FILL_SHADED:
  588. /* option1 is shading level in percent */
  589. sprintf (_plotter->data->page->point, "FT%d,%.1f;",
  590. new_hpgl_fill_type, option1);
  591. /* stash shading level */
  592. _plotter->hpgl_fill_option1 = option1;
  593. break;
  594. case HPGL_FILL_CROSSHATCHED_LINES:
  595. case HPGL_FILL_PARALLEL_LINES:
  596. /* Our convention: option1 is inter-line distance in plotter
  597. units (option2 is angle of lines). By emitting `SC' commands,
  598. we switch from using user units to plotter units, and back
  599. (for the latter, cf. setup commands in h_openpl.c). Also, we
  600. always switch to the solid line type for drawing the lines
  601. (see warning above). */
  602. sprintf (_plotter->data->page->point,
  603. "LT;SC;FT%d,%d,%d;SC%d,%d,%d,%d;",
  604. new_hpgl_fill_type, IROUND(option1), IROUND(option2),
  605. IROUND (_plotter->data->xmin), IROUND (_plotter->data->xmax),
  606. IROUND (_plotter->data->ymin), IROUND (_plotter->data->ymax));
  607. _plotter->hpgl_line_type = HPGL_L_SOLID;
  608. /* stash inter-line distance and angle of lines */
  609. _plotter->hpgl_fill_option1 = option1;
  610. _plotter->hpgl_fill_option2 = option2;
  611. break;
  612. case HPGL_FILL_PREDEFINED_CROSSHATCH: /* imported from PCL or RTL */
  613. /* option1 is pattern type, in range 1..6 */
  614. sprintf (_plotter->data->page->point, "FT%d,%d;",
  615. new_hpgl_fill_type, IROUND(option1));
  616. /* stash pattern type */
  617. _plotter->hpgl_fill_option1 = option1;
  618. break;
  619. }
  620. _update_buffer (_plotter->data->page);
  621. _plotter->hpgl_fill_type = new_hpgl_fill_type;
  622. }
  623. }
  624. /* Find closest point within the RGB color cube that is a defined pen
  625. color, using Euclidean distance as our metric. Final arg, if set,
  626. specifies that nonwhite colors should never be quantized to white. */
  627. int
  628. _pl_h_hpgl_pseudocolor (R___(Plotter *_plotter) int red, int green, int blue, bool restrict_white)
  629. {
  630. unsigned long int difference = INT_MAX;
  631. int i;
  632. int best = 0;
  633. if (red == 0xff && green == 0xff && blue == 0xff)
  634. /* white pen */
  635. return 0;
  636. for (i = (restrict_white ? 1 : 0); i < HPGL2_MAX_NUM_PENS; i++)
  637. {
  638. if (_plotter->hpgl_pen_defined[i] != 0)
  639. {
  640. unsigned long int newdifference;
  641. int ored, ogreen, oblue;
  642. ored = _plotter->hpgl_pen_color[i].red;
  643. ogreen = _plotter->hpgl_pen_color[i].green;
  644. oblue = _plotter->hpgl_pen_color[i].blue;
  645. newdifference = ((red - ored) * (red - ored)
  646. + (green - ogreen) * (green - ogreen)
  647. + (blue - oblue) * (blue - oblue));
  648. if (newdifference < difference)
  649. {
  650. difference = newdifference;
  651. best = i;
  652. }
  653. }
  654. }
  655. return best;
  656. }
  657. /* Locate closest point in RGB cube that is a desaturated ("shaded")
  658. version of one of the defined pen colors, using Euclidean distance as
  659. our metric. */
  660. void
  661. _pl_h_hpgl_shaded_pseudocolor (R___(Plotter *_plotter) int red, int green, int blue, int *pen_ptr, double *shading_ptr)
  662. {
  663. int best = 0;
  664. int i;
  665. double best_shading = 0.0;
  666. double difference = INT_MAX;
  667. double red_shifted, green_shifted, blue_shifted;
  668. /* shift color vector so that it emanates from `white' */
  669. red_shifted = (double)(red - 0xff);
  670. green_shifted = (double)(green - 0xff);
  671. blue_shifted = (double)(blue - 0xff);
  672. /* begin with pen #1 */
  673. for (i = 1; i < HPGL2_MAX_NUM_PENS; i++)
  674. {
  675. int ored, ogreen, oblue;
  676. double ored_shifted, ogreen_shifted, oblue_shifted;
  677. double red_proj_shifted, green_proj_shifted, blue_proj_shifted;
  678. double reciprocal_normsquared, dotproduct;
  679. double newdifference, shading;
  680. /* skip undefined pens */
  681. if (_plotter->hpgl_pen_defined[i] == 0)
  682. continue;
  683. /* shift each pen color vector so that it emanates from `white' */
  684. ored = _plotter->hpgl_pen_color[i].red;
  685. ogreen = _plotter->hpgl_pen_color[i].green;
  686. oblue = _plotter->hpgl_pen_color[i].blue;
  687. /* if luser specified a white pen, skip it to avoid division by 0 */
  688. if (ored == 0xff && ogreen == 0xff && oblue == 0xff)
  689. continue;
  690. ored_shifted = (double)(ored - 0xff);
  691. ogreen_shifted = (double)(ogreen - 0xff);
  692. oblue_shifted = (double)(oblue - 0xff);
  693. /* project shifted color vector onto shifted pen color vector */
  694. reciprocal_normsquared = 1.0 / (ored_shifted * ored_shifted
  695. + ogreen_shifted * ogreen_shifted
  696. + oblue_shifted * oblue_shifted);
  697. dotproduct = (red_shifted * ored_shifted
  698. + green_shifted * ogreen_shifted
  699. + blue_shifted * oblue_shifted);
  700. shading = reciprocal_normsquared * dotproduct;
  701. red_proj_shifted = shading * ored_shifted;
  702. green_proj_shifted = shading * ogreen_shifted;
  703. blue_proj_shifted = shading * oblue_shifted;
  704. newdifference = (((red_proj_shifted - red_shifted)
  705. * (red_proj_shifted - red_shifted))
  706. + ((green_proj_shifted - green_shifted)
  707. * (green_proj_shifted - green_shifted))
  708. + ((blue_proj_shifted - blue_shifted)
  709. * (blue_proj_shifted - blue_shifted)));
  710. if (newdifference < difference)
  711. {
  712. difference = newdifference;
  713. best = i;
  714. best_shading = shading;
  715. }
  716. }
  717. /* compensate for roundoff error */
  718. if (best_shading <= 0.0)
  719. best_shading = 0.0;
  720. *pen_ptr = best;
  721. *shading_ptr = best_shading;
  722. }