File: h_path.c

package info (click to toggle)
plotutils 2.6-15
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 14,040 kB
  • sloc: ansic: 68,670; sh: 20,086; cpp: 12,382; yacc: 2,588; makefile: 838; lex: 137
file content (615 lines) | stat: -rw-r--r-- 21,539 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
/* This file is part of the GNU plotutils package.  Copyright (C) 1995,
   1996, 1997, 1998, 1999, 2000, 2005, 2008, Free Software Foundation, Inc.

   The GNU plotutils package is free software.  You may redistribute it
   and/or modify it under the terms of the GNU General Public License as
   published by the Free Software foundation; either version 2, or (at your
   option) any later version.

   The GNU plotutils package is distributed in the hope that it will be
   useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License along
   with the GNU plotutils package; see the file COPYING.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
   Boston, MA 02110-1301, USA. */

/* This file contains the internal paint_path() and paint_paths() methods,
   which the public method endpath() is a wrapper around. */

/* This version is for HPGL and PCL Plotters.  By construction, for these
   Plotters our path buffer always contains either a segment list, or a
   rectangle or circle object.  If it's a segment list, it may include an
   arbitrary sequence of line, circular arc, and Bezier elements.  (For
   circular arcs to be included, the map from user to device coordinates
   must be uniform, so that e.g. the angle subtended by the arc will be the
   same in user and device coordinates.) */

#include "sys-defines.h"
#include "extern.h"

#define DIST(p0,p1) (sqrt( ((p0).x - (p1).x)*((p0).x - (p1).x) \
			  + ((p0).y - (p1).y)*((p0).y - (p1).y)))

void
_pl_h_paint_path (S___(Plotter *_plotter))
{
  if (_plotter->drawstate->pen_type == 0
      && _plotter->drawstate->fill_type == 0)
    /* nothing to draw */
    return;

  switch ((int)_plotter->drawstate->path->type)
    {
    case (int)PATH_SEGMENT_LIST:
      {
	plIntPathSegment *xarray;
	plPoint p0, pp1, pc, savedpoint;
	bool closed, use_polygon_buffer;
	double last_x, last_y;
	int i, polyline_len;
	bool identical_user_coordinates = true;

	/* sanity checks */
	if (_plotter->drawstate->path->num_segments == 0)/* nothing to do */
	  break;
	if (_plotter->drawstate->path->num_segments == 1) /* shouldn't happen*/
	  break;

	if ((_plotter->drawstate->path->num_segments >= 3)/*check for closure*/
	    && (_plotter->drawstate->path->segments[_plotter->drawstate->path->num_segments - 1].p.x == _plotter->drawstate->path->segments[0].p.x)
	    && (_plotter->drawstate->path->segments[_plotter->drawstate->path->num_segments - 1].p.y == _plotter->drawstate->path->segments[0].p.y))
	  closed = true;
	else
	  closed = false;	/* 2-point ones should be open */
      
        /* convert vertices to integer device coordinates, removing runs */
      
	/* array for points, with positions expressed in integer device coors*/
	xarray = (plIntPathSegment *)_pl_xmalloc (_plotter->drawstate->path->num_segments * sizeof(plIntPathSegment));
	
	/* add first point of path to xarray[] (type field is a moveto) */
	xarray[0].p.x = IROUND(XD(_plotter->drawstate->path->segments[0].p.x, 
				  _plotter->drawstate->path->segments[0].p.y));
	xarray[0].p.y = IROUND(YD(_plotter->drawstate->path->segments[0].p.x, 
				  _plotter->drawstate->path->segments[0].p.y));
	polyline_len = 1;
	/* save user coors of last point added to xarray[] */
	last_x = _plotter->drawstate->path->segments[0].p.x;
	last_y = _plotter->drawstate->path->segments[0].p.y;  
	
	for (i = 1; i < _plotter->drawstate->path->num_segments; i++)
	  {
	    plPathSegment datapoint;
	    double xuser, yuser, xdev, ydev;
	    int device_x, device_y;
	    
	    datapoint = _plotter->drawstate->path->segments[i];
	    xuser = datapoint.p.x;
	    yuser = datapoint.p.y;
	    if (xuser != last_x || yuser != last_y)
	      /* in user space, not all points are the same */
	      identical_user_coordinates = false;	
	    
	    xdev = XD(xuser, yuser);
	    ydev = YD(xuser, yuser);
	    device_x = IROUND(xdev);
	    device_y = IROUND(ydev);
	    
	    if (device_x != xarray[polyline_len-1].p.x
		|| device_y != xarray[polyline_len-1].p.y)
	      /* integer device coor(s) changed, so stash point (incl. type
		 field) */
	      {
		plPathSegmentType element_type;
		int device_xc, device_yc;
		
		xarray[polyline_len].p.x = device_x;
		xarray[polyline_len].p.y = device_y;
		element_type = datapoint.type;
		xarray[polyline_len].type = element_type;
		
		if (element_type == S_ARC)
		  /* an arc element, so compute center, subtended angle too */
		  {
		    double angle;
		    
		    device_xc = IROUND(XD(datapoint.pc.x, datapoint.pc.y));
		    device_yc = IROUND(YD(datapoint.pc.x, datapoint.pc.y));
		    xarray[polyline_len].pc.x = device_xc;
		    xarray[polyline_len].pc.y = device_yc;
		    p0.x = last_x; 
		    p0.y = last_y;
		    pp1 = datapoint.p;
		    pc = datapoint.pc;
		    angle = _angle_of_arc (p0, pp1, pc);

		    /* if user coors -> device coors includes a reflection,
                       flip sign */
		    if (!_plotter->drawstate->transform.nonreflection)
		      angle = -angle;
		    xarray[polyline_len].angle = angle;
		  }
		else if (element_type == S_CUBIC)
		  /* a cubic Bezier element, so compute control points too */
		  {
		    xarray[polyline_len].pc.x 
		      = IROUND(XD(datapoint.pc.x, datapoint.pc.y));
		    xarray[polyline_len].pc.y 
		      = IROUND(YD(datapoint.pc.x, datapoint.pc.y));
		    xarray[polyline_len].pd.x
		      = IROUND(XD(datapoint.pd.x, datapoint.pd.y));
		    xarray[polyline_len].pd.y
		      = IROUND(YD(datapoint.pd.x, datapoint.pd.y));
		  }
		
		/* save user coors of last point added to xarray[] */
		last_x = datapoint.p.x;
		last_y = datapoint.p.y;  
		polyline_len++;
	      }
	  }
	
	/* Check first for special subcase: all user-space juncture points
	   in the polyline were mapped to a single integer HP-GL
	   pseudo-pixel.  If (1) they weren't all the same to begin with,
	   or (2) they were all the same to begin with and the cap mode is
	   "round", then draw as a filled circle, of diameter equal to the
	   line width; otherwise draw nothing. */
      
	if (_plotter->drawstate->path->num_segments > 1 && polyline_len == 1)
	  /* all points mapped to a single integer pseudo-pixel */
	  {
	    if (identical_user_coordinates == false
		|| _plotter->drawstate->cap_type == PL_CAP_ROUND)
	      {
		double r = 0.5 * _plotter->drawstate->line_width;
		double device_frame_radius;
		
		/* draw single filled circle, using HP-GL's native
		   circle-drawing facility */
		
		/* move to center of circle */
		savedpoint = _plotter->drawstate->pos;
		_plotter->drawstate->pos = 
		  _plotter->drawstate->path->segments[0].p;
		_pl_h_set_position (S___(_plotter));
		_plotter->drawstate->pos = savedpoint;
		
		/* set fill color to pen color, arrange to do filling; sync
		   attributes too, incl. pen width */
		{
		  /* emit HP-GL directives; select a fill color that's
		     actually the pen color */
		  _pl_h_set_fill_color (R___(_plotter) true);
		  _pl_h_set_attributes (S___(_plotter));
		}

		/* compute radius in device frame */
		device_frame_radius = 
		  sqrt(XDV(r,0)*XDV(r,0)+YDV(r,0)*YDV(r,0));
		
		/* Syncing the fill color may have set the
		   _plotter->hpgl_bad_pen flag (e.g. if optimal pen is #0
		   [white] and we're not allowed to use pen #0 to draw
		   with).  So we test _plotter->hpgl_bad_pen before using
		   the pen. */
		if (_plotter->hpgl_bad_pen == false)
		  /* fill the circle (360 degree wedge) */
		  {
		    sprintf (_plotter->data->page->point, "WG%d,0,360;", 
			     IROUND(device_frame_radius));
		    _update_buffer (_plotter->data->page);
		  }
		/* KLUDGE: in pre-HP-GL/2, our `set_fill_color' function
		   may alter the line type, since it may request *solid*
		   crosshatching; so reset the line type */
		if (_plotter->hpgl_version < 2)
		  _pl_h_set_attributes (S___(_plotter));
	      }
	  
	    /* free our temporary array and depart */
	    free (xarray);
	    break;
	  }
	
	/* At this point, we know we have a nondegenerate path in our
	   pseudo-integer device space. */
	
	/* will draw vectors (or arcs) into polygon buffer if appropriate */
	use_polygon_buffer = (_plotter->hpgl_version == 2
			      || (_plotter->hpgl_version == 1 /* i.e. "1.5" */
				  && (polyline_len > 2
				      || _plotter->drawstate->fill_type)) ? true : false);
	
	/* Sync pen color.  This is needed here only if HPGL_VERSION is 1,
	   but we always do it here so that HP-GL/2 output that draws a
	   polyline, if sent erroneously to a generic HP-GL device, will
	   yield a polyline in the correct color, so long as the color
	   isn't white. */
	_pl_h_set_pen_color (R___(_plotter) HPGL_OBJECT_PATH);
	
	/* set_pen_color() sets the advisory bad_pen flag if white pen (pen
	   #0) would have been selected, and we can't use pen #0 to draw
	   with.  Such a situation isn't fatal if HPGL_VERSION is "1.5" or
	   "2", since we may be filling the polyline with a nonwhite color,
	   as well as using a white pen to draw it.  But if HPGL_VERSION is
	   "1", we don't fill polylines, so we might as well punt right
	   now. */
	if (_plotter->hpgl_bad_pen && _plotter->hpgl_version == 1)
	  {
	    /* free integer storage buffer and depart */
	    free (xarray);
	    break;
	  }
	
	/* sync attributes, incl. pen width if possible; move pen to p0 */
	_pl_h_set_attributes (S___(_plotter));
	
	savedpoint = _plotter->drawstate->pos;
	_plotter->drawstate->pos = _plotter->drawstate->path->segments[0].p;
	_pl_h_set_position (S___(_plotter));
	_plotter->drawstate->pos = savedpoint;
	
	if (use_polygon_buffer)
	  /* have a polygon buffer, and can use it to fill polyline */
	  {
	    /* enter polygon mode */
	    strcpy (_plotter->data->page->point, "PM0;");
	    _update_buffer (_plotter->data->page);
	  }
	
	if (use_polygon_buffer || _plotter->drawstate->pen_type)
	  /* either (1) we'll be drawing into a polygon buffer, and will be
	     using it for at least one of (a) filling and (b) edging, or
	     (2) we won't be drawing into a polygon buffer, so we won't be
	     filling, but we'll be edging (because pen_type isn't zero) */
	  {
	    /* ensure that pen is down for drawing */
	    if (_plotter->hpgl_pendown == false)
	      {
		strcpy (_plotter->data->page->point, "PD;");
		_update_buffer (_plotter->data->page);
		_plotter->hpgl_pendown = true;
	      }
	    
	    /* loop through points in xarray[], emitting HP-GL instructions */
	    i = 1;
	    while (i < polyline_len)
	      {
		switch ((int)xarray[i].type)
		  {
		  case (int)S_LINE:
		    /* emit one or more pen advances */
		    strcpy (_plotter->data->page->point, "PA");
		    _update_buffer (_plotter->data->page);
		    sprintf (_plotter->data->page->point, "%d,%d", 
			     xarray[i].p.x, xarray[i].p.y);
		    _update_buffer (_plotter->data->page);
		    i++;
		    while (i < polyline_len && xarray[i].type == S_LINE)
		      {
			sprintf (_plotter->data->page->point, 
				 ",%d,%d", xarray[i].p.x, xarray[i].p.y);
			_update_buffer (_plotter->data->page);
			i++;
		      }
		    sprintf (_plotter->data->page->point, ";");
		    _update_buffer (_plotter->data->page);	  
		    break;
		    
		  case (int)S_CUBIC:
		    /* emit one or more cubic Bezier segments */
		    strcpy (_plotter->data->page->point, "BZ");
		    _update_buffer (_plotter->data->page);
		    sprintf (_plotter->data->page->point, "%d,%d,%d,%d,%d,%d",
			     xarray[i].pc.x, xarray[i].pc.y,
			     xarray[i].pd.x, xarray[i].pd.y,
			     xarray[i].p.x, xarray[i].p.y);
		    _update_buffer (_plotter->data->page);
		    i++;
		    while (i < polyline_len && xarray[i].type == S_CUBIC)
		      {
			sprintf (_plotter->data->page->point, ",%d,%d,%d,%d,%d,%d",
				 xarray[i].pc.x, xarray[i].pc.y,
				 xarray[i].pd.x, xarray[i].pd.y,
				 xarray[i].p.x, xarray[i].p.y);
			_update_buffer (_plotter->data->page);
			i++;
		      }
		  sprintf (_plotter->data->page->point, ";");
		  _update_buffer (_plotter->data->page);	  
		  break;
		  
		  case (int)S_ARC:
		    {
		      double degrees;
		      int int_degrees;

		      /* emit an arc, using integer sweep angle if possible */
		      degrees = 180.0 * xarray[i].angle / M_PI;
		      int_degrees = IROUND (degrees);
		      if (_plotter->hpgl_version > 0) 
			/* HPGL_VERSION = 1.5 or 2 */
			{
			  if (degrees == (double)int_degrees)
			    sprintf (_plotter->data->page->point, "AA%d,%d,%d;",
				     xarray[i].pc.x, xarray[i].pc.y,
				     int_degrees);
			  else
			    sprintf (_plotter->data->page->point, "AA%d,%d,%.3f;",
				     xarray[i].pc.x, xarray[i].pc.y,
				     degrees);
			}
		      else
			/* HPGL_VERSION = 1, i.e. generic HP-GL */
			/* note: generic HP-GL can only handle integer
			   sweep angles */
			sprintf (_plotter->data->page->point, "AA%d,%d,%d;",
				 xarray[i].pc.x, xarray[i].pc.y,
				 int_degrees);
		      _update_buffer (_plotter->data->page);
		      i++;
		    }
		    break;
		    
		  default:
		    /* shouldn't happen: unknown type for path segment,
                       ignore */
		    i++;
		    break;
		  }
	      }
	  }
	
	if (use_polygon_buffer)
	  /* using polygon mode; will now employ polygon buffer to do
	     filling (possibly) and edging */
	  {
	    if (!closed)
	      /* polyline is open, so lift pen and exit polygon mode */
	      {
		strcpy (_plotter->data->page->point, "PU;");
		_update_buffer (_plotter->data->page);
		_plotter->hpgl_pendown = false;
		strcpy (_plotter->data->page->point, "PM2;");
		_update_buffer (_plotter->data->page);
	      }
	    else
	      /* polyline is closed, so exit polygon mode and then lift pen */
	      {
		strcpy (_plotter->data->page->point, "PM2;");
		_update_buffer (_plotter->data->page);
		strcpy (_plotter->data->page->point, "PU;");
		_update_buffer (_plotter->data->page);
		_plotter->hpgl_pendown = false;
	      }
	    
	    if (_plotter->drawstate->fill_type)
	      /* polyline should be filled */
	      {
		/* Sync fill color.  This may set the
		   _plotter->hpgl_bad_pen flag (if optimal pen is #0
		   [white] and we're not allowed to use pen #0 to draw
		   with).  So we test _plotter->hpgl_bad_pen before using
		   the pen to fill with. */
		_pl_h_set_fill_color (R___(_plotter) false);
		if (_plotter->hpgl_bad_pen == false)
		  /* fill polyline, specifying nonzero winding rule if
		     necessary */
		  {
		    switch (_plotter->drawstate->fill_rule_type)
		      {
		      case PL_FILL_ODD_WINDING:
		      default:
			strcpy (_plotter->data->page->point, "FP;");
			break;
		      case PL_FILL_NONZERO_WINDING:		  
			if (_plotter->hpgl_version == 2)
			  strcpy (_plotter->data->page->point, "FP1;");
			else	/* pre-HP-GL/2 doesn't support nonzero rule */
			  strcpy (_plotter->data->page->point, "FP;");
			break;
		      }
		    _update_buffer (_plotter->data->page);
		  }
	    /* KLUDGE: in pre-HP-GL/2, our `set_fill_color' function may
	       alter the line type, since it may request *solid*
	       crosshatching; so reset the line type */
		if (_plotter->hpgl_version < 2)
		  _pl_h_set_attributes (S___(_plotter));
	      }
	    
	    if (_plotter->drawstate->pen_type)
	      /* polyline should be edged */
	      {
		/* Sync pen color.  This may set the _plotter->hpgl_bad_pen
		   flag (if optimal pen is #0 and we're not allowed to use
		   pen #0 to draw with).  So we test _plotter->hpgl_bad_pen
		   before using the pen. */
		_pl_h_set_pen_color (R___(_plotter) HPGL_OBJECT_PATH);
		if (_plotter->hpgl_bad_pen == false)
		  /* select appropriate pen for edging, and edge the
                     polyline */
		  {
		    _pl_h_set_pen_color (R___(_plotter) HPGL_OBJECT_PATH);
		    strcpy (_plotter->data->page->point, "EP;");
		    _update_buffer (_plotter->data->page);
		  }
	      }
	  }
	
	/* We know where the pen now is: if we used a polygon buffer, then
	   _plotter->hpgl_pos is now xarray[0].p.  If we didn't (as would
	   be the case if we're outputting generic HP-GL), then
	   _plotter->hpgl_pos is now xarray[polyline_len - 1].p.
	   Unfortunately we can't simply update _plotter->hpgl_pos, because
	   we want the generated HP-GL[/2] code to work properly on both
	   HP-GL and HP-GL/2 devices.  So we punt. */
	_plotter->hpgl_position_is_unknown = true;
	
	/* free integer storage buffer and depart */
	free (xarray);
      }
      break;
	
    case (int)PATH_BOX:
      {
	plPoint p0, p1, savedpoint;

	p0 = _plotter->drawstate->path->p0;
	p1 = _plotter->drawstate->path->p1;

	/* sync line attributes, incl. pen width */
	_pl_h_set_attributes (S___(_plotter));

	/* move HP-GL pen to first vertex */
	savedpoint = _plotter->drawstate->pos;
	_plotter->drawstate->pos = p0;
	_pl_h_set_position (S___(_plotter));
	_plotter->drawstate->pos = savedpoint;
	
	if (_plotter->drawstate->fill_type)
	  /* rectangle should be filled */
	  {
	    /* Sync fill color.  This may set the _plotter->hpgl_bad_pen
	       flag (e.g. if optimal pen is #0 [white] and we're not
	       allowed to use pen #0 to draw with).  So we test
	       _plotter->hpgl_bad_pen before using the pen. */
	    _pl_h_set_fill_color (R___(_plotter) false);
	    if (_plotter->hpgl_bad_pen == false)
	      /* fill the rectangle */
	      {
		sprintf (_plotter->data->page->point, "RA%d,%d;", 
			 IROUND(XD(p1.x,p1.y)), IROUND(YD(p1.x,p1.y)));
		_update_buffer (_plotter->data->page);
	      }
	    /* KLUDGE: in pre-HP-GL/2, our `set_fill_color' function may
	       alter the line type, since it may request *solid*
	       crosshatching; so reset it */
	    if (_plotter->hpgl_version < 2)
	      _pl_h_set_attributes (S___(_plotter));
	  }	  
	
	if (_plotter->drawstate->pen_type)
	  /* rectangle should be edged */
	  {
	    /* Sync pen color.  This may set the _plotter->hpgl_bad_pen
	       flag (e.g. if optimal pen is #0 [white] and we're not
	       allowed to use pen #0 to draw with).  So we test
	       _plotter->hpgl_bad_pen before using the pen. */
	    _pl_h_set_pen_color (R___(_plotter) HPGL_OBJECT_PATH);
	    if (_plotter->hpgl_bad_pen == false)
	      /* edge the rectangle */
	      {
		sprintf (_plotter->data->page->point, "EA%d,%d;", 
			 IROUND(XD(p1.x,p1.y)), IROUND(YD(p1.x,p1.y)));
		_update_buffer (_plotter->data->page);
	      }
	  }
      }
      break;

    case (int)PATH_CIRCLE:
      {
	plPoint pc, savedpoint;
	double r = _plotter->drawstate->path->radius;
	double radius = sqrt(XDV(r,0)*XDV(r,0)+YDV(r,0)*YDV(r,0));

	pc = _plotter->drawstate->path->pc;
	
	/* sync attributes, incl. pen width; move to center of circle */
	_pl_h_set_attributes (S___(_plotter));

	savedpoint = _plotter->drawstate->pos;
	_plotter->drawstate->pos = pc;
	_pl_h_set_position (S___(_plotter));
	_plotter->drawstate->pos = savedpoint;
	
	if (_plotter->drawstate->fill_type)
	  /* circle should be filled */
	  {
	    /* Sync fill color.  This may set the _plotter->hpgl_bad_pen
	       flag (e.g. if optimal pen is #0 [white] and we're not
	       allowed to use pen #0 to draw with).  So we test
	       _plotter->hpgl_bad_pen before using the pen. */
	    _pl_h_set_fill_color (R___(_plotter) false);
	    if (_plotter->hpgl_bad_pen == false)
	      /* fill the circle (360 degree wedge) */
	      {
		sprintf (_plotter->data->page->point, "WG%d,0,360;", 
			 IROUND(radius));
		_update_buffer (_plotter->data->page);
	      }
	    /* KLUDGE: in pre-HP-GL/2, our `set_fill_color' function may
	       alter the line type, since it may request *solid*
	       crosshatching; so reset it */
	    if (_plotter->hpgl_version < 2)
	      _pl_h_set_attributes (S___(_plotter));
	  }
	
	if (_plotter->drawstate->pen_type)
	  /* circle should be edged */
	  {
	    /* Sync pen color.  This may set the _plotter->hpgl_bad_pen
	       flag (e.g. if optimal pen is #0 [white] and we're not
	       allowed to use pen #0 to draw with).  So we test
	       _plotter->hpgl_bad_pen before using the pen. */
	    _pl_h_set_pen_color (R___(_plotter) HPGL_OBJECT_PATH);
	    if (_plotter->hpgl_bad_pen == false)
	      /* do the edging */
	      {
		sprintf (_plotter->data->page->point, "CI%d;", IROUND(radius));
		_update_buffer (_plotter->data->page);
	      }
	  }
      }
      break;

    default:			/* unrecognized path type, shouldn't happen */
      break;
    }
}

/* A low-level method for moving the pen position of an HP-GL pen plotter
   to agree with the Plotter's notion of what the graphics cursor position
   should be.  The state of the pen (up vs. down) after calling this
   function is not uniquely determined.  */

void
_pl_h_set_position (S___(Plotter *_plotter))
{
  int xnew, ynew;
  
  /* if plotter's pen position doesn't agree with what it should be,
     adjust it */

  xnew = IROUND(XD(_plotter->drawstate->pos.x, _plotter->drawstate->pos.y));
  ynew = IROUND(YD(_plotter->drawstate->pos.x, _plotter->drawstate->pos.y));  

  if (_plotter->hpgl_position_is_unknown == true
      || xnew != _plotter->hpgl_pos.x || ynew != _plotter->hpgl_pos.y)
    {
      if (_plotter->hpgl_pendown == true)
	{
	  sprintf (_plotter->data->page->point, "PU;PA%d,%d;", xnew, ynew);
	  _plotter->hpgl_pendown = false;
	}
      else
	sprintf (_plotter->data->page->point, "PA%d,%d;", xnew, ynew);
      _update_buffer (_plotter->data->page);

      /* update our knowledge of pen position */
      _plotter->hpgl_position_is_unknown = false;
      _plotter->hpgl_pos.x = xnew;
      _plotter->hpgl_pos.y = ynew;
    }
}

bool
_pl_h_paint_paths (S___(Plotter *_plotter))
{
  return false;
}