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