1 /* This file is part of the GNU libxmi package.
2 
3    Copyright (C) 1985, 1986, 1987, 1988, 1989, X Consortium.  For an
4    associated permission notice, see the accompanying file README-X.
5 
6    GNU enhancements Copyright (C) 1998, 1999, 2000, 2005, Free Software
7    Foundation, Inc.
8 
9    The GNU libxmi package is free software.  You may redistribute it
10    and/or modify it under the terms of the GNU General Public License as
11    published by the Free Software foundation; either version 2, or (at your
12    option) any later version.
13 
14    The GNU libxmi package is distributed in the hope that it will be
15    useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    General Public License for more details.
18 
19    You should have received a copy of the GNU General Public License along
20    with the GNU plotutils package; see the file COPYING.  If not, write to
21    the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
22    Boston, MA 02110-1301, USA. */
23 
24 #include "sys-defines.h"
25 #include "extern.h"
26 
27 /* Authors: Keith Packard and Bob Scheifler, mid to late 1980s.
28    Hacked by Robert S. Maier <rsm@math.arizona.edu>, 1998-2000. */
29 
30 /* This module exports the miPolyArc() function and its reentrant
31    counterpart miPolyArc_r.  They scan-convert wide polyarcs, either solid
32    or dashed.  A polyarc is a list of arcs, which may or may not be
33    contiguous.  Here, an `arc' is an elliptic arc, i.e., a segment of an
34    ellipse.  The principal axes of the ellipse must be aligned with the
35    coordinate axes.
36 
37    Each arc is drawn with a circular brush, of width equal to the line
38    width.  All pixels within the brushed area are painted.
39 
40    All painting goes through the low-level fillSpans() function and the
41    MI_PAINT_SPANS() macro that it invokes, except that the miFillSppPoly()
42    routine in mi_fplycon.c is used to paint polygonal arc caps and arc
43    joins, if any.  That routine, in turn, invokes MI_PAINT_SPANS(). */
44 
45 /* Warning: this code is toxic, do not dally very long here. */
46 
47 #include "xmi.h"
48 #include "mi_spans.h"
49 #include "mi_gc.h"
50 #include "mi_api.h"
51 #include "mi_arc.h"
52 #include "mi_fply.h"		/* for miFillSppPoly() */
53 #include "mi_fllarc.h"		/* for MIWIDEARCSETUP, MIFILLINARCSTEP etc. */
54 
55 /* undefine if cbrt(), a fast cube root function for non-negative
56    arguments, is available */
57 #define cbrt(x) pow((x), 1.0/3.0)
58 
59 /* undefine if hypot is available (it's X_OPEN, but not ANSI or POSIX) */
60 #define hypot(x, y) sqrt((x)*(x) + (y)*(y))
61 
62 /**********************************************************************/
63 
64 /* To facilitate speedy drawing of elliptic arcs, we cache scan-converted
65    wide ellipses so that we can retrieve them later, by keying on ellipse
66    width, ellipse height, and line width.  Any such cache is an
67    miEllipseCache object; equivalently, a lib_miEllipseCache structure,
68    which is basically an array of (cachedEllipse *)'s.  Each cachedEllipse
69    is a record, the `value' field of which is an (miArcSpanData *),
70    i.e. basically a list of spans, computed and returned by
71    miComputeWideEllipse().
72 
73    The currently used miEllipseCache structure is accessed via the
74    ellipseCache argument of miPolyArc_r(). */
75 
76 /* one or two spans (any rasterized ellipse contains a list of these,
77    indexed by y) */
78 typedef struct
79 {
80   int lx, rx;			/* starting points of left, right spans */
81   int lw, rw;			/* widths of left, right spans */
82 } miArcSpan;
83 
84 /* `Value' part of each cache record, storing a rasterized ellipse.  A
85    rasterized ellipse is a list of ArcSpans, extending in order from the
86    top of the ellipse down to and including the centerline, if present.  It
87    consists primarily of count1 single-occupied ArcSpans (containing only a
88    single span), followed by count2 doubly-occupied ArcSpans (containing
89    two spans).
90 
91    In all, the list contains (top ? 1 : 0) + count1 + count2 + (bot ? 1 : 0)
92    ArcSpans.  The x-coordinates (lx,rx) in the ArcSpans are relative
93    to x = xorg = xorg_arc + width_arc/2, i.e. halfway across the ellipse.
94    The count1 single-occupied ArcSpans are drawn downward (i.e. at
95    successively increasing values of y), beginning at
96    y = yorgu = yorg_arc + height_arc/2 - k, and also upward beginning at
97    y = yorgl = yorg_arc + height_arc/2 + k.
98    They are followed by the count2 doubly occupied ArcSpans.
99 
100    (Here k = height_arc/2 + (linewidth-1)/2, always.)
101 
102    If top=true (which is the case iff width_arc is even and linewidth is
103    even), the first ArcSpan in the array is bogus, and should be replaced
104    by a single pixel at x=xorg, y = yorgu-1.  If bot=true, which is the
105    case iff height_arc is even, then the ellipse must be completed by
106    drawing the 2 or 1 spans contained in the final ArcSpan of the array on
107    the vertical centerline.  (rw<0 is a signal that this ArcSpan atypically
108    contains only a single span.)
109 
110    `hole' is a kludge flag.  If it is set, then after the count1 singly
111    occupied ArcSpans are drawn upward, a single additional pixel must be
112    drawn at (xorg,y), where y is the current (updated, i.e. decremented)
113    value of y.  y is not further decremented before the drawing of the
114    count2 doubly occupied ArcSpans begins. */
115 
116 typedef struct
117 {
118   int k;			/* height/2 + (linewidth-1)/2, always */
119   miArcSpan *spans;		/* array of up to k+2 miArcSpan structures */
120   bool top;			/* have initial (bogus) ArcSpan? */
121   int count1;			/* number of single-occupancy ArcSpans */
122   int count2;			/* number of double-occupancy ArcSpans */
123   bool bot;			/* have final (special) ArcSpan? */
124   bool hole;			/* add a certain pixel when drawing? */
125 } miArcSpanData;
126 
127 /* Cache record type (key/value); key consists of width,height,linewidth.
128    Also includes a timestamp. */
129 typedef struct
130 {
131   unsigned long lrustamp;	/* timestamp (time of most recent retrieval) */
132   unsigned int width, height;	/* ellipse width, height */
133   unsigned int lw;		/* line width used when rasterizing */
134   miArcSpanData *spdata;	/* `value' part of record */
135 } cachedEllipse;
136 
137 /* The cache of scan-converted ellipses, including continually updated
138    timestamp. */
139 struct lib_miEllipseCache
140 {
141   cachedEllipse *ellipses;	/* beginning of array of records */
142   int size;			/* number of records in array */
143   cachedEllipse *lastCacheHit;	/* pointer to last-accessed record */
144   unsigned long lrustamp;	/* clock, for timestamping records */
145 };
146 
147 /* Size of cache (i.e. number of (cachedEllipse *)'s the array contains) */
148 #define ELLIPSECACHE_SIZE 25
149 
150 /* Maximum height an ellipse can have, for its spans to be stored in
151    the cache. */
152 #define MAX_CACHEABLE_ELLIPSE_HEIGHT 1500
153 
154 #ifndef NO_NONREENTRANT_POLYARC_SUPPORT
155 /* An in-library cache, used by the non-reentrant functions miPolyArc()
156    and miZeroPolyArc(). */
157 miEllipseCache *_mi_ellipseCache = (miEllipseCache *)NULL;
158 #endif /* NO_NONREENTRANT_POLYARC_SUPPORT */
159 
160 /**********************************************************************/
161 
162 /* We must scan-convert poly-arcs, which consist of one or more wide
163    elliptic arcs, which may or may not be contiguous, and which may or may
164    not be dashed.  In this, the function miComputeArcs() plays a key role.
165    It doesn't do scan conversion.  Instead, it chops an ellipse into arcs
166    or small arcs representing dashes, determines whether joins or caps are
167    called for, etc.  What it returns is a list of miPolyArcs structures,
168    indexed by paint type.
169 
170    A miPolyArcs structure comprises a list of miArcData structs, a list of
171    joins, and a list of caps. */
172 
173 /* Note that self intersecting arcs (i.e. those spanning 360 degrees) never
174    join with other arcs, and are drawn without caps (unless on/off dashed,
175    in which case each dash segment is capped, except when the last segment
176    meets the first segment, when no caps are drawn). */
177 
178 #define RIGHT_END	0
179 #define LEFT_END	1
180 
181 typedef struct
182 {
183   int	arcIndex0, arcIndex1;	/* arcs to either side of the join */
184   int	paintType0, paintType1;	/* their paint types */
185   int	end0, end1;		/* either RIGHT_END or LEFT_END */
186 } miArcJoinStruct;
187 
188 typedef struct
189 {
190   int	arcIndex;		/* arc to be capped */
191   int	end;			/* either RIGHT_END or LEFT_END */
192 } miArcCapStruct;
193 
194 typedef struct
195 {
196   SppPoint	clock;
197   SppPoint	center;
198   SppPoint	counterClock;
199 } miArcFace;
200 
201 typedef struct
202 {
203   miArc		arc;
204   bool		render;		/* directive to render this arc (and
205 				   all previously non-rendered ones) */
206   int		join;		/* related join */
207   int		cap;		/* related cap */
208   bool		selfJoin;	/* arc is self-joining? */
209   miArcFace	bounds[2];	/* left face and right face (3 points each) */
210   double	x0, y0;		/* starting point (sub-pixel placement) */
211   double	x1, y1;		/* end point (sub-pixel placement) */
212 } miArcData;
213 
214 /*
215  * The miPolyArcs struct.  This is a sequence of arcs (e.g., dashes),
216  * computed and categorized according to operation.  miComputeArcs()
217  * returns a list of these, indexed by paint type.  */
218 
219 typedef struct
220 {
221   miArcData		*arcs;
222   int			narcs;
223   int			arcSize; /* number of slots allocated */
224   miArcCapStruct	*caps;
225   int			ncaps;
226   int			capSize; /* number of slots allocated */
227   miArcJoinStruct	*joins;
228   int			njoins;
229   int			joinSize; /* number of slots allocated */
230 } miPolyArcs;
231 
232 /**********************************************************************/
233 
234 /* In a sub-module below, with public functions initAccumSpans(),
235    newFinalSpan(), and fillSpans(), we initialize an miAccumSpans
236    structure, add spans to it, and finally paint and deallocate them.
237 
238    The miAccumSpans struct includes an array, indexed by y-value, each
239    element of which is a list of spans.  The y range, i.e. the range of the
240    index variable of the array, is expanded as needed.
241 
242    To facilitate rapid addition of spans to the structure, we maintain as
243    part of the miAccumSpans structure a list of unused span structures,
244    previously allocated in "chunks".  */
245 
246 struct finalSpan
247 {
248   int			min, max; /* x values */
249   struct finalSpan	*next;	/* pointer to next span at this value of y */
250 };
251 
252 #define SPAN_CHUNK_SIZE 128	/* spans are malloc'd in chunks of this size */
253 struct finalSpanChunk
254 {
255   struct finalSpan	data[SPAN_CHUNK_SIZE];
256   struct finalSpanChunk	*next;	/* pointer to previously malloc'd chunk */
257 };
258 
259 typedef struct
260 {
261   struct finalSpan **finalSpans;         /* array, indexed by y - finalMiny */
262   int              finalMiny, finalMaxy; /* y range */
263   int              finalSize;
264   int              nspans;	 /* total number of spans, not just y coors */
265   struct finalSpanChunk	*chunks; /* head of chunk list */
266   struct finalSpan *freeFinalSpans; /* next free span in chunk at list head */
267 } miAccumSpans;
268 
269 /**********************************************************************/
270 
271 /* Structure used by a sub-module that computes arc lengths via a polygonal
272    approximation to the arc.  The sub-module's external functions are
273    computeDashMap() and computeAngleFromPath(). */
274 
275 #define DASH_MAP_SIZE 91
276 typedef struct
277 {
278   double	map[DASH_MAP_SIZE];
279 } dashMap;
280 
281 /**********************************************************************/
282 
283 /* internal functions that do painting of pixels */
284 static void fillSpans (miPaintedSet *paintedSet, miPixel pixel, miAccumSpans *accumSpans);
285 static void miArcCap (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, const miArcFace *pFace, int end, int xOrg, int yOrg, double xFtrans, double yFtrans);
286 static void miArcJoin (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, const miArcFace *pLeft, const miArcFace *pRight, int xOrgLeft, int yOrgLeft, double xFtransLeft, double yFtransLeft, int xOrgRight, int yOrgRight, double xFtransRight, double yFtransRight);
287 static void miFillWideEllipse (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, const miArc *parc, miEllipseCache *ellipseCache);
288 static void miRoundCap (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, SppPoint pCenter, SppPoint pEnd, SppPoint pCorner, SppPoint pOtherCorner, int fLineEnd, int xOrg, int yOrg, double xFtrans, double yFtrans);
289 
290 /* internal functions that don't do painting of pixels */
291 static double angleBetween (SppPoint center, SppPoint point1, SppPoint point2);
292 static double miDasin (double v);
293 static double miDatan2 (double dy, double dx);
294 static double miDcos (double a);
295 static double miDsin (double a);
296 static int computeAngleFromPath (int startAngle, int endAngle, const dashMap *map, int *lenp, bool backwards);
297 static int miGetArcPts (const SppArc *parc, int cpt, SppPoint **ppPts);
298 static miArcData * addArc (miPolyArcs *polyArcs, const miArc *xarc);
299 static miArcSpanData * miComputeWideEllipse (unsigned int lw, const miArc *parc, bool *mustFree, miEllipseCache *ellipseCache);
300 static miPolyArcs * miComputeArcs (const miGC *pGC, const miArc *parcs, int narcs);
301 static void addCap (miPolyArcs *polyArcs, int end, int arcIndex);
302 static void addJoin (miPolyArcs *polyArcs, int end0, int index0, int paintType0, int end1, int index1, int paintType1);
303 static void computeDashMap (const miArc *arcp, dashMap *map);
304 static void drawArc (miAccumSpans *accumSpans, const miArc *tarc, unsigned int l, int a0, int a1, miArcFace *right, miArcFace *left, miEllipseCache *ellipseCache);
305 static void drawZeroArc (miAccumSpans *accumSpans, const miArc *tarc, unsigned int lw, miArcFace *left, miArcFace *right);
306 static void initAccumSpans (miAccumSpans *accumSpans);
307 static void miArcSegment (const miGC *pGC, miAccumSpans *accumSpans, miArc tarc, miArcFace *right, miArcFace *left, miEllipseCache *ellipseCache);
308 static void miComputeCircleSpans (unsigned int lw, const miArc *parc, miArcSpanData *spdata);
309 static void miComputeEllipseSpans (unsigned int lw, const miArc *parc, miArcSpanData *spdata);
310 static void miFreeArcs (const miGC *pGC, miPolyArcs *arcs);
311 static void translateBounds (miArcFace *b, int x, int y, double fx, double fy);
312 
313 
314 /*
315  * Comments on overall miPolyArc/miPolyArc_r strategy:
316  *
317  * If the arc is zero width and solid, we don't worry about the join style.
318  * To scan-convert wide solid circles, we use a fast integer algorithm.  To
319  * scan-convert wide solid ellipses, we use special case floating point
320  * code.
321  *
322  * The scan-conversion of wide circles and ellipse is comparatively
323  * trivial, though the latter involves some polynomial algebra.  The
324  * greater part of the code deals with chopping circles and ellipses,
325  * rasterized or not, into segments.  This includes dashing.
326  *
327  * This function is the reentrant version, miPolyArc_r.  The non-reentrant
328  * version, miPolyArc, maintains its own `rasterized ellipse' cache as
329  * static data, and simply calls this one.  */
330 
331 /* ARGS: ellipseCache = pointer to ellipse data cache */
332 void
miPolyArc_r(miPaintedSet * paintedSet,const miGC * pGC,int narcs,const miArc * parcs,miEllipseCache * ellipseCache)333 miPolyArc_r (miPaintedSet *paintedSet, const miGC *pGC, int narcs, const miArc *parcs, miEllipseCache *ellipseCache)
334 {
335   int           i;
336   const miArc   *parc;
337   int           width;
338   miPixel	pixel;
339   miPolyArcs    *polyArcs;
340   int           *cap, *join;
341   int           paintType;
342   miAccumSpans	accumSpans_struct; /* in-core accumulation of spans */
343 
344   /* ensure we have >=1 arcs */
345   if (narcs <= 0)
346     return;
347 
348   /* Initialize miAccumSpans structure (painted to by the low-level drawArc
349      function).  N.B. After drawArc() is repeatedly called to fill up the
350      miAccumSpans struct with spans of a single paint type, fillSpans() is
351      called with the desired paint type as one of its arguments.  It will
352      `paint' from the miAccumSpans struct to the miPaintedSet. */
353   initAccumSpans (&accumSpans_struct);
354 
355   pixel = pGC->pixels[1];	/* default single pixel color to use */
356 
357   width = pGC->lineWidth;
358   if (width == 0 && pGC->lineStyle == (int)MI_LINE_SOLID)
359     /* zero-width solid arcs, only */
360     {
361       for (i = narcs, parc = parcs; --i >= 0; parc++)
362 	/* Draw zero-width arc segment to the miAccumSpans struct, as a set
363 	   of spans, by invoking the low-level drawArc() function.  This
364 	   updates the ellipse span data cache. */
365 	miArcSegment (pGC,
366 		      &accumSpans_struct, *parc,
367 		      (miArcFace *)NULL, (miArcFace *)NULL,
368 		      ellipseCache);
369       /* `paint' the arc segments in the miAccumSpans struct (i.e. add them
370 	 to the miPaintedSet struct), in the current pixel color */
371       fillSpans (paintedSet, pixel, &accumSpans_struct);
372     }
373   else				/* nonzero width, or dashing */
374     {
375       if ((pGC->lineStyle == (int)MI_LINE_SOLID) && narcs)
376 	{
377 	  /* first, paint any initial complete ellipses (for speed) */
378 	  while (parcs->width && parcs->height
379 		 && (parcs->angle2 >= FULLCIRCLE ||
380 		     parcs->angle2 <= -FULLCIRCLE))
381 	    {
382 	      /* paint complete ellipse without going through the
383                  miAccumSpans struct, also update ellipse span data cache */
384 	      miFillWideEllipse (paintedSet, pixel, pGC,
385 				 parcs, ellipseCache);
386 	      if (--narcs == 0)
387 		return;
388 	      parcs++;
389 	    }
390 	}
391 
392       /* have one or more elliptic arcs that are incomplete ellipses
393          (possibly dashed, possibly contiguous) to draw */
394 
395       /* compute arc segments (i.e. dashes) in the incomplete ellipses,
396 	 indexed by color; will need to be freed with miFreeArcs() */
397       polyArcs = miComputeArcs (pGC, parcs, narcs);
398 
399       cap = (int *) mi_xmalloc (pGC->numPixels * sizeof(int));
400       join = (int *) mi_xmalloc (pGC->numPixels * sizeof(int));
401       for (i = 0; i < pGC->numPixels; i++)
402 	cap[i] = join[i] = 0;
403 
404       /* iterate over colors, drawing arc segments in each color */
405       for (paintType = 0; paintType < pGC->numPixels; paintType++)
406 	{
407 	  pixel = pGC->pixels[paintType];
408 	  for (i = 0; i < polyArcs[paintType].narcs; i++)
409 	    {
410 	      miArcData *arcData;
411 
412 	      /* Draw an arc segment to the miAccumSpans struct, via
413 		 drawArc() */
414 	      arcData = &polyArcs[paintType].arcs[i];
415 	      miArcSegment (pGC,
416 			    &accumSpans_struct, arcData->arc,
417 			    &arcData->bounds[RIGHT_END],
418 			    &arcData->bounds[LEFT_END],
419 			    ellipseCache);
420 	      if (polyArcs[paintType].arcs[i].render)
421 		{
422 		  /* `paint' the arc, and any arcs previously drawn to
423 		     the miAccumSpans struct but not painted, to the
424 		     miPaintedSet struct, in the current pixel color */
425 		  fillSpans (paintedSet, pixel, &accumSpans_struct);
426 
427 		  /* `paint' all undrawn caps to the miPaintedSet struct */
428 
429 		  /* test for self-joining arcs (won't be capped) */
430 		  if (polyArcs[paintType].arcs[i].selfJoin
431 		      && cap[paintType] < polyArcs[paintType].arcs[i].cap)
432 		    cap[paintType]++;
433 		  while (cap[paintType] < polyArcs[paintType].arcs[i].cap)
434 		    {
435 		      int	arcIndex, end;
436 		      miArcData *arcData0;
437 
438 		      arcIndex = polyArcs[paintType].caps[cap[paintType]].arcIndex;
439 		      end = polyArcs[paintType].caps[cap[paintType]].end;
440 		      arcData0 = &polyArcs[paintType].arcs[arcIndex];
441 		      /* `paint' cap to the miPaintedSet struct by invoking
442                          miFillSppPoly() */
443 		      miArcCap (paintedSet, pixel, pGC,
444 				&arcData0->bounds[end], end,
445 				arcData0->arc.x, arcData0->arc.y,
446 				(double)(0.5 * arcData0->arc.width),
447 				(double)(0.5 * arcData0->arc.height));
448 		      ++cap[paintType];
449 		    }
450 
451 		  /* `paint' all undrawn joins to the miPaintedSet struct */
452 
453 		  while (join[paintType] < polyArcs[paintType].arcs[i].join)
454 		    {
455 		      int	arcIndex0, arcIndex1, end0, end1;
456 		      int	paintType0, paintType1;
457 		      miArcData *arcData0, *arcData1;
458 		      miArcJoinStruct *joinp;
459 
460 		      joinp = &polyArcs[paintType].joins[join[paintType]];
461 		      arcIndex0 = joinp->arcIndex0;
462 		      end0 = joinp->end0;
463 		      arcIndex1 = joinp->arcIndex1;
464 		      end1 = joinp->end1;
465 		      paintType0 = joinp->paintType0;
466 		      paintType1 = joinp->paintType1;
467 		      arcData0 = &polyArcs[paintType0].arcs[arcIndex0];
468 		      arcData1 = &polyArcs[paintType1].arcs[arcIndex1];
469 		      /* `paint' join to the miPaintedSet struct by invoking
470                          miFillSppPoly() */
471 		      miArcJoin (paintedSet, pixel, pGC,
472 				 &arcData0->bounds[end0],
473 				 &arcData1->bounds[end1],
474 				 arcData0->arc.x, arcData0->arc.y,
475 				 (double) (0.5 * arcData0->arc.width),
476 				 (double) (0.5 * arcData0->arc.height),
477 				 arcData1->arc.x, arcData1->arc.y,
478 				 (double) (0.5 * arcData1->arc.width),
479 				 (double) (0.5 * arcData1->arc.height));
480 		      ++join[paintType];
481 		    }
482 		}
483 	    }
484 
485 	}
486       free (cap);
487       free (join);
488 
489       /* free arc segments computed by miComputeArcs() */
490       miFreeArcs (pGC, polyArcs);
491     }
492 }
493 
494 #ifndef NO_NONREENTRANT_POLYARC_SUPPORT
495 /* The non-reentrant version of miPolyArc, which unlike miPolyArc_r
496    maintains its own ellipse spans cache as static (persistent) data. */
497 void
miPolyArc(miPaintedSet * paintedSet,const miGC * pGC,int narcs,const miArc * parcs)498 miPolyArc (miPaintedSet *paintedSet, const miGC *pGC, int narcs, const miArc *parcs)
499 {
500   if (_mi_ellipseCache == (miEllipseCache *)NULL)
501     _mi_ellipseCache = miNewEllipseCache ();
502   miPolyArc_r (paintedSet, pGC, narcs, parcs, _mi_ellipseCache);
503 }
504 #endif /* not NO_NONREENTRANT_POLYARC_SUPPORT */
505 
506 /* Initialize a cache of rasterized elliptic arcs.  (A pointer to such an
507    object is passed to miPolyArc_r.)  Such a cache comprises an array of
508    records (i.e. cachedEllipse's), a pointer to one of them (the most
509    recently used), and a timestamp variable that is incremented when any
510    record is cached.  `Replace least recently used' is the policy. */
511 miEllipseCache *
miNewEllipseCache(void)512 miNewEllipseCache (void)
513 {
514   int k;
515   cachedEllipse *chead, *cent;
516   miEllipseCache *ellipseCache;
517 
518   ellipseCache = (miEllipseCache *)mi_xmalloc (sizeof(miEllipseCache));
519 
520   /* pointer to beginning of array of records */
521   ellipseCache->ellipses = (cachedEllipse *)mi_xmalloc (ELLIPSECACHE_SIZE * sizeof(cachedEllipse));
522   /* length of array */
523   ellipseCache->size = ELLIPSECACHE_SIZE;
524   /* pointer to beginning of last-accessed record (a dummy value) */
525   ellipseCache->lastCacheHit = ellipseCache->ellipses;
526   /* clock for timestamping */
527   ellipseCache->lrustamp = 0;
528 
529   /* initialize elements of each record with null/bogus values */
530   chead = ellipseCache->ellipses;
531   for (k = ELLIPSECACHE_SIZE, cent = chead; --k >= 0; cent++)
532     {
533       cent->lrustamp = 0;
534       cent->lw = 0;
535       cent->width = cent->height = 0;
536       cent->spdata = (miArcSpanData *)NULL;
537     }
538 
539   return ellipseCache;
540 }
541 
542 /* Free a cache of rasterized ellipses, which must previously have been
543    allocated by invoking miNewEllipseCache. */
544 void
miDeleteEllipseCache(miEllipseCache * ellipseCache)545 miDeleteEllipseCache (miEllipseCache *ellipseCache)
546 {
547   int k, cache_size;
548   cachedEllipse *chead, *cent;
549 
550   /* free span data in all records */
551   chead = ellipseCache->ellipses;
552   cache_size = ellipseCache->size;
553   for (k = cache_size, cent = chead; --k >= 0; cent++)
554     {
555       miArcSpanData *spdata;
556 
557       spdata = cent->spdata;
558       if (spdata)
559 	{
560 	  free (spdata->spans);
561 	  free (spdata);
562 	}
563     }
564   /* free the record array itself */
565   free (chead);
566 
567   /* free pointer */
568   free (ellipseCache);
569 }
570 
571 /* Draw a single arc segment to an miAccumSpans struct, via drawArc() or
572  * drawZeroArc().  Right and left faces may be specified, for mirroring
573  * purposes (they're usually computed by miComputeArcs()).  The
574  * accumulation of spans in the miAccumSpans struct will need to be painted
575  * by a later invocation of fillSpans().  This function updates the ellipse
576  * span cache. */
577 static void
miArcSegment(const miGC * pGC,miAccumSpans * accumSpans,miArc tarc,miArcFace * right,miArcFace * left,miEllipseCache * ellipseCache)578 miArcSegment (const miGC *pGC, miAccumSpans *accumSpans, miArc tarc, miArcFace *right, miArcFace *left, miEllipseCache *ellipseCache)
579 {
580   unsigned int l = pGC->lineWidth;
581   int a0, a1, startAngle, endAngle;
582   miArcFace *temp;
583 
584   if (l == 0)			/* map zero width to unit width */
585     l = 1;
586 
587   if (tarc.width == 0 || tarc.height == 0)
588     {
589       /* degenerate case, either horizontal or vertical arc */
590       drawZeroArc (accumSpans, &tarc, l, left, right);
591       return;
592     }
593 
594   a0 = tarc.angle1;
595   a1 = tarc.angle2;
596   if (a1 > FULLCIRCLE)
597     a1 = FULLCIRCLE;
598   else if (a1 < -FULLCIRCLE)
599     a1 = -FULLCIRCLE;
600   if (a1 < 0)
601     {
602       startAngle = a0 + a1;
603       endAngle = a0;
604       temp = right;
605       right = left;
606       left = temp;
607     }
608   else
609     {
610       startAngle = a0;
611       endAngle = a0 + a1;
612     }
613   /*
614    * bounds check the two angles
615    */
616   if (startAngle < 0)
617     startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE;
618   if (startAngle >= FULLCIRCLE)
619     startAngle = startAngle % FULLCIRCLE;
620   if (endAngle < 0)
621     endAngle = FULLCIRCLE - (-endAngle) % FULLCIRCLE;
622   if (endAngle > FULLCIRCLE)
623     endAngle = (endAngle-1) % FULLCIRCLE + 1;
624   if ((startAngle == endAngle) && a1)
625     {
626       startAngle = 0;
627       endAngle = FULLCIRCLE;
628     }
629 
630   /* Draw the arc to memory, as a set of spans (accumulated spans must
631      later be painted and deallocated by invoking fillSpans()).  This
632      updates the ellipse span cache. */
633   drawArc (accumSpans,
634 	   &tarc, l, startAngle, endAngle, right, left,
635 	   ellipseCache);
636 }
637 
638 /* Paint a wide, complete [i.e. undashed] ellipse, immediately.  I.e.,
639    paint it to a miPaintedSet, not to an in-core miAccumSpans struct.
640    Called by miPolyArc if angle is at least 360 degrees.  Calls
641    miComputeWideEllipse(), and updates the ellipse span cache. */
642 static void
miFillWideEllipse(miPaintedSet * paintedSet,miPixel pixel,const miGC * pGC,const miArc * parc,miEllipseCache * ellipseCache)643 miFillWideEllipse (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, const miArc *parc, miEllipseCache *ellipseCache)
644 {
645   miArcSpanData *spdata;
646   bool mustFree;
647   miArcSpan *arcSpan, *finalArcSpan;
648   int xorg, yorgu, yorgl;
649   int numArcSpans, n;
650   int numSpans_downward, numSpans_upward, numSpans, botSpans;
651   miPoint *pptInit, *ppt_downward, *ppt_upward;
652   unsigned int *pwidthInit, *pwidth_downward, *pwidth_upward;
653 
654   /* Compute span data for whole wide ellipse, updating the ellipse cache.
655      Return value will be a pointer to a miArcSpanData struct, which is
656      basically an array of miArcSpan's indexed by y.  A miArcSpan comprises
657      one or two spans. */
658   spdata = miComputeWideEllipse (pGC->lineWidth, parc, &mustFree, ellipseCache);
659   if (!spdata)
660     /* unknown failure, so punt */
661     return;
662 
663   arcSpan = spdata->spans;	/* first ArcSpan in array */
664 
665   /* initialize upper and lower y values for span generation;
666      note spdata->k = height/2 + (linewidth-1)/2, always */
667   xorg = parc->x + (int)(parc->width >> 1);
668   yorgu = parc->y + (int)(parc->height >> 1);
669   yorgl = yorgu + (parc->height & 1);
670   yorgu -= spdata->k;
671   yorgl += spdata->k;
672 
673   /* Add spans both from top of the ellipse (growing downward from y=yorgu)
674      and from bottom (growing upward from y=yorgl), computed from the
675      (top ? 1 : 0) + count1 + count2 + (bottom ? 1 : 0)
676      ArcSpans contained in spdata->spans.
677 
678      Number of `downward' spans = (top ? 1 : 0) + count1 + 2*count2
679                                   + (bot ? [1or2] : 0)
680      Number of `upward' spans = count1 + (hole ? 1 : 0) + 2*count2
681 
682      Here [1or2] = (finalArcSpan->rw <= 0 ? 1 : 2), where `finalArcSpan' is
683      the final ArcSpan in the array spdata->spans.  These final 1 or 2
684      spans, if present, are on the horizontal centerline of the ellipse.
685 
686      N.B. Presumably
687      (top ? 1 : 0) + count1 + count2 + (bottom ? 1 : 0) <= k+2,
688      since the ArcSpans array spdata->spans can contain at most k+2 ArcSpans,
689      as allocated (see miComputeWideEllipse()). */
690 
691   numArcSpans = ((spdata->top ? 1 : 0) + spdata->count1
692 		 + spdata->count2 + (spdata->bot ? 1 : 0));
693   finalArcSpan = &(spdata->spans[numArcSpans - 1]);
694   botSpans = (finalArcSpan->rw <= 0 ? 1 : 2);
695 
696   numSpans_downward = ((spdata->top ? 1 : 0)
697 		       + spdata->count1 + 2 * spdata->count2
698 		       + (spdata->bot ? botSpans : 0));
699   numSpans_upward = (spdata->count1 + (spdata->hole ? 1 : 0)
700 		     + 2 * spdata->count2);
701   numSpans = numSpans_downward + numSpans_upward;
702 
703   /* allocate span array; will fill it from both ends, so that it will be
704      sorted (i.e. in y-increasing order) */
705   pptInit = (miPoint *)mi_xmalloc (numSpans * sizeof(miPoint));
706   pwidthInit = (unsigned int *)mi_xmalloc (numSpans * sizeof(unsigned int));
707   ppt_downward = pptInit;
708   pwidth_downward = pwidthInit;
709   ppt_upward = pptInit + (numSpans - 1);
710   pwidth_upward = pwidthInit + (numSpans - 1);
711 
712   if (spdata->top)		/* true if width is even and lw is even */
713     /* begin with a special `top point' at y=yorgu-1, rather than at
714        y=yorgu; skip first ArcSpan (it may be bogus) */
715     {
716       ppt_downward->x = xorg;
717       ppt_downward->y = yorgu - 1;
718       ppt_downward++;
719       *pwidth_downward++ = 1;
720       arcSpan++;
721     }
722 
723   for (n = spdata->count1; --n >= 0; )
724     /* Add successive pairs of spans, one upper [beginning at y=yorgu], one
725        lower [beginning at y=yorgl].  Each pair is taken from one of the
726        next count1 ArcSpans in spdata; these ArcSpans are singly occupied.  */
727     {
728       ppt_downward->x = xorg + arcSpan->lx;
729       ppt_downward->y = yorgu;
730       *pwidth_downward = arcSpan->lw;
731       ppt_downward++;
732       pwidth_downward++;
733 
734       ppt_upward->x = xorg + arcSpan->lx;
735       ppt_upward->y = yorgl;
736       *pwidth_upward = arcSpan->lw;
737       ppt_upward--;
738       pwidth_upward--;
739 
740       yorgu++;
741       yorgl--;
742       arcSpan++;
743     }
744 
745   if (spdata->hole)
746     /* Kludge: add a single additional lower point, at x=xorg, y=yorgl (now
747        decremented), i.e. on the vertical center line.  Do not decrement
748        yorgl further, i.e. do not move upward.  (So this extra point will
749        fit between the two spans of the next `upward' ArcSpan to be drawn.)  */
750     {
751       ppt_upward->x = xorg;
752       ppt_upward->y = yorgl;
753       *pwidth_upward = 1;
754       ppt_upward--;
755       pwidth_upward--;
756     }
757 
758   for (n = spdata->count2; --n >= 0; )
759     /* add four spans, two above, two below (each quad taken from one of
760        the next count2 ArcSpans in spdata; these ArcSpans are doubly
761        occupied, containing both a left and a right span) */
762     {
763       /* left downward span */
764       ppt_downward->x = xorg + arcSpan->lx;
765       ppt_downward->y = yorgu;
766       *pwidth_downward = arcSpan->lw;
767       ppt_downward++;
768       pwidth_downward++;
769       /* right downward span */
770       ppt_downward->x = xorg + arcSpan->rx;
771       ppt_downward->y = yorgu;
772       *pwidth_downward = arcSpan->rw;
773       ppt_downward++;
774       pwidth_downward++;
775       /* left upward span */
776       ppt_upward->x = xorg + arcSpan->lx;
777       ppt_upward->y = yorgl;
778       *pwidth_upward = arcSpan->lw;
779       ppt_upward--;
780       pwidth_upward--;
781       /* right upward span */
782       ppt_upward->x = xorg + arcSpan->rx;
783       ppt_upward->y = yorgl;
784       *pwidth_upward = arcSpan->rw;
785       ppt_upward--;
786       pwidth_upward--;
787 
788       yorgu++;
789       yorgl--;
790       arcSpan++;
791     }
792 
793   if (spdata->bot)		/* true if height is even */
794     /* To complete the ellipse, add 1 or 2 additional `upper' spans, at
795        y=yorgu (incremented, i.e. it is now at the horizontal center line,
796        which is at y = yorg_arc + height_arc/2).  The number of spans will
797        be 2 rather than 1, unless the ellipse is not hollow. */
798     {
799       ppt_downward->x = xorg + arcSpan->lx;
800       ppt_downward->y = yorgu;
801       *pwidth_downward = arcSpan->lw;
802       ppt_downward++;
803       pwidth_downward++;
804 
805       if (arcSpan->rw > 0)
806 	/* have a second span too */
807 	{
808 	  ppt_downward->x = xorg + arcSpan->rx;
809 	  ppt_downward->y = yorgu;
810 	  *pwidth_downward = arcSpan->rw;
811 	  ppt_downward++;
812 	  pwidth_downward++;
813 	}
814     }
815 
816   if (mustFree)			/* free the ArcSpans */
817     {
818       free (spdata->spans);
819       free (spdata);
820     }
821 
822   MI_PAINT_SPANS(paintedSet, pixel, numSpans, pptInit, pwidthInit)
823 }
824 
825 /* Compute the spans that make up a wide complete ellipse, this way: (1)
826    search the cache of rasterized ellipses; if no success, (2) scan-convert
827    the ellipse, and place the spans in the cache for later retrieval, in
828    case another ellipse of the same size and width needs to be drawn.
829 
830    Return value will be a pointer to a miArcSpanData struct, which is
831    basically an array of miArcSpan's indexed by y.  A miArcSpan comprises
832    lx, lwidth, rx, rwidth, i.e., a pair of spans at a given y.  `mustFree'
833    will be set to true if the miArcSpanData struct is a one-shot creation,
834    not stored in the cache.  (This is the case if the ellipse is too large
835    to be stored in the cache -- a policy issue.)
836 
837    Called by the low-level draw-to-memory function drawArc(), and also by
838    miFillWideEllipse(), which paints an entire wide ellipse.  This function
839    calls either miComputeEllipseSpans() or miComputeCircleSpans() to do the
840    actual computation of spans, i.e. to do scan conversion.  */
841 
842 static miArcSpanData *
miComputeWideEllipse(unsigned int lw,const miArc * parc,bool * mustFree,miEllipseCache * ellipseCache)843 miComputeWideEllipse (unsigned int lw, const miArc *parc, bool *mustFree, miEllipseCache *ellipseCache)
844 {
845   miArcSpanData *spdata;
846   cachedEllipse *cent, *lruent;
847   int k, cache_size;
848   cachedEllipse fakeent;
849 
850   /* map zero line width to width unity */
851   if (lw == 0)
852     lw = 1;
853 
854   /* first, attempt to retrieve span data from cache */
855   if (parc->height <= MAX_CACHEABLE_ELLIPSE_HEIGHT)
856     {
857       *mustFree = false;
858       cent = ellipseCache->lastCacheHit;
859       if (cent->lw == lw
860 	  && cent->width == parc->width && cent->height == parc->height)
861 	/* last hit is still valid; won't need to search */
862 	{
863 	  /* hit again; do timestamp, bumping time */
864 	  cent->lrustamp = ++(ellipseCache->lrustamp);
865 	  return cent->spdata;
866 	}
867       /* search cache (an array), beginning at 0'th element */
868       lruent = ellipseCache->ellipses;
869       cache_size = ellipseCache->size;
870       for (k = cache_size, cent = lruent; --k >= 0; cent++)
871 	{
872 	  /* key on width, height, linewidth */
873 	  if (cent->lw == lw
874 	      && cent->width == parc->width && cent->height == parc->height)
875 	    /* already in cache: a hit */
876 	    {
877 	      /* do timestamp, bumping time */
878 	      cent->lrustamp = ++(ellipseCache->lrustamp);
879 	      ellipseCache->lastCacheHit = cent;
880 	      return cent->spdata;
881 	    }
882 	  /* keep track of least recently used record */
883 	  if (cent->lrustamp < lruent->lrustamp)
884 	    lruent = cent;
885 	}
886     }
887   else /* height is huge, ellipse wouldn't be stored in cache */
888     {
889       lruent = &fakeent;	/* _very_ fake; automatic variable */
890       lruent->spdata = (miArcSpanData *)NULL;
891       *mustFree = true;
892     }
893 
894   /* data not found in cache, so boot least-recently used record out of
895      cache, make new one; unless ellipse is too large, that is */
896 
897   spdata = lruent->spdata;
898   /* will allocate space for k+2 spans */
899   k = (int)(parc->height >> 1) + (int)((lw - 1) >> 1);
900   if (spdata == (miArcSpanData *)NULL || spdata->k != k)
901     {
902       if (spdata)
903 	{
904 	  free (spdata->spans);
905 	  free (spdata);
906 	}
907       spdata = (miArcSpanData *)mi_xmalloc (sizeof(miArcSpanData));
908       spdata->spans = (miArcSpan *)mi_xmalloc ((k + 2) * sizeof (miArcSpan));
909       spdata->k = k;		/* k+2 is size of empty span array */
910       lruent->spdata = spdata;
911     }
912   lruent->lrustamp = ++(ellipseCache->lrustamp);	/* set timestamp, bump clock */
913   lruent->lw = lw;
914   lruent->width = parc->width;
915   lruent->height = parc->height;
916   if (lruent != &fakeent)	/* non-huge ellipse; store in cache */
917     ellipseCache->lastCacheHit = lruent;
918 
919   /* compute spans, place them in the new cache record */
920   if (parc->width == parc->height)
921     miComputeCircleSpans (lw, parc, spdata);
922   else
923     miComputeEllipseSpans (lw, parc, spdata);
924   return spdata;
925 }
926 
927 /* Compute the spans that make up a complete wide circle, via a fast
928    integer algorithm.  On entry, lw>=1, and `spdata' is a pointer to an
929    miArcSpanData struct, which is a slot in a record in the ellipse span
930    cache.  It includes spdata->spans, an array of k+2 ArcSpans, which will
931    be filled in.  Here k=height/2 + (lw-1)/2. */
932 static void
miComputeCircleSpans(unsigned int lw,const miArc * parc,miArcSpanData * spdata)933 miComputeCircleSpans (unsigned int lw, const miArc *parc, miArcSpanData *spdata)
934 {
935   miArcSpan *span;
936   int doinner;
937   int x, y, e;
938   int xk, yk, xm, ym, dx, dy;
939   int slw, inslw;
940   int inx = 0, iny, ine = 0;
941   int inxk = 0, inyk = 0, inxm = 0, inym = 0;
942 
943   /* compute flags */
944   /* top=true iff ellipse width is even and line width is even */
945   spdata->top = !(lw & 1) && !(parc->width & 1) ? true : false;
946   /* bot=true iff ellipse height is even, so there will be an _odd_
947      number of spans, from top to bottom */
948   spdata->bot = !(parc->height & 1) ? true : false;
949 
950   doinner = -(int)lw;
951   slw = (int)parc->width - doinner;
952   y = (int)(parc->height >> 1);
953   dy = parc->height & 1;	/* dy=1 if height is odd */
954   dx = 1 - dy;			/* dx=1 if height is even */
955   MIWIDEARCSETUP(x, y, dy, slw, e, xk, xm, yk, ym);
956   inslw = (int)parc->width + doinner;
957   if (inslw > 0)
958     {
959       /* if top=true, will need to add an extra pixel (not included in the
960          generated list of ArcSpans) in the `hole'; this is a kludge */
961       spdata->hole = spdata->top;
962       MIWIDEARCSETUP(inx, iny, dy, inslw, ine, inxk, inxm, inyk, inym);
963     }
964   else
965     {
966       spdata->hole = false;
967       doinner = -y;
968     }
969 
970   /* Generate the ArcSpans at successive values of y, beginning at the top
971      of the circle and extending down to its horizontal bisector.  Also,
972      fill in the count1/count2/top/bottom elements of the miArcSpanData
973      struct pointed to by spdata.  There will be
974 
975      (top ? 1 : 0) + count1 + count2 + (bottom ? 1 : 0)
976 
977      ArcSpans in all.  The first ones [(top ? 1 : 0) + count1 in number]
978      will be single-occupied, i.e., they will include only one span.
979      The latter ones [count2 + (bottom ? 1 : 0) in number]
980      will be doubly-occupied, i.e., they will include two spans.
981 
982      For the special role of the very first and very last ArcSpans in the
983      list, to fix which the `top' and `bottom' kludge flags were
984      introduced, see following comments. */
985 
986   /* If top=true, first ArcSpan generated by the following `while' loop
987      will be bogus, and will need to be replaced, when drawing, by a single
988      point.  So decrement count1 to compensate. */
989   spdata->count1 = -doinner - (spdata->top ? 1 : 0);
990   spdata->count2 = y + doinner;
991 
992   span = spdata->spans;
993   /* initial value of y is (width+lw)/2 + (1 if height is even) */
994   while (y)
995     {
996       MIFILLARCSTEP(x, y, e, xk, xm, yk, ym, dx, slw); /* y-- */
997       span->lx = dy - x;
998       if (++doinner <= 0)
999  	{
1000 	  span->lw = slw;
1001 	  span->rx = 0;
1002 	  span->rw = span->lx + slw;
1003 	}
1004       else
1005 	{
1006 	  MIFILLINARCSTEP(inx, iny, ine, inxk, inxm, inyk, inym, dx, inslw);
1007 	  span->lw = x - inx;
1008 	  span->rx = dy - inx + inslw;
1009 	  span->rw = inx - x + slw - inslw;
1010 	}
1011       span++;
1012     }
1013 
1014   if (spdata->bot)
1015     /* last-generated ArcSpan, on the horizontal center line, is special,
1016        so modify it and decrement count2 (or count1) to compensate */
1017     {
1018       if (spdata->count2 > 0)
1019 	spdata->count2--;
1020       else
1021 	/* no two-span ArcSpans at all; ellipse isn't hollow */
1022 	{
1023 	  if (lw > parc->height)
1024 	    span[-1].rx = span[-1].rw = -(((int)lw - (int)parc->height) >> 1);
1025 	  else
1026 	    span[-1].rw = 0;
1027 	  spdata->count1--;
1028 	}
1029     }
1030 }
1031 
1032 
1033 /*
1034 The following mathematics is the background for the algorithm used in
1035 miComputeEllipseSpans() below, which scan-converts a wide ellipse.
1036 
1037 The following three equations combine to describe the boundaries of a wide
1038 ellipse, if it is drawn with a circular brush.
1039 
1040  x^2/w^2 + y^2/h^2 = 1			ellipse itself
1041  (X-x)^2 + (Y-y)^2 = r^2		circle at (x, y) on the ellipse
1042  (Y-y) = (X-x)*w^2*y/(h^2*x)		normal at (x, y) on the ellipse
1043 
1044 These lead to a quartic relating Y and y
1045 
1046 y^4 - (2Y)y^3 + (Y^2 + (h^4 - w^2*r^2)/(w^2 - h^2))y^2
1047     - (2Y*h^4/(w^2 - h^2))y + (Y^2*h^4)/(w^2 - h^2) = 0
1048 
1049 The reducible cubic obtained from this quartic is
1050 
1051 z^3 - (3N)z^2 - 2V = 0
1052 
1053 where
1054 
1055 N = (Y^2 + (h^4 - w^2*r^2/(w^2 - h^2)))/6
1056 V = w^2*r^2*Y^2*h^4/(4 *(w^2 - h^2)^2)
1057 
1058 Let
1059 
1060 t = z - N
1061 p = -N^2
1062 q = -N^3 - V
1063 
1064 Then we get
1065 
1066 t^3 + 3pt + 2q = 0
1067 
1068 The discriminant of this cubic is
1069 
1070 D = q^2 + p^3
1071 
1072 When D > 0, a real root is obtained as
1073 
1074 z = N + cbrt(-q+sqrt(D)) + cbrt(-q-sqrt(D))
1075 
1076 When D < 0, a real root is obtained as
1077 
1078 z = N - 2m*cos(acos(-q/m^3)/3)
1079 
1080 where
1081 
1082 m = sqrt(|p|) * sign(q)
1083 
1084 Given a real root Z of the cubic, the roots of the quartic are the roots
1085 of the two quadratics
1086 
1087 y^2 + ((b+A)/2)y + (Z + (bZ - d)/A) = 0
1088 
1089 where
1090 
1091 A = +/- sqrt(8Z + b^2 - 4c)
1092 b, c, d are the cubic, quadratic, and linear coefficients of the quartic
1093 
1094 Some experimentation is then required to determine which solutions
1095 correspond to the inner and outer boundaries of the wide ellipse.  */
1096 
1097 
1098 /* Compute the spans that make up a complete wide ellipse, via a floating
1099    point algorithm motivated by the above math.  On entry, lw>=1, and
1100    `spdata' is a pointer to an miArcSpanData struct, which is a slot in a
1101    record in the ellipse span cache.  It includes spdata->spans, an array
1102    of k+2 ArcSpans, which will be filled in.  Here
1103    k=height/2 + (lw-1)/2. */
1104 static void
miComputeEllipseSpans(unsigned int lw,const miArc * parc,miArcSpanData * spdata)1105 miComputeEllipseSpans (unsigned int lw, const miArc *parc, miArcSpanData *spdata)
1106 {
1107   miArcSpan *span;
1108   double w, h, r, xorg;
1109   double Hs, Hf, WH, K, Vk, Nk, Fk, Vr, N, Nc, Z, rs;
1110   double A, T, b, d, x, y, t, inx, outx = 0, hepp, hepm;
1111   int flip;
1112   bool solution;
1113 
1114   /* compute flags */
1115   /* top=true iff ellipse width is even and line width is even */
1116   spdata->top = !(lw & 1) && !(parc->width & 1) ? true : false;
1117   /* bot=true iff ellipse height is even, so there will be an _odd_
1118      number of spans, from top to bottom */
1119   spdata->bot = !(parc->height & 1) ? true : false;
1120   /* a kludge */
1121   spdata->hole = ((spdata->top
1122 		   && parc->height * lw <= parc->width * parc->width
1123 		   && lw < parc->height) ? true : false);
1124 
1125   w = 0.5 * parc->width;
1126   h = 0.5 * parc->height;
1127   r = 0.5 * lw;
1128   rs = r * r;
1129   Hs = h * h;
1130   WH = w * w - Hs;
1131   Nk = w * r;
1132   Vk = (Nk * Hs) / (WH + WH);
1133   Hf = Hs * Hs;
1134   Nk = (Hf - Nk * Nk) / WH;
1135   Fk = Hf / WH;
1136   hepp = h + EPSILON;
1137   hepm = h - EPSILON;
1138   K = h + ((lw - 1) >> 1);
1139   if (parc->width & 1)
1140     xorg = .5;
1141   else
1142     xorg = 0.0;
1143   spdata->count1 = 0;
1144   spdata->count2 = 0;
1145 
1146   /* Generate list of spans, going downward from top of ellipse,
1147      i.e. more or less at y = yorgu = yorg_arc + height_arc/2 - k.
1148      Most of these will be mirrored, going upward from the bottom
1149      of the ellipse, starting at y = yorgu = yorg_arc + height_arc/2 + k. */
1150   span = spdata->spans;
1151 
1152   if (spdata->top)
1153     /* top=true if ellipse width is even and line width is even; if so,
1154        begin with a special (non-mirrored) ArcSpan containing a single `top
1155        point', at y=yorgu-1 */
1156     {
1157       span->lx = 0;
1158       span->lw = 1;
1159       span++;
1160     }
1161 
1162   /* generate count1 + count2 ArcSpans, at y=yorgu, y=yorgu+1,...;
1163      count1 one-span ArcSpans come first, then count2 two-span ArcSpans */
1164   for (; K > 0.0; K -= 1.0)
1165     {
1166       N = (K * K + Nk) / 6.0;
1167       Nc = N * N * N;
1168       Vr = Vk * K;
1169       t = Nc + Vr * Vr;
1170       d = Nc + t;
1171       if (d < 0.0)
1172 	{
1173 	  d = Nc;
1174 	  b = N;
1175 	  if ( (b < 0.0) == (t < 0.0) )
1176 	    {
1177 	      b = -b;
1178 	      d = -d;
1179 	    }
1180 	  Z = N - 2.0 * b * cos(acos(-t / d) / 3.0);
1181 	  if ( (Z < 0.0) == (Vr < 0.0) )
1182 	    flip = 2;
1183 	  else
1184 	    flip = 1;
1185 	}
1186       else
1187 	{
1188 	  d = Vr * sqrt(d);
1189 	  Z = N + cbrt(t + d) + cbrt(t - d);
1190 	  flip = 0;
1191 	}
1192       A = sqrt((Z + Z) - Nk);
1193       T = (Fk - Z) * K / A;
1194       inx = 0.0;
1195       solution = false;
1196       b = -A + K;
1197       d = b * b - 4 * (Z + T);
1198       if (d >= 0)
1199 	{
1200 	  d = sqrt(d);
1201 	  y = 0.5 * (b + d);
1202 	  if ((y >= 0.0) && (y < hepp))
1203 	    {
1204 	      solution = true;
1205 	      if (y > hepm)
1206 		y = h;
1207 	      t = y / h;
1208 	      x = w * sqrt(1 - (t * t));
1209 	      t = K - y;
1210 	      t = sqrt(rs - (t * t));
1211 	      if (flip == 2)
1212 		inx = x - t;
1213 	      else
1214 		outx = x + t;
1215 	    }
1216 	}
1217       b = A + K;
1218       d = b * b - 4 * (Z - T);
1219       /* Because of the large magnitudes involved, we lose enough precision
1220        * that sometimes we end up with a negative value near the axis, when
1221        * it should be positive.  This is a workaround.
1222        */
1223       if (d < 0 && !solution)
1224 	d = 0.0;
1225       if (d >= 0)
1226 	{
1227 	  d = sqrt(d);
1228 	  y = 0.5 * (b + d);
1229 	  if (y < hepp)
1230 	    {
1231 	      if (y > hepm)
1232 		y = h;
1233 	      t = y / h;
1234 	      x = w * sqrt(1 - (t * t));
1235 	      t = K - y;
1236 	      inx = x - sqrt(rs - (t * t));
1237 	    }
1238 	  y = 0.5 * (b - d);
1239 	  if (y >= 0.0)
1240 	    {
1241 	      if (y > hepm)
1242 		y = h;
1243 	      t = y / h;
1244 	      x = w * sqrt(1 - (t * t));
1245 	      t = K - y;
1246 	      t = sqrt(rs - (t * t));
1247 	      if (flip == 1)
1248 		inx = x - t;
1249 	      else
1250 		outx = x + t;
1251 	    }
1252 	}
1253       span->lx = ICEIL(xorg - outx);
1254       if (inx <= 0.0)
1255 	{
1256 	  /* a one-span ArcSpan (they come first) */
1257 	  spdata->count1++;
1258 	  span->lw = ICEIL(xorg + outx) - span->lx;
1259 	  span->rx = ICEIL(xorg + inx);
1260 	  span->rw = -ICEIL(xorg - inx);
1261 	}
1262       else
1263 	{
1264 	  /* a two-span ArcSpan (they come second) */
1265 	  spdata->count2++;
1266 	  span->lw = ICEIL(xorg - inx) - span->lx;
1267 	  span->rx = ICEIL(xorg + inx);
1268 	  span->rw = ICEIL(xorg + outx) - span->rx;
1269 	}
1270       span++;
1271     }
1272 
1273   if (spdata->bot)
1274     /* bot=true if ellipse height is even; if so, complete the ellipse by
1275        adding a final ArcSpan at the horizontal center line, containing
1276        either two spans or one span (if the ellipse isn't hollow) */
1277     {
1278       outx = w + r;
1279       if (r >= h && r <= w)
1280 	inx = 0.0;
1281       else if (Nk < 0.0 && -Nk < Hs)
1282 	{
1283 	  inx = w * sqrt(1 + Nk / Hs) - sqrt(rs + Nk);
1284 	  if (inx > w - r)
1285 	    inx = w - r;
1286 	}
1287       else
1288 	inx = w - r;
1289       span->lx = ICEIL(xorg - outx);
1290       if (inx <= 0.0)
1291 	{
1292 	  span->lw = ICEIL(xorg + outx) - span->lx;
1293 	  span->rx = ICEIL(xorg + inx);
1294 	  span->rw = -ICEIL(xorg - inx);
1295 	}
1296       else
1297 	{
1298 	  span->lw = ICEIL(xorg - inx) - span->lx;
1299 	  span->rx = ICEIL(xorg + inx);
1300 	  span->rw = ICEIL(xorg + outx) - span->rx;
1301 	}
1302     }
1303 
1304   if (spdata->hole)
1305     /* convert the final one-span ArcSpan to the initial two-span ArcSpan,
1306        so that there will be a one-pixel `hole' to be filled */
1307     {
1308       span = &spdata->spans[spdata->count1];
1309       span->lw = -span->lx;
1310       span->rx = 1;
1311       span->rw = span->lw;
1312       spdata->count1--;
1313       spdata->count2++;
1314     }
1315 }
1316 
1317 
1318 /**********************************************************************/
1319 /* miComputeArcs() and miFreeArcs(), called by miPolyArc(). */
1320 /**********************************************************************/
1321 
1322 /* Compute arc segments, caps, and joins in a polyarc, taking account of
1323    dashing.  Return value is a list of miPolyArcs structs, indexed by pixel
1324    paint type, which will need to be freed with miFreeArcs().  If dashing,
1325    sub-pixel placement of arc segment endpoints will normally occur. */
1326 
1327 static miPolyArcs *
miComputeArcs(const miGC * pGC,const miArc * parcs,int narcs)1328 miComputeArcs (const miGC *pGC, const miArc *parcs, int narcs)
1329 {
1330   bool		isDashed, isDoubleDash;
1331   miPolyArcs	*arcs;
1332   int		i, start, k, nextk;
1333   miArcData	*data;
1334   int		numPixels;
1335   int		paintType, paintTypeStart, prevPaintType;
1336   int	        dashNum, dashIndex, dashRemaining;
1337   int		dashNumStart, dashIndexStart, dashRemainingStart;
1338 
1339   isDashed = (pGC->lineStyle == (int)MI_LINE_SOLID ? false : true);
1340   isDoubleDash = (pGC->lineStyle == (int)MI_LINE_DOUBLE_DASH ? true : false);
1341   numPixels = pGC->numPixels;
1342 
1343   /* allocate and initialize list of miPolyArcs that will be returned */
1344   arcs = (miPolyArcs *) mi_xmalloc (numPixels * sizeof(miPolyArcs));
1345   for (paintType = 0; paintType < numPixels; paintType++)
1346     {
1347       arcs[paintType].arcs = (miArcData *)NULL;
1348       arcs[paintType].narcs = 0;
1349       arcs[paintType].arcSize = 0; /* slots allocated */
1350 
1351       arcs[paintType].caps = (miArcCapStruct *)NULL;
1352       arcs[paintType].ncaps = 0;
1353       arcs[paintType].capSize = 0; /* slots allocated */
1354 
1355       arcs[paintType].joins = (miArcJoinStruct *)NULL;
1356       arcs[paintType].njoins = 0;
1357       arcs[paintType].joinSize = 0; /* slots allocated */
1358     }
1359 
1360   /* allocate and fill temporary struct with starting point, ending point,
1361      self-join status of each elliptic arc */
1362 
1363 #define todeg(xAngle)	(((double) (xAngle)) / 64.0)
1364 
1365   data = (miArcData *) mi_xmalloc (narcs * sizeof (miArcData));
1366   for (i = 0; i < narcs; i++)
1367     {
1368       double a0, a1;
1369       int angle2;
1370 
1371       a0 = todeg (parcs[i].angle1);
1372       angle2 = parcs[i].angle2;
1373       if (angle2 > FULLCIRCLE)
1374 	angle2 = FULLCIRCLE;
1375       else if (angle2 < -FULLCIRCLE)
1376 	angle2 = -FULLCIRCLE;
1377       data[i].selfJoin = ((angle2 == FULLCIRCLE) || (angle2 == -FULLCIRCLE)
1378 			  ? true : false);
1379       a1 = todeg (parcs[i].angle1 + angle2);
1380       data[i].x0 = parcs[i].x + (double) parcs[i].width / 2*(1 + miDcos (a0));
1381       data[i].y0 = parcs[i].y + (double) parcs[i].height / 2*(1 - miDsin (a0));
1382       data[i].x1 = parcs[i].x + (double) parcs[i].width / 2*(1 + miDcos (a1));
1383       data[i].y1 = parcs[i].y + (double) parcs[i].height / 2*(1 - miDsin (a1));
1384     }
1385 
1386   /* initialize paint type and dashing state (latter is not used in `solid'
1387      case) */
1388   paintType = 1;
1389   dashNum = 0;
1390   dashIndex = 0;
1391   dashRemaining = 0;
1392   if (isDashed)
1393     /* take offsetting into account */
1394     {
1395       int dashOffset = 0;
1396 
1397       /* alter paint type (for first dash) and dashing state */
1398       miStepDash (pGC->dashOffset, &dashNum, &dashIndex,
1399 		  pGC->dash, pGC->numInDashList, &dashOffset);
1400       paintType = (dashNum & 1) ? 0 : 1 + ((dashNum / 2) % (numPixels - 1));
1401       dashRemaining = (int)(pGC->dash[dashIndex]) - dashOffset;
1402     }
1403   /* save paint type and dashing state (will reset at each unjoined arc) */
1404   paintTypeStart = paintType;
1405   dashNumStart = dashNum;
1406   dashIndexStart = dashIndex;
1407   dashRemainingStart = dashRemaining;
1408 
1409   /* iterate backward over arcs; determine whether cap will be required
1410      after each arc, and stop when first such is seen */
1411   for (i = narcs - 1; i >= 0; i--)
1412     {
1413       int j;
1414 
1415       j = i + 1;
1416       if (j == narcs)
1417 	j = 0;
1418       if (data[i].selfJoin || i == j ||
1419 	  (UNEQUAL (data[i].x1, data[j].x0) ||
1420 	   UNEQUAL (data[i].y1, data[j].y0)))
1421 	{
1422 	  /* if starting in `on' phase, add a cap at right end */
1423 	  if (paintType != 0 || isDoubleDash)
1424 	    addCap (&arcs[paintType], RIGHT_END, 0);
1425 	  break;
1426 	}
1427     }
1428 
1429   /* iterate forward over all successive pairs of arcs (wrap if necessary) */
1430 
1431   start = i + 1;
1432   if (start == narcs)
1433     start = 0;
1434   i = start;
1435   k = nextk = 0;
1436   /* keep compiler happy by initting prevPaintType too; actually
1437      unnecessary because first thing drawn won't be a join */
1438   prevPaintType = paintType;
1439 
1440   for (;;)
1441     {
1442       int j, nexti;
1443       miArcData *arc;
1444       bool arcsJoin;
1445 
1446       j = i + 1;
1447       if (j == narcs)
1448 	j = 0;
1449       nexti = i + 1;
1450       if (nexti == narcs)
1451 	nexti = 0;
1452 
1453       if (isDashed)
1454 	{
1455 	  int		startAngle, spanAngle, endAngle;
1456 	  int		dashAngle, prevDashAngle;
1457 	  bool		backwards, selfJoin;
1458 	  dashMap	map;
1459 	  miArc		xarc;
1460 
1461 	  /*
1462 	   * precompute an approximation map for use in dashing
1463 	   */
1464 	  computeDashMap (&parcs[i], &map);
1465 	  /*
1466 	   * compute each individual dash segment using the path
1467 	   * length function
1468 	   */
1469 	  startAngle = parcs[i].angle1;
1470 	  spanAngle = parcs[i].angle2;
1471 	  if (spanAngle > FULLCIRCLE)
1472 	    spanAngle = FULLCIRCLE;
1473 	  else if (spanAngle < -FULLCIRCLE)
1474 	    spanAngle = -FULLCIRCLE;
1475 	  if (startAngle < 0)
1476 	    startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE;
1477 	  if (startAngle >= FULLCIRCLE)
1478 	    startAngle = startAngle % FULLCIRCLE;
1479 	  endAngle = startAngle + spanAngle;
1480 	  backwards = (spanAngle < 0 ? true : false);
1481 	  dashAngle = startAngle;
1482 	  selfJoin = (data[i].selfJoin && (paintType != 0 || isDoubleDash)
1483 		      ? true : false);
1484 
1485 	  /*
1486 	   * add dashed arcs to each bucket
1487 	   */
1488 	  arc = (miArcData *)NULL;
1489 	  while (dashAngle != endAngle)
1490 	    {
1491 	      prevDashAngle = dashAngle;
1492 	      dashAngle = computeAngleFromPath (prevDashAngle, endAngle, &map,
1493 						&dashRemaining, backwards);
1494 	      /* avoid troubles with huge arcs and small dashes */
1495 	      if (dashAngle == prevDashAngle)
1496 		{
1497 		  if (backwards)
1498 		    dashAngle--;
1499 		  else
1500 		    dashAngle++;
1501 		}
1502 	      if (paintType != 0 || isDoubleDash)
1503 		{
1504 		  xarc = parcs[i];
1505 		  spanAngle = prevDashAngle;
1506 		  if (spanAngle < 0)
1507 		    spanAngle = FULLCIRCLE - (-spanAngle) % FULLCIRCLE;
1508 		  if (spanAngle >= FULLCIRCLE)
1509 		    spanAngle = spanAngle % FULLCIRCLE;
1510 		  xarc.angle1 = spanAngle;
1511 		  spanAngle = dashAngle - prevDashAngle;
1512 		  if (backwards)
1513 		    {
1514 		      if (dashAngle > prevDashAngle)
1515 			spanAngle = - FULLCIRCLE + spanAngle;
1516 		    }
1517 		  else
1518 		    {
1519 		      if (dashAngle < prevDashAngle)
1520 			spanAngle = FULLCIRCLE + spanAngle;
1521 		    }
1522 		  if (spanAngle > FULLCIRCLE)
1523 		    spanAngle = FULLCIRCLE;
1524 		  if (spanAngle < -FULLCIRCLE)
1525 		    spanAngle = -FULLCIRCLE;
1526 		  xarc.angle2 = spanAngle;
1527 		  arc = addArc (&arcs[paintType], &xarc);
1528 		  /*
1529 		   * cap each end of an on/off dash
1530 		   */
1531 		  if (!isDoubleDash)
1532 		    {
1533 		      if (prevDashAngle != startAngle)
1534 			addCap (&arcs[paintType],
1535 				RIGHT_END, arc - arcs[paintType].arcs);
1536 		      if (dashAngle != endAngle)
1537 			addCap (&arcs[paintType],
1538 				LEFT_END, arc - arcs[paintType].arcs);
1539 		    }
1540 		  arc->cap = arcs[paintType].ncaps;
1541 		  arc->join = arcs[paintType].njoins;
1542 		  arc->render = false;
1543 		  arc->selfJoin = false;
1544 		  if (dashAngle == endAngle)
1545 		    arc->selfJoin = selfJoin;
1546 		}
1547 	      prevPaintType = paintType;
1548 	      if (dashRemaining <= 0)
1549 		/* on to next dash (negative means overshoot due to
1550 		   rounding; positive means undershoot due to rounding, in
1551 		   which case we don't bump dashNum or dashIndex, or toggle
1552 		   the dash phase: next dash will have same paint type */
1553 		{
1554 		  dashNum++;
1555 		  dashIndex++;
1556 		  if (dashIndex == pGC->numInDashList) /* wrap */
1557 		    dashIndex = 0;
1558 		  /* recompute paintType, dashRemaining for next dash */
1559 		  paintType =
1560 		    (dashNum & 1) ? 0 : 1 + ((dashNum / 2) % (numPixels - 1));
1561 		  dashRemaining = (int)(pGC->dash[dashIndex]);
1562 		}
1563 	    }
1564 	  /*
1565 	   * make sure a place exists for the position data if
1566 	   * we drew (i.e. didn't draw) a zero-length arc
1567 	   */
1568 	  if (startAngle == endAngle) /* zero-length */
1569 	    {
1570 	      prevPaintType = paintType;
1571 	      if (isDoubleDash == false && paintType == 0)
1572 		/* use color of most recent `on' dash */
1573 		{
1574 		  if (dashNum == 0)
1575 		    prevPaintType = numPixels - 1;
1576 		  else		/* can use infix % operator */
1577 		    prevPaintType =
1578 		      ((dashNum - 1) & 1) ? 0 : 1 + (((dashNum - 1)/ 2) % (numPixels - 1));
1579 		}
1580 	      arc = addArc (&arcs[prevPaintType], &parcs[i]);
1581 	      arc->join = arcs[prevPaintType].njoins;
1582 	      arc->cap = arcs[prevPaintType].ncaps;
1583 	      arc->selfJoin = data[i].selfJoin;
1584 	    }
1585 	}
1586       else
1587 	/* not dashing; just add whole (solid) arc */
1588 	{
1589 	  arc = addArc (&arcs[paintType], &parcs[i]);
1590 	  arc->join = arcs[paintType].njoins;
1591 	  arc->cap = arcs[paintType].ncaps;
1592 	  arc->selfJoin = data[i].selfJoin;
1593 	  prevPaintType = paintType;
1594 	}
1595 
1596       if (prevPaintType != 0 || isDoubleDash)
1597 	k = arcs[prevPaintType].narcs - 1;
1598       if (paintType != 0 || isDoubleDash)
1599 	nextk = arcs[paintType].narcs;
1600 
1601       if (nexti == start)
1602 	{
1603 	  nextk = 0;
1604 	  if (isDashed)
1605 	    /* re-initialize paint type and dashing state */
1606 	    {
1607 	      paintType = paintTypeStart;
1608 	      dashNum = dashNumStart;
1609 	      dashIndex = dashIndexStart;
1610 	      dashRemaining = dashRemainingStart;
1611 	    }
1612 	}
1613 
1614       /* does the successive pair of arcs join? */
1615       arcsJoin = (narcs > 1 && i != j
1616 		  && ISEQUAL (data[i].x1, data[j].x0)
1617 		  && ISEQUAL (data[i].y1, data[j].y0)
1618 		  && data[i].selfJoin == false
1619 		  && data[j].selfJoin == false) ? true : false;
1620       if (arc != (miArcData *)NULL)
1621 	{
1622 	  if (arcsJoin)
1623 	    arc->render = false;
1624 	  else
1625 	    /* no join; so add directive to render first arc */
1626 	    arc->render = true;
1627 	}
1628       if (arcsJoin
1629 	  && (prevPaintType != 0 || isDoubleDash)
1630 	  && (paintType != 0 || isDoubleDash))
1631 	/* arcs join, and both are `on' */
1632 	{
1633 	  int joinPaintType;
1634 
1635 	  joinPaintType = paintType;
1636 	  if (isDoubleDash)
1637 	    {
1638 	      if (nexti == start)
1639 		joinPaintType = paintTypeStart;
1640 	      /* if join is right at the dash and there are two colors to
1641 		 choose from, draw join in a foreground color */
1642 	      if (joinPaintType == 0)
1643 		{
1644 		  if (prevPaintType != 0)
1645 		    joinPaintType = prevPaintType;
1646 		  else  /* shouldn't happen; just use next dash's color */
1647 		    joinPaintType =
1648 		      ((dashNum + 1) & 1) ? 0 : 1 + (((dashNum + 1)/ 2) % (numPixels - 1));
1649 		}
1650 	    }
1651 	  if (joinPaintType != 0 || isDoubleDash)
1652 	    {
1653 	      addJoin (&arcs[joinPaintType],
1654 		       LEFT_END, k, prevPaintType,
1655 		       RIGHT_END, nextk, paintType);
1656 	      arc->join = arcs[prevPaintType].njoins;
1657 	    }
1658 	}
1659       else
1660 	/* arcs don't join (or if they do, at least one is `off') */
1661 	{
1662 	  /*
1663 	   * cap the left end of this arc
1664 	   * unless it joins itself
1665 	   */
1666 	  if ((prevPaintType != 0 || isDoubleDash)
1667 	      && arc->selfJoin == false)
1668 	    {
1669 	      addCap (&arcs[prevPaintType], LEFT_END, k);
1670 	      arc->cap = arcs[prevPaintType].ncaps;
1671 	    }
1672 	  if (isDashed && arcsJoin == false)
1673 	    /* re-initialize paint type and dashing state */
1674 	    {
1675 	      paintType = paintTypeStart;
1676 	      dashNum = dashNumStart;
1677 	      dashIndex = dashIndexStart;
1678 	      dashRemaining = dashRemainingStart;
1679 	    }
1680 	  nextk = arcs[paintType].narcs;
1681 	  if (nexti == start)
1682 	    {
1683 	      nextk = 0;
1684 	      /* re-initialize paint type and dashing state */
1685 	      paintType = paintTypeStart;
1686 	      dashNum = dashNumStart;
1687 	      dashIndex = dashIndexStart;
1688 	      dashRemaining = dashRemainingStart;
1689 	    }
1690 	  /*
1691 	   * cap the right end of the next arc.  If the
1692 	   * next arc is actually the first arc, only
1693 	   * cap it if it joins with this arc.  This
1694 	   * case will occur when the final dash segment
1695 	   * of an on/off dash is off.  Of course, this
1696 	   * cap will be drawn at a strange time, but that
1697 	   * hardly matters...
1698 	   */
1699 	  if ((paintType != 0 || isDoubleDash)
1700 	      && (nexti != start || (arcsJoin && isDashed)))
1701 	    addCap (&arcs[paintType], RIGHT_END, nextk);
1702 	}
1703 
1704       i = nexti;
1705       if (i == start)
1706 	/* have now iterated over all successive pairs (cyclically) */
1707 	break;
1708     }
1709 
1710    /* make sure the last arc if any (i.e. miArcData struct) in each
1711       paint-type-specific miPolyArcs struct includes a `render' directive */
1712   for (paintType = 0; paintType < numPixels; paintType++)
1713     if (arcs[paintType].narcs > 0)
1714       {
1715 	arcs[paintType].arcs[arcs[paintType].narcs-1].render = true;
1716 	arcs[paintType].arcs[arcs[paintType].narcs-1].join =
1717 	  arcs[paintType].njoins;
1718 	arcs[paintType].arcs[arcs[paintType].narcs-1].cap =
1719 	  arcs[paintType].ncaps;
1720       }
1721 
1722   free (data);
1723 
1724   /* return the array of paint-type-specific miPolyArcs structs */
1725   return arcs;
1726 }
1727 
1728 /* Free a list of arc segments (i.e. dashes) for an incomplete ellipse,
1729    indexed by pixel paint type, that was computed by miComputeArcs(). */
1730 static void
miFreeArcs(const miGC * pGC,miPolyArcs * arcs)1731 miFreeArcs(const miGC *pGC, miPolyArcs *arcs)
1732 {
1733   int paintType;
1734 
1735   for (paintType = 0; paintType < pGC->numPixels; paintType++)
1736     {
1737       if (arcs[paintType].narcs > 0)
1738 	free (arcs[paintType].arcs);
1739       if (arcs[paintType].njoins > 0)
1740 	free (arcs[paintType].joins);
1741       if (arcs[paintType].ncaps > 0)
1742 	free (arcs[paintType].caps);
1743     }
1744   free (arcs);
1745 }
1746 
1747 
1748 /**********************************************************************/
1749 /* addCap(), addJoin(), addArc().  These three helper functions are used by
1750    miComputeArcs(). */
1751 /**********************************************************************/
1752 
1753 #define ADD_REALLOC_STEP	20
1754 
1755 /* helper function called by miComputeArcs(); add a cap to the array of
1756    miArcCapStructs in a miPolyArcs struct */
1757 static void
addCap(miPolyArcs * polyArcs,int end,int arcIndex)1758 addCap (miPolyArcs *polyArcs, int end, int arcIndex)
1759 {
1760   miArcCapStruct *cap;
1761 
1762   if (polyArcs->ncaps == polyArcs->capSize)
1763     /* expand array */
1764     {
1765       int newsize = polyArcs->capSize + ADD_REALLOC_STEP;
1766       miArcCapStruct *newcaps;
1767 
1768       newcaps = (miArcCapStruct *) mi_xrealloc (polyArcs->caps,
1769 					     newsize * sizeof(miArcCapStruct));
1770       polyArcs->caps = newcaps;
1771       polyArcs->capSize = newsize;
1772     }
1773 
1774   cap = &(polyArcs->caps[polyArcs->ncaps]);
1775   cap->end = end;
1776   cap->arcIndex = arcIndex;
1777   ++(polyArcs->ncaps);
1778 }
1779 
1780 /* helper function called by miComputeArcs(); add a join to the array of
1781    miArcJoinStructs in a miPolyArcs struct */
1782 static void
addJoin(miPolyArcs * polyArcs,int end0,int index0,int paintType0,int end1,int index1,int paintType1)1783 addJoin (miPolyArcs *polyArcs, int end0, int index0, int paintType0, int end1, int index1, int paintType1)
1784 {
1785   miArcJoinStruct *join;
1786 
1787   if (polyArcs->njoins == polyArcs->joinSize)
1788     /* expand array */
1789     {
1790       int newsize = polyArcs->joinSize + ADD_REALLOC_STEP;
1791       miArcJoinStruct *newjoins;
1792 
1793       newjoins = (miArcJoinStruct *) mi_xrealloc (polyArcs->joins,
1794 					    newsize * sizeof(miArcJoinStruct));
1795       polyArcs->joins = newjoins;
1796       polyArcs->joinSize = newsize;
1797     }
1798 
1799   join = &(polyArcs->joins[polyArcs->njoins]);
1800   join->end0 = end0;
1801   join->arcIndex0 = index0;
1802   join->paintType0 = paintType0;
1803   join->end1 = end1;
1804   join->arcIndex1 = index1;
1805   join->paintType1 = paintType1;
1806   ++(polyArcs->njoins);
1807 }
1808 
1809 /* helper function called by miComputeArcs(); add a arc (i.e. an miArc) to
1810    the array of miArcData structs in a miPolyArcs struct, and return a
1811    pointer to the new miArcData struct */
1812 static miArcData *
addArc(miPolyArcs * polyArcs,const miArc * xarc)1813 addArc (miPolyArcs *polyArcs, const miArc *xarc)
1814 {
1815   miArcData *arc;
1816 
1817   if (polyArcs->narcs == polyArcs->arcSize)
1818     /* expand array */
1819     {
1820       int newsize = polyArcs->arcSize + ADD_REALLOC_STEP;
1821       miArcData *newarcs;
1822 
1823       newarcs = (miArcData *) mi_xrealloc (polyArcs->arcs,
1824 					   newsize * sizeof(miArcData));
1825       polyArcs->arcs = newarcs;
1826       polyArcs->arcSize = newsize;
1827     }
1828 
1829   arc = &(polyArcs->arcs[polyArcs->narcs]);
1830   arc->arc = *xarc;
1831   ++(polyArcs->narcs);
1832 
1833   return arc;
1834 }
1835 
1836 /**********************************************************************/
1837 /* miArcJoin() and miArcCap().  These two low-level functions are called by
1838    miPolyArc().  They draw joins and caps by calling miFillSppPoly(), which
1839    calls the low-level paint function.  */
1840 /**********************************************************************/
1841 
1842 /* Draw a join between two contiguous arcs, by calling miFillSppPoly(). */
1843 static void
miArcJoin(miPaintedSet * paintedSet,miPixel pixel,const miGC * pGC,const miArcFace * pLeft,const miArcFace * pRight,int xOrgLeft,int yOrgLeft,double xFtransLeft,double yFtransLeft,int xOrgRight,int yOrgRight,double xFtransRight,double yFtransRight)1844 miArcJoin (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, const miArcFace *pLeft, const miArcFace *pRight, int xOrgLeft, int yOrgLeft, double xFtransLeft, double yFtransLeft, int xOrgRight, int yOrgRight, double xFtransRight, double yFtransRight)
1845 {
1846   SppPoint	center, corner, otherCorner;
1847   SppPoint	poly[5];
1848   SppPoint	*pArcPts;
1849   int		cpt;
1850   SppArc	arc;
1851   miArcFace	Right, Left;
1852   int		polyLen = 0;
1853   int		xOrg, yOrg;
1854   double	xFtrans, yFtrans;
1855   double	a;
1856   double	width;
1857   double	halftheta;
1858 
1859   xOrg = (xOrgRight + xOrgLeft) / 2;
1860   yOrg = (yOrgRight + yOrgLeft) / 2;
1861   xFtrans = (xFtransLeft + xFtransRight) / 2;
1862   yFtrans = (yFtransLeft + yFtransRight) / 2;
1863   Right = *pRight;
1864   translateBounds (&Right, xOrg - xOrgRight, yOrg - yOrgRight,
1865 		   xFtrans - xFtransRight, yFtrans - yFtransRight);
1866   Left = *pLeft;
1867   translateBounds (&Left, xOrg - xOrgLeft, yOrg - yOrgLeft,
1868 		   xFtrans - xFtransLeft, yFtrans - yFtransLeft);
1869   pRight = &Right;
1870   pLeft = &Left;
1871 
1872   if (pRight->clock.x == pLeft->counterClock.x
1873       && pRight->clock.y == pLeft->counterClock.y)
1874     return;
1875 
1876   /* determine corners of cap */
1877   center = pRight->center;
1878   if (0 <= (a = angleBetween (center, pRight->clock, pLeft->counterClock))
1879       && a <= 180.0)
1880     {
1881       corner = pRight->clock;
1882       otherCorner = pLeft->counterClock;
1883     }
1884   else		/* interchange to make a <= 180, we hope */
1885     {
1886       a = angleBetween (center, pLeft->clock, pRight->counterClock);
1887       corner = pLeft->clock;
1888       otherCorner = pRight->counterClock;
1889     }
1890 
1891   width = (pGC->lineWidth ? pGC->lineWidth : 1);
1892   switch (pGC->joinStyle)
1893     {
1894     case MI_JOIN_MITER:
1895     default:
1896       /* miter only if MITERLIMIT * sin(theta/2) >= 1.0,
1897 	 where theta = 180-a is the join angle */
1898 
1899       if ((halftheta = 0.5 * (180.0 - a)) > 0.0
1900 	  && miDsin (halftheta) * pGC->miterLimit >= 1.0)
1901 	/* miter limit not exceeded */
1902 	{
1903 	  double ae, ac2, ec2, bc2, de;
1904 	  SppPoint e;
1905 
1906 	  /* miter, i.e. add quadrilateral */
1907 	  poly[0] = corner;
1908 	  poly[1] = center;
1909 	  poly[2] = otherCorner;
1910 	  bc2 = ((corner.x - otherCorner.x) * (corner.x - otherCorner.x) +
1911 		 (corner.y - otherCorner.y) * (corner.y - otherCorner.y));
1912 	  ec2 = 0.25 * bc2;
1913 	  ac2 = ((corner.x - center.x) * (corner.x - center.x) +
1914 		 (corner.y - center.y) * (corner.y - center.y));
1915 	  ae = sqrt (ac2 - ec2);
1916 	  de = ec2 / ae;
1917 	  e.x = 0.5 * (corner.x + otherCorner.x);
1918 	  e.y = 0.5 * (corner.y + otherCorner.y);
1919 	  poly[3].x = e.x + de * (e.x - center.x) / ae;
1920 	  poly[3].y = e.y + de * (e.y - center.y) / ae;
1921 	  poly[4] = corner;
1922 	  polyLen = 5;
1923 	}
1924       else			/* miter limit exceeded */
1925 	{
1926 	  /* bevel, i.e. add triangle */
1927 	  poly[0] = corner;
1928 	  poly[1] = center;
1929 	  poly[2] = otherCorner;
1930 	  poly[3] = corner;
1931 	  polyLen = 4;
1932 	}
1933       miFillSppPoly (paintedSet, pixel,
1934 		     polyLen, poly, xOrg, yOrg, xFtrans, yFtrans);
1935       break;
1936     case MI_JOIN_BEVEL:
1937       /* add triangle */
1938       poly[0] = corner;
1939       poly[1] = center;
1940       poly[2] = otherCorner;
1941       poly[3] = corner;
1942       polyLen = 4;
1943       miFillSppPoly (paintedSet, pixel,
1944 		     polyLen, poly, xOrg, yOrg, xFtrans, yFtrans);
1945       break;
1946     case MI_JOIN_TRIANGULAR:
1947       /* add stubby quadrilateral */
1948       {
1949 	double mid2, mid;
1950 	SppPoint e;
1951 
1952 	e.x = 0.5 * (corner.x + otherCorner.x);
1953 	e.y = 0.5 * (corner.y + otherCorner.y);
1954 	mid2 = ((e.x - center.x) * (e.x - center.x) +
1955 		(e.y - center.y) * (e.y - center.y));
1956 	mid = sqrt (mid2);
1957 
1958 	poly[0] = corner;
1959 	poly[1] = center;
1960 	poly[2] = otherCorner;
1961 	poly[3].x = e.x + 0.5 * width * (e.x - center.x) / mid;
1962 	poly[3].y = e.y + 0.5 * width * (e.y - center.y) / mid;
1963 	poly[4] = corner;
1964 	polyLen = 5;
1965 	miFillSppPoly (paintedSet, pixel,
1966 		       polyLen, poly, xOrg, yOrg, xFtrans, yFtrans);
1967       }
1968       break;
1969     case MI_JOIN_ROUND:
1970       /* add round cap */
1971       arc.x = center.x - width/2;
1972       arc.y = center.y - width/2;
1973       arc.width = width;
1974       arc.height = width;
1975       arc.angle1 = -miDatan2 (corner.y - center.y, corner.x - center.x);
1976       arc.angle2 = a;
1977 
1978       pArcPts = (SppPoint *) mi_xmalloc (3 * sizeof (SppPoint));
1979       pArcPts[0] = otherCorner;
1980       pArcPts[1] = center;
1981       pArcPts[2] = corner;
1982       /* convert semicircle to a polyline, and fill */
1983       if ((cpt = miGetArcPts (&arc, 3, &pArcPts)))
1984 	/* by drawing with miFillSppPoly and setting the endpoints of the
1985 	   arc to be the corners, we ensure that the cap will meet up with
1986 	   the rest of the line */
1987 	miFillSppPoly (paintedSet, pixel,
1988 		       cpt, pArcPts, xOrg, yOrg, xFtrans, yFtrans);
1989       free (pArcPts);
1990       break;
1991     }
1992 }
1993 
1994 /* helper function, used by miArcJoin() above */
1995 static double
angleBetween(SppPoint center,SppPoint point1,SppPoint point2)1996 angleBetween (SppPoint center, SppPoint point1, SppPoint point2)
1997 {
1998   double	a1, a2, a;
1999 
2000   /*
2001    * reflect from X coordinates back to ellipse
2002    * coordinates -- y increasing upwards
2003    */
2004   a1 = miDatan2 (- (point1.y - center.y), point1.x - center.x);
2005   a2 = miDatan2 (- (point2.y - center.y), point2.x - center.x);
2006   a = a2 - a1;
2007   if (a <= -180.0)
2008     a += 360.0;
2009   else if (a > 180.0)
2010     a -= 360.0;
2011 
2012   return a;
2013 }
2014 
2015 /* helper function, used by miArcJoin() above */
2016 static void
translateBounds(miArcFace * b,int x,int y,double fx,double fy)2017 translateBounds (miArcFace *b, int x, int y, double fx, double fy)
2018 {
2019   fx += x;
2020   fy += y;
2021   b->clock.x -= fx;
2022   b->clock.y -= fy;
2023   b->center.x -= fx;
2024   b->center.y -= fy;
2025   b->counterClock.x -= fx;
2026   b->counterClock.y -= fy;
2027 }
2028 
2029 /* Draw a cap on an arc segment, by calling miFillSppPoly(). */
2030 /*ARGSUSED*/
2031 static void
miArcCap(miPaintedSet * paintedSet,miPixel pixel,const miGC * pGC,const miArcFace * pFace,int end,int xOrg,int yOrg,double xFtrans,double yFtrans)2032 miArcCap (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, const miArcFace *pFace, int end, int xOrg, int yOrg, double xFtrans, double yFtrans)
2033 {
2034   SppPoint corner, otherCorner, center, endPoint, poly[5];
2035 
2036   corner = pFace->clock;
2037   otherCorner = pFace->counterClock;
2038   center = pFace->center;
2039   switch (pGC->capStyle)
2040     {
2041     case MI_CAP_BUTT:
2042     case MI_CAP_NOT_LAST:
2043     default:
2044       break;			/* do nothing */
2045     case MI_CAP_PROJECTING:
2046       poly[0].x = otherCorner.x;
2047       poly[0].y = otherCorner.y;
2048       poly[1].x = corner.x;
2049       poly[1].y = corner.y;
2050       poly[2].x = corner.x - (center.y - corner.y);
2051       poly[2].y = corner.y + (center.x - corner.x);
2052       poly[3].x = otherCorner.x - (otherCorner.y - center.y);
2053       poly[3].y = otherCorner.y + (otherCorner.x - center.x);
2054       poly[4].x = otherCorner.x;
2055       poly[4].y = otherCorner.y;
2056       miFillSppPoly (paintedSet, pixel,
2057 		     5, poly, xOrg, yOrg, xFtrans, yFtrans);
2058       break;
2059     case MI_CAP_TRIANGULAR:
2060       poly[0].x = otherCorner.x;
2061       poly[0].y = otherCorner.y;
2062       poly[1].x = corner.x;
2063       poly[1].y = corner.y;
2064       poly[2].x = center.x - 0.5 * (otherCorner.y - corner.y);
2065       poly[2].y = center.y + 0.5 * (otherCorner.x - corner.x);
2066       poly[3].x = otherCorner.x;
2067       poly[3].y = otherCorner.y;
2068       miFillSppPoly (paintedSet, pixel,
2069 		     4, poly, xOrg, yOrg, xFtrans, yFtrans);
2070       break;
2071     case MI_CAP_ROUND:
2072       /*
2073        * miRoundCap() just needs these to be unequal.
2074        */
2075       endPoint = center;
2076       endPoint.x = endPoint.x + 100;
2077       miRoundCap (paintedSet, pixel, pGC,
2078 		  center, endPoint, corner, otherCorner, 0,
2079 		  -xOrg, -yOrg, xFtrans, yFtrans);
2080       break;
2081     }
2082 }
2083 
2084 /* MIROUNDCAP -- a helper function used by miArcCap() above.
2085  * Put Rounded cap on end.  pCenter is the center of this end of the line
2086  * pEnd is the center of the other end of the line.  pCorner is one of the
2087  * two corners at this end of the line.
2088  * NOTE:  pOtherCorner must be counter-clockwise from pCorner.
2089  */
2090 /*ARGSUSED*/
2091 static void
miRoundCap(miPaintedSet * paintedSet,miPixel pixel,const miGC * pGC,SppPoint pCenter,SppPoint pEnd,SppPoint pCorner,SppPoint pOtherCorner,int fLineEnd,int xOrg,int yOrg,double xFtrans,double yFtrans)2092 miRoundCap (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, SppPoint pCenter, SppPoint pEnd, SppPoint pCorner, SppPoint pOtherCorner, int fLineEnd, int xOrg, int yOrg, double xFtrans, double yFtrans)
2093 {
2094   int		cpt;
2095   double	width;
2096   SppArc	arc;
2097   SppPoint	*pArcPts;
2098 
2099   width = (pGC->lineWidth ? pGC->lineWidth : 1);
2100 
2101   arc.x = pCenter.x - width/2;
2102   arc.y = pCenter.y - width/2;
2103   arc.width = width;
2104   arc.height = width;
2105   arc.angle1 = -miDatan2 (pCorner.y - pCenter.y, pCorner.x - pCenter.x);
2106   if (PTISEQUAL(pCenter, pEnd))
2107     arc.angle2 = - 180.0;
2108   else
2109     {
2110       arc.angle2 = -miDatan2 (pOtherCorner.y - pCenter.y, pOtherCorner.x - pCenter.x) - arc.angle1;
2111       if (arc.angle2 < 0)
2112 	arc.angle2 += 360.0;
2113     }
2114 
2115   /* convert semicircle to a polyline, and fill */
2116   pArcPts = (SppPoint *)NULL;
2117   if ((cpt = miGetArcPts (&arc, 0, &pArcPts)))
2118     /* by drawing with miFillSppPoly and setting the endpoints of the arc
2119      * to be the corners, we assure that the cap will meet up with the
2120      * rest of the line */
2121     miFillSppPoly (paintedSet, pixel,
2122 		   cpt, pArcPts, -xOrg, -yOrg, xFtrans, yFtrans);
2123   free (pArcPts);
2124 }
2125 
2126 /* MIGETARCPTS -- Converts an arc into a set of line segments, so the
2127  * resulting polygon can be filled -- a helper routine for drawing round
2128  * joins and caps.  Returns the number of points in the arc.  Note that it
2129  * takes a pointer to a pointer to where it should put the points and an
2130  * index (cpt).  This procedure allocates the space necessary to fit the
2131  * arc points.  Sometimes it's convenient for those points to be at the end
2132  * of an existing array. (For example, if we want to leave a spare point to
2133  * make sectors instead of segments.)  So we pass in the malloc'ed chunk
2134  * that contains the array, and an index saying where we should start
2135  * stashing the points.  If there isn't an array already, we just pass in a
2136  * null pointer and count on mi_xrealloc() to handle the null pointer
2137  * correctly.  */
2138 
2139 /* ARGS: cpt = number of points already in arc list
2140    	 ppPts = ptr to ptr to arc-list -- modified */
2141 static int
miGetArcPts(const SppArc * parc,int cpt,SppPoint ** ppPts)2142 miGetArcPts (const SppArc *parc, int cpt, SppPoint **ppPts)
2143 {
2144   double st;			/* Start Theta, start angle */
2145   double et;			/* End Theta, offset from start theta */
2146   double dt;			/* Delta Theta, angle to sweep ellipse */
2147   double cdt;			/* Cos Delta Theta, actually 2 cos(dt) */
2148   double x0, y0;		/* recurrence formula needs 2 points to start*/
2149   double x1, y1;
2150   double x2, y2;		/* this will be the new point generated */
2151   double xc, yc;		/* the center point */
2152   int count, i;
2153   SppPoint *poly;
2154   miPoint last;			/* last point on integer boundaries */
2155 
2156   /* The spec says that positive angles indicate counterclockwise motion.
2157      Given our coordinate system (with 0,0 in the upper left corner), the
2158      screen appears flipped in Y.  The easiest fix is to negate the angles
2159      given. */
2160   st = - parc->angle1;
2161   et = - parc->angle2;
2162 
2163   /* Try to get a delta theta that is within 1/2 pixel.  Then adjust it
2164    * so that it divides evenly into the total.
2165    * I'm just using cdt 'cause I'm lazy.
2166    */
2167   cdt = parc->width;
2168   if (parc->height > cdt)
2169     cdt = parc->height;
2170   cdt *= 0.5;
2171   if (cdt <= 0)
2172     return 0;
2173   if (cdt < 1.0)
2174     cdt = 1.0;
2175   dt = miDasin (1.0 / cdt);	/* minimum step necessary */
2176   count = (int)(et/dt);
2177   count = abs(count) + 1;
2178   dt = et/count;
2179   count++;
2180 
2181   cdt = 2 * miDcos(dt);
2182   poly = (SppPoint *) mi_xrealloc(*ppPts,
2183 				     (cpt + count) * sizeof(SppPoint));
2184   *ppPts = poly;
2185 
2186   xc = 0.5 * parc->width;	/* store half width and half height */
2187   yc = 0.5 * parc->height;
2188 
2189   x0 = xc * miDcos(st);
2190   y0 = yc * miDsin(st);
2191   x1 = xc * miDcos(st + dt);
2192   y1 = yc * miDsin(st + dt);
2193   xc += parc->x;		/* by adding initial point, these become */
2194   yc += parc->y;		/* the center point */
2195 
2196   poly[cpt].x = (xc + x0);
2197   poly[cpt].y = (yc + y0);
2198   poly[cpt + 1].x = (xc + x1);
2199   poly[cpt + 1].y = (yc + y1);
2200   last.x = IROUND(xc + x1);
2201   last.y = IROUND(yc + y1);
2202 
2203   for (i = 2; i < count; i++)
2204     {
2205       x2 = cdt * x1 - x0;
2206       y2 = cdt * y1 - y0;
2207 
2208       poly[cpt + i].x = (xc + x2);
2209       poly[cpt + i].y = (yc + y2);
2210 
2211       x0 = x1; y0 = y1;
2212       x1 = x2; y1 = y2;
2213     }
2214   /* adjust the last point */
2215   if (FABS(parc->angle2) >= 360.0)
2216     poly[cpt +i -1] = poly[0];
2217   else
2218     {
2219       poly[cpt +i -1].x = (miDcos(st + et) * 0.5 * parc->width + xc);
2220       poly[cpt +i -1].y = (miDsin(st + et) * 0.5 * parc->height + yc);
2221     }
2222 
2223   return count;
2224 }
2225 
2226 
2227 /**********************************************************************/
2228 /* Specially defined trig functions.  At the cardinal points, they are
2229    exact. */
2230 /**********************************************************************/
2231 
2232 #define Dsin(d)	((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0)))
2233 #define Dcos(d)	((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0)))
2234 #define mod(a,b)	((a) >= 0 ? (a) % (b) : (b) - (-a) % (b))
2235 
2236 static double
miDcos(double a)2237 miDcos (double a)
2238 {
2239   int	i;
2240 
2241   if (floor (a/90) == a/90)
2242     {
2243       i = (int) (a/90.0);
2244       switch (mod (i, 4))
2245 	{
2246 	case 0: return 1;
2247 	case 1: return 0;
2248 	case 2: return -1;
2249 	case 3: return 0;
2250 	}
2251     }
2252   return cos (a * M_PI / 180.0);
2253 }
2254 
2255 static double
miDsin(double a)2256 miDsin (double a)
2257 {
2258   int	i;
2259 
2260   if (floor (a/90) == a/90)
2261     {
2262       i = (int) (a/90.0);
2263       switch (mod (i, 4))
2264 	{
2265 	case 0: return 0;
2266 	case 1: return 1;
2267 	case 2: return 0;
2268 	case 3: return -1;
2269 	}
2270     }
2271   return sin (a * M_PI / 180.0);
2272 }
2273 
2274 static double
miDasin(double v)2275 miDasin (double v)
2276 {
2277   if (v == 0)
2278     return 0.0;
2279   if (v == 1.0)
2280     return 90.0;
2281   if (v == -1.0)
2282     return -90.0;
2283   return asin(v) * (180.0 / M_PI);
2284 }
2285 
2286 static double
miDatan2(double dy,double dx)2287 miDatan2 (double dy, double dx)
2288 {
2289   if (dy == 0)
2290     {
2291       if (dx >= 0)
2292 	return 0.0;
2293       return 180.0;
2294     }
2295   else if (dx == 0)
2296     {
2297       if (dy > 0)
2298 	return 90.0;
2299       return -90.0;
2300     }
2301   else if (FABS(dy) == FABS(dx))
2302     {
2303       if (dy > 0)
2304 	{
2305 	  if (dx > 0)
2306 	    return 45.0;
2307 	  return 135.0;
2308 	}
2309       else
2310 	{
2311 	  if (dx > 0)
2312 	    return 315.0;
2313 	  return 225.0;
2314 	}
2315     }
2316   else
2317     return atan2 (dy, dx) * (180.0 / M_PI);
2318 }
2319 
2320 
2321 /***********************************************************************/
2322 /* A sub-module that computes arc lengths via a polygonal approximation to
2323  * the arc.  External functions are computeDashMap(), which should be
2324  * called first, and the primary function computeAngleFromPath().  They are
2325  * called by miComputeArcs() above.  */
2326 /***********************************************************************/
2327 
2328 #define dashIndexToAngle(di)	((((double) (di)) * 90.0) / ((double) DASH_MAP_SIZE - 1))
2329 #define xAngleToDashIndex(xa)	((((long) (xa)) * (DASH_MAP_SIZE - 1)) / (90 * 64))
2330 #define dashIndexToXAngle(di)	((((long) (di)) * (90 * 64)) / (DASH_MAP_SIZE - 1))
2331 #define dashXAngleStep	(((double) (90 * 64)) / ((double) (DASH_MAP_SIZE - 1)))
2332 
2333 /* forward references (functions in this sub-module) */
2334 static double angleToLength (int angle, const dashMap *map);
2335 static int lengthToAngle (double len, const dashMap *map);
2336 
2337 static void
computeDashMap(const miArc * arcp,dashMap * map)2338 computeDashMap (const miArc *arcp, dashMap *map)
2339 {
2340   int di;
2341   double a, x, y, prevx = 0.0, prevy = 0.0, dist;
2342 
2343   for (di = 0; di < DASH_MAP_SIZE; di++)
2344     {
2345       a = dashIndexToAngle (di);
2346       x = (double)(0.5 * arcp->width) * miDcos (a);
2347       y = (double)(0.5 * arcp->height) * miDsin (a);
2348       if (di == 0)
2349 	map->map[di] = 0.0;
2350       else
2351 	{
2352 	  dist = hypot (x - prevx, y - prevy);
2353 	  map->map[di] = map->map[di - 1] + dist;
2354 	}
2355       prevx = x;
2356       prevy = y;
2357     }
2358 }
2359 
2360 static double
angleToLength(int angle,const dashMap * map)2361 angleToLength (int angle, const dashMap *map)
2362 {
2363   double len, excesslen, sidelen = map->map[DASH_MAP_SIZE - 1], totallen;
2364   int    di;
2365   int	 excess;
2366   bool	 oddSide = false;
2367 
2368   totallen = 0;
2369   if (angle >= 0)
2370     {
2371       while (angle >= 90 * 64)
2372 	{
2373 	  angle -= 90 * 64;
2374 	  totallen += sidelen;
2375 	  oddSide = (oddSide ? false : true);
2376 	}
2377     }
2378   else
2379     {
2380       while (angle < 0)
2381 	{
2382 	  angle += 90 * 64;
2383 	  totallen -= sidelen;
2384 	  oddSide = (oddSide ? false : true);
2385 	}
2386     }
2387   if (oddSide)
2388     angle = 90 * 64 - angle;
2389 
2390   di = xAngleToDashIndex (angle);
2391   excess = angle - dashIndexToXAngle (di);
2392 
2393   len = map->map[di];
2394   /*
2395    * linearly interpolate between this point and the next
2396    */
2397   if (excess > 0)
2398     {
2399       excesslen = (map->map[di + 1] - map->map[di]) *
2400 	((double) excess) / dashXAngleStep;
2401       len += excesslen;
2402     }
2403   if (oddSide)
2404     totallen += (sidelen - len);
2405   else
2406     totallen += len;
2407   return totallen;
2408 }
2409 
2410 /*
2411  * len is along the arc, but may be more than one rotation
2412  */
2413 
2414 static int
lengthToAngle(double len,const dashMap * map)2415 lengthToAngle (double len, const dashMap *map)
2416 {
2417   double sidelen = map->map[DASH_MAP_SIZE - 1];
2418   int angle, angleexcess;
2419   bool oddSide = false;
2420   int a0, a1, a;
2421 
2422   angle = 0;
2423   /*
2424    * step around the ellipse, subtracting sidelens and
2425    * adding 90 degrees.  oddSide will tell if the
2426    * map should be interpolated in reverse
2427    */
2428   if (len >= 0)
2429     {
2430       if (sidelen == 0)
2431 	return 2 * FULLCIRCLE;	/* infinity */
2432       while (len >= sidelen)
2433 	{
2434 	  angle += 90 * 64;
2435 	  len -= sidelen;
2436 	  oddSide = (oddSide ? false : true);
2437 	}
2438     }
2439   else
2440     {
2441       if (sidelen == 0)
2442 	return -2 * FULLCIRCLE;	/* infinity */
2443       while (len < 0)
2444 	{
2445 	  angle -= 90 * 64;
2446 	  len += sidelen;
2447 	  oddSide = (oddSide ? false : true);
2448 	}
2449     }
2450   if (oddSide)
2451     len = sidelen - len;
2452   a0 = 0;
2453   a1 = DASH_MAP_SIZE - 1;
2454   /*
2455    * binary search for the closest pre-computed length
2456    */
2457   while (a1 - a0 > 1)
2458     {
2459       a = (a0 + a1) / 2;
2460       if (len > map->map[a])
2461 	a0 = a;
2462       else
2463 	a1 = a;
2464     }
2465   angleexcess = dashIndexToXAngle (a0);
2466   /*
2467    * linearly interpolate to the next point
2468    */
2469   angleexcess += (int)((len - map->map[a0]) /
2470 		       (map->map[a0+1] - map->map[a0]) * dashXAngleStep);
2471   if (oddSide)
2472     angle += (90 * 64) - angleexcess;
2473   else
2474     angle += angleexcess;
2475   return angle;
2476 }
2477 
2478 /* Compute the subtended angle, in 1/64 degree units, of an elliptic arc
2479  * that corresponds to a specified dash length.  The correct solution to
2480  * this problem involves an elliptic integral, so we punt by approximating
2481  * (it's only for dashes anyway...).  The approximation uses a polygon.
2482  *
2483  * The specified dash length `len' is updated, to equal the amount of the
2484  * dash that will remain after drawing the arc.  This may be nonzero due to
2485  * rounding.  The new value will be negative if the arc extends beyond the
2486  * specified dash length, and positive if the specified dash length extends
2487  * beyond the arc.  */
2488 
2489 static int
computeAngleFromPath(int startAngle,int endAngle,const dashMap * map,int * lenp,bool backwards)2490 computeAngleFromPath (int startAngle, int endAngle, const dashMap *map, int *lenp, bool backwards)
2491 /* start, endAngle are angles in 1/64 degree units */
2492 {
2493   int	a0, a1, a;
2494   double len0;
2495   int	len;
2496 
2497   a0 = startAngle;
2498   a1 = endAngle;
2499   len = *lenp;
2500   if (backwards)
2501     /* flip the problem around to be forwards */
2502     {
2503       a0 = FULLCIRCLE - a0;
2504       a1 = FULLCIRCLE - a1;
2505     }
2506 
2507   if (a1 < a0)
2508     a1 += FULLCIRCLE;
2509   len0 = angleToLength (a0, map);
2510   a = lengthToAngle (len0 + len, map);
2511   if (a > a1)
2512     {
2513       a = a1;
2514       len = (int)(len - angleToLength (a1, map) - len0);
2515     }
2516   else
2517     len = 0;
2518   if (backwards)
2519     a = FULLCIRCLE - a;
2520 
2521   *lenp = len;
2522   return a;
2523 }
2524 
2525 
2526 /***********************************************************************/
2527 /* Geometry computations related to wide ellipses, e.g., computeAcc(),
2528    which computes `accelerators' (frequently used quantities), and
2529    computeBounds(). */
2530 /***********************************************************************/
2531 
2532 /* definition of a wide arc */
2533 struct arc_def
2534 {
2535   double	w, h;		/* half-width, half-height */
2536   double	l;		/* half of line width */
2537   double	a0, a1;		/* start angle, and angle range */
2538 };
2539 
2540 struct bound
2541 {
2542   double min, max;
2543 };
2544 
2545 struct ibound
2546 {
2547   int min, max;
2548 };
2549 
2550 /*
2551  * These are all y value bounds; computed by computeBounds().
2552  */
2553 struct arc_bound
2554 {
2555   struct bound ellipse;
2556   struct bound inner, outer;
2557   struct bound right, left;
2558   struct ibound inneri, outeri;
2559 };
2560 
2561 struct line
2562 {
2563   double m, b;			/* for y = mx + b */
2564   bool valid;
2565 };
2566 
2567 /* Quantities frequently used when drawn an ellipse or elliptic arc;
2568    computed by computeAcc(). */
2569 struct accelerators
2570 {
2571   double		tail_y;	/* "y value associated with bottom of tail" */
2572   double		h2;	/* half-height squared */
2573   double		w2;	/* half-width squared */
2574   double		h4;	/* half-height raised to 4th power */
2575   double		w4;	/* half-width raised to 4th power */
2576   double		h2mw2;	/* h2 minus w2 */
2577   double		h2l;	/* h2 times l (i.e. half the line width) */
2578   double		w2l;	/* w2 times l (i.e. half the line width) */
2579   double		fromIntX; /* 0.5 if width is odd, otherwise 0.0 */
2580   double		fromIntY; /* 0.5 if height is oddd, otherwise 0.0 */
2581   struct line		left, right;
2582   int			yorgu;
2583   int			yorgl;
2584   int			xorg;
2585 };
2586 
2587 #define boundedLe(value, bounds)\
2588 	((bounds).min <= (value) && (value) <= (bounds).max)
2589 
2590 #define intersectLine(y,line) (line.m * (y) + line.b)
2591 
2592 /* forward references */
2593 static double hookEllipseY (double scan_y, const struct arc_bound *bound, const struct accelerators *acc, bool left);
2594 static double hookX (double scan_y, const struct arc_def *def, const struct arc_bound *bound, const struct accelerators *acc, bool left);
2595 static double innerXfromXY (double x, double y, const struct accelerators *acc);
2596 static double innerYfromXY (double x, double y, const struct accelerators *acc);
2597 static double innerYfromY (double y, const struct arc_def *def, const struct accelerators *acc);
2598 static double outerXfromXY (double x, double y, const struct accelerators *acc);
2599 static double outerYfromXY (double x, double y, const struct accelerators *acc);
2600 static double tailX (double K, const struct arc_def *def, const struct arc_bound *bounds, const struct accelerators *acc);
2601 static void computeAcc (const miArc *tarc, unsigned int lw, struct arc_def *def, struct accelerators *acc);
2602 static void computeBound (const struct arc_def *def, struct arc_bound *bound, struct accelerators *acc, miArcFace *right, miArcFace *left);
2603 static void computeLine (double x1, double y1, double x2, double y2, struct line *line);
2604 static void tailEllipseY (const struct arc_def *def, struct accelerators *acc);
2605 
2606 static double
tailX(double K,const struct arc_def * def,const struct arc_bound * bounds,const struct accelerators * acc)2607 tailX (double K, const struct arc_def *def, const struct arc_bound *bounds, const struct accelerators *acc)
2608 {
2609   double w, h, r;
2610   double Hs, Hf, WH, Vk, Nk, Fk, Vr, N, Nc, Z, rs;
2611   double A, T, b, d, x, y, t, hepp, hepm;
2612   int flip, solution;
2613   double xs[2];
2614   double *xp;
2615 
2616   w = def->w;
2617   h = def->h;
2618   r = def->l;
2619   rs = r * r;
2620   Hs = acc->h2;
2621   WH = -acc->h2mw2;
2622   Nk = def->w * r;
2623   Vk = (Nk * Hs) / (WH + WH);
2624   Hf = acc->h4;
2625   Nk = (Hf - Nk * Nk) / WH;
2626   if (K == 0.0)
2627     {
2628       if (Nk < 0.0 && -Nk < Hs)
2629 	{
2630 	  xs[0] = w * sqrt(1 + Nk / Hs) - sqrt(rs + Nk);
2631 	  xs[1] = w - r;
2632 	  if (acc->left.valid && boundedLe(K, bounds->left) &&
2633 	      !boundedLe(K, bounds->outer) && xs[0] >= 0.0 && xs[1] >= 0.0)
2634 	    return xs[1];
2635 	  if (acc->right.valid && boundedLe(K, bounds->right) &&
2636 	      !boundedLe(K, bounds->inner) && xs[0] <= 0.0 && xs[1] <= 0.0)
2637 	    return xs[1];
2638 	  return xs[0];
2639 	}
2640       return w - r;
2641     }
2642   Fk = Hf / WH;
2643   hepp = h + EPSILON;
2644   hepm = h - EPSILON;
2645   N = (K * K + Nk) / 6.0;
2646   Nc = N * N * N;
2647   Vr = Vk * K;
2648   xp = xs;
2649   xs[0] = 0.0;
2650   t = Nc + Vr * Vr;
2651   d = Nc + t;
2652   if (d < 0.0)
2653     {
2654       d = Nc;
2655       b = N;
2656       if ( (b < 0.0) == (t < 0.0) )
2657 	{
2658 	  b = -b;
2659 	  d = -d;
2660 	}
2661       Z = N - 2.0 * b * cos (acos (-t / d) / 3.0);
2662       if ( (Z < 0.0) == (Vr < 0.0) )
2663 	flip = 2;
2664       else
2665 	flip = 1;
2666     }
2667   else
2668     {
2669       d = Vr * sqrt (d);
2670       Z = N + cbrt (t + d) + cbrt (t - d);
2671       flip = 0;
2672     }
2673   A = sqrt ((Z + Z) - Nk);
2674   T = (Fk - Z) * K / A;
2675   solution = false;
2676   b = -A + K;
2677   d = b * b - 4 * (Z + T);
2678   if (d >= 0 && flip == 2)
2679     {
2680       d = sqrt(d);
2681       y = 0.5 * (b + d);
2682       if ((y >= 0.0) && (y < hepp))
2683 	{
2684 	  solution = true;
2685 	  if (y > hepm)
2686 	    y = h;
2687 	  t = y / h;
2688 	  x = w * sqrt(1 - (t * t));
2689 	  t = K - y;
2690 	  t = sqrt(rs - (t * t));
2691 	  *xp++ = x - t;
2692 	}
2693     }
2694   b = A + K;
2695   d = b * b - 4 * (Z - T);
2696   /* Because of the large magnitudes involved, we lose enough precision
2697    * that sometimes we end up with a negative value near the axis, when
2698    * it should be positive.  This is a workaround.
2699    */
2700   if (d < 0 && !solution)
2701     d = 0.0;
2702   if (d >= 0)
2703     {
2704       d = sqrt(d);
2705       y = 0.5 * (b + d);
2706       if (y < hepp)
2707 	{
2708 	  if (y > hepm)
2709 	    y = h;
2710 	  t = y / h;
2711 	  x = w * sqrt(1 - (t * t));
2712 	  t = K - y;
2713 	  *xp++ = x - sqrt(rs - (t * t));
2714 	}
2715       y = 0.5 * (b - d);
2716       if (y >= 0.0 && flip == 1)
2717 	{
2718 	  if (y > hepm)
2719 	    y = h;
2720 	  t = y / h;
2721 	  x = w * sqrt(1 - (t * t));
2722 	  t = K - y;
2723 	  t = sqrt(rs - (t * t));
2724 	  *xp++ = x - t;
2725 	}
2726     }
2727   if (xp > &xs[1])
2728     {
2729       if (acc->left.valid && boundedLe(K, bounds->left) &&
2730 	  !boundedLe(K, bounds->outer) && xs[0] >= 0.0 && xs[1] >= 0.0)
2731 	return xs[1];
2732       if (acc->right.valid && boundedLe(K, bounds->right) &&
2733 	  !boundedLe(K, bounds->inner) && xs[0] <= 0.0 && xs[1] <= 0.0)
2734 	return xs[1];
2735     }
2736   return xs[0];
2737 }
2738 
2739 /*
2740  * This computes the ellipse y value associated with the
2741  * bottom of the tail.
2742  */
2743 
2744 #define CUBE_ROOT_2	1.2599210498948732038115849718451499938964
2745 #define CUBE_ROOT_4	1.5874010519681993173435330390930175781250
2746 
2747 static void
tailEllipseY(const struct arc_def * def,struct accelerators * acc)2748 tailEllipseY (const struct arc_def *def, struct accelerators *acc)
2749 {
2750   double t;
2751 
2752   acc->tail_y = 0.0;
2753   if (def->w == def->h)
2754     return;
2755   t = def->l * def->w;
2756   if (def->w > def->h)
2757     {
2758       if (t < acc->h2)
2759 	return;
2760     }
2761   else
2762     {
2763       if (t > acc->h2)
2764 	return;
2765     }
2766   t = 2.0 * def->h * t;
2767   t = (CUBE_ROOT_4 * acc->h2 - cbrt(t * t)) / acc->h2mw2;
2768   if (t > 0.0)
2769     acc->tail_y = def->h / CUBE_ROOT_2 * sqrt(t);
2770 }
2771 
2772 /*
2773  * inverse functions -- compute edge coordinates
2774  * from the ellipse (actually, from its precomputed accelerators)
2775  */
2776 
2777 static double
outerXfromXY(double x,double y,const struct accelerators * acc)2778 outerXfromXY (double x, double y, const struct accelerators *acc)
2779 {
2780   return x + (x * acc->h2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
2781 }
2782 
2783 static double
outerYfromXY(double x,double y,const struct accelerators * acc)2784 outerYfromXY (double x, double y, const struct accelerators *acc)
2785 {
2786   return y + (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
2787 }
2788 
2789 static double
innerXfromXY(double x,double y,const struct accelerators * acc)2790 innerXfromXY (double x, double y, const struct accelerators *acc)
2791 {
2792   return x - (x * acc->h2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
2793 }
2794 
2795 static double
innerYfromXY(double x,double y,const struct accelerators * acc)2796 innerYfromXY (double x, double y, const struct accelerators *acc)
2797 {
2798   return y - (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
2799 }
2800 
2801 static double
innerYfromY(double y,const struct arc_def * def,const struct accelerators * acc)2802 innerYfromY (double y, const struct arc_def *def, const struct accelerators *acc)
2803 {
2804   double x;
2805 										 x = (def->w / def->h) * sqrt (acc->h2 - y*y);
2806 										 return y - (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
2807 									       }
2808 
2809 /* compute a line through two points */
2810 static void
computeLine(double x1,double y1,double x2,double y2,struct line * line)2811 computeLine (double x1, double y1, double x2, double y2, struct line *line)
2812 {
2813   if (y1 == y2)
2814     line->valid = false;
2815   else
2816     {
2817       line->m = (x1 - x2) / (y1 - y2);
2818       line->b = x1  - y1 * line->m;
2819       line->valid = true;
2820     }
2821 }
2822 
2823 /* Compute accelerators for an ellipse.  These are simply values that are
2824    used repeatedly in the computations.  Also begin filling in the arc_def
2825    structure too. */
2826 static void
computeAcc(const miArc * tarc,unsigned int lw,struct arc_def * def,struct accelerators * acc)2827 computeAcc (const miArc *tarc, unsigned int lw, struct arc_def *def, struct accelerators *acc)
2828 {
2829   def->w = 0.5 * (double)tarc->width;
2830   def->h = 0.5 * (double)tarc->height;
2831   def->l = 0.5 * (double)lw;
2832   acc->h2 = def->h * def->h;
2833   acc->w2 = def->w * def->w;
2834   acc->h4 = acc->h2 * acc->h2;
2835   acc->w4 = acc->w2 * acc->w2;
2836   acc->h2l = acc->h2 * def->l;
2837   acc->w2l = acc->w2 * def->l;
2838   acc->h2mw2 = acc->h2 - acc->w2;
2839   acc->fromIntX = (tarc->width & 1) ? 0.5 : 0.0;
2840   acc->fromIntY = (tarc->height & 1) ? 0.5 : 0.0;
2841   acc->xorg = tarc->x + (int)(tarc->width >> 1);
2842   acc->yorgu = tarc->y + (int)(tarc->height >> 1);
2843   acc->yorgl = acc->yorgu + (tarc->height & 1);
2844   tailEllipseY (def, acc);	/* fill in tail_y element of acc */
2845 }
2846 
2847 /* Compute y value bounds of various portions of the arc, the outer edge,
2848    the ellipse and the inner edge.  Also invoke computeLine to compute left
2849    and right lines (stored in accelerator structure). */
2850 static void
computeBound(const struct arc_def * def,struct arc_bound * bound,struct accelerators * acc,miArcFace * right,miArcFace * left)2851 computeBound (const struct arc_def *def, struct arc_bound *bound, struct accelerators *acc, miArcFace *right, miArcFace *left)
2852 {
2853   double		t;
2854   double		innerTaily;
2855   double		tail_y;
2856   struct bound	innerx, outerx;
2857   struct bound	ellipsex;
2858 
2859   bound->ellipse.min = Dsin (def->a0) * def->h;
2860   bound->ellipse.max = Dsin (def->a1) * def->h;
2861   if (def->a0 == 45 && def->w == def->h)
2862     ellipsex.min = bound->ellipse.min;
2863   else
2864     ellipsex.min = Dcos (def->a0) * def->w;
2865   if (def->a1 == 45 && def->w == def->h)
2866     ellipsex.max = bound->ellipse.max;
2867   else
2868     ellipsex.max = Dcos (def->a1) * def->w;
2869   bound->outer.min = outerYfromXY (ellipsex.min, bound->ellipse.min, acc);
2870   bound->outer.max = outerYfromXY (ellipsex.max, bound->ellipse.max, acc);
2871   bound->inner.min = innerYfromXY (ellipsex.min, bound->ellipse.min, acc);
2872   bound->inner.max = innerYfromXY (ellipsex.max, bound->ellipse.max, acc);
2873 
2874   outerx.min = outerXfromXY (ellipsex.min, bound->ellipse.min, acc);
2875   outerx.max = outerXfromXY (ellipsex.max, bound->ellipse.max, acc);
2876   innerx.min = innerXfromXY (ellipsex.min, bound->ellipse.min, acc);
2877   innerx.max = innerXfromXY (ellipsex.max, bound->ellipse.max, acc);
2878 
2879   /* Save the line end points for the cap code to use.  Careful here, these
2880    * are in Cartesian coordinates (y increasing upwards) while the cap code
2881    * uses inverted coordinates (y increasing downwards).
2882    */
2883 
2884   if (right)
2885     {
2886       right->counterClock.y = bound->outer.min;
2887       right->counterClock.x = outerx.min;
2888       right->center.y = bound->ellipse.min;
2889       right->center.x = ellipsex.min;
2890       right->clock.y = bound->inner.min;
2891       right->clock.x = innerx.min;
2892     }
2893 
2894   if (left)
2895     {
2896       left->clock.y = bound->outer.max;
2897       left->clock.x = outerx.max;
2898       left->center.y = bound->ellipse.max;
2899       left->center.x = ellipsex.max;
2900       left->counterClock.y = bound->inner.max;
2901       left->counterClock.x = innerx.max;
2902     }
2903 
2904   bound->left.min = bound->inner.max;
2905   bound->left.max = bound->outer.max;
2906   bound->right.min = bound->inner.min;
2907   bound->right.max = bound->outer.min;
2908 
2909   computeLine (innerx.min, bound->inner.min, outerx.min, bound->outer.min,
2910 	       &acc->right);
2911   computeLine (innerx.max, bound->inner.max, outerx.max, bound->outer.max,
2912 	       &acc->left);
2913 
2914   if (bound->inner.min > bound->inner.max)
2915     {
2916       t = bound->inner.min;
2917       bound->inner.min = bound->inner.max;
2918       bound->inner.max = t;
2919     }
2920   tail_y = acc->tail_y;
2921   if (tail_y > bound->ellipse.max)
2922     tail_y = bound->ellipse.max;
2923   else if (tail_y < bound->ellipse.min)
2924     tail_y = bound->ellipse.min;
2925   innerTaily = innerYfromY (tail_y, def, acc);
2926   if (bound->inner.min > innerTaily)
2927     bound->inner.min = innerTaily;
2928   if (bound->inner.max < innerTaily)
2929     bound->inner.max = innerTaily;
2930   bound->inneri.min = ICEIL(bound->inner.min - acc->fromIntY);
2931   bound->inneri.max = IFLOOR(bound->inner.max - acc->fromIntY);
2932   bound->outeri.min = ICEIL(bound->outer.min - acc->fromIntY);
2933   bound->outeri.max = IFLOOR(bound->outer.max - acc->fromIntY);
2934 }
2935 
2936 /*
2937  * this section computes the x value of the span at y
2938  * intersected with the specified face of the ellipse.
2939  *
2940  * this is the min/max X value over the set of normal
2941  * lines to the entire ellipse,  the equation of the
2942  * normal lines is:
2943  *
2944  *     ellipse_x h^2                   h^2
2945  * x = ------------ y + ellipse_x (1 - --- )
2946  *     ellipse_y w^2                   w^2
2947  *
2948  * compute the derivative with-respect-to ellipse_y and solve
2949  * for zero:
2950  *
2951  *       (w^2 - h^2) ellipse_y^3 + h^4 y
2952  * 0 = - ----------------------------------
2953  *       h w ellipse_y^2 sqrt (h^2 - ellipse_y^2)
2954  *
2955  *             (   h^4 y     )
2956  * ellipse_y = ( ----------  ) ^ (1/3)
2957  *             ( (h^2 - w^2) )
2958  *
2959  * The other two solutions to the equation are imaginary.
2960  *
2961  * This gives the position on the ellipse which generates
2962  * the normal with the largest/smallest x intersection point.
2963  *
2964  * Now compute the second derivative to check whether
2965  * the intersection is a minimum or maximum:
2966  *
2967  *    h (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2))
2968  * -  -------------------------------------------
2969  *          w y0^3 (sqrt (h^2 - y^2)) ^ 3
2970  *
2971  * as we only care about the sign,
2972  *
2973  * - (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2))
2974  *
2975  * or (to use accelerators),
2976  *
2977  * y0^3 (h^2 - w^2) - h^2 y (3y0^2 - 2h^2)
2978  *
2979  */
2980 
2981 /* Compute the position on the ellipse whose normal line intersects the
2982    given scan line maximally. */
2983 static double
hookEllipseY(double scan_y,const struct arc_bound * bound,const struct accelerators * acc,bool left)2984 hookEllipseY (double scan_y, const struct arc_bound *bound, const struct accelerators *acc, bool left)
2985 {
2986   double ret;
2987 
2988   if (acc->h2mw2 == 0)
2989     {
2990       if ( (scan_y > 0 && (left ? false : true)) || (scan_y < 0 && left) )
2991 	return bound->ellipse.min;
2992       return bound->ellipse.max;
2993     }
2994   ret = (acc->h4 * scan_y) / (acc->h2mw2);
2995   if (ret >= 0)
2996     return cbrt (ret);
2997   else
2998     return -cbrt (-ret);
2999 }
3000 
3001 /* Compute the X value of the intersection of the given scan line with the
3002    right side of the lower hook. */
3003 static double
hookX(double scan_y,const struct arc_def * def,const struct arc_bound * bound,const struct accelerators * acc,bool left)3004 hookX (double scan_y, const struct arc_def *def, const struct arc_bound *bound, const struct accelerators *acc, bool left)
3005 {
3006   double	ellipse_y, x;
3007   double	maxMin;
3008 
3009   if (def->w != def->h)
3010     {
3011       ellipse_y = hookEllipseY (scan_y, bound, acc, left);
3012       if (boundedLe (ellipse_y, bound->ellipse))
3013 	{
3014 	  /*
3015 	   * compute the value of the second
3016 	   * derivative
3017 	   */
3018 	  maxMin = ellipse_y*ellipse_y*ellipse_y * acc->h2mw2 -
3019 	    acc->h2 * scan_y * (3 * ellipse_y*ellipse_y - 2*acc->h2);
3020 	  if ((left && maxMin > 0) || ((left ? false : true) && maxMin < 0))
3021 	    {
3022 	      if (ellipse_y == 0)
3023 		return def->w + left ? -def->l : def->l;
3024 	      x = (acc->h2 * scan_y - ellipse_y * acc->h2mw2) *
3025 		sqrt (acc->h2 - ellipse_y * ellipse_y) /
3026 		  (def->h * def->w * ellipse_y);
3027 	      return x;
3028 	    }
3029 	}
3030     }
3031   if (left)
3032     {
3033       if (acc->left.valid && boundedLe (scan_y, bound->left))
3034 	x = intersectLine (scan_y, acc->left);
3035       else
3036 	{
3037 	  if (acc->right.valid)
3038 	    x = intersectLine (scan_y, acc->right);
3039 	  else
3040 	    x = def->w - def->l;
3041 	}
3042     }
3043   else
3044     {
3045       if (acc->right.valid && boundedLe (scan_y, bound->right))
3046 	x = intersectLine (scan_y, acc->right);
3047       else
3048 	{
3049 	  if (acc->left.valid)
3050 	    x = intersectLine (scan_y, acc->left);
3051 	  else
3052 	    x = def->w - def->l;
3053 	}
3054     }
3055   return x;
3056 }
3057 
3058 
3059 /**********************************************************************/
3060 /* The following three sub-modules, taken together, provide only five
3061    public functions: initAccumSpans(), which initializes an miAccumSpans
3062    structure, newFinalSpan(), which draws a single span to a miAccumSpans
3063    structure, drawArc(), which draws a single arc to a miAccumSpans
3064    structure as a collection of spans, drawZeroArc(), which draws a single
3065    degenerate (horizontal or vertical) arc, and finally fillSpans(), which
3066    paints the miAccumSpans structure, deallocates the spans, and resets the
3067    structure. */
3068 /**********************************************************************/
3069 
3070 /**********************************************************************/
3071 /* A sub-module that accumulates an in-core cache of spans and on request,
3072    paints them.  Only two public functions are newFinalSpan() and
3073    fillSpans().  Former is invoked by the succeeding sub-module, which
3074    draws arcs as spans and in turn is invoked by the drawArc() sub-module.
3075    Latter is invoked above, in miPolyArc(), to clean things up. */
3076 /**********************************************************************/
3077 
3078 /* ???!!! a ceiling on amount by which finalSpans array is expanded !!!??? */
3079 #define SPAN_REALLOC	100
3080 
3081 /* forward references */
3082 static struct finalSpan * realAllocSpan (miAccumSpans *accumSpans);
3083 static struct finalSpan ** realFindSpan (miAccumSpans *accumSpans, int y);
3084 static void disposeFinalSpans (miAccumSpans *accumSpans);
3085 static void newFinalSpan (miAccumSpans *accumSpans, int y, int xmin, int xmax);
3086 
3087 /*** allocation-related functions ***/
3088 
3089 /* A public function for this module: initialize an miAccumSpans structure
3090    (an in-core accumulation of spans, which is added to by newFinalSpan(),
3091    and painted and deallocated by fillSpans()). */
3092 static void
initAccumSpans(miAccumSpans * accumSpans)3093 initAccumSpans (miAccumSpans *accumSpans)
3094 {
3095   accumSpans->finalSpans = (struct finalSpan **)NULL;
3096   accumSpans->finalMiny = 0;
3097   accumSpans->finalMaxy = -1;
3098   accumSpans->finalSize = 0;
3099   accumSpans->nspans = 0;
3100   accumSpans->chunks = (struct finalSpanChunk *)NULL;
3101   accumSpans->freeFinalSpans = (struct finalSpan *)NULL;
3102 }
3103 
3104 /* A public function for this module: add a span to an miAccumSpans
3105    structure.  By convention, span is [xmin, xmax-1] in terms of pixels.
3106    This agrees with the libxmi convention that `right edges' (as well as
3107    bottom edges) of polygons should be omitted, so that adjacent polygons
3108    can abut with no overlaps or gaps. */
3109 static void
newFinalSpan(miAccumSpans * accumSpans,int y,int xmin,int xmax)3110 newFinalSpan (miAccumSpans *accumSpans, int y, int xmin, int xmax)
3111 {
3112   struct finalSpan *x, *oldx, *prev, **f;
3113 
3114   /* find list of spans at this value of y in finalSpans array; if y isn't
3115      in the range finalMiny..finalMaxy, invoke realFindSpan() to expand
3116      finalSpans array */
3117   if (accumSpans->finalMiny <= y && y <= accumSpans->finalMaxy)
3118     f = &((accumSpans->finalSpans)[(y) - (accumSpans->finalMiny)]);
3119   else
3120     f = realFindSpan (accumSpans, y);
3121 
3122   /* loop through spans at y, trying to expand an existing one */
3123   if (f == (struct finalSpan **)NULL)
3124     return;
3125   oldx = (struct finalSpan *)NULL;
3126   for (;;)
3127     {
3128       prev = (struct finalSpan *)NULL;
3129       for (x = *f; x; x = x->next)
3130 	{
3131 	  if (x == oldx)
3132 	    {
3133 	      prev = x;
3134 	      continue;
3135 	    }
3136 	  if (x->min <= xmax && xmin <= x->max)
3137 	    /* expand span */
3138 	    {
3139 	      if (oldx)
3140 		{
3141 		  oldx->min = IMIN (x->min, xmin);
3142 		  oldx->max = IMAX (x->max, xmax);
3143 		  if (prev)
3144 		    prev->next = x->next;
3145 		  else
3146 		    *f = x->next;
3147 		  --(accumSpans->nspans);
3148 		}
3149 	      else
3150 		{
3151 		  x->min = IMIN (x->min, xmin);
3152 		  x->max = IMAX (x->max, xmax);
3153 		  oldx = x;
3154 		}
3155 	      xmin = oldx->min;
3156 	      xmax = oldx->max;
3157 	      break;
3158 	    }
3159 	  prev = x;
3160 	}
3161       if (!x)
3162 	break;
3163     }
3164 
3165   if (!oldx)
3166     /* couldn't expand an existing span at this value of y, so create a new
3167        one and add it to the list */
3168     {
3169       /* obtain new span from current chunk; if chunk is exhausted, invoke
3170 	 realAllocSpan() to allocate a new one */
3171       if (accumSpans->freeFinalSpans != (struct finalSpan *)NULL)
3172 	{
3173 	  x = accumSpans->freeFinalSpans;
3174 	  accumSpans->freeFinalSpans = accumSpans->freeFinalSpans->next;
3175 	  x->next = (struct finalSpan *)NULL;
3176 	}
3177       else
3178 	x = realAllocSpan (accumSpans);
3179 
3180       if (x)
3181 	{
3182 	  x->min = xmin;
3183 	  x->max = xmax;
3184 	  x->next = *f;
3185 	  *f = x;
3186 	  ++(accumSpans->nspans);
3187 	}
3188     }
3189 }
3190 
3191 /* Reallocate the finalSpans array in an miAccumSpans structure to include
3192    the specified value y.  This is called only if y is outside the range
3193    finalMiny..finalMaxy, which indexes the array.  Returns the address, in
3194    the finalSpans array, of the pointer to the head of the list of spans at
3195    the new value of y. */
3196 static struct finalSpan **
realFindSpan(miAccumSpans * accumSpans,int y)3197 realFindSpan (miAccumSpans *accumSpans, int y)
3198 {
3199   struct finalSpan	**newSpans, **t;
3200   int			newSize, newMiny, newMaxy;
3201   int			change;
3202   int			i, k;
3203 
3204   if (y < accumSpans->finalMiny || y > accumSpans->finalMaxy)
3205     /* need to expand... */
3206     {
3207       if (accumSpans->finalSize == 0)
3208 	{
3209 	  accumSpans->finalMiny = y;
3210 	  accumSpans->finalMaxy = y - 1;
3211 	}
3212       if (y < accumSpans->finalMiny)
3213 	change = accumSpans->finalMiny - y;
3214       else
3215 	change = y - accumSpans->finalMaxy;
3216 
3217       /* ???!!! a ceiling on amount by which finalSpans is expanded !!!??? */
3218       if (change >= SPAN_REALLOC)
3219 	change += SPAN_REALLOC;
3220       else
3221 	change = SPAN_REALLOC;
3222 
3223       newSize = accumSpans->finalSize + change;
3224 
3225       newSpans =
3226 	(struct finalSpan **)mi_xmalloc (newSize * sizeof (struct finalSpan *));
3227       newMiny = accumSpans->finalMiny;
3228       newMaxy = accumSpans->finalMaxy;
3229       if (y < accumSpans->finalMiny)
3230 	newMiny = accumSpans->finalMiny - change;
3231       else
3232 	newMaxy = accumSpans->finalMaxy + change;
3233       if (accumSpans->finalSpans)
3234 	{
3235 	  memmove ((void *)(newSpans + (accumSpans->finalMiny - newMiny)),
3236 		   (void *)(accumSpans->finalSpans),
3237 		   accumSpans->finalSize * sizeof(struct finalSpan *));
3238 	  free (accumSpans->finalSpans);
3239 	}
3240 
3241       if ((i = accumSpans->finalMiny - newMiny) > 0)
3242 	for (k = 0, t = newSpans; k < i; k++, t++)
3243 	  *t = (struct finalSpan *)NULL;
3244       if ((i = newMaxy - accumSpans->finalMaxy) > 0)
3245 	for (k = 0, t = newSpans + newSize - i; k < i; k++, t++)
3246 	  *t = (struct finalSpan *)NULL;
3247       accumSpans->finalSpans = newSpans;
3248       accumSpans->finalMaxy = newMaxy;
3249       accumSpans->finalMiny = newMiny;
3250       accumSpans->finalSize = newSize;
3251     }
3252 
3253   return &((accumSpans->finalSpans)[(y) - (accumSpans->finalMiny)]);
3254 }
3255 
3256 /* Return an unused span, by allocating a new chunk of spans and returning
3257    the first span in the chunk.  Called only if freeFinalSpans pointer in
3258    the miAccumSpans structure is NULL, i.e., previously allocated chunk (if
3259    any) is exhausted.  The freeFinalSpans and chunks pointers are
3260    updated. */
3261 static struct finalSpan *
realAllocSpan(miAccumSpans * accumSpans)3262 realAllocSpan (miAccumSpans *accumSpans)
3263 {
3264   struct finalSpanChunk	*newChunk;
3265   struct finalSpan	*span;
3266   int			i;
3267 
3268   /* allocate new chunk, add to head of chunk list */
3269   newChunk = (struct finalSpanChunk *) mi_xmalloc (sizeof (struct finalSpanChunk));
3270   newChunk->next = accumSpans->chunks;
3271   accumSpans->chunks = newChunk;
3272 
3273   /* point freeFinalSpans to the second span in the new chunk */
3274   accumSpans->freeFinalSpans = newChunk->data + 1;
3275 
3276   /* be sure `next' pointer of each span in the new chunk is NULL */
3277   span = newChunk->data + 1;
3278   for (i = 1; i < SPAN_CHUNK_SIZE - 1; i++)
3279     {
3280       span->next = span + 1;
3281       span++;
3282     }
3283   span->next = (struct finalSpan *)NULL;
3284 
3285   span = newChunk->data;
3286   span->next = (struct finalSpan *)NULL;
3287   return span;
3288 }
3289 
3290 /*** deallocation-related functions ***/
3291 
3292 /* A public function for this module: paint spans that have been
3293    accumulated in an miAccumSpans structure, in a specified pixel color;
3294    also reset the structure, as if initAccumSpans() had been called.
3295    Painting takes place to the specified miPaintedSet structure, by
3296    invoking MI_PAINT_SPANS(). */
3297 
3298 /* All painting done in this file goes through this function. */
3299 
3300 static void
fillSpans(miPaintedSet * paintedSet,miPixel pixel,miAccumSpans * accumSpans)3301 fillSpans (miPaintedSet *paintedSet, miPixel pixel, miAccumSpans *accumSpans)
3302 {
3303   struct finalSpan	*span;
3304   struct finalSpan	**f;
3305   int			spany;
3306   miPoint		*ppt, *pptInit;
3307   unsigned int		*pwidth, *pwidthInit;
3308 
3309   if (accumSpans->nspans == 0)
3310     return;
3311 
3312   /* from the miAccumSpans struct, construct an array of spans */
3313   ppt = pptInit = (miPoint *) mi_xmalloc (accumSpans->nspans * sizeof (miPoint));
3314   pwidth = pwidthInit = (unsigned int *) mi_xmalloc (accumSpans->nspans * sizeof (unsigned int));
3315 
3316   for (spany = accumSpans->finalMiny, f = accumSpans->finalSpans;
3317        spany <= accumSpans->finalMaxy;
3318        spany++, f++)
3319     {
3320       for (span = *f; span; span = span->next)
3321 	{
3322 	  if (span->max <= span->min)
3323 	    continue;
3324 	  ppt->x = span->min;
3325 	  ppt->y = spany;
3326 	  ++ppt;
3327 	  *pwidth++ = (unsigned int)(span->max - span->min);
3328 	}
3329     }
3330 
3331   /* paint the spans to the miPaintedSet */
3332   MI_PAINT_SPANS(paintedSet, pixel, ppt - pptInit, pptInit, pwidthInit)
3333 
3334   /* free all spans in the miAccumSpans struct, reset it */
3335   disposeFinalSpans (accumSpans);
3336   accumSpans->finalMiny = 0;
3337   accumSpans->finalMaxy = -1;
3338   accumSpans->finalSize = 0;
3339   accumSpans->nspans = 0;
3340 }
3341 
3342 static void
disposeFinalSpans(miAccumSpans * accumSpans)3343 disposeFinalSpans (miAccumSpans *accumSpans)
3344 {
3345   struct finalSpanChunk	*chunk, *next;
3346 
3347   for (chunk = accumSpans->chunks; chunk; chunk = next)
3348     {
3349       next = chunk->next;
3350       free (chunk);
3351     }
3352   accumSpans->chunks = (struct finalSpanChunk *)NULL;
3353   accumSpans->freeFinalSpans = (struct finalSpan *)NULL;
3354   free (accumSpans->finalSpans);
3355   accumSpans->finalSpans = (struct finalSpan **)NULL;
3356 }
3357 
3358 
3359 /**********************************************************************/
3360 /* A sub-module, used by drawArc(), that generates the spans associated
3361    with an arc, and writes them to an in-core span accumulation by calling
3362    newFinalSpan().  When this is used, computeAcc() and computeBounds()
3363    have already been called, to compute `accelerators' (frequently used
3364    quantities associated with the ellipse).  hookX() and tailX() are called
3365    to do additional geometry computations. */
3366 /**********************************************************************/
3367 
3368 /* forward references */
3369 static void arcSpan (miAccumSpans *accumSpans, int y, int lx, int lw, int rx, int rw, const struct arc_def *def, const struct arc_bound *bounds, const struct accelerators *acc, unsigned int mask);
3370 static void arcSpan0 (miAccumSpans *accumSpans, int lx, int lw, int rx, int rw, const struct arc_def *def, const struct arc_bound *bounds, const struct accelerators *acc, unsigned int mask);
3371 static void tailSpan (miAccumSpans *accumSpans, int y, int lw, int rw, const struct arc_def *def, const struct arc_bound *bounds, const struct accelerators *acc, unsigned int mask);
3372 
3373 /* Generate the set of spans with the given y coordinate. */
3374 static void
arcSpan(miAccumSpans * accumSpans,int y,int lx,int lw,int rx,int rw,const struct arc_def * def,const struct arc_bound * bounds,const struct accelerators * acc,unsigned int mask)3375 arcSpan (miAccumSpans *accumSpans, int y, int lx, int lw, int rx, int rw, const struct arc_def *def, const struct arc_bound *bounds, const struct accelerators *acc, unsigned int mask)
3376 {
3377   int linx, loutx, rinx, routx;
3378   double x, altx;
3379 
3380   if (boundedLe (y, bounds->inneri))
3381     {
3382       linx = -(lx + lw);
3383       rinx = rx;
3384     }
3385   else
3386     {
3387       /*
3388        * intersection with left face
3389        */
3390       x = hookX (y + acc->fromIntY, def, bounds, acc, true);
3391       if (acc->right.valid
3392 	  && boundedLe (y + acc->fromIntY, bounds->right))
3393 	{
3394 	  altx = intersectLine (y + acc->fromIntY, acc->right);
3395 	  if (altx < x)
3396 	    x = altx;
3397 	}
3398       linx = -ICEIL(acc->fromIntX - x);
3399       rinx = ICEIL(acc->fromIntX + x);
3400     }
3401 
3402   if (boundedLe (y, bounds->outeri))
3403     {
3404       loutx = -lx;
3405       routx = rx + rw;
3406     }
3407   else
3408     {
3409       /*
3410        * intersection with right face
3411        */
3412       x = hookX (y + acc->fromIntY, def, bounds, acc, false);
3413       if (acc->left.valid
3414 	  && boundedLe (y + acc->fromIntY, bounds->left))
3415 	{
3416 	  altx = x;
3417 	  x = intersectLine (y + acc->fromIntY, acc->left);
3418 	  if (x < altx)
3419 	    x = altx;
3420 	}
3421       loutx = -ICEIL(acc->fromIntX - x);
3422       routx = ICEIL(acc->fromIntX + x);
3423     }
3424 
3425   if (routx > rinx)
3426     {
3427       if (mask & 1)
3428 	newFinalSpan (accumSpans,
3429 		      acc->yorgu - y,
3430 		      acc->xorg + rinx, acc->xorg + routx);
3431       if (mask & 8)
3432 	newFinalSpan (accumSpans,
3433 		      acc->yorgl + y,
3434 		      acc->xorg + rinx, acc->xorg + routx);
3435     }
3436 
3437   if (loutx > linx)
3438     {
3439       if (mask & 2)
3440 	newFinalSpan (accumSpans,
3441 		      acc->yorgu - y,
3442 		      acc->xorg - loutx, acc->xorg - linx);
3443       if (mask & 4)
3444 	newFinalSpan (accumSpans,
3445 		      acc->yorgl + y,
3446 		      acc->xorg - loutx, acc->xorg - linx);
3447     }
3448 }
3449 
3450 static void
arcSpan0(miAccumSpans * accumSpans,int lx,int lw,int rx,int rw,const struct arc_def * def,const struct arc_bound * bounds,const struct accelerators * acc,unsigned int mask)3451 arcSpan0 (miAccumSpans *accumSpans, int lx, int lw, int rx, int rw, const struct arc_def *def, const struct arc_bound *bounds, const struct accelerators *acc, unsigned int mask)
3452 {
3453   double x;
3454 
3455   if (boundedLe (0, bounds->inneri)
3456       && acc->left.valid && boundedLe (0, bounds->left)
3457       && acc->left.b > 0)
3458     {
3459       x = def->w - def->l;
3460       if (acc->left.b < x)
3461 	x = acc->left.b;
3462       lw = ICEIL(acc->fromIntX - x) - lx;
3463       rw += rx;
3464       rx = ICEIL(acc->fromIntX + x);
3465       rw -= rx;
3466     }
3467   arcSpan (accumSpans, 0, lx, lw, rx, rw, def, bounds, acc, mask);
3468 }
3469 
3470 static void
tailSpan(miAccumSpans * accumSpans,int y,int lw,int rw,const struct arc_def * def,const struct arc_bound * bounds,const struct accelerators * acc,unsigned int mask)3471 tailSpan (miAccumSpans *accumSpans, int y, int lw, int rw, const struct arc_def *def, const struct arc_bound *bounds, const struct accelerators *acc, unsigned int mask)
3472 {
3473   double yy, xalt, x, lx, rx;
3474   int n;
3475 
3476   if (boundedLe(y, bounds->outeri))
3477     arcSpan (accumSpans, y, 0, lw, -rw, rw, def, bounds, acc, mask);
3478   else if (def->w != def->h)
3479     {
3480       yy = y + acc->fromIntY;
3481       x = tailX(yy, def, bounds, acc);
3482       if (yy == 0.0 && x == -rw - acc->fromIntX)
3483 	return;
3484       if (acc->right.valid && boundedLe (yy, bounds->right))
3485 	{
3486 	  rx = x;
3487 	  lx = -x;
3488 	  xalt = intersectLine (yy, acc->right);
3489 	  if (xalt >= -rw - acc->fromIntX && xalt <= rx)
3490 	    rx = xalt;
3491 	  n = ICEIL(acc->fromIntX + lx);
3492 	  if (lw > n)
3493 	    {
3494 	      if (mask & 2)
3495 		newFinalSpan (accumSpans,
3496 			      acc->yorgu - y,
3497 			      acc->xorg + n, acc->xorg + lw);
3498 	      if (mask & 4)
3499 		newFinalSpan (accumSpans,
3500 			      acc->yorgl + y,
3501 			      acc->xorg + n, acc->xorg + lw);
3502 	    }
3503 	  n = ICEIL(acc->fromIntX + rx);
3504 	  if (n > -rw)
3505 	    {
3506 	      if (mask & 1)
3507 		newFinalSpan (accumSpans,
3508 			      acc->yorgu - y,
3509 			      acc->xorg - rw, acc->xorg + n);
3510 	      if (mask & 8)
3511 		newFinalSpan (accumSpans,
3512 			      acc->yorgl + y,
3513 			      acc->xorg - rw, acc->xorg + n);
3514 	    }
3515 	}
3516       arcSpan (accumSpans, y,
3517 	       ICEIL(acc->fromIntX - x), 0,
3518 	       ICEIL(acc->fromIntX + x), 0,
3519 	       def, bounds, acc, mask);
3520     }
3521 }
3522 
3523 
3524 /**********************************************************************/
3525 /* The drawArc() function, which draws an arc to an in-core span
3526    accumulation by invoking the functions in the previous sub-module.  This
3527    calls miComputeWideEllipse() to rasterize the ellipse of which the arc
3528    is a part, and the helper functions computeAcc() and computeBounds().
3529    It is the low-level `draw to memory' function invoked by miArcSegment().
3530 
3531    drawZeroArc(), which follows, is simpler; it draws a degenerate
3532    (horizontal or vertical) arc. */
3533 /**********************************************************************/
3534 
3535 /* forward references */
3536 static void drawQuadrant (miAccumSpans *accumSpans, struct arc_def *def, struct accelerators *acc, int a0, int a1, unsigned int mask, miArcFace *right, miArcFace *left, miArcSpanData *spdata);
3537 static void mirrorSppPoint (int quadrant, SppPoint *sppPoint);
3538 
3539 /* Split an arc into pieces which are scan-converted in the first quadrant
3540  * and mirrored into position.  This is necessary as the scan-conversion
3541  * code can only deal with arcs completely contained in the first quadrant.
3542  */
3543 
3544 /* ARGS: right,left save arc endpoints */
3545 static void
drawArc(miAccumSpans * accumSpans,const miArc * tarc,unsigned int l,int a0,int a1,miArcFace * right,miArcFace * left,miEllipseCache * ellipseCache)3546 drawArc (miAccumSpans *accumSpans, const miArc *tarc, unsigned int l, int a0, int a1, miArcFace *right, miArcFace *left, miEllipseCache *ellipseCache)
3547 {
3548   struct arc_def	def;
3549   struct accelerators	acc;
3550   int			startq, endq, curq;
3551   int			rightq, leftq = 0, righta = 0, lefta = 0;
3552   miArcFace		*passRight, *passLeft;
3553   int			q0 = 0, q1 = 0;
3554   unsigned int		mask;
3555   struct band
3556     {
3557       int		a0, a1;
3558       unsigned int	mask;
3559     }			band[5], sweep[20];
3560   int			bandno, sweepno;
3561   int			i, j;
3562   bool			flipRight = false, flipLeft = false;
3563   bool			copyEnd = false;
3564   miArcSpanData		*spdata;
3565   bool			mustFree;
3566 
3567   /* compute span data for the whole wide ellipse, also caching it for
3568      speedy later retrieval */
3569   spdata = miComputeWideEllipse (l, tarc, &mustFree, ellipseCache);
3570   if (!spdata)
3571     /* unknown failure, so punt */
3572     return;
3573 
3574   if (a1 < a0)
3575     a1 += 360 * 64;
3576   startq = a0 / (90 * 64);
3577   if (a0 == a1)
3578     endq = startq;
3579   else
3580     endq = (a1-1) / (90 * 64);
3581   bandno = 0;
3582   curq = startq;
3583   rightq = -1;
3584   for (;;)
3585     {
3586       switch (curq)
3587 	{
3588 	case 0:
3589 	  if (a0 > 90 * 64)
3590 	    q0 = 0;
3591 	  else
3592 	    q0 = a0;
3593 	  if (a1 < 360 * 64)
3594 	    q1 = IMIN (a1, 90 * 64);
3595 	  else
3596 	    q1 = 90 * 64;
3597 	  if (curq == startq && a0 == q0 && rightq < 0)
3598 	    {
3599 	      righta = q0;
3600 	      rightq = curq;
3601 	    }
3602 	  if (curq == endq && a1 == q1)
3603 	    {
3604 	      lefta = q1;
3605 	      leftq = curq;
3606 	    }
3607 	  break;
3608 	case 1:
3609 	  if (a1 < 90 * 64)
3610 	    q0 = 0;
3611 	  else
3612 	    q0 = 180 * 64 - IMIN (a1, 180 * 64);
3613 	  if (a0 > 180 * 64)
3614 	    q1 = 90 * 64;
3615 	  else
3616 	    q1 = 180 * 64 - IMAX (a0, 90 * 64);
3617 	  if (curq == startq && 180 * 64 - a0 == q1)
3618 	    {
3619 	      righta = q1;
3620 	      rightq = curq;
3621 	    }
3622 	  if (curq == endq && 180 * 64 - a1 == q0)
3623 	    {
3624 	      lefta = q0;
3625 	      leftq = curq;
3626 	    }
3627 	  break;
3628 	case 2:
3629 	  if (a0 > 270 * 64)
3630 	    q0 = 0;
3631 	  else
3632 	    q0 = IMAX (a0, 180 * 64) - 180 * 64;
3633 	  if (a1 < 180 * 64)
3634 	    q1 = 90 * 64;
3635 	  else
3636 	    q1 = IMIN (a1, 270 * 64) - 180 * 64;
3637 	  if (curq == startq && a0 - 180*64 == q0)
3638 	    {
3639 	      righta = q0;
3640 	      rightq = curq;
3641 	    }
3642 	  if (curq == endq && a1 - 180 * 64 == q1)
3643 	    {
3644 	      lefta = q1;
3645 	      leftq = curq;
3646 	    }
3647 	  break;
3648 	case 3:
3649 	  if (a1 < 270 * 64)
3650 	    q0 = 0;
3651 	  else
3652 	    q0 = 360 * 64 - IMIN (a1, 360 * 64);
3653 	  q1 = 360 * 64 - IMAX (a0, 270 * 64);
3654 	  if (curq == startq && 360 * 64 - a0 == q1)
3655 	    {
3656 	      righta = q1;
3657 	      rightq = curq;
3658 	    }
3659 	  if (curq == endq && 360 * 64 - a1 == q0)
3660 	    {
3661 	      lefta = q0;
3662 	      leftq = curq;
3663 	    }
3664 	  break;
3665 	}
3666       band[bandno].a0 = q0;
3667       band[bandno].a1 = q1;
3668       band[bandno].mask = 1 << curq;
3669       bandno++;
3670       if (curq == endq)
3671 	break;
3672       curq++;
3673       if (curq == 4)
3674 	{
3675 	  a0 = 0;
3676 	  a1 -= 360 * 64;
3677 	  curq = 0;
3678 	  endq -= 4;
3679 	}
3680     }
3681   sweepno = 0;
3682   for (;;)
3683     {
3684       q0 = 90 * 64;
3685       mask = 0;
3686       /*
3687        * find left-most point
3688        */
3689       for (i = 0; i < bandno; i++)
3690 	if (band[i].a0 <= q0)
3691 	  {
3692 	    q0 = band[i].a0;
3693 	    q1 = band[i].a1;
3694 	    mask = band[i].mask;
3695 	  }
3696       if (mask == 0)
3697 	break;
3698       /*
3699        * locate next point of change
3700        */
3701       for (i = 0; i < bandno; i++)
3702 	if (!(mask & band[i].mask))
3703 	  {
3704 	    if (band[i].a0 == q0)
3705 	      {
3706 		if (band[i].a1 < q1)
3707 		  q1 = band[i].a1;
3708 		mask |= band[i].mask;
3709 	      }
3710 	    else if (band[i].a0 < q1)
3711 	      q1 = band[i].a0;
3712 	  }
3713       /*
3714        * create a new sweep
3715        */
3716       sweep[sweepno].a0 = q0;
3717       sweep[sweepno].a1 = q1;
3718       sweep[sweepno].mask = mask;
3719       sweepno++;
3720       /*
3721        * subtract the sweep from the affected bands
3722        */
3723       for (i = 0; i < bandno; i++)
3724 	if (band[i].a0 == q0)
3725 	  {
3726 	    band[i].a0 = q1;
3727 	    /*
3728 	     * check if this band is empty
3729 	     */
3730 	    if (band[i].a0 == band[i].a1)
3731 	      band[i].a1 = band[i].a0 = 90 * 64 + 1;
3732 	  }
3733     }
3734   computeAcc (tarc, l, &def, &acc);
3735   for (j = 0; j < sweepno; j++)
3736     {
3737       mask = sweep[j].mask;
3738       passRight = passLeft = (miArcFace *)NULL;
3739       if (mask & (1 << rightq))
3740 	{
3741 	  if (sweep[j].a0 == righta)
3742 	    passRight = right;
3743 	  else if (sweep[j].a1 == righta)
3744 	    {
3745 	      passLeft = right;
3746 	      flipRight = true;
3747 	    }
3748 	}
3749       if (mask & (1 << leftq))
3750 	{
3751 	  if (sweep[j].a1 == lefta)
3752 	    {
3753 	      if (passLeft)
3754 		copyEnd = true;
3755 	      passLeft = left;
3756 	    }
3757 	  else if (sweep[j].a0 == lefta)
3758 	    {
3759 	      if (passRight)
3760 		copyEnd = true;
3761 	      passRight = left;
3762 	      flipLeft = true;
3763 	    }
3764 	}
3765 
3766       drawQuadrant (accumSpans, &def, &acc, sweep[j].a0, sweep[j].a1, mask,
3767 		    passRight, passLeft, spdata);
3768     }
3769 
3770   /* when copyEnd is true, both ends of the arc were computed at the same
3771    * time; drawQuadrant only takes one end though, so the left end will be
3772    * the only one holding the data.  Copy it from there.
3773    */
3774   if (copyEnd)
3775     *right = *left;
3776   /*
3777    * mirror the coordinates generated for the
3778    * faces of the arc
3779    */
3780   if (right)
3781     {
3782       mirrorSppPoint (rightq, &right->clock);
3783       mirrorSppPoint (rightq, &right->center);
3784       mirrorSppPoint (rightq, &right->counterClock);
3785       if (flipRight)
3786 	{
3787 	  SppPoint	temp;
3788 
3789 	  temp = right->clock;
3790 	  right->clock = right->counterClock;
3791 	  right->counterClock = temp;
3792 	}
3793     }
3794   if (left)
3795     {
3796       mirrorSppPoint (leftq,  &left->counterClock);
3797       mirrorSppPoint (leftq,  &left->center);
3798       mirrorSppPoint (leftq,  &left->clock);
3799       if (flipLeft)
3800 	{
3801 	  SppPoint	temp;
3802 
3803 	  temp = left->clock;
3804 	  left->clock = left->counterClock;
3805 	  left->counterClock = temp;
3806 	}
3807     }
3808   if (mustFree)
3809     {
3810       free (spdata->spans);
3811       free (spdata);
3812     }
3813 }
3814 
3815 /* ARGS: spdata = rasterized wide ellipse */
3816 static void
drawQuadrant(miAccumSpans * accumSpans,struct arc_def * def,struct accelerators * acc,int a0,int a1,unsigned int mask,miArcFace * right,miArcFace * left,miArcSpanData * spdata)3817 drawQuadrant (miAccumSpans *accumSpans, struct arc_def *def, struct accelerators *acc, int a0, int a1, unsigned int mask, miArcFace *right, miArcFace *left, miArcSpanData *spdata)
3818 {
3819   struct arc_bound	bound;
3820   double		yy, x, xalt;
3821   int			y, miny, maxy;
3822   int			n;
3823   miArcSpan		*span;
3824 
3825   def->a0 = ((double) a0) / 64.0;
3826   def->a1 = ((double) a1) / 64.0;
3827   computeBound (def, &bound, acc, right, left);
3828 
3829   yy = bound.inner.min;
3830   if (bound.outer.min < yy)
3831     yy = bound.outer.min;
3832   miny = ICEIL(yy - acc->fromIntY);
3833   yy = bound.inner.max;
3834   if (bound.outer.max > yy)
3835     yy = bound.outer.max;
3836   maxy = (int)floor(yy - acc->fromIntY);
3837   y = spdata->k;
3838   span = spdata->spans;
3839 
3840   if (spdata->top)
3841     /* rasterized ellipse contains a `top point' */
3842     {
3843       if (a1 == 90 * 64 && (mask & 1))
3844 	newFinalSpan (accumSpans,
3845 		      acc->yorgu - y - 1, acc->xorg, acc->xorg + 1);
3846       span++;
3847     }
3848 
3849   /* loop through one-span ArcSpans, at successive values of y */
3850   for (n = spdata->count1; --n >= 0; )
3851     {
3852       if (y < miny)
3853 	return;
3854       if (y <= maxy)
3855 	{
3856 	  /* generate spans at this y value */
3857 	  arcSpan (accumSpans, y,
3858 		   span->lx, -span->lx, 0, span->lx + span->lw,
3859 		   def, &bound, acc, mask);
3860 	  if (span->rw + span->rx)
3861 	    tailSpan (accumSpans, y, -span->rw, -span->rx, def, &bound, acc, mask);
3862 	}
3863       y--;
3864       span++;
3865     }
3866   if (y < miny)
3867     return;
3868 
3869   if (spdata->hole)
3870     /* have a one-pixel hole to fill in */
3871     {
3872       if (y <= maxy)
3873 	/* generate a one-point span at this y value */
3874 	arcSpan (accumSpans, y, 0, 0, 0, 1,
3875 		 def, &bound, acc, mask & 0xc);
3876     }
3877 
3878   /* loop through two-span ArcSpans, at successive values of y */
3879   for (n = spdata->count2; --n >= 0; )
3880     {
3881       if (y < miny)
3882 	return;
3883       if (y <= maxy)
3884 	/* generate the two spans at this y value */
3885 	arcSpan (accumSpans, y, span->lx, span->lw, span->rx, span->rw,
3886 		 def, &bound, acc, mask);
3887 
3888       y--;
3889       span++;
3890     }
3891 
3892   if (spdata->bot && miny <= y && y <= maxy)
3893     /* have a `horizontal centerline' ArcSpan; treat it specially */
3894     {
3895       unsigned int m = mask;
3896 
3897       if (y == miny)
3898 	m &= 0xc;
3899       if (span->rw <= 0)
3900 	{
3901 	  arcSpan0 (accumSpans, span->lx, -span->lx, 0, span->lx + span->lw,
3902 		    def, &bound, acc, m);
3903 	  if (span->rw + span->rx)
3904 	    tailSpan (accumSpans, y, -span->rw, -span->rx, def, &bound, acc, m);
3905 	}
3906       else
3907 	arcSpan0 (accumSpans, span->lx, span->lw, span->rx, span->rw,
3908 		  def, &bound, acc, m);
3909       y--;
3910     }
3911 
3912   while (y >= miny)
3913     {
3914       yy = y + acc->fromIntY;
3915       if (def->w == def->h)
3916 	{
3917 	  xalt = def->w - def->l;
3918 	  x = -sqrt(xalt * xalt - yy * yy);
3919 	}
3920       else
3921 	{
3922 	  x = tailX(yy, def, &bound, acc);
3923 	  if (acc->left.valid && boundedLe (yy, bound.left))
3924 	    {
3925 	      xalt = intersectLine (yy, acc->left);
3926 	      if (xalt < x)
3927 		x = xalt;
3928 	    }
3929 	  if (acc->right.valid && boundedLe (yy, bound.right))
3930 	    {
3931 	      xalt = intersectLine (yy, acc->right);
3932 	      if (xalt < x)
3933 		x = xalt;
3934 	    }
3935 	}
3936       /* generate span at this y value */
3937       arcSpan (accumSpans, y,
3938 	       ICEIL(acc->fromIntX - x), 0,
3939 	       ICEIL(acc->fromIntX + x), 0,
3940 	       def, &bound, acc, mask);
3941       y--;
3942     }
3943 }
3944 
3945 static void
mirrorSppPoint(int quadrant,SppPoint * sppPoint)3946 mirrorSppPoint (int quadrant, SppPoint *sppPoint)
3947 {
3948   switch (quadrant)
3949     {
3950     case 0:
3951       break;
3952     case 1:
3953       sppPoint->x = -sppPoint->x;
3954       break;
3955     case 2:
3956       sppPoint->x = -sppPoint->x;
3957       sppPoint->y = -sppPoint->y;
3958       break;
3959     case 3:
3960       sppPoint->y = -sppPoint->y;
3961       break;
3962     }
3963   /*
3964    * and translate to X coordinate system
3965    */
3966   sppPoint->y = -sppPoint->y;
3967 }
3968 
3969 
3970 /***********************************************************************/
3971 /* Draw a degenerate (zero width/height) arc.  Left and right faces are
3972  * computed.  Called by miArcSegment() to handle the degenerate case:
3973  * tarc->width = 0 or tarc->height = 0. */
3974 /***********************************************************************/
3975 
3976 /* ARGS: left,right save arc endpoints */
3977 static void
drawZeroArc(miAccumSpans * accumSpans,const miArc * tarc,unsigned int lw,miArcFace * left,miArcFace * right)3978 drawZeroArc (miAccumSpans *accumSpans, const miArc *tarc, unsigned int lw, miArcFace *left, miArcFace *right)
3979 {
3980   double	x0 = 0.0, y0 = 0.0, x1 = 0.0, y1 = 0.0;
3981   double	w, h, x, y;
3982   double	xmax, ymax, xmin, ymin;
3983   int		a0, a1;
3984   double	a, startAngle, endAngle;
3985   double	l, lx, ly;
3986 
3987   l = 0.5 * lw;
3988   a0 = tarc->angle1;
3989   a1 = tarc->angle2;
3990   if (a1 > FULLCIRCLE)
3991     a1 = FULLCIRCLE;
3992   else if (a1 < -FULLCIRCLE)
3993     a1 = -FULLCIRCLE;
3994   w = 0.5 * tarc->width;
3995   h = 0.5 * tarc->height;
3996   /*
3997    * play in X coordinates right away
3998    */
3999   startAngle = - ((double) a0 / 64.0);
4000   endAngle = - ((double) (a0 + a1) / 64.0);
4001 
4002   xmax = -w;
4003   xmin = w;
4004   ymax = -h;
4005   ymin = h;
4006   a = startAngle;
4007   for (;;)
4008     {
4009       x = w * miDcos(a);
4010       y = h * miDsin(a);
4011       if (a == startAngle)
4012 	{
4013 	  x0 = x;
4014 	  y0 = y;
4015 	}
4016       if (a == endAngle)
4017 	{
4018 	  x1 = x;
4019 	  y1 = y;
4020 	}
4021       if (x > xmax)
4022 	xmax = x;
4023       if (x < xmin)
4024 	xmin = x;
4025       if (y > ymax)
4026 	ymax = y;
4027       if (y < ymin)
4028 	ymin = y;
4029       if (a == endAngle)
4030 	break;
4031       if (a1 < 0)		/* clockwise */
4032 	{
4033 	  if (floor (a / 90.0) == floor (endAngle / 90.0))
4034 	    a = endAngle;
4035 	  else
4036 	    a = 90 * (floor (a/90.0) + 1);
4037 	}
4038       else
4039 	{
4040 	  if (ceil (a / 90.0) == ceil (endAngle / 90.0))
4041 	    a = endAngle;
4042 	  else
4043 	    a = 90 * (ceil (a/90.0) - 1);
4044 	}
4045     }
4046   lx = ly = l;
4047   if ((x1 - x0) + (y1 - y0) < 0)
4048     lx = ly = -l;
4049   if (h)
4050     ly = 0.0;
4051   else
4052     lx = 0.0;
4053   if (right)
4054     {
4055       right->center.x = x0;
4056       right->center.y = y0;
4057       right->clock.x = x0 - lx;
4058       right->clock.y = y0 - ly;
4059       right->counterClock.x = x0 + lx;
4060       right->counterClock.y = y0 + ly;
4061     }
4062   if (left)
4063     {
4064       left->center.x = x1;
4065       left->center.y = y1;
4066       left->clock.x = x1 + lx;
4067       left->clock.y = y1 + ly;
4068       left->counterClock.x = x1 - lx;
4069       left->counterClock.y = y1 - ly;
4070     }
4071 
4072   x0 = xmin;
4073   x1 = xmax;
4074   y0 = ymin;
4075   y1 = ymax;
4076   if (ymin != y1)
4077     {
4078       xmin = -l;
4079       xmax = l;
4080     }
4081   else
4082     {
4083       ymin = -l;
4084       ymax = l;
4085     }
4086 
4087   if (xmax != xmin && ymax != ymin)
4088     /* construct a rectangle and `paint' it */
4089     {
4090       int		minx, maxx, miny, maxy;
4091       int		xorg, yorg, width, height;
4092 
4093       minx = ICEIL(xmin + w) + tarc->x;
4094       maxx = ICEIL(xmax + w) + tarc->x;
4095       miny = ICEIL(ymin + h) + tarc->y;
4096       maxy = ICEIL(ymax + h) + tarc->y;
4097       xorg = minx;
4098       yorg = miny;
4099       width = maxx - minx;
4100       height = maxy - miny;
4101 
4102       /* paint rectangle to the in-core miAccumSpans struct, except for its
4103          right and bottom edges */
4104       while (height--)
4105 	newFinalSpan (accumSpans, yorg, xorg, xorg + width);
4106     }
4107 }
4108