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 /* This version is for HPGL and PCL Plotters.  By construction, for these
23    Plotters our path buffer always contains either a segment list, or a
24    rectangle or circle object.  If it's a segment list, it may include an
25    arbitrary sequence of line, circular arc, and Bezier elements.  (For
26    circular arcs to be included, the map from user to device coordinates
27    must be uniform, so that e.g. the angle subtended by the arc will be the
28    same in user and device coordinates.) */
29 
30 #include "sys-defines.h"
31 #include "extern.h"
32 
33 #define DIST(p0,p1) (sqrt( ((p0).x - (p1).x)*((p0).x - (p1).x) \
34 			  + ((p0).y - (p1).y)*((p0).y - (p1).y)))
35 
36 void
_pl_h_paint_path(S___ (Plotter * _plotter))37 _pl_h_paint_path (S___(Plotter *_plotter))
38 {
39   if (_plotter->drawstate->pen_type == 0
40       && _plotter->drawstate->fill_type == 0)
41     /* nothing to draw */
42     return;
43 
44   switch ((int)_plotter->drawstate->path->type)
45     {
46     case (int)PATH_SEGMENT_LIST:
47       {
48 	plIntPathSegment *xarray;
49 	plPoint p0, pp1, pc, savedpoint;
50 	bool closed, use_polygon_buffer;
51 	double last_x, last_y;
52 	int i, polyline_len;
53 	bool identical_user_coordinates = true;
54 
55 	/* sanity checks */
56 	if (_plotter->drawstate->path->num_segments == 0)/* nothing to do */
57 	  break;
58 	if (_plotter->drawstate->path->num_segments == 1) /* shouldn't happen*/
59 	  break;
60 
61 	if ((_plotter->drawstate->path->num_segments >= 3)/*check for closure*/
62 	    && (_plotter->drawstate->path->segments[_plotter->drawstate->path->num_segments - 1].p.x == _plotter->drawstate->path->segments[0].p.x)
63 	    && (_plotter->drawstate->path->segments[_plotter->drawstate->path->num_segments - 1].p.y == _plotter->drawstate->path->segments[0].p.y))
64 	  closed = true;
65 	else
66 	  closed = false;	/* 2-point ones should be open */
67 
68         /* convert vertices to integer device coordinates, removing runs */
69 
70 	/* array for points, with positions expressed in integer device coors*/
71 	xarray = (plIntPathSegment *)_pl_xmalloc (_plotter->drawstate->path->num_segments * sizeof(plIntPathSegment));
72 
73 	/* add first point of path to xarray[] (type field is a moveto) */
74 	xarray[0].p.x = IROUND(XD(_plotter->drawstate->path->segments[0].p.x,
75 				  _plotter->drawstate->path->segments[0].p.y));
76 	xarray[0].p.y = IROUND(YD(_plotter->drawstate->path->segments[0].p.x,
77 				  _plotter->drawstate->path->segments[0].p.y));
78 	polyline_len = 1;
79 	/* save user coors of last point added to xarray[] */
80 	last_x = _plotter->drawstate->path->segments[0].p.x;
81 	last_y = _plotter->drawstate->path->segments[0].p.y;
82 
83 	for (i = 1; i < _plotter->drawstate->path->num_segments; i++)
84 	  {
85 	    plPathSegment datapoint;
86 	    double xuser, yuser, xdev, ydev;
87 	    int device_x, device_y;
88 
89 	    datapoint = _plotter->drawstate->path->segments[i];
90 	    xuser = datapoint.p.x;
91 	    yuser = datapoint.p.y;
92 	    if (xuser != last_x || yuser != last_y)
93 	      /* in user space, not all points are the same */
94 	      identical_user_coordinates = false;
95 
96 	    xdev = XD(xuser, yuser);
97 	    ydev = YD(xuser, yuser);
98 	    device_x = IROUND(xdev);
99 	    device_y = IROUND(ydev);
100 
101 	    if (device_x != xarray[polyline_len-1].p.x
102 		|| device_y != xarray[polyline_len-1].p.y)
103 	      /* integer device coor(s) changed, so stash point (incl. type
104 		 field) */
105 	      {
106 		plPathSegmentType element_type;
107 		int device_xc, device_yc;
108 
109 		xarray[polyline_len].p.x = device_x;
110 		xarray[polyline_len].p.y = device_y;
111 		element_type = datapoint.type;
112 		xarray[polyline_len].type = element_type;
113 
114 		if (element_type == S_ARC)
115 		  /* an arc element, so compute center, subtended angle too */
116 		  {
117 		    double angle;
118 
119 		    device_xc = IROUND(XD(datapoint.pc.x, datapoint.pc.y));
120 		    device_yc = IROUND(YD(datapoint.pc.x, datapoint.pc.y));
121 		    xarray[polyline_len].pc.x = device_xc;
122 		    xarray[polyline_len].pc.y = device_yc;
123 		    p0.x = last_x;
124 		    p0.y = last_y;
125 		    pp1 = datapoint.p;
126 		    pc = datapoint.pc;
127 		    angle = _angle_of_arc (p0, pp1, pc);
128 
129 		    /* if user coors -> device coors includes a reflection,
130                        flip sign */
131 		    if (!_plotter->drawstate->transform.nonreflection)
132 		      angle = -angle;
133 		    xarray[polyline_len].angle = angle;
134 		  }
135 		else if (element_type == S_CUBIC)
136 		  /* a cubic Bezier element, so compute control points too */
137 		  {
138 		    xarray[polyline_len].pc.x
139 		      = IROUND(XD(datapoint.pc.x, datapoint.pc.y));
140 		    xarray[polyline_len].pc.y
141 		      = IROUND(YD(datapoint.pc.x, datapoint.pc.y));
142 		    xarray[polyline_len].pd.x
143 		      = IROUND(XD(datapoint.pd.x, datapoint.pd.y));
144 		    xarray[polyline_len].pd.y
145 		      = IROUND(YD(datapoint.pd.x, datapoint.pd.y));
146 		  }
147 
148 		/* save user coors of last point added to xarray[] */
149 		last_x = datapoint.p.x;
150 		last_y = datapoint.p.y;
151 		polyline_len++;
152 	      }
153 	  }
154 
155 	/* Check first for special subcase: all user-space juncture points
156 	   in the polyline were mapped to a single integer HP-GL
157 	   pseudo-pixel.  If (1) they weren't all the same to begin with,
158 	   or (2) they were all the same to begin with and the cap mode is
159 	   "round", then draw as a filled circle, of diameter equal to the
160 	   line width; otherwise draw nothing. */
161 
162 	if (_plotter->drawstate->path->num_segments > 1 && polyline_len == 1)
163 	  /* all points mapped to a single integer pseudo-pixel */
164 	  {
165 	    if (identical_user_coordinates == false
166 		|| _plotter->drawstate->cap_type == PL_CAP_ROUND)
167 	      {
168 		double r = 0.5 * _plotter->drawstate->line_width;
169 		double device_frame_radius;
170 
171 		/* draw single filled circle, using HP-GL's native
172 		   circle-drawing facility */
173 
174 		/* move to center of circle */
175 		savedpoint = _plotter->drawstate->pos;
176 		_plotter->drawstate->pos =
177 		  _plotter->drawstate->path->segments[0].p;
178 		_pl_h_set_position (S___(_plotter));
179 		_plotter->drawstate->pos = savedpoint;
180 
181 		/* set fill color to pen color, arrange to do filling; sync
182 		   attributes too, incl. pen width */
183 		{
184 		  /* emit HP-GL directives; select a fill color that's
185 		     actually the pen color */
186 		  _pl_h_set_fill_color (R___(_plotter) true);
187 		  _pl_h_set_attributes (S___(_plotter));
188 		}
189 
190 		/* compute radius in device frame */
191 		device_frame_radius =
192 		  sqrt(XDV(r,0)*XDV(r,0)+YDV(r,0)*YDV(r,0));
193 
194 		/* Syncing the fill color may have set the
195 		   _plotter->hpgl_bad_pen flag (e.g. if optimal pen is #0
196 		   [white] and we're not allowed to use pen #0 to draw
197 		   with).  So we test _plotter->hpgl_bad_pen before using
198 		   the pen. */
199 		if (_plotter->hpgl_bad_pen == false)
200 		  /* fill the circle (360 degree wedge) */
201 		  {
202 		    sprintf (_plotter->data->page->point, "WG%d,0,360;",
203 			     IROUND(device_frame_radius));
204 		    _update_buffer (_plotter->data->page);
205 		  }
206 		/* KLUDGE: in pre-HP-GL/2, our `set_fill_color' function
207 		   may alter the line type, since it may request *solid*
208 		   crosshatching; so reset the line type */
209 		if (_plotter->hpgl_version < 2)
210 		  _pl_h_set_attributes (S___(_plotter));
211 	      }
212 
213 	    /* free our temporary array and depart */
214 	    free (xarray);
215 	    break;
216 	  }
217 
218 	/* At this point, we know we have a nondegenerate path in our
219 	   pseudo-integer device space. */
220 
221 	/* will draw vectors (or arcs) into polygon buffer if appropriate */
222 	use_polygon_buffer = (_plotter->hpgl_version == 2
223 			      || (_plotter->hpgl_version == 1 /* i.e. "1.5" */
224 				  && (polyline_len > 2
225 				      || _plotter->drawstate->fill_type)) ? true : false);
226 
227 	/* Sync pen color.  This is needed here only if HPGL_VERSION is 1,
228 	   but we always do it here so that HP-GL/2 output that draws a
229 	   polyline, if sent erroneously to a generic HP-GL device, will
230 	   yield a polyline in the correct color, so long as the color
231 	   isn't white. */
232 	_pl_h_set_pen_color (R___(_plotter) HPGL_OBJECT_PATH);
233 
234 	/* set_pen_color() sets the advisory bad_pen flag if white pen (pen
235 	   #0) would have been selected, and we can't use pen #0 to draw
236 	   with.  Such a situation isn't fatal if HPGL_VERSION is "1.5" or
237 	   "2", since we may be filling the polyline with a nonwhite color,
238 	   as well as using a white pen to draw it.  But if HPGL_VERSION is
239 	   "1", we don't fill polylines, so we might as well punt right
240 	   now. */
241 	if (_plotter->hpgl_bad_pen && _plotter->hpgl_version == 1)
242 	  {
243 	    /* free integer storage buffer and depart */
244 	    free (xarray);
245 	    break;
246 	  }
247 
248 	/* sync attributes, incl. pen width if possible; move pen to p0 */
249 	_pl_h_set_attributes (S___(_plotter));
250 
251 	savedpoint = _plotter->drawstate->pos;
252 	_plotter->drawstate->pos = _plotter->drawstate->path->segments[0].p;
253 	_pl_h_set_position (S___(_plotter));
254 	_plotter->drawstate->pos = savedpoint;
255 
256 	if (use_polygon_buffer)
257 	  /* have a polygon buffer, and can use it to fill polyline */
258 	  {
259 	    /* enter polygon mode */
260 	    strcpy (_plotter->data->page->point, "PM0;");
261 	    _update_buffer (_plotter->data->page);
262 	  }
263 
264 	if (use_polygon_buffer || _plotter->drawstate->pen_type)
265 	  /* either (1) we'll be drawing into a polygon buffer, and will be
266 	     using it for at least one of (a) filling and (b) edging, or
267 	     (2) we won't be drawing into a polygon buffer, so we won't be
268 	     filling, but we'll be edging (because pen_type isn't zero) */
269 	  {
270 	    /* ensure that pen is down for drawing */
271 	    if (_plotter->hpgl_pendown == false)
272 	      {
273 		strcpy (_plotter->data->page->point, "PD;");
274 		_update_buffer (_plotter->data->page);
275 		_plotter->hpgl_pendown = true;
276 	      }
277 
278 	    /* loop through points in xarray[], emitting HP-GL instructions */
279 	    i = 1;
280 	    while (i < polyline_len)
281 	      {
282 		switch ((int)xarray[i].type)
283 		  {
284 		  case (int)S_LINE:
285 		    /* emit one or more pen advances */
286 		    strcpy (_plotter->data->page->point, "PA");
287 		    _update_buffer (_plotter->data->page);
288 		    sprintf (_plotter->data->page->point, "%d,%d",
289 			     xarray[i].p.x, xarray[i].p.y);
290 		    _update_buffer (_plotter->data->page);
291 		    i++;
292 		    while (i < polyline_len && xarray[i].type == S_LINE)
293 		      {
294 			sprintf (_plotter->data->page->point,
295 				 ",%d,%d", xarray[i].p.x, xarray[i].p.y);
296 			_update_buffer (_plotter->data->page);
297 			i++;
298 		      }
299 		    sprintf (_plotter->data->page->point, ";");
300 		    _update_buffer (_plotter->data->page);
301 		    break;
302 
303 		  case (int)S_CUBIC:
304 		    /* emit one or more cubic Bezier segments */
305 		    strcpy (_plotter->data->page->point, "BZ");
306 		    _update_buffer (_plotter->data->page);
307 		    sprintf (_plotter->data->page->point, "%d,%d,%d,%d,%d,%d",
308 			     xarray[i].pc.x, xarray[i].pc.y,
309 			     xarray[i].pd.x, xarray[i].pd.y,
310 			     xarray[i].p.x, xarray[i].p.y);
311 		    _update_buffer (_plotter->data->page);
312 		    i++;
313 		    while (i < polyline_len && xarray[i].type == S_CUBIC)
314 		      {
315 			sprintf (_plotter->data->page->point, ",%d,%d,%d,%d,%d,%d",
316 				 xarray[i].pc.x, xarray[i].pc.y,
317 				 xarray[i].pd.x, xarray[i].pd.y,
318 				 xarray[i].p.x, xarray[i].p.y);
319 			_update_buffer (_plotter->data->page);
320 			i++;
321 		      }
322 		  sprintf (_plotter->data->page->point, ";");
323 		  _update_buffer (_plotter->data->page);
324 		  break;
325 
326 		  case (int)S_ARC:
327 		    {
328 		      double degrees;
329 		      int int_degrees;
330 
331 		      /* emit an arc, using integer sweep angle if possible */
332 		      degrees = 180.0 * xarray[i].angle / M_PI;
333 		      int_degrees = IROUND (degrees);
334 		      if (_plotter->hpgl_version > 0)
335 			/* HPGL_VERSION = 1.5 or 2 */
336 			{
337 			  if (degrees == (double)int_degrees)
338 			    sprintf (_plotter->data->page->point, "AA%d,%d,%d;",
339 				     xarray[i].pc.x, xarray[i].pc.y,
340 				     int_degrees);
341 			  else
342 			    sprintf (_plotter->data->page->point, "AA%d,%d,%.3f;",
343 				     xarray[i].pc.x, xarray[i].pc.y,
344 				     degrees);
345 			}
346 		      else
347 			/* HPGL_VERSION = 1, i.e. generic HP-GL */
348 			/* note: generic HP-GL can only handle integer
349 			   sweep angles */
350 			sprintf (_plotter->data->page->point, "AA%d,%d,%d;",
351 				 xarray[i].pc.x, xarray[i].pc.y,
352 				 int_degrees);
353 		      _update_buffer (_plotter->data->page);
354 		      i++;
355 		    }
356 		    break;
357 
358 		  default:
359 		    /* shouldn't happen: unknown type for path segment,
360                        ignore */
361 		    i++;
362 		    break;
363 		  }
364 	      }
365 	  }
366 
367 	if (use_polygon_buffer)
368 	  /* using polygon mode; will now employ polygon buffer to do
369 	     filling (possibly) and edging */
370 	  {
371 	    if (!closed)
372 	      /* polyline is open, so lift pen and exit polygon mode */
373 	      {
374 		strcpy (_plotter->data->page->point, "PU;");
375 		_update_buffer (_plotter->data->page);
376 		_plotter->hpgl_pendown = false;
377 		strcpy (_plotter->data->page->point, "PM2;");
378 		_update_buffer (_plotter->data->page);
379 	      }
380 	    else
381 	      /* polyline is closed, so exit polygon mode and then lift pen */
382 	      {
383 		strcpy (_plotter->data->page->point, "PM2;");
384 		_update_buffer (_plotter->data->page);
385 		strcpy (_plotter->data->page->point, "PU;");
386 		_update_buffer (_plotter->data->page);
387 		_plotter->hpgl_pendown = false;
388 	      }
389 
390 	    if (_plotter->drawstate->fill_type)
391 	      /* polyline should be filled */
392 	      {
393 		/* Sync fill color.  This may set the
394 		   _plotter->hpgl_bad_pen flag (if optimal pen is #0
395 		   [white] and we're not allowed to use pen #0 to draw
396 		   with).  So we test _plotter->hpgl_bad_pen before using
397 		   the pen to fill with. */
398 		_pl_h_set_fill_color (R___(_plotter) false);
399 		if (_plotter->hpgl_bad_pen == false)
400 		  /* fill polyline, specifying nonzero winding rule if
401 		     necessary */
402 		  {
403 		    switch (_plotter->drawstate->fill_rule_type)
404 		      {
405 		      case PL_FILL_ODD_WINDING:
406 		      default:
407 			strcpy (_plotter->data->page->point, "FP;");
408 			break;
409 		      case PL_FILL_NONZERO_WINDING:
410 			if (_plotter->hpgl_version == 2)
411 			  strcpy (_plotter->data->page->point, "FP1;");
412 			else	/* pre-HP-GL/2 doesn't support nonzero rule */
413 			  strcpy (_plotter->data->page->point, "FP;");
414 			break;
415 		      }
416 		    _update_buffer (_plotter->data->page);
417 		  }
418 	    /* KLUDGE: in pre-HP-GL/2, our `set_fill_color' function may
419 	       alter the line type, since it may request *solid*
420 	       crosshatching; so reset the line type */
421 		if (_plotter->hpgl_version < 2)
422 		  _pl_h_set_attributes (S___(_plotter));
423 	      }
424 
425 	    if (_plotter->drawstate->pen_type)
426 	      /* polyline should be edged */
427 	      {
428 		/* Sync pen color.  This may set the _plotter->hpgl_bad_pen
429 		   flag (if optimal pen is #0 and we're not allowed to use
430 		   pen #0 to draw with).  So we test _plotter->hpgl_bad_pen
431 		   before using the pen. */
432 		_pl_h_set_pen_color (R___(_plotter) HPGL_OBJECT_PATH);
433 		if (_plotter->hpgl_bad_pen == false)
434 		  /* select appropriate pen for edging, and edge the
435                      polyline */
436 		  {
437 		    _pl_h_set_pen_color (R___(_plotter) HPGL_OBJECT_PATH);
438 		    strcpy (_plotter->data->page->point, "EP;");
439 		    _update_buffer (_plotter->data->page);
440 		  }
441 	      }
442 	  }
443 
444 	/* We know where the pen now is: if we used a polygon buffer, then
445 	   _plotter->hpgl_pos is now xarray[0].p.  If we didn't (as would
446 	   be the case if we're outputting generic HP-GL), then
447 	   _plotter->hpgl_pos is now xarray[polyline_len - 1].p.
448 	   Unfortunately we can't simply update _plotter->hpgl_pos, because
449 	   we want the generated HP-GL[/2] code to work properly on both
450 	   HP-GL and HP-GL/2 devices.  So we punt. */
451 	_plotter->hpgl_position_is_unknown = true;
452 
453 	/* free integer storage buffer and depart */
454 	free (xarray);
455       }
456       break;
457 
458     case (int)PATH_BOX:
459       {
460 	plPoint p0, p1, savedpoint;
461 
462 	p0 = _plotter->drawstate->path->p0;
463 	p1 = _plotter->drawstate->path->p1;
464 
465 	/* sync line attributes, incl. pen width */
466 	_pl_h_set_attributes (S___(_plotter));
467 
468 	/* move HP-GL pen to first vertex */
469 	savedpoint = _plotter->drawstate->pos;
470 	_plotter->drawstate->pos = p0;
471 	_pl_h_set_position (S___(_plotter));
472 	_plotter->drawstate->pos = savedpoint;
473 
474 	if (_plotter->drawstate->fill_type)
475 	  /* rectangle should be filled */
476 	  {
477 	    /* Sync fill color.  This may set the _plotter->hpgl_bad_pen
478 	       flag (e.g. if optimal pen is #0 [white] and we're not
479 	       allowed to use pen #0 to draw with).  So we test
480 	       _plotter->hpgl_bad_pen before using the pen. */
481 	    _pl_h_set_fill_color (R___(_plotter) false);
482 	    if (_plotter->hpgl_bad_pen == false)
483 	      /* fill the rectangle */
484 	      {
485 		sprintf (_plotter->data->page->point, "RA%d,%d;",
486 			 IROUND(XD(p1.x,p1.y)), IROUND(YD(p1.x,p1.y)));
487 		_update_buffer (_plotter->data->page);
488 	      }
489 	    /* KLUDGE: in pre-HP-GL/2, our `set_fill_color' function may
490 	       alter the line type, since it may request *solid*
491 	       crosshatching; so reset it */
492 	    if (_plotter->hpgl_version < 2)
493 	      _pl_h_set_attributes (S___(_plotter));
494 	  }
495 
496 	if (_plotter->drawstate->pen_type)
497 	  /* rectangle should be edged */
498 	  {
499 	    /* Sync pen color.  This may set the _plotter->hpgl_bad_pen
500 	       flag (e.g. if optimal pen is #0 [white] and we're not
501 	       allowed to use pen #0 to draw with).  So we test
502 	       _plotter->hpgl_bad_pen before using the pen. */
503 	    _pl_h_set_pen_color (R___(_plotter) HPGL_OBJECT_PATH);
504 	    if (_plotter->hpgl_bad_pen == false)
505 	      /* edge the rectangle */
506 	      {
507 		sprintf (_plotter->data->page->point, "EA%d,%d;",
508 			 IROUND(XD(p1.x,p1.y)), IROUND(YD(p1.x,p1.y)));
509 		_update_buffer (_plotter->data->page);
510 	      }
511 	  }
512       }
513       break;
514 
515     case (int)PATH_CIRCLE:
516       {
517 	plPoint pc, savedpoint;
518 	double r = _plotter->drawstate->path->radius;
519 	double radius = sqrt(XDV(r,0)*XDV(r,0)+YDV(r,0)*YDV(r,0));
520 
521 	pc = _plotter->drawstate->path->pc;
522 
523 	/* sync attributes, incl. pen width; move to center of circle */
524 	_pl_h_set_attributes (S___(_plotter));
525 
526 	savedpoint = _plotter->drawstate->pos;
527 	_plotter->drawstate->pos = pc;
528 	_pl_h_set_position (S___(_plotter));
529 	_plotter->drawstate->pos = savedpoint;
530 
531 	if (_plotter->drawstate->fill_type)
532 	  /* circle should be filled */
533 	  {
534 	    /* Sync fill color.  This may set the _plotter->hpgl_bad_pen
535 	       flag (e.g. if optimal pen is #0 [white] and we're not
536 	       allowed to use pen #0 to draw with).  So we test
537 	       _plotter->hpgl_bad_pen before using the pen. */
538 	    _pl_h_set_fill_color (R___(_plotter) false);
539 	    if (_plotter->hpgl_bad_pen == false)
540 	      /* fill the circle (360 degree wedge) */
541 	      {
542 		sprintf (_plotter->data->page->point, "WG%d,0,360;",
543 			 IROUND(radius));
544 		_update_buffer (_plotter->data->page);
545 	      }
546 	    /* KLUDGE: in pre-HP-GL/2, our `set_fill_color' function may
547 	       alter the line type, since it may request *solid*
548 	       crosshatching; so reset it */
549 	    if (_plotter->hpgl_version < 2)
550 	      _pl_h_set_attributes (S___(_plotter));
551 	  }
552 
553 	if (_plotter->drawstate->pen_type)
554 	  /* circle should be edged */
555 	  {
556 	    /* Sync pen color.  This may set the _plotter->hpgl_bad_pen
557 	       flag (e.g. if optimal pen is #0 [white] and we're not
558 	       allowed to use pen #0 to draw with).  So we test
559 	       _plotter->hpgl_bad_pen before using the pen. */
560 	    _pl_h_set_pen_color (R___(_plotter) HPGL_OBJECT_PATH);
561 	    if (_plotter->hpgl_bad_pen == false)
562 	      /* do the edging */
563 	      {
564 		sprintf (_plotter->data->page->point, "CI%d;", IROUND(radius));
565 		_update_buffer (_plotter->data->page);
566 	      }
567 	  }
568       }
569       break;
570 
571     default:			/* unrecognized path type, shouldn't happen */
572       break;
573     }
574 }
575 
576 /* A low-level method for moving the pen position of an HP-GL pen plotter
577    to agree with the Plotter's notion of what the graphics cursor position
578    should be.  The state of the pen (up vs. down) after calling this
579    function is not uniquely determined.  */
580 
581 void
_pl_h_set_position(S___ (Plotter * _plotter))582 _pl_h_set_position (S___(Plotter *_plotter))
583 {
584   int xnew, ynew;
585 
586   /* if plotter's pen position doesn't agree with what it should be,
587      adjust it */
588 
589   xnew = IROUND(XD(_plotter->drawstate->pos.x, _plotter->drawstate->pos.y));
590   ynew = IROUND(YD(_plotter->drawstate->pos.x, _plotter->drawstate->pos.y));
591 
592   if (_plotter->hpgl_position_is_unknown == true
593       || xnew != _plotter->hpgl_pos.x || ynew != _plotter->hpgl_pos.y)
594     {
595       if (_plotter->hpgl_pendown == true)
596 	{
597 	  sprintf (_plotter->data->page->point, "PU;PA%d,%d;", xnew, ynew);
598 	  _plotter->hpgl_pendown = false;
599 	}
600       else
601 	sprintf (_plotter->data->page->point, "PA%d,%d;", xnew, ynew);
602       _update_buffer (_plotter->data->page);
603 
604       /* update our knowledge of pen position */
605       _plotter->hpgl_position_is_unknown = false;
606       _plotter->hpgl_pos.x = xnew;
607       _plotter->hpgl_pos.y = ynew;
608     }
609 }
610 
611 bool
_pl_h_paint_paths(S___ (Plotter * _plotter))612 _pl_h_paint_paths (S___(Plotter *_plotter))
613 {
614   return false;
615 }
616