c_path.c 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151
  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 CGMPlotters. By construction, for CGMPlotters our
  18. path storage buffer may include any of the three builtin closed
  19. primitives (box, circle, ellipse), or a sequence of segments, such as
  20. line segments.
  21. If the parameter CGM_MAX_VERSION is "1", the only possible contents of
  22. the segment list is a sequence of line segments, i.e., a polyline. If
  23. CGM_MAX_VERSION is "2", the segment list may contain, instead, a single
  24. elliptic or circular arc. If CGM_MAX_VERSION is "3", the segment list
  25. may contain an arbitrary sequence of line segments, arc segments, and
  26. cubic Beziers too, i.e., an arbitrary `mixed path'.
  27. These restrictions on the segment list contents are implemented by
  28. setting internal Plotter parameters at initialization time (e.g.,
  29. _plotter->data->have_mixed_paths; see c_defplot.c). The reason for the
  30. restrictions is obvious: to store in the segment list only those
  31. primitives that can be represented by a single CGM object, either simple
  32. or compound. For example, circular arcs are not stored unless the
  33. emitting of version-2 CGM primitives is supported. That's because
  34. although version-1 CGM's support counterclockwise arcs, clockwise arcs
  35. are supported only beginning with version 2. And even though version-2
  36. CGM's support arbitrary closed mixed paths, at least ones that don't
  37. contain Beziers ("closed figures"), arbitrary open mixed paths
  38. ("compound lines") are supported only beginning with version 3. */
  39. #include "sys-defines.h"
  40. #include "extern.h"
  41. void
  42. _pl_c_paint_path (S___(Plotter *_plotter))
  43. {
  44. if (_plotter->drawstate->pen_type == 0
  45. && _plotter->drawstate->fill_type == 0)
  46. /* nothing to draw */
  47. return;
  48. switch ((int)_plotter->drawstate->path->type)
  49. {
  50. case (int)PATH_SEGMENT_LIST:
  51. {
  52. bool closed;
  53. plIntPathSegment *xarray;
  54. int polyline_len;
  55. bool draw_as_cgm_compound, path_is_single_polyline;
  56. int pass;
  57. plPathSegmentType first_element_type;
  58. int i, byte_count, data_byte_count, data_len;
  59. int desired_interior_style;
  60. const char *desired_interior_style_string;
  61. /* sanity checks */
  62. if (_plotter->drawstate->path->num_segments == 0)/* nothing to do */
  63. break;
  64. if (_plotter->drawstate->path->num_segments == 1) /*shouldn't happen */
  65. break;
  66. /* check for closure */
  67. if ((_plotter->drawstate->path->num_segments >= 3)
  68. && (_plotter->drawstate->path->segments[_plotter->drawstate->path->num_segments - 1].p.x == _plotter->drawstate->path->segments[0].p.x)
  69. && (_plotter->drawstate->path->segments[_plotter->drawstate->path->num_segments - 1].p.y == _plotter->drawstate->path->segments[0].p.y))
  70. closed = true;
  71. else
  72. closed = false; /* 2-point ones should be open */
  73. /* set CGM pen/fill colors and line attributes, by emitting
  74. appropriate commands */
  75. /* N.B. pen color and line attributes don't need to be set if
  76. pen_type is zero, signifying an edgeless (presumably filled)
  77. path */
  78. _pl_c_set_pen_color (R___(_plotter)
  79. closed ? CGM_OBJECT_CLOSED : CGM_OBJECT_OPEN);
  80. _pl_c_set_fill_color (R___(_plotter)
  81. closed ? CGM_OBJECT_CLOSED : CGM_OBJECT_OPEN);
  82. _pl_c_set_attributes (R___(_plotter)
  83. closed ? CGM_OBJECT_CLOSED : CGM_OBJECT_OPEN);
  84. /* array for points, with positions expressed in integer device
  85. coors */
  86. xarray = (plIntPathSegment *)_pl_xmalloc (_plotter->drawstate->path->num_segments * sizeof(plIntPathSegment));
  87. /* add first point of path to xarray[] (a moveto, presumably) */
  88. xarray[0].p.x = IROUND(XD(_plotter->drawstate->path->segments[0].p.x,
  89. _plotter->drawstate->path->segments[0].p.y));
  90. xarray[0].p.y = IROUND(YD(_plotter->drawstate->path->segments[0].p.x,
  91. _plotter->drawstate->path->segments[0].p.y));
  92. polyline_len = 1;
  93. /* convert to integer CGM coordinates (unlike the HP-GL case [see
  94. h_path.c], we don't remove runs, so after this loop completes,
  95. polyline_len equals _plotter->drawstate->path->num_segments) */
  96. for (i = 1; i < _plotter->drawstate->path->num_segments; i++)
  97. {
  98. plPathSegment datapoint;
  99. double xuser, yuser, xdev, ydev;
  100. int device_x, device_y;
  101. datapoint = _plotter->drawstate->path->segments[i];
  102. xuser = datapoint.p.x;
  103. yuser = datapoint.p.y;
  104. xdev = XD(xuser, yuser);
  105. ydev = YD(xuser, yuser);
  106. device_x = IROUND(xdev);
  107. device_y = IROUND(ydev);
  108. {
  109. plPathSegmentType element_type;
  110. int device_xc, device_yc;
  111. xarray[polyline_len].p.x = device_x;
  112. xarray[polyline_len].p.y = device_y;
  113. element_type = datapoint.type;
  114. xarray[polyline_len].type = element_type;
  115. if (element_type == S_ARC || element_type == S_ELLARC)
  116. /* an arc or elliptic arc element, so compute center too */
  117. {
  118. device_xc = IROUND(XD(datapoint.pc.x, datapoint.pc.y));
  119. device_yc = IROUND(YD(datapoint.pc.x, datapoint.pc.y));
  120. xarray[polyline_len].pc.x = device_xc;
  121. xarray[polyline_len].pc.y = device_yc;
  122. }
  123. else if (element_type == S_CUBIC)
  124. /* a cubic Bezier element, so compute control points too */
  125. {
  126. xarray[polyline_len].pc.x
  127. = IROUND(XD(datapoint.pc.x, datapoint.pc.y));
  128. xarray[polyline_len].pc.y
  129. = IROUND(YD(datapoint.pc.x, datapoint.pc.y));
  130. xarray[polyline_len].pd.x
  131. = IROUND(XD(datapoint.pd.x, datapoint.pd.y));
  132. xarray[polyline_len].pd.y
  133. = IROUND(YD(datapoint.pd.x, datapoint.pd.y));
  134. }
  135. polyline_len++;
  136. }
  137. }
  138. /* A hack for CGM: if a circular or elliptic arc segment in integer
  139. device coordinates looks bogus, i.e. endpoints are the same or
  140. either is the same as the center point, replace it by a line
  141. segment. This will allow us to assume, later, that the
  142. displacement vectors from the center to the two endpoints are
  143. nonzero and unequal. */
  144. for (i = 1; i < polyline_len; i++)
  145. {
  146. if (xarray[i].type == S_ARC || xarray[i].type == S_ELLARC)
  147. if ((xarray[i-1].p.x == xarray[i].p.x
  148. && xarray[i-1].p.y == xarray[i].p.y)
  149. || (xarray[i-1].p.x == xarray[i].pc.x
  150. && xarray[i-1].p.y == xarray[i].pc.y)
  151. || (xarray[i].p.x == xarray[i].pc.x
  152. && xarray[i].p.y == xarray[i].pc.y))
  153. xarray[i].type = S_LINE;
  154. }
  155. /* set CGM attributes (differently, depending on whether path is
  156. closed or open, because different CGM graphical primitives will be
  157. emitted in the two cases to draw the path) */
  158. if (closed)
  159. {
  160. if (_plotter->drawstate->fill_type == 0)
  161. /* won't do filling */
  162. {
  163. desired_interior_style = CGM_INT_STYLE_EMPTY;
  164. desired_interior_style_string = "empty";
  165. }
  166. else
  167. /* will do filling */
  168. {
  169. desired_interior_style = CGM_INT_STYLE_SOLID;
  170. desired_interior_style_string = "solid";
  171. }
  172. if (_plotter->cgm_interior_style != desired_interior_style)
  173. /* emit "INTERIOR STYLE" command */
  174. {
  175. data_len = 2; /* 2 bytes per enum */
  176. byte_count = data_byte_count = 0;
  177. _cgm_emit_command_header (_plotter->data->page, _plotter->cgm_encoding,
  178. CGM_ATTRIBUTE_ELEMENT, 22,
  179. data_len, &byte_count,
  180. "INTSTYLE");
  181. _cgm_emit_enum (_plotter->data->page, false, _plotter->cgm_encoding,
  182. desired_interior_style,
  183. data_len, &data_byte_count, &byte_count,
  184. desired_interior_style_string);
  185. _cgm_emit_command_terminator (_plotter->data->page,
  186. _plotter->cgm_encoding,
  187. &byte_count);
  188. /* update interior style */
  189. _plotter->cgm_interior_style = desired_interior_style;
  190. }
  191. if (_plotter->drawstate->pen_type)
  192. /* should draw the closed path so that edge is visible */
  193. {
  194. if (_plotter->cgm_edge_is_visible != true)
  195. /* emit "EDGE VISIBILITY" command */
  196. {
  197. data_len = 2; /* 2 bytes per enum */
  198. byte_count = data_byte_count = 0;
  199. _cgm_emit_command_header (_plotter->data->page,
  200. _plotter->cgm_encoding,
  201. CGM_ATTRIBUTE_ELEMENT, 30,
  202. data_len, &byte_count,
  203. "EDGEVIS");
  204. _cgm_emit_enum (_plotter->data->page, false,
  205. _plotter->cgm_encoding,
  206. 1,
  207. data_len, &data_byte_count, &byte_count,
  208. "on");
  209. _cgm_emit_command_terminator (_plotter->data->page,
  210. _plotter->cgm_encoding,
  211. &byte_count);
  212. /* update edge visibility */
  213. _plotter->cgm_edge_is_visible = true;
  214. }
  215. }
  216. else
  217. /* shouldn't edge the closed path */
  218. {
  219. if (_plotter->cgm_edge_is_visible != false)
  220. /* emit "EDGE VISIBILITY" command */
  221. {
  222. data_len = 2; /* 2 bytes per enum */
  223. byte_count = data_byte_count = 0;
  224. _cgm_emit_command_header (_plotter->data->page,
  225. _plotter->cgm_encoding,
  226. CGM_ATTRIBUTE_ELEMENT, 30,
  227. data_len, &byte_count,
  228. "EDGEVIS");
  229. _cgm_emit_enum (_plotter->data->page, false,
  230. _plotter->cgm_encoding,
  231. 0,
  232. data_len, &data_byte_count, &byte_count,
  233. "off");
  234. _cgm_emit_command_terminator (_plotter->data->page,
  235. _plotter->cgm_encoding,
  236. &byte_count);
  237. /* update edge visibility */
  238. _plotter->cgm_edge_is_visible = false;
  239. }
  240. }
  241. }
  242. else
  243. /* open! */
  244. {
  245. if (_plotter->drawstate->fill_type != 0)
  246. /* will `fill' the path by first drawing an edgeless
  247. solid-filled polygon, or an edgeless solid-filled closed
  248. figure; in both cases edge visibility will be turned off */
  249. {
  250. if (_plotter->cgm_interior_style != CGM_INT_STYLE_SOLID)
  251. /* emit "INTERIOR STYLE" command */
  252. {
  253. data_len = 2; /* 2 bytes per enum */
  254. byte_count = data_byte_count = 0;
  255. _cgm_emit_command_header (_plotter->data->page,
  256. _plotter->cgm_encoding,
  257. CGM_ATTRIBUTE_ELEMENT, 22,
  258. data_len, &byte_count,
  259. "INTSTYLE");
  260. _cgm_emit_enum (_plotter->data->page, false,
  261. _plotter->cgm_encoding,
  262. CGM_INT_STYLE_SOLID,
  263. data_len, &data_byte_count, &byte_count,
  264. "solid");
  265. _cgm_emit_command_terminator (_plotter->data->page,
  266. _plotter->cgm_encoding,
  267. &byte_count);
  268. /* update interior style */
  269. _plotter->cgm_interior_style = CGM_INT_STYLE_SOLID;
  270. }
  271. if (_plotter->cgm_edge_is_visible)
  272. /* emit "EDGE VISIBILITY" command */
  273. {
  274. data_len = 2; /* 2 bytes per enum */
  275. byte_count = data_byte_count = 0;
  276. _cgm_emit_command_header (_plotter->data->page,
  277. _plotter->cgm_encoding,
  278. CGM_ATTRIBUTE_ELEMENT, 30,
  279. data_len, &byte_count,
  280. "EDGEVIS");
  281. _cgm_emit_enum (_plotter->data->page, false,
  282. _plotter->cgm_encoding,
  283. 0,
  284. data_len, &data_byte_count, &byte_count,
  285. "off");
  286. _cgm_emit_command_terminator (_plotter->data->page,
  287. _plotter->cgm_encoding,
  288. &byte_count);
  289. /* update edge visibility */
  290. _plotter->cgm_edge_is_visible = false;
  291. }
  292. }
  293. }
  294. /* Will path be drawn as a CGM compound primitive, containing > 1
  295. graphical primitives? If it contains more than one type of path
  296. segment, or if it contains more than a single circular arc
  297. segment or elliptic arc segment, answer is `yes'.
  298. Because of our policies, implemented elsewhere, on what may be
  299. stored in the segment buffer (see above), we'll draw as a
  300. compound primitive only if CGM_MAX_VERSION >= 3. */
  301. draw_as_cgm_compound = false;
  302. first_element_type = xarray[1].type;
  303. for (i = 2; i < polyline_len; i++)
  304. {
  305. if (xarray[i].type == S_ARC || xarray[i].type == S_ELLARC
  306. || xarray[i].type != first_element_type)
  307. {
  308. draw_as_cgm_compound = true;
  309. break;
  310. }
  311. }
  312. /* is path simply a polyline? */
  313. {
  314. path_is_single_polyline = true;
  315. for (i = 1; i < polyline_len; i++)
  316. {
  317. if (xarray[i].type != S_LINE)
  318. {
  319. path_is_single_polyline = false;
  320. break;
  321. }
  322. }
  323. }
  324. /* Make two passes through segment buffer: (0) draw and fill, if
  325. necessary, a closed CGM object, e.g. a `closed figure' [necessary
  326. iff path is closed, or is open and filled], and (1) edge an open
  327. CGM object, e.g. a `compound line' [necessary iff path is
  328. open]. */
  329. for (pass = 0; pass < 2; pass++)
  330. {
  331. int primitives_emitted;
  332. if (pass == 0 && !(closed || _plotter->drawstate->fill_type != 0))
  333. /* no drawing of a closed object needed: skip pass 0 */
  334. continue;
  335. if (pass == 1
  336. && (closed || (!closed && _plotter->drawstate->pen_type == 0)))
  337. /* no need for a special `draw edge' pass: skip pass 1 */
  338. continue;
  339. /* keep track of individual graphical primitives emitted per pass
  340. (profile requires <=128 per composite primitive, closed or
  341. open) */
  342. primitives_emitted = 0;
  343. if (pass == 0 && !path_is_single_polyline)
  344. /* emit `BEGIN CLOSED FIGURE' command (no parameters); drawing
  345. of closed polylines and filling of open ones is handled
  346. specially (see below) */
  347. {
  348. data_len = 0;
  349. byte_count = data_byte_count = 0;
  350. _cgm_emit_command_header (_plotter->data->page, _plotter->cgm_encoding,
  351. CGM_DELIMITER_ELEMENT, 8,
  352. data_len, &byte_count,
  353. "BEGFIGURE");
  354. _cgm_emit_command_terminator (_plotter->data->page,
  355. _plotter->cgm_encoding,
  356. &byte_count);
  357. /* update CGM version needed for this page */
  358. _plotter->cgm_page_version = IMAX(2, _plotter->cgm_page_version);
  359. }
  360. if (pass == 1 && draw_as_cgm_compound)
  361. /* emit `BEGIN COMPOUND LINE' command (no parameters) */
  362. {
  363. data_len = 0;
  364. byte_count = data_byte_count = 0;
  365. _cgm_emit_command_header (_plotter->data->page, _plotter->cgm_encoding,
  366. CGM_DELIMITER_ELEMENT, 15,
  367. data_len, &byte_count,
  368. "BEGCOMPOLINE");
  369. _cgm_emit_command_terminator (_plotter->data->page,
  370. _plotter->cgm_encoding,
  371. &byte_count);
  372. /* update CGM version needed for this page */
  373. _plotter->cgm_page_version = IMAX(3, _plotter->cgm_page_version);
  374. }
  375. /* iterate over path elements, combining runs of line segments
  376. into polylines, and runs of Beziers into poly-Beziers, but
  377. emitting each circular arc and elliptic arc individually
  378. (since CGM doesn't support poly-arcs) */
  379. i = 0;
  380. while (i + 1 < polyline_len)
  381. {
  382. int j, end_of_run;
  383. plPathSegmentType element_type;
  384. /* determine `run' (relevant only for lines, Beziers) */
  385. element_type = xarray[i + 1].type;
  386. for (j = i + 1;
  387. j < polyline_len && xarray[j].type == element_type;
  388. j++)
  389. ;
  390. end_of_run = j - 1;
  391. switch ((int)element_type)
  392. {
  393. case (int)S_LINE:
  394. if ((pass == 0 && !path_is_single_polyline) || (pass == 1))
  395. /* normal case: emit "POLYLINE" command to draw polyline */
  396. /* number of line segments in polyline: end_of_run - i */
  397. /* number of points in polyline: 1 + (end_of_run - i) */
  398. {
  399. /* update CGM profile for this page */
  400. if (1 + (end_of_run - i) > 4096)
  401. _plotter->cgm_page_profile =
  402. IMAX(_plotter->cgm_page_profile, CGM_PROFILE_NONE);
  403. data_len = 2 * CGM_BINARY_BYTES_PER_INTEGER * (1 + end_of_run - i);
  404. byte_count = data_byte_count = 0;
  405. _cgm_emit_command_header (_plotter->data->page, _plotter->cgm_encoding,
  406. CGM_GRAPHICAL_PRIMITIVE_ELEMENT, 1,
  407. data_len, &byte_count,
  408. "LINE");
  409. /* combine line segments into polyline */
  410. for ( ; i <= end_of_run; i++)
  411. _cgm_emit_point (_plotter->data->page, false, _plotter->cgm_encoding,
  412. xarray[i].p.x, xarray[i].p.y,
  413. data_len, &data_byte_count, &byte_count);
  414. _cgm_emit_command_terminator (_plotter->data->page,
  415. _plotter->cgm_encoding,
  416. &byte_count);
  417. primitives_emitted++;
  418. /* next CGM component object begins at i=end_of_run */
  419. i--;
  420. }
  421. else
  422. /* Special case: we're running pass 0, and path
  423. consists of a single polyline. So emit "POLYGON"
  424. command, omitting the final point if the polyline is
  425. closed, to agree with CGM conventions. */
  426. {
  427. /* update CGM profile for this page */
  428. if (polyline_len - (closed ? 1 : 0) > 4096)
  429. _plotter->cgm_page_profile =
  430. IMAX(_plotter->cgm_page_profile, CGM_PROFILE_NONE);
  431. data_len = 2 * CGM_BINARY_BYTES_PER_INTEGER * (polyline_len - (closed ? 1 : 0));
  432. byte_count = data_byte_count = 0;
  433. _cgm_emit_command_header (_plotter->data->page,
  434. _plotter->cgm_encoding,
  435. CGM_GRAPHICAL_PRIMITIVE_ELEMENT, 7,
  436. data_len, &byte_count,
  437. "POLYGON");
  438. for (i = 0; i < polyline_len - (closed ? 1 : 0); i++)
  439. _cgm_emit_point (_plotter->data->page,
  440. false, _plotter->cgm_encoding,
  441. xarray[i].p.x, xarray[i].p.y,
  442. data_len, &data_byte_count, &byte_count);
  443. _cgm_emit_command_terminator (_plotter->data->page,
  444. _plotter->cgm_encoding,
  445. &byte_count);
  446. primitives_emitted++;
  447. /* we've used up the entire segment buffer: no more
  448. primitives to emit */
  449. i = polyline_len - 1;
  450. }
  451. break;
  452. case (int)S_ARC:
  453. /* emit "CIRCULAR ARC CENTRE [REVERSED]" command */
  454. {
  455. int delta0_x = xarray[i].p.x - xarray[i + 1].pc.x;
  456. int delta0_y = xarray[i].p.y - xarray[i + 1].pc.y;
  457. int delta1_x = xarray[i + 1].p.x - xarray[i + 1].pc.x;
  458. int delta1_y = xarray[i + 1].p.y - xarray[i + 1].pc.y;
  459. double radius = sqrt((double)delta0_x * (double)delta0_x
  460. + (double)delta0_y * (double)delta0_y);
  461. int i_radius = IROUND(radius);
  462. double dot = ((double)delta0_x * (double)delta1_y
  463. - (double)delta0_y * (double)delta1_x);
  464. bool reversed = (dot >= 0.0 ? false : true);
  465. /* args: 1 point, 2 vectors, and the radius */
  466. data_len = (3 * 2 + 1) * CGM_BINARY_BYTES_PER_INTEGER;
  467. byte_count = data_byte_count = 0;
  468. if (reversed)
  469. _cgm_emit_command_header (_plotter->data->page, _plotter->cgm_encoding,
  470. CGM_GRAPHICAL_PRIMITIVE_ELEMENT, 20,
  471. data_len, &byte_count,
  472. "ARCCTRREV");
  473. else
  474. _cgm_emit_command_header (_plotter->data->page, _plotter->cgm_encoding,
  475. CGM_GRAPHICAL_PRIMITIVE_ELEMENT, 15,
  476. data_len, &byte_count,
  477. "ARCCTR");
  478. /* center point */
  479. _cgm_emit_point (_plotter->data->page,
  480. false, _plotter->cgm_encoding,
  481. xarray[i + 1].pc.x, xarray[i + 1].pc.y,
  482. data_len, &data_byte_count, &byte_count);
  483. /* vector from center to starting point */
  484. _cgm_emit_point (_plotter->data->page,
  485. false, _plotter->cgm_encoding,
  486. delta0_x, delta0_y,
  487. data_len, &data_byte_count, &byte_count);
  488. /* vector from center to ending point */
  489. _cgm_emit_point (_plotter->data->page,
  490. false, _plotter->cgm_encoding,
  491. delta1_x, delta1_y,
  492. data_len, &data_byte_count, &byte_count);
  493. /* radius (distance from center to starting point) */
  494. _cgm_emit_integer (_plotter->data->page,
  495. false, _plotter->cgm_encoding,
  496. i_radius,
  497. data_len, &data_byte_count, &byte_count);
  498. _cgm_emit_command_terminator (_plotter->data->page, _plotter->cgm_encoding,
  499. &byte_count);
  500. primitives_emitted++;
  501. /* update CGM version needed for this page */
  502. if (reversed)
  503. _plotter->cgm_page_version =
  504. IMAX(2, _plotter->cgm_page_version);
  505. }
  506. /* on to next CGM component object */
  507. i++;
  508. break;
  509. case (int)S_ELLARC:
  510. /* emit "ELLIPTICAL ARC" command to draw quarter-ellipse */
  511. {
  512. /* args: 3 points, 2 vectors */
  513. data_len = 5 * 2 * CGM_BINARY_BYTES_PER_INTEGER;
  514. byte_count = data_byte_count = 0;
  515. _cgm_emit_command_header (_plotter->data->page,
  516. _plotter->cgm_encoding,
  517. CGM_GRAPHICAL_PRIMITIVE_ELEMENT, 18,
  518. data_len, &byte_count,
  519. "ELLIPARC");
  520. /* center point */
  521. _cgm_emit_point (_plotter->data->page,
  522. false, _plotter->cgm_encoding,
  523. xarray[i + 1].pc.x, xarray[i + 1].pc.y,
  524. data_len, &data_byte_count, &byte_count);
  525. /* starting point */
  526. _cgm_emit_point (_plotter->data->page,
  527. false, _plotter->cgm_encoding,
  528. xarray[i].p.x, xarray[i].p.y,
  529. data_len, &data_byte_count, &byte_count);
  530. /* ending point */
  531. _cgm_emit_point (_plotter->data->page,
  532. false, _plotter->cgm_encoding,
  533. xarray[i + 1].p.x, xarray[i + 1].p.y,
  534. data_len, &data_byte_count, &byte_count);
  535. /* vector from center to starting point */
  536. _cgm_emit_point (_plotter->data->page,
  537. false, _plotter->cgm_encoding,
  538. xarray[i].p.x - xarray[i + 1].pc.x,
  539. xarray[i].p.y - xarray[i + 1].pc.y,
  540. data_len, &data_byte_count, &byte_count);
  541. /* vector from center to ending point */
  542. _cgm_emit_point (_plotter->data->page,
  543. false, _plotter->cgm_encoding,
  544. xarray[i + 1].p.x - xarray[i + 1].pc.x,
  545. xarray[i + 1].p.y - xarray[i + 1].pc.y,
  546. data_len, &data_byte_count, &byte_count);
  547. _cgm_emit_command_terminator (_plotter->data->page,
  548. _plotter->cgm_encoding,
  549. &byte_count);
  550. primitives_emitted++;
  551. }
  552. /* on to next CGM component object */
  553. i++;
  554. break;
  555. case (int)S_CUBIC:
  556. /* emit "POLYBEZIER" command */
  557. /* number of Bezier segments in path: end_of_run - i */
  558. /* number of points in path: 1 + 3 * (end_of_run - i) */
  559. /* Note: arguments include also a single `continuity
  560. indicator' (a two-byte CGM index) */
  561. {
  562. /* update CGM profile for this page */
  563. if (1 + 3 * (end_of_run - i) > 4096)
  564. _plotter->cgm_page_profile =
  565. IMAX(_plotter->cgm_page_profile, CGM_PROFILE_NONE);
  566. data_len = 2 + (2 * CGM_BINARY_BYTES_PER_INTEGER) * (1 + 3 * (end_of_run - i));
  567. byte_count = data_byte_count = 0;
  568. _cgm_emit_command_header (_plotter->data->page,
  569. _plotter->cgm_encoding,
  570. CGM_GRAPHICAL_PRIMITIVE_ELEMENT, 26,
  571. data_len, &byte_count,
  572. "POLYBEZIER");
  573. _cgm_emit_index (_plotter->data->page,
  574. false, _plotter->cgm_encoding,
  575. /* poly-Bezier continuity index: `2'
  576. means successive Beziers abut, so
  577. (after the first) each is
  578. specified by only three points;
  579. `1' means they don't abut. Our
  580. Beziers are contiguous, so we
  581. specify `2'. We used to specify
  582. `1' if there's only one Bezier,
  583. but the browser plug-in from
  584. SYSDEV didn't like that (it
  585. produced a parse error when such
  586. a Bezier was the only element of
  587. a CGM `closed figure'). */
  588. #if 0
  589. (end_of_run - i > 1 ? 2 : 1),
  590. #else
  591. (end_of_run - i > 1 ? 2 : 2),
  592. #endif
  593. data_len, &data_byte_count, &byte_count);
  594. /* starting point */
  595. _cgm_emit_point (_plotter->data->page,
  596. false, _plotter->cgm_encoding,
  597. xarray[i].p.x, xarray[i].p.y,
  598. data_len, &data_byte_count, &byte_count);
  599. i++;
  600. /* combine Bezier segments into poly-Bezier */
  601. for ( ; i <= end_of_run; i++)
  602. {
  603. _cgm_emit_point (_plotter->data->page,
  604. false, _plotter->cgm_encoding,
  605. xarray[i].pc.x, xarray[i].pc.y,
  606. data_len, &data_byte_count, &byte_count);
  607. _cgm_emit_point (_plotter->data->page,
  608. false, _plotter->cgm_encoding,
  609. xarray[i].pd.x, xarray[i].pd.y,
  610. data_len, &data_byte_count, &byte_count);
  611. _cgm_emit_point (_plotter->data->page,
  612. false, _plotter->cgm_encoding,
  613. xarray[i].p.x, xarray[i].p.y,
  614. data_len, &data_byte_count, &byte_count);
  615. }
  616. _cgm_emit_command_terminator (_plotter->data->page,
  617. _plotter->cgm_encoding,
  618. &byte_count);
  619. primitives_emitted++;
  620. /* update CGM version needed for this page */
  621. _plotter->cgm_page_version =
  622. IMAX(3, _plotter->cgm_page_version);
  623. /* next CGM component object begins at i=end_of_run */
  624. i--;
  625. }
  626. break;
  627. default:
  628. /* shouldn't happen: unknown path segment type, ignore */
  629. i++;
  630. break;
  631. }
  632. }
  633. if (pass == 0 && !path_is_single_polyline)
  634. /* emit `END CLOSED FIGURE' command (no parameters) */
  635. {
  636. data_len = 0;
  637. byte_count = data_byte_count = 0;
  638. _cgm_emit_command_header (_plotter->data->page, _plotter->cgm_encoding,
  639. CGM_DELIMITER_ELEMENT, 9,
  640. data_len, &byte_count,
  641. "ENDFIGURE");
  642. _cgm_emit_command_terminator (_plotter->data->page,
  643. _plotter->cgm_encoding,
  644. &byte_count);
  645. /* update CGM version needed for this page */
  646. _plotter->cgm_page_version = IMAX(2, _plotter->cgm_page_version);
  647. /* update CGM profile for this page */
  648. if (primitives_emitted > 128)
  649. _plotter->cgm_page_profile =
  650. IMAX(_plotter->cgm_page_profile, CGM_PROFILE_NONE);
  651. }
  652. if (pass == 1 && draw_as_cgm_compound)
  653. /* emit `END COMPOUND LINE' command (no parameters) */
  654. {
  655. data_len = 0;
  656. byte_count = data_byte_count = 0;
  657. _cgm_emit_command_header (_plotter->data->page, _plotter->cgm_encoding,
  658. CGM_DELIMITER_ELEMENT, 16,
  659. data_len, &byte_count,
  660. "ENDCOMPOLINE");
  661. _cgm_emit_command_terminator (_plotter->data->page,
  662. _plotter->cgm_encoding,
  663. &byte_count);
  664. /* update CGM version needed for this page */
  665. _plotter->cgm_page_version =
  666. IMAX(3, _plotter->cgm_page_version);
  667. /* update CGM profile for this page */
  668. if (primitives_emitted > 128)
  669. _plotter->cgm_page_profile =
  670. IMAX(_plotter->cgm_page_profile, CGM_PROFILE_NONE);
  671. }
  672. } /* end of loop over passes */
  673. /* free arrays of device-frame points */
  674. free (xarray);
  675. }
  676. break;
  677. case (int)PATH_BOX:
  678. {
  679. plPoint p0, p1;
  680. int xd0, xd1, yd0, yd1; /* in integer device coordinates */
  681. int byte_count, data_byte_count, data_len;
  682. int desired_interior_style;
  683. const char *desired_interior_style_string;
  684. p0 = _plotter->drawstate->path->p0;
  685. p1 = _plotter->drawstate->path->p1;
  686. /* compute corners in device coors */
  687. xd0 = IROUND(XD(p0.x, p0.y));
  688. yd0 = IROUND(YD(p0.x, p0.y));
  689. xd1 = IROUND(XD(p1.x, p1.y));
  690. yd1 = IROUND(YD(p1.x, p1.y));
  691. /* set CGM edge color and attributes, by emitting appropriate
  692. commands */
  693. _pl_c_set_pen_color (R___(_plotter) CGM_OBJECT_CLOSED);
  694. _pl_c_set_fill_color (R___(_plotter) CGM_OBJECT_CLOSED);
  695. _pl_c_set_attributes (R___(_plotter) CGM_OBJECT_CLOSED);
  696. if (_plotter->drawstate->fill_type == 0)
  697. /* won't do filling */
  698. {
  699. desired_interior_style = CGM_INT_STYLE_EMPTY;
  700. desired_interior_style_string = "empty";
  701. }
  702. else
  703. /* will do filling */
  704. {
  705. desired_interior_style = CGM_INT_STYLE_SOLID;
  706. desired_interior_style_string = "solid";
  707. }
  708. if (_plotter->cgm_interior_style != desired_interior_style)
  709. /* emit "INTERIOR STYLE" command */
  710. {
  711. data_len = 2; /* 2 bytes per enum */
  712. byte_count = data_byte_count = 0;
  713. _cgm_emit_command_header (_plotter->data->page, _plotter->cgm_encoding,
  714. CGM_ATTRIBUTE_ELEMENT, 22,
  715. data_len, &byte_count,
  716. "INTSTYLE");
  717. _cgm_emit_enum (_plotter->data->page, false, _plotter->cgm_encoding,
  718. desired_interior_style,
  719. data_len, &data_byte_count, &byte_count,
  720. desired_interior_style_string);
  721. _cgm_emit_command_terminator (_plotter->data->page, _plotter->cgm_encoding,
  722. &byte_count);
  723. /* update interior style */
  724. _plotter->cgm_interior_style = desired_interior_style;
  725. }
  726. if (_plotter->drawstate->pen_type)
  727. /* should edge the rectangle */
  728. {
  729. if (_plotter->cgm_edge_is_visible != true)
  730. /* emit "EDGE VISIBILITY" command */
  731. {
  732. data_len = 2; /* 2 bytes per enum */
  733. byte_count = data_byte_count = 0;
  734. _cgm_emit_command_header (_plotter->data->page, _plotter->cgm_encoding,
  735. CGM_ATTRIBUTE_ELEMENT, 30,
  736. data_len, &byte_count,
  737. "EDGEVIS");
  738. _cgm_emit_enum (_plotter->data->page, false, _plotter->cgm_encoding,
  739. 1,
  740. data_len, &data_byte_count, &byte_count,
  741. "on");
  742. _cgm_emit_command_terminator (_plotter->data->page, _plotter->cgm_encoding,
  743. &byte_count);
  744. /* update edge visibility */
  745. _plotter->cgm_edge_is_visible = true;
  746. }
  747. }
  748. else
  749. /* shouldn't edge the rectangle */
  750. {
  751. if (_plotter->cgm_edge_is_visible != false)
  752. /* emit "EDGE VISIBILITY" command */
  753. {
  754. data_len = 2; /* 2 bytes per enum */
  755. byte_count = data_byte_count = 0;
  756. _cgm_emit_command_header (_plotter->data->page, _plotter->cgm_encoding,
  757. CGM_ATTRIBUTE_ELEMENT, 30,
  758. data_len, &byte_count,
  759. "EDGEVIS");
  760. _cgm_emit_enum (_plotter->data->page, false, _plotter->cgm_encoding,
  761. 0,
  762. data_len, &data_byte_count, &byte_count,
  763. "off");
  764. _cgm_emit_command_terminator (_plotter->data->page, _plotter->cgm_encoding,
  765. &byte_count);
  766. /* update edge visibility */
  767. _plotter->cgm_edge_is_visible = false;
  768. }
  769. }
  770. /* emit "RECTANGLE" command */
  771. {
  772. data_len = 2 * 2 * CGM_BINARY_BYTES_PER_INTEGER;
  773. byte_count = data_byte_count = 0;
  774. _cgm_emit_command_header (_plotter->data->page, _plotter->cgm_encoding,
  775. CGM_GRAPHICAL_PRIMITIVE_ELEMENT, 11,
  776. data_len, &byte_count,
  777. "RECT");
  778. _cgm_emit_point (_plotter->data->page, false, _plotter->cgm_encoding,
  779. xd0, yd0,
  780. data_len, &data_byte_count, &byte_count);
  781. _cgm_emit_point (_plotter->data->page, false, _plotter->cgm_encoding,
  782. xd1, yd1,
  783. data_len, &data_byte_count, &byte_count);
  784. _cgm_emit_command_terminator (_plotter->data->page, _plotter->cgm_encoding,
  785. &byte_count);
  786. }
  787. }
  788. break;
  789. case (int)PATH_CIRCLE:
  790. {
  791. double xd, yd, radius_d;
  792. int i_x, i_y, i_radius; /* center and radius, quantized */
  793. plPoint pc;
  794. double radius;
  795. int byte_count, data_byte_count, data_len;
  796. int desired_interior_style;
  797. const char *desired_interior_style_string;
  798. pc = _plotter->drawstate->path->pc;
  799. radius = _plotter->drawstate->path->radius;
  800. /* known to be a circle in device frame, so compute center and
  801. radius in that frame */
  802. xd = XD(pc.x, pc.y);
  803. yd = YD(pc.x, pc.y);
  804. radius_d = sqrt (XDV(radius,0) * XDV(radius,0)
  805. + YDV(radius,0) * YDV(radius,0));
  806. i_x = IROUND(xd);
  807. i_y = IROUND(yd);
  808. i_radius = IROUND(radius_d);
  809. /* set CGM edge color and attributes, by emitting appropriate
  810. commands */
  811. _pl_c_set_pen_color (R___(_plotter) CGM_OBJECT_CLOSED);
  812. _pl_c_set_fill_color (R___(_plotter) CGM_OBJECT_CLOSED);
  813. _pl_c_set_attributes (R___(_plotter) CGM_OBJECT_CLOSED);
  814. if (_plotter->drawstate->fill_type == 0)
  815. /* won't do filling */
  816. {
  817. desired_interior_style = CGM_INT_STYLE_EMPTY;
  818. desired_interior_style_string = "empty";
  819. }
  820. else
  821. /* will do filling */
  822. {
  823. desired_interior_style = CGM_INT_STYLE_SOLID;
  824. desired_interior_style_string = "solid";
  825. }
  826. if (_plotter->cgm_interior_style != desired_interior_style)
  827. /* emit "INTERIOR STYLE" command */
  828. {
  829. data_len = 2; /* 2 bytes per enum */
  830. byte_count = data_byte_count = 0;
  831. _cgm_emit_command_header (_plotter->data->page, _plotter->cgm_encoding,
  832. CGM_ATTRIBUTE_ELEMENT, 22,
  833. data_len, &byte_count,
  834. "INTSTYLE");
  835. _cgm_emit_enum (_plotter->data->page, false, _plotter->cgm_encoding,
  836. desired_interior_style,
  837. data_len, &data_byte_count, &byte_count,
  838. desired_interior_style_string);
  839. _cgm_emit_command_terminator (_plotter->data->page,
  840. _plotter->cgm_encoding,
  841. &byte_count);
  842. /* update interior style */
  843. _plotter->cgm_interior_style = desired_interior_style;
  844. }
  845. if (_plotter->drawstate->pen_type)
  846. /* should edge the circle */
  847. {
  848. if (_plotter->cgm_edge_is_visible != true)
  849. /* emit "EDGE VISIBILITY" command */
  850. {
  851. data_len = 2; /* 2 bytes per enum */
  852. byte_count = data_byte_count = 0;
  853. _cgm_emit_command_header (_plotter->data->page,
  854. _plotter->cgm_encoding,
  855. CGM_ATTRIBUTE_ELEMENT, 30,
  856. data_len, &byte_count,
  857. "EDGEVIS");
  858. _cgm_emit_enum (_plotter->data->page, false, _plotter->cgm_encoding,
  859. 1,
  860. data_len, &data_byte_count, &byte_count,
  861. "on");
  862. _cgm_emit_command_terminator (_plotter->data->page, _plotter->cgm_encoding,
  863. &byte_count);
  864. /* update edge visibility */
  865. _plotter->cgm_edge_is_visible = true;
  866. }
  867. }
  868. else
  869. {
  870. if (_plotter->cgm_edge_is_visible != false)
  871. /* emit "EDGE VISIBILITY" command */
  872. {
  873. data_len = 2; /* 2 bytes per enum */
  874. byte_count = data_byte_count = 0;
  875. _cgm_emit_command_header (_plotter->data->page,
  876. _plotter->cgm_encoding,
  877. CGM_ATTRIBUTE_ELEMENT, 30,
  878. data_len, &byte_count,
  879. "EDGEVIS");
  880. _cgm_emit_enum (_plotter->data->page, false, _plotter->cgm_encoding,
  881. 0,
  882. data_len, &data_byte_count, &byte_count,
  883. "off");
  884. _cgm_emit_command_terminator (_plotter->data->page,
  885. _plotter->cgm_encoding,
  886. &byte_count);
  887. /* update edge visibility */
  888. _plotter->cgm_edge_is_visible = false;
  889. }
  890. }
  891. /* emit "CIRCLE" command */
  892. {
  893. data_len = 3 * CGM_BINARY_BYTES_PER_INTEGER;
  894. byte_count = data_byte_count = 0;
  895. _cgm_emit_command_header (_plotter->data->page, _plotter->cgm_encoding,
  896. CGM_GRAPHICAL_PRIMITIVE_ELEMENT, 12,
  897. data_len, &byte_count,
  898. "CIRCLE");
  899. _cgm_emit_point (_plotter->data->page, false, _plotter->cgm_encoding,
  900. i_x, i_y,
  901. data_len, &data_byte_count, &byte_count);
  902. _cgm_emit_integer (_plotter->data->page, false, _plotter->cgm_encoding,
  903. i_radius,
  904. data_len, &data_byte_count, &byte_count);
  905. _cgm_emit_command_terminator (_plotter->data->page, _plotter->cgm_encoding,
  906. &byte_count);
  907. }
  908. }
  909. break;
  910. case (int)PATH_ELLIPSE:
  911. {
  912. double xd, yd; /* center, in device frame */
  913. int i_x, i_y; /* center, quantized */
  914. double theta, costheta, sintheta;
  915. double cd1_endpoint_x, cd1_endpoint_y; /* conjugate diameter endpts */
  916. double cd2_endpoint_x, cd2_endpoint_y;
  917. int i1_x, i1_y, i2_x, i2_y; /* same, quantized */
  918. plPoint pc;
  919. double rx, ry, angle;
  920. int byte_count, data_byte_count, data_len;
  921. int desired_interior_style;
  922. const char *desired_interior_style_string;
  923. pc = _plotter->drawstate->path->pc;
  924. rx = _plotter->drawstate->path->rx;
  925. ry = _plotter->drawstate->path->ry;
  926. angle = _plotter->drawstate->path->angle;
  927. /* compute center, in device frame */
  928. xd = XD(pc.x, pc.y);
  929. yd = YD(pc.x, pc.y);
  930. i_x = IROUND(xd);
  931. i_y = IROUND(yd);
  932. /* inclination angle (radians), in user frame */
  933. theta = M_PI * angle / 180.0;
  934. costheta = cos (theta);
  935. sintheta = sin (theta);
  936. /* perform affine user->device coor transformation, computing
  937. endpoints of conjugate diameter pair, in device frame */
  938. cd1_endpoint_x = XD(pc.x + rx * costheta, pc.y + rx * sintheta);
  939. cd1_endpoint_y = YD(pc.x + rx * costheta, pc.y + rx * sintheta);
  940. cd2_endpoint_x = XD(pc.x - ry * sintheta, pc.y + ry * costheta);
  941. cd2_endpoint_y = YD(pc.x - ry * sintheta, pc.y + ry * costheta);
  942. i1_x = IROUND(cd1_endpoint_x);
  943. i1_y = IROUND(cd1_endpoint_y);
  944. i2_x = IROUND(cd2_endpoint_x);
  945. i2_y = IROUND(cd2_endpoint_y);
  946. /* set CGM edge color and attributes, by emitting appropriate
  947. commands */
  948. _pl_c_set_pen_color (R___(_plotter) CGM_OBJECT_CLOSED);
  949. _pl_c_set_fill_color (R___(_plotter) CGM_OBJECT_CLOSED);
  950. _pl_c_set_attributes (R___(_plotter) CGM_OBJECT_CLOSED);
  951. if (_plotter->drawstate->fill_type == 0)
  952. /* won't do filling */
  953. {
  954. desired_interior_style = CGM_INT_STYLE_EMPTY;
  955. desired_interior_style_string = "empty";
  956. }
  957. else
  958. /* will do filling */
  959. {
  960. desired_interior_style = CGM_INT_STYLE_SOLID;
  961. desired_interior_style_string = "solid";
  962. }
  963. if (_plotter->cgm_interior_style != desired_interior_style)
  964. /* emit "INTERIOR STYLE" command */
  965. {
  966. data_len = 2; /* 2 bytes per enum */
  967. byte_count = data_byte_count = 0;
  968. _cgm_emit_command_header (_plotter->data->page, _plotter->cgm_encoding,
  969. CGM_ATTRIBUTE_ELEMENT, 22,
  970. data_len, &byte_count,
  971. "INTSTYLE");
  972. _cgm_emit_enum (_plotter->data->page, false, _plotter->cgm_encoding,
  973. desired_interior_style,
  974. data_len, &data_byte_count, &byte_count,
  975. desired_interior_style_string);
  976. _cgm_emit_command_terminator (_plotter->data->page,
  977. _plotter->cgm_encoding,
  978. &byte_count);
  979. /* update interior style */
  980. _plotter->cgm_interior_style = desired_interior_style;
  981. }
  982. if (_plotter->drawstate->pen_type)
  983. /* should edge the ellipse */
  984. {
  985. if (_plotter->cgm_edge_is_visible != true)
  986. /* emit "EDGE VISIBILITY" command */
  987. {
  988. data_len = 2; /* 2 bytes per enum */
  989. byte_count = data_byte_count = 0;
  990. _cgm_emit_command_header (_plotter->data->page,
  991. _plotter->cgm_encoding,
  992. CGM_ATTRIBUTE_ELEMENT, 30,
  993. data_len, &byte_count,
  994. "EDGEVIS");
  995. _cgm_emit_enum (_plotter->data->page, false, _plotter->cgm_encoding,
  996. 1,
  997. data_len, &data_byte_count, &byte_count,
  998. "on");
  999. _cgm_emit_command_terminator (_plotter->data->page,
  1000. _plotter->cgm_encoding,
  1001. &byte_count);
  1002. /* update edge visibility */
  1003. _plotter->cgm_edge_is_visible = true;
  1004. }
  1005. }
  1006. else
  1007. {
  1008. if (_plotter->cgm_edge_is_visible != false)
  1009. /* emit "EDGE VISIBILITY" command */
  1010. {
  1011. data_len = 2; /* 2 bytes per enum */
  1012. byte_count = data_byte_count = 0;
  1013. _cgm_emit_command_header (_plotter->data->page,
  1014. _plotter->cgm_encoding,
  1015. CGM_ATTRIBUTE_ELEMENT, 30,
  1016. data_len, &byte_count,
  1017. "EDGEVIS");
  1018. _cgm_emit_enum (_plotter->data->page, false, _plotter->cgm_encoding,
  1019. 0,
  1020. data_len, &data_byte_count, &byte_count,
  1021. "off");
  1022. _cgm_emit_command_terminator (_plotter->data->page, _plotter->cgm_encoding,
  1023. &byte_count);
  1024. /* update edge visibility */
  1025. _plotter->cgm_edge_is_visible = false;
  1026. }
  1027. }
  1028. /* emit "ELLIPSE" command */
  1029. {
  1030. data_len = 3 * 2 * CGM_BINARY_BYTES_PER_INTEGER;
  1031. byte_count = data_byte_count = 0;
  1032. _cgm_emit_command_header (_plotter->data->page, _plotter->cgm_encoding,
  1033. CGM_GRAPHICAL_PRIMITIVE_ELEMENT, 17,
  1034. data_len, &byte_count,
  1035. "ELLIPSE");
  1036. _cgm_emit_point (_plotter->data->page, false, _plotter->cgm_encoding,
  1037. i_x, i_y,
  1038. data_len, &data_byte_count, &byte_count);
  1039. _cgm_emit_point (_plotter->data->page, false, _plotter->cgm_encoding,
  1040. i1_x, i1_y,
  1041. data_len, &data_byte_count, &byte_count);
  1042. _cgm_emit_point (_plotter->data->page, false, _plotter->cgm_encoding,
  1043. i2_x, i2_y,
  1044. data_len, &data_byte_count, &byte_count);
  1045. _cgm_emit_command_terminator (_plotter->data->page, _plotter->cgm_encoding,
  1046. &byte_count);
  1047. }
  1048. }
  1049. break;
  1050. default: /* shouldn't happen */
  1051. break;
  1052. }
  1053. }
  1054. bool
  1055. _pl_c_paint_paths (S___(Plotter *_plotter))
  1056. {
  1057. return false;
  1058. }