1 /* This file is part of the GNU plotutils package. Copyright (C) 1995,
2 1996, 1997, 1998, 1999, 2000, 2005, 2008, 2009, Free Software
3 Foundation, Inc.
4
5 The GNU plotutils package is free software. You may redistribute it
6 and/or modify it under the terms of the GNU General Public License as
7 published by the Free Software foundation; either version 2, or (at your
8 option) any later version.
9
10 The GNU plotutils package is distributed in the hope that it will be
11 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with the GNU plotutils package; see the file COPYING. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
18 Boston, MA 02110-1301, USA. */
19
20 /* This file contains the internal paint_path() and paint_paths() methods,
21 which the public method endpath() is a wrapper around. */
22
23 /* This version is for FigPlotters. By construction, for FigPlotters our
24 path buffer always contains either a segment list, or a rectangle or
25 circle or ellipse object. If it's a segment list, it consists of either
26 (1) a sequence of line segments, or (2) a single circular arc segment.
27 Those are the only sorts of path that xfig can handle. (For the last to
28 be included, the map from user to device coordinates must be uniform.) */
29
30 #include "sys-defines.h"
31 #include "extern.h"
32
33 /* subtypes of xfig POLYLINE object type (xfig numbering) */
34 #define P_OPEN 1
35 #define P_BOX 2
36 #define P_CLOSED 3
37
38 /* subtypes of xfig ELLIPSE object type (xfig numbering) */
39 #define SUBTYPE_ELLIPSE 1 /* ellipse defined by radii */
40 #define SUBTYPE_CIRCLE 3 /* circle defined by radius */
41
42 /* Fig's line styles, indexed into by internal line number
43 (PL_L_SOLID/PL_L_DOTTED/PL_L_DOTDASHED/PL_L_SHORTDASHED/PL_L_LONGDASHED/PL_L_DOTDOTDASHED) */
44 const int _pl_f_fig_line_style[PL_NUM_LINE_TYPES] =
45 { FIG_L_SOLID, FIG_L_DOTTED, FIG_L_DASHDOTTED, FIG_L_DASHED, FIG_L_DASHED,
46 FIG_L_DASHDOUBLEDOTTED, FIG_L_DASHTRIPLEDOTTED };
47
48 /* Fig join styles, indexed by internal number (miter/rd./bevel/triangular) */
49 const int _pl_f_fig_join_style[PL_NUM_JOIN_TYPES] =
50 { FIG_JOIN_MITER, FIG_JOIN_ROUND, FIG_JOIN_BEVEL, FIG_JOIN_ROUND };
51
52 /* Fig cap styles, indexed by internal number (butt/rd./project/triangular) */
53 const int _pl_f_fig_cap_style[PL_NUM_CAP_TYPES] =
54 { FIG_CAP_BUTT, FIG_CAP_ROUND, FIG_CAP_PROJECT, FIG_CAP_ROUND };
55
56 #define FUZZ 0.0000001
57
58 void
_pl_f_paint_path(S___ (Plotter * _plotter))59 _pl_f_paint_path (S___(Plotter *_plotter))
60 {
61 if (_plotter->drawstate->pen_type == 0
62 && _plotter->drawstate->fill_type == 0)
63 /* nothing to draw */
64 return;
65
66 switch ((int)_plotter->drawstate->path->type)
67 {
68 case (int)PATH_SEGMENT_LIST:
69 {
70 bool closed;
71 const char *format;
72 int i, polyline_subtype, line_style;
73 double nominal_spacing;
74 double device_line_width;
75 int quantized_device_line_width;
76
77 /* sanity checks */
78 if (_plotter->drawstate->path->num_segments == 0)/* nothing to do */
79 break;
80 if (_plotter->drawstate->path->num_segments == 1) /*shouldn't happen */
81 break;
82
83 if (_plotter->drawstate->path->num_segments == 2
84 && _plotter->drawstate->path->segments[1].type == S_ARC)
85 /* segment buffer contains a single arc, not a polyline */
86 {
87 double x0 = _plotter->drawstate->path->segments[0].p.x;
88 double y0 = _plotter->drawstate->path->segments[0].p.y;
89 double x1 = _plotter->drawstate->path->segments[1].p.x;
90 double y1 = _plotter->drawstate->path->segments[1].p.y;
91 double xc = _plotter->drawstate->path->segments[1].pc.x;
92 double yc = _plotter->drawstate->path->segments[1].pc.y;
93
94 _pl_f_draw_arc_internal (R___(_plotter) xc, yc, x0, y0, x1, y1);
95 break;
96 }
97
98 if ((_plotter->drawstate->path->num_segments >= 3)/*check for closure*/
99 && (_plotter->drawstate->path->segments[_plotter->drawstate->path->num_segments - 1].p.x == _plotter->drawstate->path->segments[0].p.x)
100 && (_plotter->drawstate->path->segments[_plotter->drawstate->path->num_segments - 1].p.y == _plotter->drawstate->path->segments[0].p.y))
101 closed = true;
102 else
103 closed = false; /* 2-point ones should be open */
104
105 if (closed)
106 {
107 polyline_subtype = P_CLOSED;
108 format = "#POLYLINE [CLOSED]\n%d %d %d %d %d %d %d %d %d %.3f %d %d %d %d %d %d";
109 }
110 else
111 {
112 polyline_subtype = P_OPEN;
113 format = "#POLYLINE [OPEN]\n%d %d %d %d %d %d %d %d %d %.3f %d %d %d %d %d %d";
114 }
115
116 /* evaluate fig colors lazily, i.e. only when needed */
117 _pl_f_set_pen_color (S___(_plotter));
118 _pl_f_set_fill_color (S___(_plotter));
119
120 /* In a .fig file, the width of a line is expressed as a
121 non-negative integer (a positive integer, if the line is to be
122 visible). Originally, the width, if positive, was interpreted
123 as a multiple of a fundamental `Fig display unit', namely 1/80
124 inch. However, the interpretation of the in-file line width was
125 subsequently changed, thus:
126
127 Width in .fig file Width as actually displayed by xfig
128 1 0.5
129 2 1
130 3 2
131 4 3
132 etc.
133
134 In consequence, our line width in terms of Fig display units
135 usually needs to be adjusted upward, before we round it to the
136 closest integer. Thanks to Wolfgang Glunz and Bart De Schutter
137 for pointing this out. (See the addition of 0.75 below, which
138 is what they recommend.)
139 */
140
141 device_line_width =
142 FIG_UNITS_TO_FIG_DISPLAY_UNITS(_plotter->drawstate->device_line_width);
143 if (device_line_width > 0.75)
144 device_line_width += 1.0;
145
146 /* round xfig's notion of the line width to the closest integer;
147 but never round it down to 0 (which would yield an invisible
148 line) if the line width in user coordinates is positive;
149 instead, round it upward to 1 */
150 quantized_device_line_width = IROUND(device_line_width);
151 if (quantized_device_line_width == 0 && device_line_width > 0.0)
152 quantized_device_line_width = 1;
153
154 /* compute line style (type of dotting/dashing, spacing of
155 dots/dashes)*/
156 _pl_f_compute_line_style (R___(_plotter) &line_style, &nominal_spacing);
157
158 /* update xfig's `depth' attribute */
159 if (_plotter->fig_drawing_depth > 0)
160 (_plotter->fig_drawing_depth)--;
161
162 sprintf(_plotter->data->page->point,
163 format,
164 2, /* polyline object */
165 polyline_subtype, /* polyline subtype */
166 line_style, /* Fig line style */
167 /* thickness, in Fig display units */
168 (_plotter->drawstate->pen_type == 0 ? 0 :
169 quantized_device_line_width),
170 _plotter->drawstate->fig_fgcolor, /* pen color */
171 _plotter->drawstate->fig_fillcolor, /* fill color */
172 _plotter->fig_drawing_depth, /* depth */
173 0, /* pen style, ignored */
174 _plotter->drawstate->fig_fill_level, /* area fill */
175 nominal_spacing, /* style val, in Fig display units (float) */
176 _pl_f_fig_join_style[_plotter->drawstate->join_type],/*join style */
177 _pl_f_fig_cap_style[_plotter->drawstate->cap_type], /* cap style */
178 0, /* radius(of arc boxes, ignored here) */
179 0, /* forward arrow */
180 0, /* backward arrow */
181 _plotter->drawstate->path->num_segments /*num points in line */
182 );
183 _update_buffer (_plotter->data->page);
184
185 for (i=0; i<_plotter->drawstate->path->num_segments; i++)
186 {
187 plPathSegment datapoint;
188 double xu, yu, xd, yd;
189 int device_x, device_y;
190
191 datapoint = _plotter->drawstate->path->segments[i];
192 xu = datapoint.p.x;
193 yu = datapoint.p.y;
194 xd = XD(xu, yu);
195 yd = YD(xu, yu);
196 device_x = IROUND(xd);
197 device_y = IROUND(yd);
198
199 if ((i%5) == 0)
200 sprintf (_plotter->data->page->point, "\n\t");/* make human-readable */
201 else
202 sprintf (_plotter->data->page->point, " ");
203 _update_buffer (_plotter->data->page);
204
205 sprintf (_plotter->data->page->point, "%d %d", device_x, device_y);
206 _update_buffer (_plotter->data->page);
207 }
208 sprintf (_plotter->data->page->point, "\n");
209 _update_buffer (_plotter->data->page);
210 }
211 break;
212
213 case (int)PATH_BOX:
214 {
215 plPoint p0, p1;
216
217 p0 = _plotter->drawstate->path->p0;
218 p1 = _plotter->drawstate->path->p1;
219
220 _pl_f_draw_box_internal (R___(_plotter) p0, p1);
221 }
222 break;
223
224 case (int)PATH_CIRCLE:
225 {
226 double x = _plotter->drawstate->path->pc.x;
227 double y = _plotter->drawstate->path->pc.y;
228 double r = _plotter->drawstate->path->radius;
229
230 _pl_f_draw_ellipse_internal (R___(_plotter)
231 x, y, r, r, 0.0, SUBTYPE_CIRCLE);
232 }
233 break;
234
235 case (int)PATH_ELLIPSE:
236 {
237 double x = _plotter->drawstate->path->pc.x;
238 double y = _plotter->drawstate->path->pc.y;
239 double rx = _plotter->drawstate->path->rx;
240 double ry = _plotter->drawstate->path->ry;
241 double angle = _plotter->drawstate->path->angle;
242
243 _pl_f_draw_ellipse_internal (R___(_plotter)
244 x, y, rx, ry, angle, SUBTYPE_ELLIPSE);
245 }
246 break;
247
248 default: /* shouldn't happen */
249 break;
250 }
251 }
252
253 /* Emit Fig code for an arc. This is called if the segment buffer contains
254 not a polyline, but a single circular arc. If an arc was placed there,
255 we can count on the map from the user frame to the device frame being
256 isotropic (so the arc will be circular in the device frame too), and we
257 can count on the arc not being of zero length. See g_arc.c. */
258
259 #define DIST(p1, p2) sqrt( ((p1).x - (p2).x) * ((p1).x - (p2).x) \
260 + ((p1).y - (p2).y) * ((p1).y - (p2).y))
261
262 void
_pl_f_draw_arc_internal(R___ (Plotter * _plotter)double xc,double yc,double x0,double y0,double x1,double y1)263 _pl_f_draw_arc_internal (R___(Plotter *_plotter) double xc, double yc, double x0, double y0, double x1, double y1)
264 {
265 plPoint p0, p1, pc, pb;
266 plVector v, v0, v1;
267 double cross, radius, nominal_spacing;
268 int line_style, orientation;
269 double device_line_width;
270 int quantized_device_line_width;
271
272 pc.x = xc, pc.y = yc;
273 p0.x = x0, p0.y = y0;
274 p1.x = x1, p1.y = y1;
275
276 /* vectors from pc to p0, and pc to p1 */
277 v0.x = p0.x - pc.x;
278 v0.y = p0.y - pc.y;
279 v1.x = p1.x - pc.x;
280 v1.y = p1.y - pc.y;
281
282 /* cross product, zero means points are collinear */
283 cross = v0.x * v1.y - v1.x * v0.y;
284
285 /* Compute orientation. Note libplot convention: if p0, p1, pc are
286 collinear then arc goes counterclockwise from p0 to p1. */
287 orientation = (cross >= 0.0 ? 1 : -1);
288
289 radius = DIST(pc, p0); /* radius is distance to p0 or p1 */
290
291 v.x = p1.x - p0.x; /* chord vector from p0 to p1 */
292 v.y = p1.y - p0.y;
293
294 _vscale(&v, radius);
295 pb.x = pc.x + orientation * v.y; /* bisection point of arc */
296 pb.y = pc.y - orientation * v.x;
297
298 /* evaluate fig colors lazily, i.e. only when needed */
299 _pl_f_set_pen_color (S___(_plotter));
300 _pl_f_set_fill_color (S___(_plotter));
301
302 /* xfig expresses the width of a line as an integer number of `Fig
303 display units', so convert the width to those units */
304 device_line_width =
305 FIG_UNITS_TO_FIG_DISPLAY_UNITS(_plotter->drawstate->device_line_width);
306
307 /* the interpretation of line width in a .fig file is now more
308 complicated (see comments in _pl_f_paint_path() above), so this value
309 must usually be incremented */
310 if (device_line_width > 0.75)
311 device_line_width += 1.0;
312
313 /* round xfig's notion of the line width to the closest integer; but
314 never round it down to 0 (which would yield an invisible line) if the
315 line width in user coordinates is positive; instead, round it upward
316 to 1 */
317 quantized_device_line_width = IROUND(device_line_width);
318 if (quantized_device_line_width == 0 && device_line_width > 0.0)
319 quantized_device_line_width = 1;
320
321 /* compute line style (type of dotting/dashing, spacing of dots/dashes) */
322 _pl_f_compute_line_style (R___(_plotter) &line_style, &nominal_spacing);
323
324 /* update xfig's `depth' attribute */
325 if (_plotter->fig_drawing_depth > 0)
326 (_plotter->fig_drawing_depth)--;
327
328 /* compute orientation in NDC frame */
329 orientation *= (_plotter->drawstate->transform.nonreflection ? 1 : -1);
330
331 if (orientation == -1)
332 /* interchange p0, p1 (since xfig insists that p0, pb, p1 must appear
333 in counterclockwise order around the arc) */
334 {
335 plPoint ptmp;
336
337 ptmp = p0;
338 p0 = p1;
339 p1 = ptmp;
340 }
341
342 sprintf(_plotter->data->page->point,
343 "#ARC\n%d %d %d %d %d %d %d %d %d %.3f %d %d %d %d %.3f %.3f %d %d %d %d %d %d\n",
344 5, /* arc object */
345 1, /* open-ended arc subtype */
346 line_style, /* Fig line style */
347 /* thickness, in Fig display units */
348 (_plotter->drawstate->pen_type == 0 ? 0 :
349 quantized_device_line_width),
350 _plotter->drawstate->fig_fgcolor, /* pen color */
351 _plotter->drawstate->fig_fillcolor, /* fill color */
352 _plotter->fig_drawing_depth, /* depth */
353 0, /* pen style, ignored */
354 _plotter->drawstate->fig_fill_level, /* area fill */
355 nominal_spacing, /* style val, in Fig display units (float) */
356 _pl_f_fig_cap_style[_plotter->drawstate->cap_type], /* cap style */
357 1, /* counterclockwise */
358 0, /* no forward arrow */
359 0, /* no backward arrow */
360 XD(pc.x, pc.y), /* center_x (float) */
361 YD(pc.x, pc.y), /* center_y (float) */
362 IROUND(XD(p0.x, p0.y)), /* 1st point user entered (p0) */
363 IROUND(YD(p0.x, p0.y)),
364 IROUND(XD(pb.x, pb.y)), /* 2nd point user entered (bisection point)*/
365 IROUND(YD(pb.x, pb.y)),
366 IROUND(XD(p1.x, p1.y)), /* last point user entered (p1) */
367 IROUND(YD(p1.x, p1.y)));
368 _update_buffer (_plotter->data->page);
369 }
370
371 void
_pl_f_draw_box_internal(R___ (Plotter * _plotter)plPoint p0,plPoint p1)372 _pl_f_draw_box_internal (R___(Plotter *_plotter) plPoint p0, plPoint p1)
373 {
374 int xd0, xd1, yd0, yd1; /* in device coordinates */
375 double nominal_spacing;
376 int line_style;
377 double device_line_width;
378 int quantized_device_line_width;
379
380 /* evaluate fig colors lazily, i.e. only when needed */
381 _pl_f_set_pen_color (S___(_plotter));
382 _pl_f_set_fill_color (S___(_plotter));
383
384 /* xfig expresses the width of a line as an integer number of `Fig
385 display units', so convert the width to those units */
386 device_line_width =
387 FIG_UNITS_TO_FIG_DISPLAY_UNITS(_plotter->drawstate->device_line_width);
388
389 /* the interpretation of line width in a .fig file is now more
390 complicated (see comments in _pl_f_paint_path() above), so this value
391 must usually be incremented */
392 if (device_line_width > 0.75)
393 device_line_width += 1.0;
394
395 /* round xfig's notion of the line width to the closest integer; but
396 never round it down to 0 (which would yield an invisible line) if the
397 line width in user coordinates is positive; instead, round it upward
398 to 1 */
399 quantized_device_line_width = IROUND(device_line_width);
400 if (quantized_device_line_width == 0 && device_line_width > 0.0)
401 quantized_device_line_width = 1;
402
403 /* compute line style (type of dotting/dashing, spacing of dots/dashes)*/
404 _pl_f_compute_line_style (R___(_plotter) &line_style, &nominal_spacing);
405
406 /* update xfig's `depth' attribute */
407 if (_plotter->fig_drawing_depth > 0)
408 (_plotter->fig_drawing_depth)--;
409
410 sprintf(_plotter->data->page->point,
411 "#POLYLINE [BOX]\n%d %d %d %d %d %d %d %d %d %.3f %d %d %d %d %d %d\n",
412 2, /* polyline object */
413 P_BOX, /* polyline subtype */
414 line_style, /* Fig line style */
415 /* thickness, in Fig display units */
416 (_plotter->drawstate->pen_type == 0 ? 0 :
417 quantized_device_line_width),
418 _plotter->drawstate->fig_fgcolor, /* pen color */
419 _plotter->drawstate->fig_fillcolor, /* fill color */
420 _plotter->fig_drawing_depth, /* depth */
421 0, /* pen style, ignored */
422 _plotter->drawstate->fig_fill_level, /* area fill */
423 nominal_spacing, /* style val, in Fig display units (float) */
424 _pl_f_fig_join_style[_plotter->drawstate->join_type], /* join style */
425 _pl_f_fig_cap_style[_plotter->drawstate->cap_type], /* cap style */
426 0, /* radius (of arc boxes, ignored here) */
427 0, /* forward arrow */
428 0, /* backward arrow */
429 5 /* number of points in line */
430 );
431 _update_buffer (_plotter->data->page);
432
433 p0 = _plotter->drawstate->path->p0;
434 p1 = _plotter->drawstate->path->p1;
435 xd0 = IROUND(XD(p0.x, p0.y));
436 yd0 = IROUND(YD(p0.x, p0.y));
437 xd1 = IROUND(XD(p1.x, p1.y));
438 yd1 = IROUND(YD(p1.x, p1.y));
439
440 sprintf (_plotter->data->page->point, "\t%d %d ", xd0, yd0);
441 _update_buffer (_plotter->data->page);
442 sprintf (_plotter->data->page->point, "%d %d ", xd0, yd1);
443 _update_buffer (_plotter->data->page);
444 sprintf (_plotter->data->page->point, "%d %d ", xd1, yd1);
445 _update_buffer (_plotter->data->page);
446 sprintf (_plotter->data->page->point, "%d %d ", xd1, yd0);
447 _update_buffer (_plotter->data->page);
448 sprintf (_plotter->data->page->point, "%d %d\n", xd0, yd0);
449 _update_buffer (_plotter->data->page);
450 }
451
452 void
_pl_f_draw_ellipse_internal(R___ (Plotter * _plotter)double x,double y,double rx,double ry,double angle,int subtype)453 _pl_f_draw_ellipse_internal (R___(Plotter *_plotter) double x, double y, double rx, double ry, double angle, int subtype)
454 {
455 const char *format;
456 double theta, mixing_angle;
457 double ux, uy, vx, vy;
458 double semi_axis_1_x, semi_axis_1_y;
459 double semi_axis_2_x, semi_axis_2_y;
460 double rx_device, ry_device, theta_device;
461 double costheta, sintheta;
462 double nominal_spacing;
463 int line_style;
464 double device_line_width;
465 int quantized_device_line_width;
466
467 /* inclination angle (radians), in user frame */
468 theta = M_PI * angle / 180.0;
469 costheta = cos (theta);
470 sintheta = sin (theta);
471
472 /* perform affine user->device coor transformation; (ux,uy) and (vx,vy)
473 are forward images of the semiaxes, i.e. they are conjugate radial
474 vectors in the device frame */
475
476 ux = XDV(rx * costheta, rx * sintheta);
477 uy = YDV(rx * costheta, rx * sintheta);
478
479 vx = XDV(-ry * sintheta, ry * costheta);
480 vy = YDV(-ry * sintheta, ry * costheta);
481
482 /* angle by which the conjugate radial vectors should be mixed, in order
483 to yield vectors along the major and minor axes in the device frame */
484 mixing_angle = 0.5 * _xatan2 (2.0 * (ux * vx + uy * vy),
485 ux * ux + uy * uy - vx * vx + vy * vy);
486
487 /* semi-axis vectors in device coordinates */
488 semi_axis_1_x = ux * cos(mixing_angle) + vx * sin(mixing_angle);
489 semi_axis_1_y = uy * cos(mixing_angle) + vy * sin(mixing_angle);
490 semi_axis_2_x = ux * cos(mixing_angle + M_PI_2)
491 + vx * sin(mixing_angle + M_PI_2);
492 semi_axis_2_y = uy * cos(mixing_angle + M_PI_2)
493 + vy * sin(mixing_angle + M_PI_2);
494
495 /* semi-axis lengths in device coordinates */
496 rx_device = sqrt (semi_axis_1_x * semi_axis_1_x
497 + semi_axis_1_y * semi_axis_1_y);
498 ry_device = sqrt (semi_axis_2_x * semi_axis_2_x
499 + semi_axis_2_y * semi_axis_2_y);
500
501 /* angle of inclination of the first semi-axis, in device frame
502 (note flipped-y convention) */
503 theta_device = - _xatan2 (semi_axis_1_y, semi_axis_1_x);
504 if (theta_device == 0.0)
505 theta_device = 0.0; /* remove sign bit if any */
506
507 if (subtype == SUBTYPE_CIRCLE &&
508 IROUND (rx_device) != IROUND (ry_device))
509 subtype = SUBTYPE_ELLIPSE;
510
511 /* evaluate fig colors lazily, i.e. only when needed */
512 _pl_f_set_pen_color (S___(_plotter));
513 _pl_f_set_fill_color (S___(_plotter));
514
515 /* xfig expresses the width of a line as an integer number of `Fig
516 display units', so convert the width to those units */
517 device_line_width =
518 FIG_UNITS_TO_FIG_DISPLAY_UNITS(_plotter->drawstate->device_line_width);
519
520 /* the interpretation of line width in a .fig file is now more
521 complicated (see comments in _pl_f_paint_path() above), so this value
522 must usually be incremented */
523 if (device_line_width > 0.75)
524 device_line_width += 1.0;
525
526 /* round xfig's notion of the line width to the closest integer; but
527 never round it down to 0 (which would yield an invisible line) if the
528 line width in user coordinates is positive; instead, round it upward
529 to 1 */
530 quantized_device_line_width = IROUND(device_line_width);
531 if (quantized_device_line_width == 0 && device_line_width > 0.0)
532 quantized_device_line_width = 1;
533
534 /* compute line style (type of dotting/dashing, spacing of dots/dashes) */
535 _pl_f_compute_line_style (R___(_plotter) &line_style, &nominal_spacing);
536
537 /* update xfig's `depth' attribute */
538 if (_plotter->fig_drawing_depth > 0)
539 (_plotter->fig_drawing_depth)--;
540
541 if (subtype == SUBTYPE_CIRCLE)
542 format = "#ELLIPSE [CIRCLE]\n%d %d %d %d %d %d %d %d %d %.3f %d %.3f %d %d %d %d %d %d %d %d\n";
543 else
544 format = "#ELLIPSE\n%d %d %d %d %d %d %d %d %d %.3f %d %.3f %d %d %d %d %d %d %d %d\n";
545
546 sprintf(_plotter->data->page->point,
547 format,
548 1, /* ellipse object */
549 subtype, /* subtype, see above */
550 line_style, /* Fig line style */
551 /* thickness, in Fig display units */
552 (_plotter->drawstate->pen_type == 0 ? 0 :
553 quantized_device_line_width),
554 _plotter->drawstate->fig_fgcolor, /* pen color */
555 _plotter->drawstate->fig_fillcolor, /* fill color */
556 _plotter->fig_drawing_depth, /* depth */
557 0, /* pen style, ignored */
558 _plotter->drawstate->fig_fill_level, /* area fill */
559 nominal_spacing, /* style val, in Fig display units (float) */
560 1, /* direction, always 1 */
561 theta_device, /* inclination angle, in radians (float) */
562 IROUND(XD(x,y)), /* center_x (not float, unlike arc) */
563 IROUND(YD(x,y)), /* center_y (not float, unlike arc) */
564 IROUND(rx_device), /* radius_x */
565 IROUND(ry_device), /* radius_y */
566 IROUND(XD(x,y)), /* start_x, 1st point entered */
567 IROUND(YD(x,y)), /* start_y, 1st point entered */
568 IROUND(XD(x,y) /* end_x, last point entered */
569 + semi_axis_1_x + semi_axis_2_x),
570 IROUND(YD(x,y) /* end_y, last point entered */
571 + semi_axis_1_y + semi_axis_2_y)
572 );
573 _update_buffer(_plotter->data->page);
574 }
575
576 /* compute appropriate Fig line style, and also appropriate value for Fig's
577 notion of `dash length/dot gap' (in Fig display units) */
578 void
_pl_f_compute_line_style(R___ (Plotter * _plotter)int * style,double * spacing)579 _pl_f_compute_line_style (R___(Plotter *_plotter) int *style, double *spacing)
580 {
581 int fig_line_style;
582 double fig_nominal_spacing;
583
584 if (_plotter->drawstate->dash_array_in_effect
585 && _plotter->drawstate->dash_array_len == 2
586 && (_plotter->drawstate->dash_array[1]
587 == _plotter->drawstate->dash_array[0]))
588 /* special case of user-specified dashing (equal on/off lengths);
589 we map this into Fig's `dashed' line type */
590 {
591 double min_sing_val, max_sing_val;
592
593 /* Minimum singular value is the nominal device-frame line width
594 divided by the actual user-frame line-width (see g_linewidth.c),
595 so it's the user->device frame conversion factor. */
596 _matrix_sing_vals (_plotter->drawstate->transform.m,
597 &min_sing_val, &max_sing_val);
598
599 /* desired cycle length in Fig display units */
600 fig_nominal_spacing =
601 FIG_UNITS_TO_FIG_DISPLAY_UNITS(min_sing_val * 2.0 * _plotter->drawstate->dash_array[0]);
602 fig_line_style = FIG_L_DASHED;
603 }
604 else if (_plotter->drawstate->dash_array_in_effect
605 && _plotter->drawstate->dash_array_len == 2
606 && (_plotter->drawstate->dash_array[1]
607 > (3 - FUZZ) * _plotter->drawstate->dash_array[0])
608 && (_plotter->drawstate->dash_array[1]
609 < (3 + FUZZ) * _plotter->drawstate->dash_array[0]))
610 /* special case of user-specified dashing (gap length = 3 * dash length);
611 we map this into Fig's `dotted' line type, since it agrees with
612 libplot's convention for dashing `dotted' lines (see g_dash2.c) */
613 {
614 double min_sing_val, max_sing_val;
615
616 _matrix_sing_vals (_plotter->drawstate->transform.m,
617 &min_sing_val, &max_sing_val);
618
619 /* desired cycle length in Fig display units */
620 fig_nominal_spacing =
621 FIG_UNITS_TO_FIG_DISPLAY_UNITS(min_sing_val * 4.0 * _plotter->drawstate->dash_array[0]);
622 fig_line_style = FIG_L_DOTTED;
623 }
624 else
625 /* canonical line type; retrieve dash array from database (in g_dash2.c) */
626 {
627 int i, num_dashes, cycle_length;
628 const int *dash_array;
629 double display_size_in_fig_units, min_dash_unit, dash_unit;
630
631 num_dashes =
632 _pl_g_line_styles[_plotter->drawstate->line_type].dash_array_len;
633 dash_array = _pl_g_line_styles[_plotter->drawstate->line_type].dash_array;
634 cycle_length = 0;
635 for (i = 0; i < num_dashes; i++)
636 cycle_length += dash_array[i];
637 /* multiply cycle length of dash array by device-frame line width in
638 Fig display units, with a floor on the latter (see comments at
639 head of file) */
640 display_size_in_fig_units = DMIN(_plotter->data->xmax - _plotter->data->xmin,
641 /* flipped y */
642 _plotter->data->ymin - _plotter->data->ymax);
643 min_dash_unit = PL_MIN_DASH_UNIT_AS_FRACTION_OF_DISPLAY_SIZE
644 * FIG_UNITS_TO_FIG_DISPLAY_UNITS(display_size_in_fig_units);
645 dash_unit = DMAX(min_dash_unit,
646 FIG_UNITS_TO_FIG_DISPLAY_UNITS(_plotter->drawstate->device_line_width));
647
648 /* desired cycle length in Fig display units */
649 fig_nominal_spacing = cycle_length * dash_unit;
650 fig_line_style = _pl_f_fig_line_style[_plotter->drawstate->line_type];
651 }
652
653 /* compensate for Fig's (or fig2dev's) peculiarities; value stored in Fig
654 output file isn't really the cycle length */
655 switch (fig_line_style)
656 {
657 case FIG_L_SOLID:
658 default: /* shouldn't happen */
659 break;
660 case FIG_L_DOTTED:
661 fig_nominal_spacing -= 1.0;
662 break;
663 case FIG_L_DASHDOTTED:
664 fig_nominal_spacing -= 1.0;
665 /* fall thru */
666 case FIG_L_DASHED:
667 fig_nominal_spacing *= 0.5;
668 break;
669 case FIG_L_DASHDOUBLEDOTTED:
670 fig_nominal_spacing -= 2.0;
671 fig_nominal_spacing /= (1.9 + 1/3.0); /* really */
672 break;
673 case FIG_L_DASHTRIPLEDOTTED:
674 fig_nominal_spacing -= 3.0;
675 fig_nominal_spacing /= 2.4;
676 break;
677 }
678 if (fig_nominal_spacing <= 1.0)
679 fig_nominal_spacing = 1.0;
680
681 /* pass back what Fig will need */
682 *style = fig_line_style;
683 *spacing = fig_nominal_spacing;
684 }
685
686 bool
_pl_f_paint_paths(S___ (Plotter * _plotter))687 _pl_f_paint_paths (S___(Plotter *_plotter))
688 {
689 return false;
690 }
691