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
4 The GNU plotutils package is free software. You may redistribute it
5 and/or modify it under the terms of the GNU General Public License as
6 published by the Free Software foundation; either version 2, or (at your
7 option) any later version.
8
9 The GNU plotutils package is distributed in the hope that it will be
10 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with the GNU plotutils package; see the file COPYING. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
17 Boston, MA 02110-1301, USA. */
18
19 /* This file contains the internal paint_path() and paint_paths() methods,
20 which the public method endpath() is a wrapper around. */
21
22 #include "sys-defines.h"
23 #include "extern.h"
24
25 void
_pl_m_paint_path(S___ (Plotter * _plotter))26 _pl_m_paint_path (S___(Plotter *_plotter))
27 {
28 const plPath *path;
29 bool explicit_endpath, sync_miter_limit = false;
30
31 /* sync basic path attributes */
32 _pl_m_set_attributes (R___(_plotter)
33 PL_ATTR_TRANSFORMATION_MATRIX
34 | PL_ATTR_PEN_COLOR | PL_ATTR_PEN_TYPE
35 | PL_ATTR_LINE_STYLE | PL_ATTR_LINE_WIDTH
36 | PL_ATTR_JOIN_STYLE | PL_ATTR_CAP_STYLE
37 | PL_ATTR_FILL_COLOR | PL_ATTR_FILL_TYPE
38 | PL_ATTR_FILL_RULE);
39
40 /* our one and only simple path to paint */
41 path = _plotter->drawstate->path;
42
43 if (_plotter->drawstate->join_type == PL_JOIN_MITER
44 && (path->type == PATH_SEGMENT_LIST || path->type == PATH_BOX))
45 /* path may have mitered juncture points */
46 sync_miter_limit = true;
47 if (sync_miter_limit)
48 _pl_m_set_attributes (R___(_plotter) PL_ATTR_MITER_LIMIT);
49
50 if (path->type == PATH_SEGMENT_LIST)
51 explicit_endpath = true;
52 else
53 explicit_endpath = false;
54
55 /* emit metafile object-drawing instructions to draw the path; include a
56 preliminary syncing of the `orientation' attribute if relevant */
57 _pl_m_paint_path_internal (R___(_plotter) path);
58
59 if (explicit_endpath)
60 {
61 _pl_m_emit_op_code (R___(_plotter) O_ENDPATH);
62 _pl_m_emit_terminator (S___(_plotter));
63 }
64 }
65
66 bool
_pl_m_paint_paths(S___ (Plotter * _plotter))67 _pl_m_paint_paths (S___(Plotter *_plotter))
68 {
69 const plPath *path;
70 bool sync_miter_limit = false;
71 int i;
72
73 /* sanity check */
74 if (_plotter->drawstate->num_paths == 0)
75 return true;
76
77 /* sync basic path attributes */
78 _pl_m_set_attributes (R___(_plotter)
79 PL_ATTR_TRANSFORMATION_MATRIX
80 | PL_ATTR_PEN_COLOR | PL_ATTR_PEN_TYPE
81 | PL_ATTR_LINE_STYLE | PL_ATTR_LINE_WIDTH
82 | PL_ATTR_JOIN_STYLE | PL_ATTR_CAP_STYLE
83 | PL_ATTR_FILL_COLOR | PL_ATTR_FILL_TYPE
84 | PL_ATTR_FILL_RULE);
85
86 if (_plotter->drawstate->join_type == PL_JOIN_MITER)
87 {
88 for (i = 0; i < _plotter->drawstate->num_paths; i++)
89 {
90 path = _plotter->drawstate->paths[i];
91 if (path->type == PATH_SEGMENT_LIST || path->type == PATH_BOX)
92 /* compound path may have mitered juncture points */
93 {
94 sync_miter_limit = true;
95 break;
96 }
97 }
98 }
99 if (sync_miter_limit)
100 _pl_m_set_attributes (R___(_plotter) PL_ATTR_MITER_LIMIT);
101
102 /* loop over simple paths in compound path */
103 for (i = 0; i < _plotter->drawstate->num_paths; i++)
104 {
105 path = _plotter->drawstate->paths[i];
106
107 /* emit metafile object-drawing instructions to draw the path; first
108 sync `orientation' attribute, if relevant */
109 _pl_m_paint_path_internal (R___(_plotter) path);
110
111 if (i < _plotter->drawstate->num_paths - 1)
112 {
113 _pl_m_emit_op_code (R___(_plotter) O_ENDSUBPATH);
114 _pl_m_emit_terminator (S___(_plotter));
115 }
116 }
117
118 if (_plotter->drawstate->paths[_plotter->drawstate->num_paths - 1]->type == PATH_SEGMENT_LIST)
119 /* append explicit (as opposed to implicit) endpath; if we didn't wish
120 to be clever, we'd append one even if the final simple path isn't a
121 segment list */
122 {
123 _pl_m_emit_op_code (R___(_plotter) O_ENDPATH);
124 _pl_m_emit_terminator (S___(_plotter));
125 }
126
127 /* succesfully painted compound path */
128 return true;
129 }
130
131 /* Internal routine, called by the MetaPlotter-specific versions of
132 paint_path() and paint_paths(). Besides emitting metafile instructions
133 to draw a path, it may emit an instruction to update the `orientation'
134 attribute, relevant to paths that are boxes/circles/ellipses. */
135
136 void
_pl_m_paint_path_internal(R___ (Plotter * _plotter)const plPath * path)137 _pl_m_paint_path_internal (R___(Plotter *_plotter) const plPath *path)
138 {
139 if (path->type == PATH_BOX
140 || path->type == PATH_CIRCLE || path->type == PATH_ELLIPSE)
141 /* sync orientation; orientation is stored in the path itself, not in
142 the drawing state */
143 {
144 int orientation = (path->clockwise ? -1 : 1);
145
146 if (_plotter->meta_orientation != orientation)
147 {
148 _pl_m_emit_op_code (R___(_plotter) O_ORIENTATION);
149 _pl_m_emit_integer (R___(_plotter) orientation);
150 _pl_m_emit_terminator (S___(_plotter));
151 _plotter->meta_orientation = orientation;
152 }
153 }
154
155 switch ((int)path->type)
156 {
157 case (int)PATH_SEGMENT_LIST:
158 {
159 plPathSegment segment;
160 int i;
161
162 /* last-minute sanity check */
163 if (path->num_segments == 0)/* nothing to do */
164 break;
165 if (path->num_segments == 1) /* shouldn't happen */
166 break;
167
168 segment = path->segments[0]; /* initial moveto */
169 if (_plotter->meta_pos.x != segment.p.x
170 || _plotter->meta_pos.y != segment.p.y)
171 {
172 _pl_m_emit_op_code (R___(_plotter) O_FMOVE);
173 _pl_m_emit_float (R___(_plotter) segment.p.x);
174 _pl_m_emit_float (R___(_plotter) segment.p.y);
175 _pl_m_emit_terminator (S___(_plotter));
176 _plotter->meta_pos = segment.p;
177 }
178
179 for (i = 1; i < path->num_segments; i++)
180 {
181 plPathSegment prev_segment;
182
183 prev_segment = segment;
184 segment = path->segments[i];
185 switch ((int)segment.type)
186 {
187 case (int)S_LINE:
188 _pl_m_emit_op_code (R___(_plotter) O_FCONT);
189 _pl_m_emit_float (R___(_plotter) segment.p.x);
190 _pl_m_emit_float (R___(_plotter) segment.p.y);
191 _pl_m_emit_terminator (S___(_plotter));
192 _plotter->meta_pos = segment.p;
193 break;
194
195 case (int)S_ARC:
196 _pl_m_emit_op_code (R___(_plotter) O_FARC);
197 _pl_m_emit_float (R___(_plotter) segment.pc.x);
198 _pl_m_emit_float (R___(_plotter) segment.pc.y);
199 _pl_m_emit_float (R___(_plotter) prev_segment.p.x);
200 _pl_m_emit_float (R___(_plotter) prev_segment.p.y);
201 _pl_m_emit_float (R___(_plotter) segment.p.x);
202 _pl_m_emit_float (R___(_plotter) segment.p.y);
203 _pl_m_emit_terminator (S___(_plotter));
204 _plotter->meta_pos = segment.p;
205 break;
206
207 case (int)S_ELLARC:
208 _pl_m_emit_op_code (R___(_plotter) O_FELLARC);
209 _pl_m_emit_float (R___(_plotter) segment.pc.x);
210 _pl_m_emit_float (R___(_plotter) segment.pc.y);
211 _pl_m_emit_float (R___(_plotter) prev_segment.p.x);
212 _pl_m_emit_float (R___(_plotter) prev_segment.p.y);
213 _pl_m_emit_float (R___(_plotter) segment.p.x);
214 _pl_m_emit_float (R___(_plotter) segment.p.y);
215 _pl_m_emit_terminator (S___(_plotter));
216 _plotter->meta_pos = segment.p;
217 break;
218
219 case (int)S_QUAD:
220 _pl_m_emit_op_code (R___(_plotter) O_FBEZIER2);
221 _pl_m_emit_float (R___(_plotter) prev_segment.p.x);
222 _pl_m_emit_float (R___(_plotter) prev_segment.p.y);
223 _pl_m_emit_float (R___(_plotter) segment.pc.x);
224 _pl_m_emit_float (R___(_plotter) segment.pc.y);
225 _pl_m_emit_float (R___(_plotter) segment.p.x);
226 _pl_m_emit_float (R___(_plotter) segment.p.y);
227 _pl_m_emit_terminator (S___(_plotter));
228 _plotter->meta_pos = segment.p;
229 break;
230
231 case (int)S_CUBIC:
232 _pl_m_emit_op_code (R___(_plotter) O_FBEZIER3);
233 _pl_m_emit_float (R___(_plotter) prev_segment.p.x);
234 _pl_m_emit_float (R___(_plotter) prev_segment.p.y);
235 _pl_m_emit_float (R___(_plotter) segment.pc.x);
236 _pl_m_emit_float (R___(_plotter) segment.pc.y);
237 _pl_m_emit_float (R___(_plotter) segment.pd.x);
238 _pl_m_emit_float (R___(_plotter) segment.pd.y);
239 _pl_m_emit_float (R___(_plotter) segment.p.x);
240 _pl_m_emit_float (R___(_plotter) segment.p.y);
241 _pl_m_emit_terminator (S___(_plotter));
242 _plotter->meta_pos = segment.p;
243 break;
244
245 default: /* shouldn't happen */
246 break;
247 }
248 }
249 }
250 break;
251
252 case (int)PATH_BOX:
253 {
254 _pl_m_emit_op_code (R___(_plotter) O_FBOX);
255 _pl_m_emit_float (R___(_plotter) path->p0.x);
256 _pl_m_emit_float (R___(_plotter) path->p0.y);
257 _pl_m_emit_float (R___(_plotter) path->p1.x);
258 _pl_m_emit_float (R___(_plotter) path->p1.y);
259 _pl_m_emit_terminator (S___(_plotter));
260
261 _plotter->meta_pos.x = 0.5 * (path->p0.x + path->p1.x);
262 _plotter->meta_pos.y = 0.5 * (path->p0.y + path->p1.y);
263 }
264 break;
265
266 case (int)PATH_CIRCLE:
267 {
268 _pl_m_emit_op_code (R___(_plotter) O_FCIRCLE);
269 _pl_m_emit_float (R___(_plotter) path->pc.x);
270 _pl_m_emit_float (R___(_plotter) path->pc.y);
271 _pl_m_emit_float (R___(_plotter) path->radius);
272 _pl_m_emit_terminator (S___(_plotter));
273
274 _plotter->meta_pos = path->pc;
275 }
276 break;
277
278 case (int)PATH_ELLIPSE:
279 {
280 _pl_m_emit_op_code (R___(_plotter) O_FELLIPSE);
281 _pl_m_emit_float (R___(_plotter) path->pc.x);
282 _pl_m_emit_float (R___(_plotter) path->pc.y);
283 _pl_m_emit_float (R___(_plotter) path->rx);
284 _pl_m_emit_float (R___(_plotter) path->ry);
285 _pl_m_emit_float (R___(_plotter) path->angle);
286 _pl_m_emit_terminator (S___(_plotter));
287
288 _plotter->meta_pos = path->pc;
289 }
290 break;
291
292 default: /* shouldn't happen */
293 break;
294 }
295 }
296
297 bool
_pl_m_path_is_flushable(S___ (Plotter * _plotter))298 _pl_m_path_is_flushable (S___(Plotter *_plotter))
299 {
300 return true;
301 }
302
303 void
_pl_m_maybe_prepaint_segments(R___ (Plotter * _plotter)int prev_num_segments)304 _pl_m_maybe_prepaint_segments (R___(Plotter *_plotter) int prev_num_segments)
305 {
306 return;
307 }
308
309