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() method, which the public
20    method endpath() is a wrapper around. */
21 
22 /* This version is for Bitmap Plotters.  By construction, for Bitmap
23    Plotters our path buffer always contains either a segment list, or an
24    ellipse object.  If it's a segment list, it contains either (1) a
25    sequence of line segments, or (2) a single circular or elliptic arc
26    segment.  Those are all sorts of path that libxmi can handle.  (For an
27    ellipse or circular/elliptic arc segment to have been added to the path
28    buffer, the map from user to device coordinates must preserve axes.) */
29 
30 #include "sys-defines.h"
31 #include "extern.h"
32 #include "xmi.h"		/* use libxmi scan conversion module */
33 
34 #define DIST(p1, p2) sqrt( ((p1).x - (p2).x) * ((p1).x - (p2).x) \
35 			  + ((p1).y - (p2).y) * ((p1).y - (p2).y))
36 
37 void
_pl_b_paint_path(S___ (Plotter * _plotter))38 _pl_b_paint_path (S___(Plotter *_plotter))
39 {
40   if (_plotter->drawstate->pen_type == 0
41       && _plotter->drawstate->fill_type == 0)
42     /* nothing to draw */
43     return;
44 
45   switch ((int)_plotter->drawstate->path->type)
46     {
47     case (int)PATH_SEGMENT_LIST:
48       {
49 	int i, polyline_len;
50 	bool identical_user_coordinates = true;
51 	double xu_last, yu_last;
52 	miGC *pGC;
53 	miPoint *miPoints, offset;
54 	miPixel fgPixel, bgPixel;
55 	miPixel pixels[2];
56 	unsigned char red, green, blue;
57 	plPoint p0, p1, pc;
58 
59 	/* sanity checks */
60 	if (_plotter->drawstate->path->num_segments == 0)/* nothing to do */
61 	  break;
62 	if (_plotter->drawstate->path->num_segments == 1)/* shouldn't happen */
63 	  break;
64 
65 	if (_plotter->drawstate->path->num_segments == 2
66 	    && _plotter->drawstate->path->segments[1].type == S_ARC)
67 	  /* segment buffer contains a single circular arc, not a polyline */
68 	  {
69 	    p0 = _plotter->drawstate->path->segments[0].p;
70 	    p1 = _plotter->drawstate->path->segments[1].p;
71 	    pc = _plotter->drawstate->path->segments[1].pc;
72 
73 	    /* use libxmi rendering */
74 	    _pl_b_draw_elliptic_arc (R___(_plotter) p0, p1, pc);
75 
76 	    break;
77 	  }
78 
79 	if (_plotter->drawstate->path->num_segments == 2
80 	    && _plotter->drawstate->path->segments[1].type == S_ELLARC)
81 	  /* segment buffer contains a single elliptic arc, not a polyline */
82 	  {
83 	    p0 = _plotter->drawstate->path->segments[0].p;
84 	    p1 = _plotter->drawstate->path->segments[1].p;
85 	    pc = _plotter->drawstate->path->segments[1].pc;
86 
87 	    /* use libxmi rendering */
88 	    _pl_b_draw_elliptic_arc_2 (R___(_plotter) p0, p1, pc);
89 
90 	    break;
91 	  }
92 
93 	/* neither of above applied, so segment buffer contains a polyline,
94 	   not an arc */
95 
96 	/* construct point array for libxmi module; convert vertices to
97 	   device coordinates, removing runs */
98 	miPoints = (miPoint *)_pl_xmalloc (_plotter->drawstate->path->num_segments * sizeof(miPoint));
99 
100 	polyline_len = 0;
101 	xu_last = 0.0;
102 	yu_last = 0.0;
103 	identical_user_coordinates = true;
104 	for (i = 0; i < _plotter->drawstate->path->num_segments; i++)
105 	  {
106 	    double xu, yu;
107 	    int device_x, device_y;
108 
109 	    xu = _plotter->drawstate->path->segments[i].p.x;
110 	    yu = _plotter->drawstate->path->segments[i].p.y;
111 	    if (i > 0 && (xu != xu_last || yu != yu_last))
112 	      /* in user space, not all points are the same */
113 	      identical_user_coordinates = false;
114 	    device_x = IROUND(XD(xu, yu));
115 	    device_y = IROUND(YD(xu, yu));
116 	    if ((polyline_len == 0)
117 		|| (device_x != miPoints[polyline_len-1].x)
118 		|| (device_y != miPoints[polyline_len-1].y))
119 	      /* add point, in integer device coordinates, to the array */
120 	      {
121 		miPoints[polyline_len].x = device_x;
122 		miPoints[polyline_len].y = device_y;
123 		polyline_len++;
124 	      }
125 	    xu_last = xu;
126 	    yu_last = yu;
127 	  }
128 
129 	/* determine background pixel color */
130 	bgPixel.type = MI_PIXEL_RGB_TYPE;
131 	bgPixel.u.rgb[0] = _plotter->drawstate->bgcolor.red & 0xff;
132 	bgPixel.u.rgb[1] = _plotter->drawstate->bgcolor.green & 0xff;
133 	bgPixel.u.rgb[2] = _plotter->drawstate->bgcolor.blue & 0xff;
134 	pixels[0] = bgPixel;
135 	pixels[1] = bgPixel;
136 
137 	/* construct an miGC (graphics context for the libxmi module); copy
138 	   attributes from the Plotter's GC to it */
139 	pGC = miNewGC (2, pixels);
140 	_set_common_mi_attributes (_plotter->drawstate, (void *)pGC);
141 
142 	if (_plotter->drawstate->fill_type)
143 	  /* not transparent, will fill */
144 	  {
145 	    /* flattened drawing primitives, i.e., box/circle/ellipse,
146 	       are always convex */
147 	    miPolygonShape polygon_shape
148 	      = (_plotter->drawstate->path->primitive ? MI_SHAPE_CONVEX : MI_SHAPE_GENERAL);
149 
150 	    /* set fg color in GC to a 24-bit version of our fill color */
151 	    red = ((unsigned int)(_plotter->drawstate->fillcolor.red) >> 8) & 0xff;
152 	    green = ((unsigned int)(_plotter->drawstate->fillcolor.green) >> 8) & 0xff;
153 	    blue = ((unsigned int)(_plotter->drawstate->fillcolor.blue) >> 8) & 0xff;
154 	    fgPixel.type = MI_PIXEL_RGB_TYPE;
155 	    fgPixel.u.rgb[0] = red;
156 	    fgPixel.u.rgb[1] = green;
157 	    fgPixel.u.rgb[2] = blue;
158 	    pixels[0] = bgPixel;
159 	    pixels[1] = fgPixel;
160 	    miSetGCPixels (pGC, 2, pixels);
161 
162 	    /* do the filling */
163 
164 	    if (_plotter->drawstate->path->num_segments > 1
165 		&& polyline_len == 1)
166 	      /* special case: all user-space points in polyline were
167 		 mapped to a single integer pixel, so just paint it */
168 	      miDrawPoints ((miPaintedSet *)_plotter->b_painted_set, pGC,
169 			    MI_COORD_MODE_ORIGIN, 1, miPoints);
170 	    else
171 	      /* normal case */
172 	      miFillPolygon ((miPaintedSet *)_plotter->b_painted_set, pGC,
173 			     polygon_shape,
174 			     MI_COORD_MODE_ORIGIN, polyline_len, miPoints);
175 	  }
176 
177 	if (_plotter->drawstate->pen_type)
178 	  /* pen is present, so edge the polyline */
179 	  {
180 	    /* set pen color in GC to a 24-bit version of our pen color
181 	       (and set bg color too) */
182 	    red = ((unsigned int)(_plotter->drawstate->fgcolor.red) >> 8) & 0xff;
183 	    green = ((unsigned int)(_plotter->drawstate->fgcolor.green) >> 8) & 0xff;
184 	    blue = ((unsigned int)(_plotter->drawstate->fgcolor.blue) >> 8) & 0xff;
185 	    fgPixel.type = MI_PIXEL_RGB_TYPE;
186 	    fgPixel.u.rgb[0] = red;
187 	    fgPixel.u.rgb[1] = green;
188 	    fgPixel.u.rgb[2] = blue;
189 	    pixels[0] = bgPixel;
190 	    pixels[1] = fgPixel;
191 	    miSetGCPixels (pGC, 2, pixels);
192 
193 	    if (polyline_len == 1)
194 	      /* Special case: all user-space points in the polyline were
195 		 mapped to a single pixel.  If (1) they weren't all the
196 		 same to begin with, or (2) they were all the same to begin
197 		 with and the cap mode is "round", then draw as a filled
198 		 circle of diameter equal to the line width; otherwise draw
199 		 nothing. */
200 	      {
201 		if (identical_user_coordinates == false
202 		    || _plotter->drawstate->cap_type == PL_CAP_ROUND)
203 		  {
204 		    unsigned int sp_size
205 		      = (unsigned int)_plotter->drawstate->quantized_device_line_width;
206 		    if (sp_size == 0)
207 		      sp_size = 1;
208 
209 		    if (sp_size == 1)
210 		      /* subcase: just draw a point */
211 		      miDrawPoints ((miPaintedSet *)_plotter->b_painted_set, pGC,
212 				    MI_COORD_MODE_ORIGIN, 1, miPoints);
213 		    else
214 		      /* draw a filled circle */
215 		      {
216 			int sp_offset;
217 			miArc arc;
218 
219 			sp_offset =
220 			  (_plotter->drawstate->quantized_device_line_width + 1) / 2;
221 			arc.x = miPoints[0].x - sp_offset;
222 			arc.y = miPoints[0].y - sp_offset;
223 			arc.width = sp_size;
224 			arc.height = sp_size;
225 			arc.angle1 = 0;
226 			arc.angle2 = 64 * 360;
227 			miFillArcs ((miPaintedSet *)_plotter->b_painted_set,
228 				    pGC, 1, &arc);
229 		      }
230 		  }
231 	      }
232 
233 	    else
234 	      /* normal case: draw a nondegenerate polyline in integer
235                  device space */
236 	      miDrawLines ((miPaintedSet *)_plotter->b_painted_set, pGC,
237 			   MI_COORD_MODE_ORIGIN, polyline_len, miPoints);
238 	  }
239 
240 	/* deallocate miGC and free temporary points array */
241 	miDeleteGC (pGC);
242 	free (miPoints);
243 
244 	/* copy from painted set to canvas, and clear */
245 	offset.x = 0;
246 	offset.y = 0;
247 	miCopyPaintedSetToCanvas ((miPaintedSet *)_plotter->b_painted_set,
248 				  (miCanvas *)_plotter->b_canvas,
249 				  offset);
250 	miClearPaintedSet ((miPaintedSet *)_plotter->b_painted_set);
251       }
252       break;
253 
254     case (int)PATH_ELLIPSE:
255       {
256 	int ninetymult;
257 	int x_orientation, y_orientation;
258 	int xorigin, yorigin;
259 	unsigned int squaresize_x, squaresize_y;
260 	plPoint pc;
261 	double rx, ry, angle;
262 
263 	pc = _plotter->drawstate->path->pc;
264 	rx = _plotter->drawstate->path->rx;
265 	ry = _plotter->drawstate->path->ry;
266 	angle = _plotter->drawstate->path->angle;
267 
268 	/* if angle is multiple of 90 degrees, modify to permit use of
269 	   libxmi's arc rendering */
270 	ninetymult = IROUND(angle / 90.0);
271 	if (angle == (double) (90 * ninetymult))
272 	  {
273 	    angle = 0.0;
274 	    if (ninetymult % 2)
275 	      {
276 		double temp;
277 
278 		temp = rx;
279 		rx = ry;
280 		ry = temp;
281 	      }
282 	  }
283 
284 	rx = (rx < 0.0 ? -rx : rx);	/* avoid obscure libxmi problems */
285 	ry = (ry < 0.0 ? -ry : ry);
286 
287 	/* axes flipped? (by default y-axis is, due to libxmi's flipped-y
288            convention) */
289 	x_orientation = (_plotter->drawstate->transform.m[0] >= 0 ? 1 : -1);
290 	y_orientation = (_plotter->drawstate->transform.m[3] >= 0 ? 1 : -1);
291 
292 	/* location of `origin' (upper left corner of bounding rect. for
293 	   ellipse) and width and height; libxmi's flipped-y convention
294 	   affects these values */
295 	xorigin = IROUND(XD(pc.x - x_orientation * rx,
296 			    pc.y - y_orientation * ry));
297 	yorigin = IROUND(YD(pc.x - x_orientation * rx,
298 			    pc.y - y_orientation * ry));
299 	squaresize_x = (unsigned int)IROUND(XDV(2 * x_orientation * rx, 0.0));
300 	squaresize_y = (unsigned int)IROUND(YDV(0.0, 2 * y_orientation * ry));
301 	/* Because this ellipse object was added to the path buffer, we
302 	   already know that (1) the user->device frame map preserves
303 	   coordinate axes, (2) effectively, angle == 0.  These are
304 	   necessary for the libxmi scan-conversion module to do the
305 	   drawing. */
306 
307 	/* draw ellipse (elliptic arc aligned with the coordinate axes, arc
308 	   range = 64*360 64'ths of a degree) */
309 	_pl_b_draw_elliptic_arc_internal (R___(_plotter)
310 					  xorigin, yorigin,
311 					  squaresize_x, squaresize_y,
312 					  0, 64 * 360);
313       }
314       break;
315 
316     default:			/* shouldn't happen */
317       break;
318     }
319 }
320 
321 /* Use libxmi rendering to draw what would be a circular arc in the user
322    frame.  If this is called, the map from user to device coordinates is
323    assumed to preserve coordinate axes (it may be anisotropic [x and y
324    directions scaled differently], and it may include a reflection through
325    either or both axes).  So it will be a circular or elliptic arc in the
326    device frame, of the sort that libxmi supports. */
327 
328 void
_pl_b_draw_elliptic_arc(R___ (Plotter * _plotter)plPoint p0,plPoint p1,plPoint pc)329 _pl_b_draw_elliptic_arc (R___(Plotter *_plotter) plPoint p0, plPoint p1, plPoint pc)
330 {
331   double radius;
332   double theta0, theta1;
333   int startangle, anglerange;
334   int x_orientation, y_orientation;
335   int xorigin, yorigin;
336   unsigned int squaresize_x, squaresize_y;
337 
338   /* axes flipped? (by default y-axis is, due to xmi's flipped-y convention) */
339   x_orientation = (_plotter->drawstate->transform.m[0] >= 0 ? 1 : -1);
340   y_orientation = (_plotter->drawstate->transform.m[3] >= 0 ? 1 : -1);
341 
342   /* radius of circular arc in user frame is distance to p0, and also to p1 */
343   radius = DIST(pc, p0);
344 
345   /* location of `origin' (upper left corner of bounding rect. on display)
346      and width and height; X's flipped-y convention affects these values */
347   xorigin = IROUND(XD(pc.x - x_orientation * radius,
348 		      pc.y - y_orientation * radius));
349   yorigin = IROUND(YD(pc.x - x_orientation * radius,
350 		      pc.y - y_orientation * radius));
351   squaresize_x = (unsigned int)IROUND(XDV(2 * x_orientation * radius, 0.0));
352   squaresize_y = (unsigned int)IROUND(YDV(0.0, 2 * y_orientation * radius));
353 
354   theta0 = _xatan2 (-y_orientation * (p0.y - pc.y),
355 		    x_orientation * (p0.x - pc.x)) / M_PI;
356   theta1 = _xatan2 (-y_orientation * (p1.y - pc.y),
357 		    x_orientation * (p1.x - pc.x)) / M_PI;
358 
359   if (theta1 < theta0)
360     theta1 += 2.0;		/* adjust so that difference > 0 */
361   if (theta0 < 0.0)
362     {
363       theta0 += 2.0;		/* adjust so that startangle > 0 */
364       theta1 += 2.0;
365     }
366 
367   if (theta1 - theta0 > 1.0)	/* swap if angle appear to be > 180 degrees */
368     {
369       double tmp;
370 
371       tmp = theta0;
372       theta0 = theta1;
373       theta1 = tmp;
374       theta1 += 2.0;		/* adjust so that difference > 0 */
375     }
376 
377   if (theta0 >= 2.0 && theta1 >= 2.0)
378     /* avoid obscure X bug */
379     {
380       theta0 -= 2.0;
381       theta1 -= 2.0;
382     }
383 
384   startangle = IROUND(64 * theta0 * 180.0); /* in 64'ths of a degree */
385   anglerange = IROUND(64 * (theta1 - theta0) * 180.0); /* likewise */
386 
387   _pl_b_draw_elliptic_arc_internal (R___(_plotter)
388 				    xorigin, yorigin,
389 				    squaresize_x, squaresize_y,
390 				    startangle, anglerange);
391 }
392 
393 /* Use libxmi rendering to draw what would be a quarter-ellipse in the user
394    frame.  If this is called, the map from user to device coordinates is
395    assumed to preserve coordinate axes (it may be anisotropic [x and y
396    directions scaled differently], and it may include a reflection through
397    either or both axes).  So it will be a quarter-ellipse in the device
398    frame, of the sort that libxmi supports. */
399 void
_pl_b_draw_elliptic_arc_2(R___ (Plotter * _plotter)plPoint p0,plPoint p1,plPoint pc)400 _pl_b_draw_elliptic_arc_2 (R___(Plotter *_plotter) plPoint p0, plPoint p1, plPoint pc)
401 {
402   double rx, ry;
403   double x0, y0, x1, y1, xc, yc;
404   int startangle, endangle, anglerange;
405   int x_orientation, y_orientation;
406   int xorigin, yorigin;
407   unsigned int squaresize_x, squaresize_y;
408 
409   /* axes flipped? (by default y-axis is, due to xmi's flipped-y convention) */
410   x_orientation = (_plotter->drawstate->transform.m[0] >= 0 ? 1 : -1);
411   y_orientation = (_plotter->drawstate->transform.m[3] >= 0 ? 1 : -1);
412 
413   xc = pc.x, yc = pc.y;
414   x0 = p0.x, y0 = p0.y;
415   x1 = p1.x, y1 = p1.y;
416 
417   if (y0 == yc && x1 == xc)
418     /* initial pt. on x-axis, final pt. on y-axis */
419     {
420       /* semi-axes in user frame */
421       rx = (x0 > xc) ? x0 - xc : xc - x0;
422       ry = (y1 > yc) ? y1 - yc : yc - y1;
423       /* starting and ending angles; note flipped-y convention */
424       startangle = ((x0 > xc ? 1 : -1) * x_orientation == 1) ? 0 : 180;
425       endangle = ((y1 > yc ? 1 : -1) * y_orientation == -1) ? 90 : 270;
426     }
427   else
428     /* initial pt. on y-axis, final pt. on x-axis */
429     {
430       /* semi-axes in user frame */
431       rx = (x1 > xc) ? x1 - xc : xc - x1;
432       ry = (y0 > yc) ? y0 - yc : yc - y0;
433       /* starting and ending angles; note flipped-y convention */
434       startangle = ((y0 > yc ? 1 : -1) * y_orientation == -1) ? 90 : 270;
435       endangle = ((x1 > xc ? 1 : -1) * x_orientation == 1) ? 0 : 180;
436     }
437 
438   if (endangle < startangle)
439     endangle += 360;
440   anglerange = endangle - startangle; /* always 90 or 270 */
441 
442   /* our convention: a quarter-ellipse can only be 90 degrees
443      of a libxmi ellipse, not 270 degrees, so interchange points */
444   if (anglerange == 270)
445     {
446       int tmp;
447 
448       tmp = startangle;
449       startangle = endangle;
450       endangle = tmp;
451       anglerange = 90;
452     }
453 
454   if (startangle >= 360)
455     /* avoid obscure libxmi bug */
456     startangle -= 360;		/* endangle no longer relevant */
457 
458   /* location of `origin' (upper left corner of bounding rect. on display)
459      and width and height; xmi's flipped-y convention affects these values */
460   xorigin = IROUND(XD(xc - x_orientation * rx,
461 		      yc - y_orientation * ry));
462   yorigin = IROUND(YD(xc - x_orientation * rx,
463 		      yc - y_orientation * ry));
464   squaresize_x = (unsigned int)IROUND(XDV(2 * x_orientation * rx, 0.0));
465   squaresize_y = (unsigned int)IROUND(YDV(0.0, 2 * y_orientation * ry));
466 
467   /* reexpress in 64'ths of a degree (libxmi convention) */
468   startangle *= 64;
469   anglerange *= 64;
470 
471   _pl_b_draw_elliptic_arc_internal (R___(_plotter)
472 				    xorigin, yorigin,
473 				    squaresize_x, squaresize_y,
474 				    startangle, anglerange);
475 }
476 
477 /* Draw an elliptic arc aligned with the coordinate axes, by invoking
478    functions in the libxmi API.  Takes account of the possible need for
479    filling.
480 
481    The cases squaresize_x = 0 and squaresize_y = 0 are handled specially,
482    since miFillArcs() and miDrawArcs() do not support them. */
483 
484 void
_pl_b_draw_elliptic_arc_internal(R___ (Plotter * _plotter)int xorigin,int yorigin,unsigned int squaresize_x,unsigned int squaresize_y,int startangle,int anglerange)485 _pl_b_draw_elliptic_arc_internal (R___(Plotter *_plotter) int xorigin, int yorigin, unsigned int squaresize_x, unsigned int squaresize_y, int startangle, int anglerange)
486 {
487   miGC *pGC;
488   miArc arc;
489   miPixel fgPixel, bgPixel;
490   miPixel pixels[2];
491   miPoint offset;
492   unsigned char red, green, blue;
493 
494   /* determine background pixel color */
495   bgPixel.type = MI_PIXEL_RGB_TYPE;
496   bgPixel.u.rgb[0] = _plotter->drawstate->bgcolor.red & 0xff;
497   bgPixel.u.rgb[1] = _plotter->drawstate->bgcolor.green & 0xff;
498   bgPixel.u.rgb[2] = _plotter->drawstate->bgcolor.blue & 0xff;
499   pixels[0] = bgPixel;
500   pixels[1] = bgPixel;
501 
502   /* construct an miGC (graphics context for the libxmi module); copy
503      attributes from the Plotter's GC to it */
504   pGC = miNewGC (2, pixels);
505   _set_common_mi_attributes (_plotter->drawstate, (void *)pGC);
506 
507   /* libxmi's definition of an elliptic arc aligned with the axes */
508   arc.x = xorigin;
509   arc.y = yorigin;
510   arc.width = squaresize_x;
511   arc.height = squaresize_y;
512   arc.angle1 = startangle;
513   arc.angle2 = anglerange;
514 
515   if (_plotter->drawstate->fill_type)
516     /* not transparent, so fill the arc */
517     {
518       double red_d, green_d, blue_d;
519       double desaturate;
520 
521       /* scale fillcolor RGB values from 16-bits to range [0.0,1.0] */
522       red_d = ((double)((_plotter->drawstate->fillcolor).red))/0xFFFF;
523       green_d = ((double)((_plotter->drawstate->fillcolor).green))/0xFFFF;
524       blue_d = ((double)((_plotter->drawstate->fillcolor).blue))/0xFFFF;
525 
526       /* fill_type, if nonzero, specifies the extent to which the
527 	 nominal fill color should be desaturated.  1 means no
528 	 desaturation, 0xffff means complete desaturation (white). */
529       desaturate = ((double)_plotter->drawstate->fill_type - 1.)/0xFFFE;
530       red_d = red_d + desaturate * (1.0 - red_d);
531       green_d = green_d + desaturate * (1.0 - green_d);
532       blue_d = blue_d + desaturate * (1.0 - blue_d);
533 
534       /* convert desaturated RGB values to 8 bits each (24 bits in all) */
535       red = IROUND(0xff * red_d);
536       green = IROUND(0xff * green_d);
537       blue = IROUND(0xff * blue_d);
538 
539       /* set fg color in GC to the 24-bit desaturated RGB (and set bg color
540 	 too) */
541       fgPixel.type = MI_PIXEL_RGB_TYPE;
542       fgPixel.u.rgb[0] = red;
543       fgPixel.u.rgb[1] = green;
544       fgPixel.u.rgb[2] = blue;
545       pixels[0] = bgPixel;
546       pixels[1] = fgPixel;
547       miSetGCPixels (pGC, 2, pixels);
548 
549       /* fill the arc */
550       if (squaresize_x <= 1 || squaresize_y <= 1)
551 	/* a special case, which miFillArcs() doesn't handle in the way we'd
552 	   like; just paint a single pixel, irrespective of angle range */
553 	{
554 	  miPoint point;
555 
556 	  point.x = xorigin;
557 	  point.y = yorigin;
558 	  miDrawPoints ((miPaintedSet *)_plotter->b_painted_set,
559 			pGC, MI_COORD_MODE_ORIGIN, 1, &point);
560 	}
561       else
562 	/* default case */
563 	miFillArcs ((miPaintedSet *)_plotter->b_painted_set, pGC, 1, &arc);
564     }
565 
566   if (_plotter->drawstate->pen_type)
567     /* pen is present, so edge the arc */
568     {
569       unsigned int sp_size = 0;	/* keep compiler happy */
570 
571       /* set fg color in GC to a 24-bit version of our pen color (and set
572 	 bg color too) */
573       red = ((unsigned int)(_plotter->drawstate->fgcolor.red) >> 8) & 0xff;
574       green = ((unsigned int)(_plotter->drawstate->fgcolor.green) >> 8) & 0xff;
575       blue = ((unsigned int)(_plotter->drawstate->fgcolor.blue) >> 8) & 0xff;
576       fgPixel.type = MI_PIXEL_RGB_TYPE;
577       fgPixel.u.rgb[0] = red;
578       fgPixel.u.rgb[1] = green;
579       fgPixel.u.rgb[2] = blue;
580       pixels[0] = bgPixel;
581       pixels[1] = fgPixel;
582       miSetGCPixels (pGC, 2, pixels);
583 
584       if (squaresize_x <= 1 || squaresize_y <= 1)
585 	/* Won't call miDrawArcs in the usual way, because it performs
586            poorly when one of these two is zero, at least.  Irrespective of
587            angle range, will fill a disk of diameter equal to line width */
588 	{
589 	  int sp_offset;
590 
591 	  sp_size
592 	    = (unsigned int)_plotter->drawstate->quantized_device_line_width;
593 	  sp_offset
594 	    = (int)(_plotter->drawstate->quantized_device_line_width + 1) / 2;
595 
596 	  if (sp_size == 0)
597 	    sp_size = 1;
598 	  arc.x -= sp_offset;
599 	  arc.y -= sp_offset;
600 	  arc.width = sp_size;
601 	  arc.height = sp_size;
602 	  arc.angle1 = 0;
603 	  arc.angle2 = 64 * 360;
604 	}
605 
606       /* edge the arc by invoking libxmi's reentrant arc-drawing function,
607 	 passing it as final argument a pointer to persistent storage
608 	 maintained by the Plotter */
609 
610       if (squaresize_x <= 1 || squaresize_y <= 1)
611 	/* miDrawArcs doesn't handle this case as we'd wish, will
612 	   treat specially */
613 	{
614 	  if (sp_size == 1)
615 	    /* special subcase: line width is small too, so just paint a
616 	       single pixel rather than filling abovementioned disk */
617 	    {
618 	      miPoint point;
619 
620 	      point.x = xorigin;
621 	      point.y = yorigin;
622 	      miDrawPoints ((miPaintedSet *)_plotter->b_painted_set,
623 			    pGC, MI_COORD_MODE_ORIGIN, 1, &point);
624 	    }
625 	  else
626 	    /* normal version of special case: draw filled disk of diameter
627 	       equal to the line width, irrespective of the angle range */
628 	    miFillArcs((miPaintedSet *)_plotter->b_painted_set, pGC, 1, &arc);
629 	}
630       else
631 	/* default case, which is what is almost always used */
632 	miDrawArcs_r ((miPaintedSet *)_plotter->b_painted_set, pGC, 1, &arc,
633 		      (miEllipseCache *)(_plotter->b_arc_cache_data));
634     }
635 
636   /* deallocate miGC */
637   miDeleteGC (pGC);
638 
639   /* copy from painted set to canvas, and clear */
640   offset.x = 0;
641   offset.y = 0;
642   miCopyPaintedSetToCanvas ((miPaintedSet *)_plotter->b_painted_set,
643 			    (miCanvas *)_plotter->b_canvas,
644 			    offset);
645   miClearPaintedSet ((miPaintedSet *)_plotter->b_painted_set);
646 }
647 
648 bool
_pl_b_paint_paths(S___ (Plotter * _plotter))649 _pl_b_paint_paths (S___(Plotter *_plotter))
650 {
651   return false;
652 }
653