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