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 endpath() method, which is a GNU extension to
20 libplot. A path object may be constructed incrementally, by repeated
21 invocation of such operations as cont(), arc(), etc. The construction
22 may be terminated, and the path object finalized, by an explict
23 invocation of endpath(). If endpath() is invoked when no path is under
24 construction, it has no effect. */
25
26 /* endpath() is a wrapper around the internal paint_path() method, which
27 any Plotter can define as it chooses. Any path is stored as a plPath
28 structure in the drawing state. This may contain a list of segments
29 (line segments, curve segments etc.; which are allowed is
30 Plotter-dependent) or simply a Plotter-specific drawing primitive such
31 as a circle, ellipse, or rectangle. paint_path() should be able to
32 handle anything that is appropriate for the given type of Plotter. */
33
34 /* This file also contains the endsubpath() and closepath() methods. */
35
36 #include "sys-defines.h"
37 #include "extern.h"
38
39 int
_API_endpath(S___ (Plotter * _plotter))40 _API_endpath (S___(Plotter *_plotter))
41 {
42 int i;
43
44 if (!_plotter->data->open)
45 {
46 _plotter->error (R___(_plotter)
47 "endpath: invalid operation");
48 return -1;
49 }
50
51 /* end simple path under construction (if any), and move it to the array
52 of stored simple paths */
53 _API_endsubpath (S___(_plotter));
54
55 if (_plotter->drawstate->num_paths == 0)
56 /* no stored simple paths; so nothing to do, and we're out of here */
57 return 0;
58
59 /* at this point, compound path is available as an array of simple paths,
60 of length at least 1, in _plotter->drawstate->paths[] */
61
62 /* Two cases: either the line mode is `disconnected', or it isn't (the
63 normal case). */
64
65 if (!_plotter->drawstate->points_are_connected)
66 /* Special case: "disconnected" linemode. If we have a pen, path will
67 be drawn as a sequence of filled circles, one per juncture point.
68 Path will not be filled (our convention). */
69 {
70 if (_plotter->drawstate->pen_type != 0)
71 /* have a pen, so we can draw something */
72 {
73 plPath **saved_paths;
74 int saved_num_paths;
75 double radius = 0.5 * _plotter->drawstate->line_width;
76 int i;
77
78 /* Switch to a temporary paths buffer. Needed because the
79 fcircle() method calls endpath(), which would otherwise mess
80 up the real paths buffer. */
81 saved_paths = _plotter->drawstate->paths;
82 saved_num_paths = _plotter->drawstate->num_paths;
83 _plotter->drawstate->paths = (plPath **)NULL;
84 _plotter->drawstate->num_paths = 0;
85
86 /* save graphics state */
87 _API_savestate (S___(_plotter));
88
89 /* set attributes appropriate for drawing filled edgeless
90 circles, in the current pen (rather than filling) color */
91 _API_filltype (R___(_plotter) 1);
92 _API_fillcolor (R___(_plotter)
93 _plotter->drawstate->fgcolor.red,
94 _plotter->drawstate->fgcolor.green,
95 _plotter->drawstate->fgcolor.blue);
96 _API_pentype (R___(_plotter) 0); /* edgeless */
97 _API_linemod (R___(_plotter) "solid"); /* necessary; see below*/
98
99 /* loop over saved simple paths */
100 for (i = 0; i < saved_num_paths; i++)
101 {
102 plPath *path;
103 bool closed;
104 int j;
105
106 path = saved_paths[i];
107
108 /* sanity check: if linemode is disconnected, we should never
109 have created any simple path other than a segment list;
110 also, should have at least two juncture points */
111 if (path->type != PATH_SEGMENT_LIST || path->num_segments < 2)
112 continue;
113
114 /* check for closure */
115 if ((path->num_segments >= 3)
116 && (path->segments[path->num_segments - 1].p.x ==
117 path->segments[0].p.x)
118 && (path->segments[path->num_segments - 1].p.y ==
119 path->segments[0].p.y))
120 closed = true;
121 else
122 closed = false; /* 2-point ones should be open */
123
124 /* draw each point as a filled circle, diameter = line width */
125 for (j = 0; j < path->num_segments - (closed ? 1 : 0); j++)
126 _API_fcircle (R___(_plotter)
127 path->segments[j].p.x,
128 path->segments[j].p.y,
129 radius);
130 if (closed)
131 /* restore graphics cursor */
132 _plotter->drawstate->pos = path->segments[0].p;
133 }
134
135 /* Restore graphics state. This will first do a recursive
136 endpath() and hence reset the newly populated paths buffer.
137 That won't result in infinite recursion: since the line type
138 was set to "solid" above, the `points_are_connected' element
139 is now `false', and this code won't be invoked again. */
140 _API_restorestate (S___(_plotter));
141
142 /* switch back to original paths buffer */
143 _plotter->drawstate->paths = saved_paths;
144 _plotter->drawstate->num_paths = saved_num_paths;
145 }
146 }
147
148 else
149 /* normal case: line mode isn't disconnected, so no contortions needed */
150 {
151 if (_plotter->drawstate->num_paths == 1)
152 /* compound path is just a single simple path, so paint it by
153 calling the Plotter-specific paint_path() method (the painting
154 may involve both filling and/or edging) */
155 {
156 _plotter->drawstate->path = _plotter->drawstate->paths[0];
157 _plotter->paint_path (S___(_plotter));
158 _plotter->drawstate->path = (plPath *)NULL;
159 }
160 else
161 /* compound path comprises more than one simple path */
162 {
163 /* first, attempt to use Plotter-specific support for painting
164 compound paths (not many Plotters have this) */
165
166 if (_plotter->paint_paths (S___(_plotter)) == false)
167 /* Plotter either has no such support, or was unable to paint
168 this particular compound path; so we paint it in a clever,
169 device-independent way. For filling, we merge the simple
170 paths into a single path, and invoke paint_path() on the
171 result. For edging, we stroke each of the simple paths
172 individually. */
173 {
174 int fill_type, pen_type;
175
176 fill_type = _plotter->drawstate->fill_type;
177 pen_type = _plotter->drawstate->pen_type;
178
179 if (fill_type && _plotter->data->have_solid_fill)
180 /* fill the compound path, by merging its simple paths into
181 a single simple path, and then invoking paint_path() on
182 the result */
183 {
184 plPath **merged_paths;
185 _plotter->drawstate->fill_type = fill_type;
186 _plotter->drawstate->pen_type = 0; /* unedged */
187
188 merged_paths = _merge_paths ((const plPath **)_plotter->drawstate->paths,
189 _plotter->drawstate->num_paths);
190 for (i = 0; i < _plotter->drawstate->num_paths; i++)
191 {
192
193 if (merged_paths[i] == (plPath *)NULL)
194 continue;
195
196 _plotter->drawstate->path = merged_paths[i];
197 _plotter->paint_path (S___(_plotter));
198 if (merged_paths[i] != _plotter->drawstate->paths[i])
199 _delete_plPath (merged_paths[i]);
200 }
201 _plotter->drawstate->path = (plPath *)NULL;
202 }
203
204 if (pen_type)
205 /* edge the compound path, i.e., edge each of its simple
206 paths */
207 {
208 _plotter->drawstate->pen_type = pen_type;
209 _plotter->drawstate->fill_type = 0; /* unfilled */
210 for (i = 0; i < _plotter->drawstate->num_paths; i++)
211 {
212 _plotter->drawstate->path = _plotter->drawstate->paths[i];
213 _plotter->paint_path (S___(_plotter));
214 }
215 _plotter->drawstate->path = (plPath *)NULL;
216 }
217
218 /* restore filling/edging attributes */
219 _plotter->drawstate->fill_type = fill_type;
220 _plotter->drawstate->pen_type = pen_type;
221 }
222 }
223 }
224
225 /* compound path is now painted, so remove it from paths buffer */
226 for (i = 0; i < _plotter->drawstate->num_paths; i++)
227 _delete_plPath (_plotter->drawstate->paths[i]);
228 free (_plotter->drawstate->paths);
229 _plotter->drawstate->paths = (plPath **)NULL;
230 _plotter->drawstate->num_paths = 0;
231
232 return 0;
233 }
234
235 int
_API_endsubpath(S___ (Plotter * _plotter))236 _API_endsubpath (S___(Plotter *_plotter))
237 {
238 if (!_plotter->data->open)
239 {
240 _plotter->error (R___(_plotter)
241 "endsubpath: invalid operation");
242 return -1;
243 }
244
245 if (_plotter->drawstate->path)
246 /* have a simple path under construction, so move it to list of stored
247 simple paths */
248 {
249 if (_plotter->drawstate->num_paths == 0)
250 _plotter->drawstate->paths =
251 (plPath **)_pl_xmalloc(sizeof (plPath *));
252 else
253 _plotter->drawstate->paths =
254 (plPath **)_pl_xrealloc(_plotter->drawstate->paths,
255 (_plotter->drawstate->num_paths + 1)
256 * sizeof (plPath *));
257 _plotter->drawstate->paths[_plotter->drawstate->num_paths++] =
258 _plotter->drawstate->path;
259 _plotter->drawstate->path = (plPath *)NULL;
260 }
261
262 return 0;
263 }
264
265 int
_API_closepath(S___ (Plotter * _plotter))266 _API_closepath (S___(Plotter *_plotter))
267 {
268 if (!_plotter->data->open)
269 {
270 _plotter->error (R___(_plotter)
271 "closepath: invalid operation");
272 return -1;
273 }
274
275 /* NOT YET IMPLEMENTED */
276
277 return 0;
278 }
279
280
281