home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / server / ddx / mi / miarc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-21  |  87.8 KB  |  3,903 lines

  1. /***********************************************************
  2. Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
  3. and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
  4.  
  5.                         All Rights Reserved
  6.  
  7. Permission to use, copy, modify, and distribute this software and its 
  8. documentation for any purpose and without fee is hereby granted, 
  9. provided that the above copyright notice appear in all copies and that
  10. both that copyright notice and this permission notice appear in 
  11. supporting documentation, and that the names of Digital or MIT not be
  12. used in advertising or publicity pertaining to distribution of the
  13. software without specific, written prior permission.  
  14.  
  15. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  16. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  17. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  18. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  19. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  20. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  21. SOFTWARE.
  22.  
  23. ******************************************************************/
  24. /* $XConsortium: miarc.c,v 5.41 92/05/17 10:50:34 rws Exp $ */
  25. /* Author: Keith Packard */
  26.  
  27. #include <math.h>
  28. #include "X.h"
  29. #include "Xprotostr.h"
  30. #include "misc.h"
  31. #include "gcstruct.h"
  32. #include "scrnintstr.h"
  33. #include "pixmapstr.h"
  34. #include "windowstr.h"
  35. #include "mifpoly.h"
  36. #include "mi.h"
  37. #include "mifillarc.h"
  38. #include "Xfuncproto.h"
  39.  
  40. #if defined(SVR4) && __STDC__
  41. extern double hypot(double, double);
  42. #endif
  43. static double miDsin(), miDcos(), miDasin(), miDatan2();
  44. double    cbrt(
  45. #if NeedFunctionPrototypes
  46.          double
  47. #endif
  48. );
  49.  
  50. #ifdef ICEILTEMPDECL
  51. ICEILTEMPDECL
  52. #endif
  53.  
  54. /*
  55.  * some interesting sematic interpretation of the protocol:
  56.  *
  57.  * Self intersecting arcs (i.e. those spanning 360 degrees) 
  58.  *  never join with other arcs, and are drawn without caps
  59.  *  (unless on/off dashed, in which case each dash segment
  60.  *  is capped, except when the last segment meets the
  61.  *  first segment, when no caps are drawn)
  62.  *
  63.  * double dash arcs are drawn in two parts, first the
  64.  *  odd dashes (drawn in background) then the even dashes
  65.  *  (drawn in foreground).  This means that overlapping
  66.  *  sections of foreground/background are drawn twice,
  67.  *  first in background then in foreground.  The double-draw
  68.  *  occurs even when the function uses the destination values
  69.  *  (e.g. xor mode).  This is the same way the wide-line
  70.  *  code works and should be "fixed".
  71.  *
  72.  * the wide arc code will never be "correct" -- the protocol
  73.  *  document specifies exact pixelization which is impossible
  74.  *  when calculating pixel positions with complicated floating-
  75.  *  point expressions.
  76.  */
  77.  
  78. # define todeg(xAngle)    (((double) (xAngle)) / 64.0)
  79.  
  80. #ifndef X_AXIS
  81. # define X_AXIS 0
  82. # define Y_AXIS 1
  83. #endif
  84.  
  85. # define RIGHT_END    0
  86. # define LEFT_END    1
  87.  
  88. typedef struct _miArcJoin {
  89.     int    arcIndex0, arcIndex1;
  90.     int    phase0, phase1;
  91.     int    end0, end1;
  92. } miArcJoinRec, *miArcJoinPtr;
  93.  
  94. typedef struct _miArcCap {
  95.     int        arcIndex;
  96.     int        end;        
  97. } miArcCapRec, *miArcCapPtr;
  98.  
  99. typedef struct _miArcFace {
  100.     SppPointRec    clock;
  101.     SppPointRec    center;
  102.     SppPointRec    counterClock;
  103. } miArcFaceRec, *miArcFacePtr;
  104.  
  105. typedef struct _miArcData {
  106.     xArc        arc;
  107.     int        render;        /* non-zero means render after drawing */
  108.     int        join;        /* related join */
  109.     int        cap;        /* related cap */
  110.     int        selfJoin;    /* final dash meets first dash */
  111.     miArcFaceRec    bounds[2];
  112.     double        x0, y0, x1, y1;
  113. } miArcDataRec, *miArcDataPtr;
  114.  
  115. /*
  116.  * This is an entire sequence of arcs, computed and categorized according
  117.  * to operation.  miDashArcs generates either one or two of these.
  118.  */
  119.  
  120. typedef struct _miPolyArc {
  121.     int        narcs;
  122.     miArcDataPtr    arcs;
  123.     int        ncaps;
  124.     miArcCapPtr    caps;
  125.     int        njoins;
  126.     miArcJoinPtr    joins;
  127. } miPolyArcRec, *miPolyArcPtr;
  128.  
  129. #define GCValsFunction        0
  130. #define GCValsForeground     1
  131. #define GCValsBackground     2
  132. #define GCValsLineWidth     3
  133. #define GCValsCapStyle         4
  134. #define GCValsJoinStyle        5
  135. #define GCValsMask        (GCFunction | GCForeground | GCBackground | \
  136.                  GCLineWidth | GCCapStyle | GCJoinStyle)
  137. static XID gcvals[6];
  138.  
  139. extern void miFillSppPoly();
  140. static void fillSpans(), span(), drawArc(), drawQuadrant(), drawZeroArc();
  141. static void miFreeArcs(), miArcJoin(), miArcCap(), miRoundCap();
  142. static int computeAngleFromPath(), miGetArcPts();
  143. static miPolyArcPtr miComputeArcs ();
  144.  
  145. #undef max
  146. #undef min
  147.  
  148. #if defined (__GNUC__) && defined (__STDC__) && !defined (__STRICT_ANSI__)
  149. #define USE_INLINE
  150. #endif
  151.  
  152. #ifdef USE_INLINE
  153. inline static const int max (const int x, const int y)
  154. {
  155.     return x>y? x:y;
  156. }
  157.  
  158. inline static const int min (const int x, const int y)
  159. {
  160.     return x<y? x:y;
  161. }
  162.  
  163. inline static const double fmax (const double x, const double y)
  164. {
  165.     return x>y? x:y;
  166. }
  167.  
  168. inline static const double fmin (const double x, const double y)
  169. {
  170.     return x<y? x:y;
  171. }
  172.  
  173. #else
  174.  
  175. static int
  176. max (x, y)
  177. {
  178.     return x>y? x:y;
  179. }
  180.  
  181. static int
  182. min (x, y)
  183. {
  184.     return x<y? x:y;
  185. }
  186.  
  187. static double
  188. fmax (a, b)
  189. double    a,b;
  190. {
  191.     return a > b? a : b;
  192. }
  193.  
  194. static double
  195. fmin (a, b)
  196. double    a, b;
  197. {
  198.     return a < b ? a : b;
  199. }
  200.  
  201. #endif
  202.  
  203. /*
  204.  * draw one segment of the arc using the arc spans generation routines
  205.  */
  206.  
  207. static void
  208. miArcSegment(pDraw, pGC, tarc, right, left)
  209.     DrawablePtr   pDraw;
  210.     GCPtr         pGC;
  211.     xArc          tarc;
  212.     miArcFacePtr    right, left;
  213. {
  214.     int l = pGC->lineWidth;
  215.     int a0, a1, startAngle, endAngle;
  216.     miArcFacePtr    temp;
  217.  
  218.     if (tarc.width == 0 || tarc.height == 0) {
  219.         drawZeroArc (pDraw, pGC, tarc, left, right);
  220.     return;
  221.     }
  222.  
  223.     if (pGC->miTranslate) {
  224.     tarc.x += pDraw->x;
  225.     tarc.y += pDraw->y;
  226.     }
  227.  
  228.     a0 = tarc.angle1;
  229.     a1 = tarc.angle2;
  230.     if (a1 > FULLCIRCLE)
  231.     a1 = FULLCIRCLE;
  232.     else if (a1 < -FULLCIRCLE)
  233.     a1 = -FULLCIRCLE;
  234.     if (a1 < 0) {
  235.         startAngle = a0 + a1;
  236.     endAngle = a0;
  237.     temp = right;
  238.     right = left;
  239.     left = temp;
  240.     } else {
  241.     startAngle = a0;
  242.     endAngle = a0 + a1;
  243.     }
  244.     /*
  245.      * bounds check the two angles
  246.      */
  247.     if (startAngle < 0)
  248.     startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE;
  249.     if (startAngle >= FULLCIRCLE)
  250.     startAngle = startAngle % FULLCIRCLE;
  251.     if (endAngle < 0)
  252.     endAngle = FULLCIRCLE - (-endAngle) % FULLCIRCLE;
  253.     if (endAngle > FULLCIRCLE)
  254.     endAngle = (endAngle-1) % FULLCIRCLE + 1;
  255.     if ((startAngle == endAngle) && a1) {
  256.     startAngle = 0;
  257.     endAngle = FULLCIRCLE;
  258.     }
  259.  
  260.     drawArc ((int) tarc.x, (int) tarc.y,
  261.              (int) tarc.width, (int) tarc.height, l, startAngle, endAngle,
  262.          right, left);
  263. }
  264.  
  265. /*
  266.  
  267. Three equations combine to describe the boundaries of the arc
  268.  
  269. x^2/w^2 + y^2/h^2 = 1            ellipse itself
  270. (X-x)^2 + (Y-y)^2 = r^2            circle at (x, y) on the ellipse
  271. (Y-y) = (X-x)*w^2*y/(h^2*x)        normal at (x, y) on the ellipse
  272.  
  273. These lead to a quartic relating Y and y
  274.  
  275. y^4 - (2Y)y^3 + (Y^2 + (h^4 - w^2*r^2)/(w^2 - h^2))y^2
  276.     - (2Y*h^4/(w^2 - h^2))y + (Y^2*h^4)/(w^2 - h^2) = 0
  277.  
  278. The reducible cubic obtained from this quartic is
  279.  
  280. z^3 - (3N)z^2 - 2V = 0
  281.  
  282. where
  283.  
  284. N = (Y^2 + (h^4 - w^2*r^2/(w^2 - h^2)))/6
  285. V = w^2*r^2*Y^2*h^4/(4 *(w^2 - h^2)^2)
  286.  
  287. Let
  288.  
  289. t = z - N
  290. p = -N^2
  291. q = -N^3 - V
  292.  
  293. Then we get
  294.  
  295. t^3 + 3pt + 2q = 0
  296.  
  297. The discriminant of this cubic is
  298.  
  299. D = q^2 + p^3
  300.  
  301. When D > 0, a real root is obtained as
  302.  
  303. z = N + cbrt(-q+sqrt(D)) + cbrt(-q-sqrt(D))
  304.  
  305. When D < 0, a real root is obtained as
  306.  
  307. z = N - 2m*cos(acos(-q/m^3)/3)
  308.  
  309. where
  310.  
  311. m = sqrt(|p|) * sign(q)
  312.  
  313. Given a real root Z of the cubic, the roots of the quartic are the roots
  314. of the two quadratics
  315.  
  316. y^2 + ((b+A)/2)y + (Z + (bZ - d)/A) = 0
  317.  
  318. where 
  319.  
  320. A = +/- sqrt(8Z + b^2 - 4c)
  321. b, c, d are the cubic, quadratic, and linear coefficients of the quartic
  322.  
  323. Some experimentation is then required to determine which solutions
  324. correspond to the inner and outer boundaries.
  325.  
  326. */
  327.  
  328. typedef struct {
  329.     short lx, lw, rx, rw;
  330. } miArcSpan;
  331.  
  332. typedef struct {
  333.     miArcSpan *spans;
  334.     int count1, count2, k;
  335.     char top, bot, hole;
  336. } miArcSpanData;
  337.  
  338. typedef struct {
  339.     unsigned long lrustamp;
  340.     unsigned short lw;
  341.     unsigned short width, height;
  342.     miArcSpanData *spdata;
  343. } arcCacheRec;
  344.  
  345. #define CACHESIZE 25
  346.  
  347. static arcCacheRec arcCache[CACHESIZE];
  348. static unsigned long lrustamp;
  349. static arcCacheRec *lastCacheHit = &arcCache[0];
  350. static RESTYPE cacheType;
  351.  
  352. /*
  353.  * External so it can be called when low on memory.
  354.  * Call with a zero ID in that case.
  355.  */
  356. /*ARGSUSED*/
  357. int
  358. miFreeArcCache (data, id)
  359.     pointer        data;
  360.     XID            id;
  361. {
  362.     int k;
  363.     arcCacheRec *cent;
  364.  
  365.     if (id)
  366.     cacheType = 0;
  367.  
  368.     for (k = CACHESIZE, cent = &arcCache[0]; --k >= 0; cent++)
  369.     {
  370.     if (cent->spdata)
  371.     {
  372.         cent->lrustamp = 0;
  373.         cent->lw = 0;
  374.         xfree(cent->spdata);
  375.         cent->spdata = NULL;
  376.     }
  377.     }
  378.     lrustamp = 0;
  379. }
  380.  
  381. static void
  382. miComputeCircleSpans(lw, parc, spdata)
  383.     int lw;
  384.     xArc *parc;
  385.     miArcSpanData *spdata;
  386. {
  387.     register miArcSpan *span;
  388.     int doinner;
  389.     register int x, y, e;
  390.     int xk, yk, xm, ym, dx, dy;
  391.     register int slw, inslw;
  392.     int inx, iny, ine;
  393.     int inxk, inyk, inxm, inym;
  394.  
  395.     doinner = -lw;
  396.     slw = parc->width - doinner;
  397.     y = parc->height >> 1;
  398.     dy = parc->height & 1;
  399.     dx = 1 - dy;
  400.     MIWIDEARCSETUP(x, y, dy, slw, e, xk, xm, yk, ym);
  401.     inslw = parc->width + doinner;
  402.     if (inslw > 0)
  403.     {
  404.     spdata->hole = spdata->top;
  405.     MIWIDEARCSETUP(inx, iny, dy, inslw, ine, inxk, inxm, inyk, inym);
  406.     }
  407.     else
  408.     {
  409.     spdata->hole = FALSE;
  410.     doinner = -y;
  411.     }
  412.     spdata->count1 = -doinner - spdata->top;
  413.     spdata->count2 = y + doinner;
  414.     span = spdata->spans;
  415.     while (y)
  416.     {
  417.     MIFILLARCSTEP(slw);
  418.     span->lx = dy - x;
  419.     if (++doinner <= 0)
  420.      {
  421.         span->lw = slw;
  422.     }
  423.     else
  424.     {
  425.         MIFILLINARCSTEP(inslw);
  426.         span->lw = x - inx;
  427.         span->rx = dy - inx + inslw;
  428.         span->rw = inx - x + slw - inslw;
  429.     }
  430.     span++;
  431.     }
  432.     if (spdata->bot)
  433.     {
  434.     if (spdata->count2)
  435.         spdata->count2--;
  436.     else
  437.     {
  438.         span[-1].rw = 0;
  439.         spdata->count1--;
  440.     }
  441.     }
  442. }
  443.  
  444. static void
  445. miComputeEllipseSpans(lw, parc, spdata)
  446.     int lw;
  447.     xArc *parc;
  448.     miArcSpanData *spdata;
  449. {
  450.     register miArcSpan *span;
  451.     double w, h, r, xorg;
  452.     double Hs, Hf, WH, K, Vk, Nk, Fk, Vr, N, Nc, Z, rs;
  453.     double A, T, b, d, x, y, t, inx, outx, hepp, hepm;
  454.     int flip, solution;
  455.  
  456.     w = parc->width / 2.0;
  457.     h = parc->height / 2.0;
  458.     r = lw / 2.0;
  459.     rs = r * r;
  460.     Hs = h * h;
  461.     WH = w * w - Hs;
  462.     Nk = w * r;
  463.     Vk = (Nk * Hs) / (WH + WH);
  464.     Hf = Hs * Hs;
  465.     Nk = (Hf - Nk * Nk) / WH;
  466.     Fk = Hf / WH;
  467.     hepp = h + EPSILON;
  468.     hepm = h - EPSILON;
  469.     K = h + ((lw - 1) >> 1);
  470.     span = spdata->spans;
  471.     if (parc->width & 1)
  472.     xorg = .5;
  473.     else
  474.     xorg = 0.0;
  475.     if (spdata->top)
  476.     {
  477.     span->lx = 0;
  478.     span->lw = 1;
  479.     span++;
  480.     }
  481.     spdata->count1 = 0;
  482.     spdata->count2 = 0;
  483.     spdata->hole = (spdata->top &&
  484.             parc->height * lw <= parc->width * parc->width &&
  485.             lw < parc->height);
  486.     for (; K > 0.0; K -= 1.0)
  487.     {
  488.     N = (K * K + Nk) / 6.0;
  489.     Nc = N * N * N;
  490.     Vr = Vk * K;
  491.     t = Nc + Vr * Vr;
  492.     d = Nc + t;
  493.     if (d < 0.0) {
  494.         d = Nc;
  495.         b = N;
  496.         if (b < 0.0 == t < 0.0)
  497.         {
  498.         b = -b;
  499.         d = -d;
  500.         }
  501.         Z = N - 2.0 * b * cos(acos(-t / d) / 3.0);
  502.         if (Z < 0.0 == Vr < 0.0)
  503.         flip = 2;
  504.         else
  505.         flip = 1;
  506.     }
  507.     else
  508.     {
  509.         d = Vr * sqrt(d);
  510.         Z = N + cbrt(t + d) + cbrt(t - d);
  511.         flip = 0;
  512.     }
  513.     A = sqrt((Z + Z) - Nk);
  514.     T = (Fk - Z) * K / A;
  515.     inx = 0.0;
  516.     solution = FALSE;
  517.     b = -A + K;
  518.     d = b * b - 4 * (Z + T);
  519.     if (d >= 0)
  520.     {
  521.         d = sqrt(d);
  522.         y = (b + d) / 2;
  523.         if ((y >= 0.0) && (y < hepp))
  524.         {
  525.         solution = TRUE;
  526.         if (y > hepm)
  527.             y = h;
  528.         t = y / h;
  529.         x = w * sqrt(1 - (t * t));
  530.         t = K - y;
  531.         t = sqrt(rs - (t * t));
  532.         if (flip == 2)
  533.             inx = x - t;
  534.         else
  535.             outx = x + t;
  536.         }
  537.     }
  538.     b = A + K;
  539.     d = b * b - 4 * (Z - T);
  540.     /* Because of the large magnitudes involved, we lose enough precision
  541.      * that sometimes we end up with a negative value near the axis, when
  542.      * it should be positive.  This is a workaround.
  543.      */
  544.     if (d < 0 && !solution)
  545.         d = 0.0;
  546.     if (d >= 0) {
  547.         d = sqrt(d);
  548.         y = (b + d) / 2;
  549.         if (y < hepp)
  550.         {
  551.         if (y > hepm)
  552.             y = h;
  553.         t = y / h;
  554.         x = w * sqrt(1 - (t * t));
  555.         t = K - y;
  556.         inx = x - sqrt(rs - (t * t));
  557.         }
  558.         y = (b - d) / 2;
  559.         if (y >= 0.0)
  560.         {
  561.         if (y > hepm)
  562.             y = h;
  563.         t = y / h;
  564.         x = w * sqrt(1 - (t * t));
  565.         t = K - y;
  566.         t = sqrt(rs - (t * t));
  567.         if (flip == 1)
  568.             inx = x - t;
  569.         else
  570.             outx = x + t;
  571.         }
  572.     }
  573.     span->lx = ICEIL(xorg - outx);
  574.     if (inx <= 0.0)
  575.     {
  576.         spdata->count1++;
  577.         span->lw = ICEIL(xorg + outx) - span->lx;
  578.     }
  579.     else
  580.     {
  581.         spdata->count2++;
  582.         span->lw = ICEIL(xorg - inx) - span->lx;
  583.         span->rx = ICEIL(xorg + inx);
  584.         span->rw = ICEIL(xorg + outx) - span->rx;
  585.     }
  586.     span++;
  587.     }
  588.     if (spdata->bot)
  589.     {
  590.     outx = w + r;
  591.     if (r >= h)
  592.         inx = 0.0;
  593.     else if (Nk < 0.0 && -Nk < Hs)
  594.         inx = w * sqrt(1 + Nk / Hs) - sqrt(rs + Nk);
  595.     else
  596.         inx = w - r;
  597.     span->lx = ICEIL(xorg - outx);
  598.     if (inx <= 0.0)
  599.     {
  600.         span->lw = ICEIL(xorg + outx) - span->lx;
  601.         span->rw = 0;
  602.     }
  603.     else
  604.     {
  605.         span->lw = ICEIL(xorg - inx) - span->lx;
  606.         span->rx = ICEIL(xorg + inx);
  607.         span->rw = ICEIL(xorg + outx) - span->rx;
  608.     }
  609.     }
  610.     if (spdata->hole)
  611.     {
  612.     span = &spdata->spans[spdata->count1];
  613.     span->lw = -span->lx;
  614.     span->rx = 1;
  615.     span->rw = span->lw;
  616.     spdata->count1--;
  617.     spdata->count2++;
  618.     }
  619. }
  620.  
  621. static miArcSpanData *
  622. miComputeWideEllipse(lw, parc, mustFree)
  623.     int           lw;
  624.     register xArc *parc;
  625.     Bool      *mustFree;
  626. {
  627.     register miArcSpanData *spdata;
  628.     register arcCacheRec *cent, *lruent;
  629.     register int k;
  630.     arcCacheRec fakeent;
  631.  
  632.     if (!lw)
  633.     lw = 1;
  634.     if (parc->height <= 1500)
  635.     {
  636.     *mustFree = FALSE;
  637.     cent = lastCacheHit;
  638.     if (cent->lw == lw &&
  639.         cent->width == parc->width && cent->height == parc->height)
  640.     {
  641.         cent->lrustamp = ++lrustamp;
  642.         return cent->spdata;
  643.     }
  644.     lruent = &arcCache[0];
  645.     for (k = CACHESIZE, cent = lruent; --k >= 0; cent++)
  646.     {
  647.         if (cent->lw == lw &&
  648.         cent->width == parc->width && cent->height == parc->height)
  649.         {
  650.         cent->lrustamp = ++lrustamp;
  651.         lastCacheHit = cent;
  652.         return cent->spdata;
  653.         }
  654.         if (cent->lrustamp < lruent->lrustamp)
  655.         lruent = cent;
  656.     }
  657.     if (!cacheType)
  658.     {
  659.         cacheType = CreateNewResourceType(miFreeArcCache);
  660.         (void) AddResource(FakeClientID(0), cacheType, NULL);
  661.     }
  662.     } else {
  663.     lruent = &fakeent;
  664.     lruent->spdata = NULL;
  665.     *mustFree = TRUE;
  666.     }
  667.     k = (parc->height >> 1) + ((lw - 1) >> 1);
  668.     spdata = lruent->spdata;
  669.     if (!spdata || spdata->k != k)
  670.     {
  671.     if (spdata)
  672.         xfree(spdata);
  673.     spdata = (miArcSpanData *)xalloc(sizeof(miArcSpanData) +
  674.                      sizeof(miArcSpan) * (k + 2));
  675.     lruent->spdata = spdata;
  676.     if (!spdata)
  677.     {
  678.         lruent->lrustamp = 0;
  679.         lruent->lw = 0;
  680.         return spdata;
  681.     }
  682.     spdata->spans = (miArcSpan *)(spdata + 1);
  683.     spdata->k = k;
  684.     }
  685.     spdata->top = !(lw & 1) && !(parc->width & 1);
  686.     spdata->bot = !(parc->height & 1);
  687.     lruent->lrustamp = ++lrustamp;
  688.     lruent->lw = lw;
  689.     lruent->width = parc->width;
  690.     lruent->height = parc->height;
  691.     lastCacheHit = lruent;
  692.     if (parc->width == parc->height)
  693.     miComputeCircleSpans(lw, parc, spdata);
  694.     else
  695.     miComputeEllipseSpans(lw, parc, spdata);
  696.     return spdata;
  697. }
  698.  
  699. static void
  700. miFillWideEllipse(pDraw, pGC, parc)
  701.     DrawablePtr    pDraw;
  702.     GCPtr    pGC;
  703.     xArc    *parc;
  704. {
  705.     DDXPointPtr points;
  706.     register DDXPointPtr pts;
  707.     int *widths;
  708.     register int *wids;
  709.     miArcSpanData *spdata;
  710.     Bool mustFree;
  711.     register miArcSpan *span;
  712.     register int xorg, yorgu, yorgl;
  713.     register int n;
  714.  
  715.     yorgu = parc->height + pGC->lineWidth;
  716.     n = (sizeof(int) * 2) * yorgu;
  717.     widths = (int *)ALLOCATE_LOCAL(n + (sizeof(DDXPointRec) * 2) * yorgu);
  718.     if (!widths)
  719.     return;
  720.     points = (DDXPointPtr)((char *)widths + n);
  721.     spdata = miComputeWideEllipse(pGC->lineWidth, parc, &mustFree);
  722.     if (!spdata)
  723.     {
  724.     DEALLOCATE_LOCAL(widths);
  725.     return;
  726.     }
  727.     pts = points;
  728.     wids = widths;
  729.     span = spdata->spans;
  730.     xorg = parc->x + (parc->width >> 1);
  731.     yorgu = parc->y + (parc->height >> 1);
  732.     yorgl = yorgu + (parc->height & 1);
  733.     if (pGC->miTranslate)
  734.     {
  735.     xorg += pDraw->x;
  736.     yorgu += pDraw->y;
  737.     yorgl += pDraw->y;
  738.     }
  739.     yorgu -= spdata->k;
  740.     yorgl += spdata->k;
  741.     if (spdata->top)
  742.     {
  743.     pts->x = xorg;
  744.     pts->y = yorgu - 1;
  745.     pts++;
  746.     *wids++ = 1;
  747.     span++;
  748.     }
  749.     for (n = spdata->count1; --n >= 0; )
  750.     {
  751.     pts[0].x = xorg + span->lx;
  752.     pts[0].y = yorgu;
  753.     wids[0] = span->lw;
  754.     pts[1].x = pts[0].x;
  755.     pts[1].y = yorgl;
  756.     wids[1] = wids[0];
  757.     yorgu++;
  758.     yorgl--;
  759.     pts += 2;
  760.     wids += 2;
  761.     span++;
  762.     }
  763.     if (spdata->hole)
  764.     {
  765.     pts[0].x = xorg;
  766.     pts[0].y = yorgl;
  767.     wids[0] = 1;
  768.     pts++;
  769.     wids++;
  770.     }
  771.     for (n = spdata->count2; --n >= 0; )
  772.     {
  773.     pts[0].x = xorg + span->lx;
  774.     pts[0].y = yorgu;
  775.     wids[0] = span->lw;
  776.     pts[1].x = xorg + span->rx;
  777.     pts[1].y = pts[0].y;
  778.     wids[1] = span->rw;
  779.     pts[2].x = pts[0].x;
  780.     pts[2].y = yorgl;
  781.     wids[2] = wids[0];
  782.     pts[3].x = pts[1].x;
  783.     pts[3].y = pts[2].y;
  784.     wids[3] = wids[1];
  785.     yorgu++;
  786.     yorgl--;
  787.     pts += 4;
  788.     wids += 4;
  789.     span++;
  790.     }
  791.     if (spdata->bot)
  792.     {
  793.     if (!span->rw)
  794.     {
  795.         pts[0].x = xorg + span->lx;
  796.         pts[0].y = yorgu;
  797.         wids[0] = span->lw;
  798.         pts++;
  799.         wids++;
  800.     }    
  801.     else
  802.     {
  803.         pts[0].x = xorg + span->lx;
  804.         pts[0].y = yorgu;
  805.         wids[0] = span->lw;
  806.         pts[1].x = xorg + span->rx;
  807.         pts[1].y = pts[0].y;
  808.         wids[1] = span->rw;
  809.         pts += 2;
  810.         wids += 2;
  811.     }
  812.     }
  813.     if (mustFree)
  814.     xfree(spdata);
  815.     (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE);
  816.  
  817.     DEALLOCATE_LOCAL(widths);
  818. }
  819.  
  820. /*
  821.  * miPolyArc strategy:
  822.  *
  823.  * If arc is zero width and solid, we don't have to worry about the rasterop
  824.  * or join styles.  For wide solid circles, we use a fast integer algorithm.
  825.  * For wide solid ellipses, we use special case floating point code.
  826.  * Otherwise, we set up pDrawTo and pGCTo according to the rasterop, then
  827.  * draw using pGCTo and pDrawTo.  If the raster-op was "tricky," that is,
  828.  * if it involves the destination, then we use PushPixels to move the bits
  829.  * from the scratch drawable to pDraw. (See the wide line code for a
  830.  * fuller explanation of this.)
  831.  */
  832.  
  833. void
  834. miPolyArc(pDraw, pGC, narcs, parcs)
  835.     DrawablePtr    pDraw;
  836.     GCPtr    pGC;
  837.     int        narcs;
  838.     xArc    *parcs;
  839. {
  840.     register int        i;
  841.     xArc            *parc;
  842.     int                xMin, xMax, yMin, yMax;
  843.     int                dx, dy;
  844.     int                xOrg, yOrg;
  845.     int                width;
  846.     Bool            fTricky;
  847.     DrawablePtr            pDrawTo;
  848.     unsigned long        fg, bg;
  849.     GCPtr            pGCTo;
  850.     miPolyArcPtr        polyArcs;
  851.     int                cap[2], join[2];
  852.     int                iphase;
  853.  
  854.     width = pGC->lineWidth;
  855.     if(width == 0 && pGC->lineStyle == LineSolid)
  856.     {
  857.     for(i = narcs, parc = parcs; --i >= 0; parc++)
  858.         miArcSegment( pDraw, pGC, *parc,
  859.          (miArcFacePtr) 0, (miArcFacePtr) 0 );
  860.     fillSpans (pDraw, pGC);
  861.     }
  862.     else 
  863.     {
  864.     if ((pGC->lineStyle == LineSolid) && narcs)
  865.     {
  866.         while (parcs->width && parcs->height &&
  867.            (parcs->angle2 >= FULLCIRCLE ||
  868.             parcs->angle2 <= -FULLCIRCLE))
  869.         {
  870.         miFillWideEllipse(pDraw, pGC, parcs);
  871.         if (!--narcs)
  872.             return;
  873.         parcs++;
  874.         }
  875.     }
  876.  
  877.     /* Set up pDrawTo and pGCTo based on the rasterop */
  878.     switch(pGC->alu)
  879.     {
  880.       case GXclear:        /* 0 */
  881.       case GXcopy:        /* src */
  882.       case GXcopyInverted:    /* NOT src */
  883.       case GXset:        /* 1 */
  884.         fTricky = FALSE;
  885.         pDrawTo = pDraw;
  886.         pGCTo = pGC;
  887.         break;
  888.       default:
  889.         fTricky = TRUE;
  890.  
  891.         xMin = yMin = MAXSHORT;
  892.         xMax = yMax = MINSHORT;
  893.  
  894.         for(i = narcs, parc = parcs; --i >= 0; parc++)
  895.         {
  896.         xMin = min (xMin, parc->x);
  897.         yMin = min (yMin, parc->y);
  898.         xMax = max (xMax, (parc->x + (int) parc->width));
  899.         yMax = max (yMax, (parc->y + (int) parc->height));
  900.         }
  901.  
  902.         pGCTo = GetScratchGC(1, pDraw->pScreen);
  903.         if (!pGCTo)
  904.         return;
  905.         gcvals[GCValsFunction] = GXcopy;
  906.         gcvals[GCValsForeground] = 1;
  907.         gcvals[GCValsBackground] = 0;
  908.         gcvals[GCValsLineWidth] = pGC->lineWidth;
  909.         gcvals[GCValsCapStyle] = pGC->capStyle;
  910.         gcvals[GCValsJoinStyle] = pGC->joinStyle;
  911.         DoChangeGC(pGCTo, GCValsMask, gcvals, 0);
  912.     
  913.             xOrg = xMin - (width + 1)/2;
  914.         yOrg = yMin - (width + 1)/2;
  915.         dx = (xMax - xMin) + width + 1;
  916.         dy = (yMax - yMin) + width + 1;
  917.         for(i = narcs, parc = parcs; --i >= 0; parc++)
  918.         {
  919.         parc->x -= xOrg;
  920.         parc->y -= yOrg;
  921.         }
  922.         if (pGC->miTranslate)
  923.         {
  924.         xOrg += pDraw->x;
  925.         yOrg += pDraw->y;
  926.         }
  927.  
  928.         /* allocate a 1 bit deep pixmap of the appropriate size, and
  929.          * validate it */
  930.         pDrawTo = (DrawablePtr)(*pDraw->pScreen->CreatePixmap)
  931.                     (pDraw->pScreen, dx, dy, 1);
  932.         if (!pDrawTo)
  933.         {
  934.         FreeScratchGC(pGCTo);
  935.         return;
  936.         }
  937.         ValidateGC(pDrawTo, pGCTo);
  938.         miClearDrawable(pDrawTo, pGCTo);
  939.     }
  940.  
  941.     fg = pGC->fgPixel;
  942.     bg = pGC->bgPixel;
  943.     if ((pGC->fillStyle == FillTiled) ||
  944.         (pGC->fillStyle == FillOpaqueStippled))
  945.         bg = fg; /* the protocol sez these don't cause color changes */
  946.  
  947.     polyArcs = miComputeArcs (parcs, narcs, pGC);
  948.  
  949.     if (!polyArcs)
  950.     {
  951.         if (fTricky) {
  952.         (*pDraw->pScreen->DestroyPixmap) ((PixmapPtr)pDrawTo);
  953.         FreeScratchGC (pGCTo);
  954.         }
  955.         return;
  956.     }
  957.  
  958.     cap[0] = cap[1] = 0;
  959.     join[0] = join[1] = 0;
  960.     for (iphase = ((pGC->lineStyle == LineDoubleDash) ? 1 : 0);
  961.           iphase >= 0;
  962.          iphase--)
  963.     {
  964.         if (iphase == 1) {
  965.         DoChangeGC (pGC, GCForeground, (XID *)&bg, 0);
  966.         ValidateGC (pDraw, pGC);
  967.         } else if (pGC->lineStyle == LineDoubleDash) {
  968.         DoChangeGC (pGC, GCForeground, (XID *)&fg, 0);
  969.         ValidateGC (pDraw, pGC);
  970.         }
  971.         for (i = 0; i < polyArcs[iphase].narcs; i++) {
  972.         miArcDataPtr    arcData;
  973.  
  974.         arcData = &polyArcs[iphase].arcs[i];
  975.         miArcSegment(pDrawTo, pGCTo, arcData->arc,
  976.                  &arcData->bounds[RIGHT_END],
  977.                  &arcData->bounds[LEFT_END]);
  978.         if (polyArcs[iphase].arcs[i].render) {
  979.             fillSpans (pDrawTo, pGCTo);
  980.             /*
  981.              * don't cap self-joining arcs
  982.              */
  983.             if (polyArcs[iphase].arcs[i].selfJoin &&
  984.                 cap[iphase] < polyArcs[iphase].arcs[i].cap)
  985.                 cap[iphase]++;
  986.             while (cap[iphase] < polyArcs[iphase].arcs[i].cap) {
  987.             int    arcIndex, end;
  988.             miArcDataPtr    arcData0;
  989.  
  990.             arcIndex = polyArcs[iphase].caps[cap[iphase]].arcIndex;
  991.             end = polyArcs[iphase].caps[cap[iphase]].end;
  992.             arcData0 = &polyArcs[iphase].arcs[arcIndex];
  993.             miArcCap (pDrawTo, pGCTo,
  994.                    &arcData0->bounds[end], end,
  995.                   arcData0->arc.x, arcData0->arc.y,
  996.                   (double) arcData0->arc.width / 2.0,
  997.                    (double) arcData0->arc.height / 2.0);
  998.             ++cap[iphase];
  999.             }
  1000.             while (join[iphase] < polyArcs[iphase].arcs[i].join) {
  1001.             int    arcIndex0, arcIndex1, end0, end1;
  1002.             int    phase0, phase1;
  1003.             miArcDataPtr    arcData0, arcData1;
  1004.             miArcJoinPtr    joinp;
  1005.  
  1006.             joinp = &polyArcs[iphase].joins[join[iphase]];
  1007.             arcIndex0 = joinp->arcIndex0;
  1008.             end0 = joinp->end0;
  1009.             arcIndex1 = joinp->arcIndex1;
  1010.             end1 = joinp->end1;
  1011.             phase0 = joinp->phase0;
  1012.             phase1 = joinp->phase1;
  1013.             arcData0 = &polyArcs[phase0].arcs[arcIndex0];
  1014.             arcData1 = &polyArcs[phase1].arcs[arcIndex1];
  1015.             miArcJoin (pDrawTo, pGCTo,
  1016.                   &arcData0->bounds[end0],
  1017.                    &arcData1->bounds[end1],
  1018.                   arcData0->arc.x, arcData0->arc.y,
  1019.                   (double) arcData0->arc.width / 2.0,
  1020.                    (double) arcData0->arc.height / 2.0,
  1021.                   arcData1->arc.x, arcData1->arc.y,
  1022.                   (double) arcData1->arc.width / 2.0,
  1023.                    (double) arcData1->arc.height / 2.0);
  1024.             ++join[iphase];
  1025.             }
  1026.             if (fTricky) {
  1027.             if (pGC->serialNumber != pDraw->serialNumber)
  1028.                 ValidateGC (pDraw, pGC);
  1029.                 (*pGC->ops->PushPixels) (pGC, pDrawTo, pDraw, dx,
  1030.                         dy, xOrg, yOrg);
  1031.             miClearDrawable ((DrawablePtr) pDrawTo, pGCTo);
  1032.             }
  1033.         }
  1034.         }
  1035.     }
  1036.     miFreeArcs(polyArcs, pGC);
  1037.  
  1038.     if(fTricky)
  1039.     {
  1040.         (*pGCTo->pScreen->DestroyPixmap)((PixmapPtr)pDrawTo);
  1041.         FreeScratchGC(pGCTo);
  1042.     }
  1043.     }
  1044. }
  1045.  
  1046. static double
  1047. angleBetween (center, point1, point2)
  1048.     SppPointRec    center, point1, point2;
  1049. {
  1050.     double    a1, a2, a;
  1051.     
  1052.     /*
  1053.      * reflect from X coordinates back to ellipse
  1054.      * coordinates -- y increasing upwards
  1055.      */
  1056.     a1 = miDatan2 (- (point1.y - center.y), point1.x - center.x);
  1057.     a2 = miDatan2 (- (point2.y - center.y), point2.x - center.x);
  1058.     a = a2 - a1;
  1059.     if (a <= -180.0)
  1060.         a += 360.0;
  1061.     else if (a > 180.0)
  1062.         a -= 360.0;
  1063.     return a;
  1064. }
  1065.  
  1066. static
  1067. translateBounds (b, x, y, fx, fy)
  1068. miArcFacePtr    b;
  1069. int        x, y;
  1070. double        fx, fy;
  1071. {
  1072.     b->clock.x -= x + fx;
  1073.     b->clock.y -= y + fy;
  1074.     b->center.x -= x + fx;
  1075.     b->center.y -= y + fy;
  1076.     b->counterClock.x -= x + fx;
  1077.     b->counterClock.y -= y + fy;
  1078. }
  1079.  
  1080. static void
  1081. miArcJoin (pDraw, pGC, pLeft, pRight,
  1082.        xOrgLeft, yOrgLeft, xFtransLeft, yFtransLeft,
  1083.        xOrgRight, yOrgRight, xFtransRight, yFtransRight)
  1084.     DrawablePtr    pDraw;
  1085.     GCPtr        pGC;
  1086.     miArcFacePtr    pRight, pLeft;
  1087.     int        xOrgRight, yOrgRight;
  1088.     double        xFtransRight, yFtransRight;
  1089.     int        xOrgLeft, yOrgLeft;
  1090.     double        xFtransLeft, yFtransLeft;
  1091. {
  1092.     SppPointRec    center, corner, otherCorner;
  1093.     SppPointRec    poly[5], e;
  1094.     SppPointPtr    pArcPts;
  1095.     int        cpt;
  1096.     SppArcRec    arc;
  1097.     miArcFaceRec    Right, Left;
  1098.     int        polyLen;
  1099.     int        xOrg, yOrg;
  1100.     double        xFtrans, yFtrans;
  1101.     double        a;
  1102.     double        ae, ac2, ec2, bc2, de;
  1103.     double        width;
  1104.     
  1105.     xOrg = (xOrgRight + xOrgLeft) / 2;
  1106.     yOrg = (yOrgRight + yOrgLeft) / 2;
  1107.     xFtrans = (xFtransLeft + xFtransRight) / 2;
  1108.     yFtrans = (yFtransLeft + yFtransRight) / 2;
  1109.     Right = *pRight;
  1110.     translateBounds (&Right, xOrg - xOrgRight, yOrg - yOrgRight,
  1111.                  xFtrans - xFtransRight, yFtrans - yFtransRight);
  1112.     Left = *pLeft;
  1113.     translateBounds (&Left, xOrg - xOrgLeft, yOrg - yOrgLeft,
  1114.                  xFtrans - xFtransLeft, yFtrans - yFtransLeft);
  1115.     pRight = &Right;
  1116.     pLeft = &Left;
  1117.  
  1118.     if (pRight->clock.x == pLeft->counterClock.x &&
  1119.         pRight->clock.y == pLeft->counterClock.y)
  1120.         return;
  1121.     center = pRight->center;
  1122.     if (0 <= (a = angleBetween (center, pRight->clock, pLeft->counterClock))
  1123.          && a <= 180.0)
  1124.      {
  1125.         corner = pRight->clock;
  1126.         otherCorner = pLeft->counterClock;
  1127.     } else {
  1128.         a = angleBetween (center, pLeft->clock, pRight->counterClock);
  1129.         corner = pLeft->clock;
  1130.         otherCorner = pRight->counterClock;
  1131.     }
  1132.     switch (pGC->joinStyle) {
  1133.     case JoinRound:
  1134.         width = (pGC->lineWidth ? pGC->lineWidth : 1);
  1135.  
  1136.         arc.x = center.x - width/2;
  1137.         arc.y = center.y - width/2;
  1138.         arc.width = width;
  1139.         arc.height = width;
  1140.         arc.angle1 = -miDatan2 (corner.y - center.y, corner.x - center.x);
  1141.         arc.angle2 = a;
  1142.         pArcPts = (SppPointPtr) xalloc (3 * sizeof (SppPointRec));
  1143.         if (!pArcPts)
  1144.             return;
  1145.         pArcPts[0].x = otherCorner.x;
  1146.         pArcPts[0].y = otherCorner.y;
  1147.         pArcPts[1].x = center.x;
  1148.         pArcPts[1].y = center.y;
  1149.         pArcPts[2].x = corner.x;
  1150.         pArcPts[2].y = corner.y;
  1151.         if( cpt = miGetArcPts(&arc, 3, &pArcPts))
  1152.         {
  1153.             /* by drawing with miFillSppPoly and setting the endpoints of the arc
  1154.              * to be the corners, we assure that the cap will meet up with the
  1155.              * rest of the line */
  1156.             miFillSppPoly(pDraw, pGC, cpt, pArcPts, xOrg, yOrg, xFtrans, yFtrans);
  1157.         }
  1158.         xfree(pArcPts);
  1159.         return;
  1160.     case JoinMiter:
  1161.         /*
  1162.          * don't miter arcs with less than 11 degrees between them
  1163.          */
  1164.         if (a < 169.0) {
  1165.             poly[0] = corner;
  1166.             poly[1] = center;
  1167.             poly[2] = otherCorner;
  1168.             bc2 = (corner.x - otherCorner.x) * (corner.x - otherCorner.x) +
  1169.                   (corner.y - otherCorner.y) * (corner.y - otherCorner.y);
  1170.             ec2 = bc2 / 4;
  1171.             ac2 = (corner.x - center.x) * (corner.x - center.x) +
  1172.                   (corner.y - center.y) * (corner.y - center.y);
  1173.             ae = sqrt (ac2 - ec2);
  1174.             de = ec2 / ae;
  1175.             e.x = (corner.x + otherCorner.x) / 2;
  1176.             e.y = (corner.y + otherCorner.y) / 2;
  1177.             poly[3].x = e.x + de * (e.x - center.x) / ae;
  1178.             poly[3].y = e.y + de * (e.y - center.y) / ae;
  1179.             poly[4] = corner;
  1180.             polyLen = 5;
  1181.             break;
  1182.         }
  1183.     case JoinBevel:
  1184.         poly[0] = corner;
  1185.         poly[1] = center;
  1186.         poly[2] = otherCorner;
  1187.         poly[3] = corner;
  1188.         polyLen = 4;
  1189.         break;
  1190.     }
  1191.     miFillSppPoly (pDraw, pGC, polyLen, poly, xOrg, yOrg, xFtrans, yFtrans);
  1192. }
  1193.  
  1194. /*ARGSUSED*/
  1195. static void
  1196. miArcCap (pDraw, pGC, pFace, end, xOrg, yOrg, xFtrans, yFtrans)
  1197.     DrawablePtr    pDraw;
  1198.     GCPtr        pGC;
  1199.     miArcFacePtr    pFace;
  1200.     int        end;
  1201.     int        xOrg, yOrg;
  1202.     double        xFtrans, yFtrans;
  1203. {
  1204.     SppPointRec    corner, otherCorner, center, endPoint, poly[5];
  1205.  
  1206.     corner = pFace->clock;
  1207.     otherCorner = pFace->counterClock;
  1208.     center = pFace->center;
  1209.     switch (pGC->capStyle) {
  1210.     case CapProjecting:
  1211.         poly[0].x = otherCorner.x;
  1212.         poly[0].y = otherCorner.y;
  1213.         poly[1].x = corner.x;
  1214.         poly[1].y = corner.y;
  1215.         poly[2].x = corner.x -
  1216.                  (center.y - corner.y);
  1217.         poly[2].y = corner.y +
  1218.                  (center.x - corner.x);
  1219.         poly[3].x = otherCorner.x -
  1220.                  (otherCorner.y - center.y);
  1221.         poly[3].y = otherCorner.y +
  1222.                  (otherCorner.x - center.x);
  1223.         poly[4].x = otherCorner.x;
  1224.         poly[4].y = otherCorner.y;
  1225.         miFillSppPoly (pDraw, pGC, 5, poly, xOrg, yOrg, xFtrans, yFtrans);
  1226.         break;
  1227.     case CapRound:
  1228.         /*
  1229.          * miRoundCap just needs these to be unequal.
  1230.          */
  1231.         endPoint = center;
  1232.         endPoint.x = endPoint.x + 100;
  1233.         miRoundCap (pDraw, pGC, center, endPoint, corner, otherCorner, 0,
  1234.                 -xOrg, -yOrg, xFtrans, yFtrans);
  1235.         break;
  1236.     }
  1237. }
  1238.  
  1239. /* MIROUNDCAP -- a private helper function
  1240.  * Put Rounded cap on end. pCenter is the center of this end of the line
  1241.  * pEnd is the center of the other end of the line. pCorner is one of the
  1242.  * two corners at this end of the line.  
  1243.  * NOTE:  pOtherCorner must be counter-clockwise from pCorner.
  1244.  */
  1245. /*ARGSUSED*/
  1246. static void
  1247. miRoundCap(pDraw, pGC, pCenter, pEnd, pCorner, pOtherCorner, fLineEnd,
  1248.      xOrg, yOrg, xFtrans, yFtrans)
  1249.     DrawablePtr    pDraw;
  1250.     GCPtr    pGC;
  1251.     SppPointRec    pCenter, pEnd;
  1252.     SppPointRec    pCorner, pOtherCorner;
  1253.     int        fLineEnd, xOrg, yOrg;
  1254.     double    xFtrans, yFtrans;
  1255. {
  1256.     int        cpt;
  1257.     double    width;
  1258.     double    miDatan2 ();
  1259.     SppArcRec    arc;
  1260.     SppPointPtr    pArcPts;
  1261.  
  1262.     width = (pGC->lineWidth ? pGC->lineWidth : 1);
  1263.  
  1264.     arc.x = pCenter.x - width/2;
  1265.     arc.y = pCenter.y - width/2;
  1266.     arc.width = width;
  1267.     arc.height = width;
  1268.     arc.angle1 = -miDatan2 (pCorner.y - pCenter.y, pCorner.x - pCenter.x);
  1269.     if(PTISEQUAL(pCenter, pEnd))
  1270.     arc.angle2 = - 180.0;
  1271.     else {
  1272.     arc.angle2 = -miDatan2 (pOtherCorner.y - pCenter.y, pOtherCorner.x - pCenter.x) - arc.angle1;
  1273.     if (arc.angle2 < 0)
  1274.         arc.angle2 += 360.0;
  1275.     }
  1276.     pArcPts = (SppPointPtr) NULL;
  1277.     if( cpt = miGetArcPts(&arc, 0, &pArcPts))
  1278.     {
  1279.     /* by drawing with miFillSppPoly and setting the endpoints of the arc
  1280.      * to be the corners, we assure that the cap will meet up with the
  1281.      * rest of the line */
  1282.     miFillSppPoly(pDraw, pGC, cpt, pArcPts, -xOrg, -yOrg, xFtrans, yFtrans);
  1283.     }
  1284.     xfree(pArcPts);
  1285. }
  1286.  
  1287. /*
  1288.  * To avoid inaccuracy at the cardinal points, use trig functions
  1289.  * which are exact for those angles
  1290.  */
  1291.  
  1292. #ifndef M_PI
  1293. #define M_PI    3.14159265358979323846
  1294. #endif
  1295. #ifndef M_PI_2
  1296. #define M_PI_2    1.57079632679489661923
  1297. #endif
  1298.  
  1299. # define Dsin(d)    ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0)))
  1300. # define Dcos(d)    ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0)))
  1301. # define mod(a,b)    ((a) >= 0 ? (a) % (b) : (b) - (-a) % (b))
  1302.  
  1303. static double
  1304. miDcos (a)
  1305. double    a;
  1306. {
  1307.     int    i;
  1308.  
  1309.     if (floor (a/90) == a/90) {
  1310.         i = (int) (a/90.0);
  1311.         switch (mod (i, 4)) {
  1312.         case 0: return 1;
  1313.         case 1: return 0;
  1314.         case 2: return -1;
  1315.         case 3: return 0;
  1316.         }
  1317.     }
  1318.     return cos (a * M_PI / 180.0);
  1319. }
  1320.  
  1321. static double
  1322. miDsin (a)
  1323. double    a;
  1324. {
  1325.     int    i;
  1326.  
  1327.     if (floor (a/90) == a/90) {
  1328.         i = (int) (a/90.0);
  1329.         switch (mod (i, 4)) {
  1330.         case 0: return 0;
  1331.         case 1: return 1;
  1332.         case 2: return 0;
  1333.         case 3: return -1;
  1334.         }
  1335.     }
  1336.     return sin (a * M_PI / 180.0);
  1337. }
  1338.  
  1339. static double
  1340. miDasin (v)
  1341. double    v;
  1342. {
  1343.     if (v == 0)
  1344.     return 0.0;
  1345.     if (v == 1.0)
  1346.     return 90.0;
  1347.     if (v == -1.0)
  1348.     return -90.0;
  1349.     return asin(v) * (180.0 / M_PI);
  1350. }
  1351.  
  1352. static double
  1353. miDatan2 (dy, dx)
  1354. double    dy, dx;
  1355. {
  1356.     if (dy == 0) {
  1357.     if (dx >= 0)
  1358.         return 0.0;
  1359.     return 180.0;
  1360.     } else if (dx == 0) {
  1361.     if (dy > 0)
  1362.         return 90.0;
  1363.     return -90.0;
  1364.     } else if (fabs (dy) == fabs (dx)) {
  1365.     if (dy > 0) {
  1366.         if (dx > 0)
  1367.         return 45.0;
  1368.         return 135.0;
  1369.     } else {
  1370.         if (dx > 0)
  1371.         return 315.0;
  1372.         return 225.0;
  1373.     }
  1374.     } else {
  1375.     return atan2 (dy, dx) * (180.0 / M_PI);
  1376.     }
  1377. }
  1378.  
  1379. #define REALLOC_STEP 10        /* how often to realloc */
  1380. #define NOARCCOMPRESSION    /* don't bother with this stuff */
  1381.  
  1382. /* MIGETARCPTS -- Converts an arc into a set of line segments -- a helper
  1383.  * routine for filled arc and line (round cap) code.
  1384.  * Returns the number of points in the arc.  Note that it takes a pointer
  1385.  * to a pointer to where it should put the points and an index (cpt).
  1386.  * This procedure allocates the space necessary to fit the arc points.
  1387.  * Sometimes it's convenient for those points to be at the end of an existing
  1388.  * array. (For example, if we want to leave a spare point to make sectors
  1389.  * instead of segments.)  So we pass in the Xalloc()ed chunk that contains the
  1390.  * array and an index saying where we should start stashing the points.
  1391.  * If there isn't an array already, we just pass in a null pointer and 
  1392.  * count on Xrealloc() to handle the null pointer correctly.
  1393.  */
  1394. static int
  1395. miGetArcPts(parc, cpt, ppPts)
  1396.     SppArcPtr    parc;    /* points to an arc */
  1397.     int        cpt;    /* number of points already in arc list */
  1398.     SppPointPtr    *ppPts; /* pointer to pointer to arc-list -- modified */
  1399. {
  1400.     double     st,    /* Start Theta, start angle */
  1401.                 et,    /* End Theta, offset from start theta */
  1402.         dt,    /* Delta Theta, angle to sweep ellipse */
  1403.         cdt,    /* Cos Delta Theta, actually 2 cos(dt) */
  1404.             x0, y0,    /* the recurrence formula needs two points to start */
  1405.         x1, y1,
  1406.         x2, y2, /* this will be the new point generated */
  1407.         xc, yc; /* the center point */
  1408.     int        count, i;
  1409.     SppPointPtr    poly;
  1410.     DDXPointRec last;        /* last point on integer boundaries */
  1411. #ifndef NOARCCOMPRESSION
  1412.     double    xt, yt;
  1413.     int        axis, npts = 2;
  1414. #endif
  1415.  
  1416.     /* The spec says that positive angles indicate counterclockwise motion.
  1417.      * Given our coordinate system (with 0,0 in the upper left corner), 
  1418.      * the screen appears flipped in Y.  The easiest fix is to negate the
  1419.      * angles given */
  1420.     
  1421.     st = - parc->angle1;
  1422.  
  1423.     et = - parc->angle2;
  1424.  
  1425.     /* Try to get a delta theta that is within 1/2 pixel.  Then adjust it
  1426.      * so that it divides evenly into the total.
  1427.      * I'm just using cdt 'cause I'm lazy.
  1428.      */
  1429.     cdt = fmax(parc->width, parc->height)/2.0;
  1430.     if(cdt <= 0)
  1431.     return 0;
  1432.     if (cdt < 1.0)
  1433.     cdt = 1.0;
  1434.     dt = miDasin ( 1.0 / cdt ); /* minimum step necessary */
  1435.     count = et/dt;
  1436.     count = abs(count) + 1;
  1437.     dt = et/count;    
  1438.     count++;
  1439.  
  1440.     cdt = 2 * miDcos(dt);
  1441. #ifdef NOARCCOMPRESSION
  1442.     if (!(poly = (SppPointPtr) xrealloc((pointer)*ppPts,
  1443.                     (cpt + count) * sizeof(SppPointRec))))
  1444.     return(0);
  1445. #else                /* ARCCOMPRESSION */
  1446.     if (!(poly = (SppPointPtr) xrealloc((pointer)*ppPts,
  1447.                     (cpt + 2) * sizeof(SppPointRec))))
  1448.     return(0);
  1449. #endif                /* ARCCOMPRESSION */
  1450.     *ppPts = poly;
  1451.  
  1452.     xc = parc->width/2.0;        /* store half width and half height */
  1453.     yc = parc->height/2.0;
  1454. #ifndef NOARCCOMPRESSION
  1455.     axis = (xc >= yc) ? X_AXIS : Y_AXIS;
  1456. #endif
  1457.     
  1458.     x0 = xc * miDcos(st);
  1459.     y0 = yc * miDsin(st);
  1460.     x1 = xc * miDcos(st + dt);
  1461.     y1 = yc * miDsin(st + dt);
  1462.     xc += parc->x;        /* by adding initial point, these become */
  1463.     yc += parc->y;        /* the center point */
  1464.  
  1465.     poly[cpt].x = (xc + x0);
  1466.     poly[cpt].y = (yc + y0);
  1467.     last.x = ROUNDTOINT( poly[cpt + 1].x = (xc + x1) );
  1468.     last.y = ROUNDTOINT( poly[cpt + 1].y = (yc + y1) );
  1469.  
  1470.     for(i = 2; i < count; i++)
  1471.     {
  1472.     x2 = cdt * x1 - x0;
  1473.     y2 = cdt * y1 - y0;
  1474.  
  1475. #ifdef NOARCCOMPRESSION
  1476.      poly[cpt + i].x = (xc + x2);
  1477.      poly[cpt + i].y = (yc + y2);
  1478. #else                /* ARCCOMPRESSION */
  1479.     xt = xc + x2;
  1480.     yt = yc + y2;
  1481.      if (((axis == X_AXIS) ?
  1482.          (ROUNDTOINT(yt) != last.y) :
  1483.          (ROUNDTOINT(xt) != last.x)) ||
  1484.         i > count - 3)    /* insure 2 at the end */
  1485.      {
  1486.         /* allocate more space if we are about to need it */
  1487.         /* include 1 extra in case minor axis swaps */
  1488.          if ((npts - 2) % REALLOC_STEP == 0)
  1489.         {
  1490.          if (!(poly = (SppPointPtr)
  1491.               xrealloc((pointer) poly,
  1492.                    ((npts + REALLOC_STEP + cpt) *
  1493.                 sizeof(SppPointRec)))))
  1494.             return(0);
  1495.         *ppPts = poly;
  1496.         }
  1497.         /* check if we just switched direction in the minor axis */
  1498.         if (((poly[cpt + npts - 2].y - poly[cpt + npts - 1].y > 0.0) ?
  1499.          (yt - poly[cpt + npts - 1].y > 0.0) :
  1500.          (poly[cpt + npts - 1].y - yt > 0.0)) ||
  1501.         ((poly[cpt + npts - 2].x - poly[cpt + npts - 1].x > 0.0) ?
  1502.          (xt - poly[cpt + npts - 1].x > 0.0) :
  1503.          (poly[cpt + npts - 1].x - xt > 0.0)))
  1504.         {
  1505.         /* Since the minor axis direction just switched, the final *
  1506.          * point before the change must be included, or the        *
  1507.          * following segment will begin before the minor swap.     */
  1508.         poly[cpt + npts].x = xc + x1;
  1509.         poly[cpt + npts].y = yc + y1;
  1510.         npts++;
  1511.         if ((npts - 2) % REALLOC_STEP == 0)
  1512.         {
  1513.             if (!(poly = (SppPointPtr)
  1514.               xrealloc((pointer) poly,
  1515.                    ((npts + REALLOC_STEP + cpt) *
  1516.                     sizeof(SppPointRec)))))
  1517.             return(0);
  1518.             *ppPts = poly;
  1519.         }
  1520.         }
  1521.          last.x = ROUNDTOINT( poly[cpt + npts].x = xt );
  1522.          last.y = ROUNDTOINT( poly[cpt + npts].y = yt );
  1523.          npts++;
  1524.      }
  1525. #endif                /* ARCCOMPRESSION */
  1526.  
  1527.     x0 = x1; y0 = y1;
  1528.     x1 = x2; y1 = y2;
  1529.     }
  1530. #ifndef NOARCCOMPRESSION    /* i.e.:  ARCCOMPRESSION */
  1531.     count = i = npts;
  1532. #endif                /* ARCCOMPRESSION */
  1533.     /* adjust the last point */
  1534.     if (abs(parc->angle2) >= 360.0)
  1535.     poly[cpt +i -1] = poly[0];
  1536.     else {
  1537.     poly[cpt +i -1].x = (miDcos(st + et) * parc->width/2.0 + xc);
  1538.     poly[cpt +i -1].y = (miDsin(st + et) * parc->height/2.0 + yc);
  1539.     }
  1540.  
  1541.     return(count);
  1542. }
  1543.  
  1544. struct arcData {
  1545.     double    x0, y0, x1, y1;
  1546.     int    selfJoin;
  1547. };
  1548.  
  1549. # define ADD_REALLOC_STEP    20
  1550.  
  1551. static void
  1552. addCap (capsp, ncapsp, sizep, end, arcIndex)
  1553.     miArcCapPtr    *capsp;
  1554.     int        *ncapsp, *sizep;
  1555.     int        end, arcIndex;
  1556. {
  1557.     int newsize;
  1558.     miArcCapPtr    cap;
  1559.  
  1560.     if (*ncapsp == *sizep)
  1561.     {
  1562.         newsize = *sizep + ADD_REALLOC_STEP;
  1563.         cap = (miArcCapPtr) xrealloc (*capsp,
  1564.                       newsize * sizeof (**capsp));
  1565.         if (!cap)
  1566.         return;
  1567.         *sizep = newsize;
  1568.         *capsp = cap;
  1569.     }
  1570.     cap = &(*capsp)[*ncapsp];
  1571.     cap->end = end;
  1572.     cap->arcIndex = arcIndex;
  1573.     ++*ncapsp;
  1574. }
  1575.  
  1576. static void
  1577. addJoin (joinsp, njoinsp, sizep, end0, index0, phase0, end1, index1, phase1)
  1578.     miArcJoinPtr    *joinsp;
  1579.     int        *njoinsp, *sizep;
  1580.     int        end0, index0, end1, index1;
  1581. {
  1582.     int newsize;
  1583.     miArcJoinPtr    join;
  1584.  
  1585.     if (*njoinsp == *sizep)
  1586.     {
  1587.         newsize = *sizep + ADD_REALLOC_STEP;
  1588.         join = (miArcJoinPtr) xrealloc (*joinsp,
  1589.                         newsize * sizeof (**joinsp));
  1590.         if (!join)
  1591.         return;
  1592.         *sizep = newsize;
  1593.         *joinsp = join;
  1594.     }
  1595.     join = &(*joinsp)[*njoinsp];
  1596.     join->end0 = end0;
  1597.     join->arcIndex0 = index0;
  1598.     join->phase0 = phase0;
  1599.     join->end1 = end1;
  1600.     join->arcIndex1 = index1;
  1601.     join->phase1 = phase1;
  1602.     ++*njoinsp;
  1603. }
  1604.  
  1605. static miArcDataPtr
  1606. addArc (arcsp, narcsp, sizep, xarc)
  1607.     miArcDataPtr    *arcsp;
  1608.     int        *narcsp, *sizep;
  1609.     xArc        xarc;
  1610. {
  1611.     int newsize;
  1612.     miArcDataPtr    arc;
  1613.  
  1614.     if (*narcsp == *sizep)
  1615.     {
  1616.         newsize = *sizep + ADD_REALLOC_STEP;
  1617.         arc = (miArcDataPtr) xrealloc (*arcsp,
  1618.                        newsize * sizeof (**arcsp));
  1619.         if (!arc)
  1620.         return (miArcDataPtr)NULL;
  1621.         *sizep = newsize;
  1622.         *arcsp = arc;
  1623.     }
  1624.     arc = &(*arcsp)[*narcsp];
  1625.     arc->arc = xarc;
  1626.     ++*narcsp;
  1627.     return arc;
  1628. }
  1629.  
  1630. static void
  1631. miFreeArcs(arcs, pGC)
  1632.     miPolyArcPtr arcs;
  1633.     GCPtr pGC;
  1634. {
  1635.     int iphase;
  1636.  
  1637.     for (iphase = ((pGC->lineStyle == LineDoubleDash) ? 1 : 0);
  1638.           iphase >= 0;
  1639.          iphase--)
  1640.     {
  1641.         if (arcs[iphase].narcs > 0)
  1642.         xfree(arcs[iphase].arcs);
  1643.         if (arcs[iphase].njoins > 0)
  1644.         xfree(arcs[iphase].joins);
  1645.         if (arcs[iphase].ncaps > 0)
  1646.         xfree(arcs[iphase].caps);
  1647.     }
  1648.     xfree(arcs);
  1649. }
  1650.  
  1651. /*
  1652.  * map angles to radial distance.  This only deals with the first quadrant
  1653.  */
  1654.  
  1655. /*
  1656.  * a polygonal approximation to the arc for computing arc lengths
  1657.  */
  1658.  
  1659. # define DASH_MAP_SIZE    91
  1660.  
  1661. # define dashIndexToAngle(di)    ((((double) (di)) * 90.0) / ((double) DASH_MAP_SIZE - 1))
  1662. # define xAngleToDashIndex(xa)    ((((long) (xa)) * (DASH_MAP_SIZE - 1)) / (90 * 64))
  1663. # define dashIndexToXAngle(di)    ((((long) (di)) * (90 * 64)) / (DASH_MAP_SIZE - 1))
  1664. # define dashXAngleStep    (((double) (90 * 64)) / ((double) (DASH_MAP_SIZE - 1)))
  1665.  
  1666. typedef struct {
  1667.     double    map[DASH_MAP_SIZE];
  1668. } dashMap;
  1669.  
  1670. static void
  1671. computeDashMap (arcp, map)
  1672.     xArc    *arcp;
  1673.     dashMap    *map;
  1674. {
  1675.     int    di;
  1676.     double    a, x, y, prevx, prevy, dist;
  1677.  
  1678.     for (di = 0; di < DASH_MAP_SIZE; di++) {
  1679.         a = dashIndexToAngle (di);
  1680.         x = ((double) arcp->width / 2.0) * miDcos (a);
  1681.         y = ((double) arcp->height / 2.0) * miDsin (a);
  1682.         if (di == 0) {
  1683.             map->map[di] = 0.0;
  1684.         } else {
  1685.             dist = hypot (x - prevx, y - prevy);
  1686.             map->map[di] = map->map[di - 1] + dist;
  1687.         }
  1688.         prevx = x;
  1689.         prevy = y;
  1690.     }
  1691. }
  1692.  
  1693. /* this routine is a bit gory */
  1694.  
  1695. static miPolyArcPtr
  1696. miComputeArcs (parcs, narcs, pGC)
  1697.     xArc    *parcs;
  1698.     int    narcs;
  1699.     GCPtr    pGC;
  1700. {
  1701.     int        isDashed, isDoubleDash;
  1702.     int        dashOffset;
  1703.     miPolyArcPtr    arcs;
  1704.     int        start, i, j, k, nexti, nextk;
  1705.     int        joinSize[2];
  1706.     int        capSize[2];
  1707.     int        arcSize[2];
  1708.     int        angle2;
  1709.     double        a0, a1;
  1710.     struct arcData    *data;
  1711.     miArcDataPtr    arc;
  1712.     xArc        xarc;
  1713.     int        iphase, prevphase, joinphase;
  1714.     int        arcsJoin;
  1715.     int        selfJoin;
  1716.  
  1717.     int        iDash, dashRemaining;
  1718.     int        iDashStart, dashRemainingStart, iphaseStart;
  1719.     int        startAngle, spanAngle, endAngle, backwards;
  1720.     int        prevDashAngle, dashAngle;
  1721.     dashMap        map;
  1722.  
  1723.     isDashed = !(pGC->lineStyle == LineSolid);
  1724.     isDoubleDash = (pGC->lineStyle == LineDoubleDash);
  1725.     dashOffset = pGC->dashOffset;
  1726.  
  1727.     data = (struct arcData *) ALLOCATE_LOCAL (narcs * sizeof (struct arcData));
  1728.     if (!data)
  1729.         return (miPolyArcPtr)NULL;
  1730.     arcs = (miPolyArcPtr) xalloc (sizeof (*arcs) * (isDoubleDash ? 2 : 1));
  1731.     if (!arcs)
  1732.     {
  1733.         DEALLOCATE_LOCAL(data);
  1734.         return (miPolyArcPtr)NULL;
  1735.     }
  1736.     for (i = 0; i < narcs; i++) {
  1737.         a0 = todeg (parcs[i].angle1);
  1738.         angle2 = parcs[i].angle2;
  1739.         if (angle2 > FULLCIRCLE)
  1740.             angle2 = FULLCIRCLE;
  1741.         else if (angle2 < -FULLCIRCLE)
  1742.             angle2 = -FULLCIRCLE;
  1743.         data[i].selfJoin = angle2 == FULLCIRCLE || angle2 == -FULLCIRCLE;
  1744.         a1 = todeg (parcs[i].angle1 + angle2);
  1745.         data[i].x0 = parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos (a0));
  1746.         data[i].y0 = parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin (a0));
  1747.         data[i].x1 = parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos (a1));
  1748.         data[i].y1 = parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin (a1));
  1749.     }
  1750.  
  1751.     for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++) {
  1752.         arcs[iphase].njoins = 0;
  1753.         arcs[iphase].joins = 0;
  1754.         joinSize[iphase] = 0;
  1755.         
  1756.         arcs[iphase].ncaps = 0;
  1757.         arcs[iphase].caps = 0;
  1758.         capSize[iphase] = 0;
  1759.         
  1760.         arcs[iphase].narcs = 0;
  1761.         arcs[iphase].arcs = 0;
  1762.         arcSize[iphase] = 0;
  1763.     }
  1764.  
  1765.     iphase = 0;
  1766.     if (isDashed) {
  1767.         iDash = 0;
  1768.         dashRemaining = pGC->dash[0];
  1769.          while (dashOffset > 0) {
  1770.             if (dashOffset >= dashRemaining) {
  1771.                 dashOffset -= dashRemaining;
  1772.                 iphase = iphase ? 0 : 1;
  1773.                 iDash++;
  1774.                 if (iDash == pGC->numInDashList)
  1775.                     iDash = 0;
  1776.                 dashRemaining = pGC->dash[iDash];
  1777.             } else {
  1778.                 dashRemaining -= dashOffset;
  1779.                 dashOffset = 0;
  1780.             }
  1781.         }
  1782.         iDashStart = iDash;
  1783.         dashRemainingStart = dashRemaining;
  1784.     }
  1785.     iphaseStart = iphase;
  1786.  
  1787.     for (i = narcs - 1; i >= 0; i--) {
  1788.         j = i + 1;
  1789.         if (j == narcs)
  1790.             j = 0;
  1791.         if (data[i].selfJoin || i == j ||
  1792.              (UNEQUAL (data[i].x1, data[j].x0) ||
  1793.               UNEQUAL (data[i].y1, data[j].y0)))
  1794.          {
  1795.             if (iphase == 0 || isDoubleDash)
  1796.                 addCap (&arcs[iphase].caps, &arcs[iphase].ncaps,
  1797.                      &capSize[iphase], RIGHT_END, 0);
  1798.             break;
  1799.         }
  1800.     }
  1801.     start = i + 1;
  1802.     if (start == narcs)
  1803.         start = 0;
  1804.     i = start;
  1805.     for (;;) {
  1806.         j = i + 1;
  1807.         if (j == narcs)
  1808.             j = 0;
  1809.         nexti = i+1;
  1810.         if (nexti == narcs)
  1811.             nexti = 0;
  1812.         if (isDashed) {
  1813.             /*
  1814.              * precompute an approximation map
  1815.              */
  1816.             computeDashMap (&parcs[i], &map);
  1817.             /*
  1818.              * compute each individual dash segment using the path
  1819.              * length function
  1820.              */
  1821.             startAngle = parcs[i].angle1;
  1822.             spanAngle = parcs[i].angle2;
  1823.             if (spanAngle > FULLCIRCLE)
  1824.                 spanAngle = FULLCIRCLE;
  1825.             else if (spanAngle < -FULLCIRCLE)
  1826.                 spanAngle = -FULLCIRCLE;
  1827.             if (startAngle < 0)
  1828.                 startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE;
  1829.             if (startAngle >= FULLCIRCLE)
  1830.                 startAngle = startAngle % FULLCIRCLE;
  1831.             endAngle = startAngle + spanAngle;
  1832.             backwards = spanAngle < 0;
  1833.             dashAngle = startAngle;
  1834.             selfJoin = data[i].selfJoin &&
  1835.                      (iphase == 0 || isDoubleDash);
  1836.             /*
  1837.              * add dashed arcs to each bucket
  1838.              */
  1839.             arc = 0;
  1840.             while (dashAngle != endAngle) {
  1841.                 prevDashAngle = dashAngle;
  1842.                 dashAngle = computeAngleFromPath (prevDashAngle, endAngle,
  1843.                             &map, &dashRemaining, backwards);
  1844.                 /* avoid troubles with huge arcs and small dashes */
  1845.                 if (dashAngle == prevDashAngle) {
  1846.                     if (backwards)
  1847.                         dashAngle--;
  1848.                     else
  1849.                         dashAngle++;
  1850.                 }
  1851.                 if (iphase == 0 || isDoubleDash) {
  1852.                     xarc = parcs[i];
  1853.                     spanAngle = prevDashAngle;
  1854.                         if (spanAngle < 0)
  1855.                         spanAngle = FULLCIRCLE - (-spanAngle) % FULLCIRCLE;
  1856.                     if (spanAngle >= FULLCIRCLE)
  1857.                         spanAngle = spanAngle % FULLCIRCLE;
  1858.                     xarc.angle1 = spanAngle;
  1859.                     spanAngle = dashAngle - prevDashAngle;
  1860.                     if (backwards) {
  1861.                         if (dashAngle > prevDashAngle)
  1862.                             spanAngle = - FULLCIRCLE + spanAngle;
  1863.                     } else {
  1864.                         if (dashAngle < prevDashAngle)
  1865.                             spanAngle = FULLCIRCLE + spanAngle;
  1866.                     }
  1867.                     if (spanAngle > FULLCIRCLE)
  1868.                         spanAngle = FULLCIRCLE;
  1869.                     if (spanAngle < -FULLCIRCLE)
  1870.                         spanAngle = -FULLCIRCLE;
  1871.                     xarc.angle2 = spanAngle;
  1872.                     arc = addArc (&arcs[iphase].arcs, &arcs[iphase].narcs,
  1873.                              &arcSize[iphase], xarc);
  1874.                     if (!arc)
  1875.                         goto arcfail;
  1876.                     /*
  1877.                      * cap each end of an on/off dash
  1878.                      */
  1879.                     if (!isDoubleDash) {
  1880.                         if (prevDashAngle != startAngle) {
  1881.                             addCap (&arcs[iphase].caps,
  1882.                                  &arcs[iphase].ncaps,
  1883.                                  &capSize[iphase], RIGHT_END,
  1884.                                  arc - arcs[iphase].arcs);
  1885.                             
  1886.                         }
  1887.                         if (dashAngle != endAngle) {
  1888.                             addCap (&arcs[iphase].caps,
  1889.                                  &arcs[iphase].ncaps,
  1890.                                  &capSize[iphase], LEFT_END,
  1891.                                  arc - arcs[iphase].arcs);
  1892.                         }
  1893.                     }
  1894.                     arc->cap = arcs[iphase].ncaps;
  1895.                     arc->join = arcs[iphase].njoins;
  1896.                     arc->render = 0;
  1897.                     arc->selfJoin = 0;
  1898.                     if (dashAngle == endAngle)
  1899.                         arc->selfJoin = selfJoin;
  1900.                 }
  1901.                 prevphase = iphase;
  1902.                 if (dashRemaining <= 0) {
  1903.                     ++iDash;
  1904.                     if (iDash == pGC->numInDashList)
  1905.                         iDash = 0;
  1906.                     iphase = iphase ? 0:1;
  1907.                     dashRemaining = pGC->dash[iDash];
  1908.                 }
  1909.             }
  1910.             /*
  1911.              * make sure a place exists for the position data when
  1912.              * drawing a zero-length arc
  1913.              */
  1914.             if (startAngle == endAngle) {
  1915.                 prevphase = iphase;
  1916.                 if (!isDoubleDash && iphase == 1)
  1917.                     prevphase = 0;
  1918.                 arc = addArc (&arcs[prevphase].arcs, &arcs[prevphase].narcs,
  1919.                           &arcSize[prevphase], parcs[i]);
  1920.                 if (!arc)
  1921.                     goto arcfail;
  1922.                 arc->join = arcs[prevphase].njoins;
  1923.                 arc->cap = arcs[prevphase].ncaps;
  1924.                 arc->selfJoin = data[i].selfJoin;
  1925.             }
  1926.         } else {
  1927.             arc = addArc (&arcs[iphase].arcs, &arcs[iphase].narcs,
  1928.                        &arcSize[iphase], parcs[i]);
  1929.             if (!arc)
  1930.                 goto arcfail;
  1931.             arc->join = arcs[iphase].njoins;
  1932.             arc->cap = arcs[iphase].ncaps;
  1933.             arc->selfJoin = data[i].selfJoin;
  1934.             prevphase = iphase;
  1935.         }
  1936.         if (prevphase == 0 || isDoubleDash)
  1937.             k = arcs[prevphase].narcs - 1;
  1938.         if (iphase == 0 || isDoubleDash)
  1939.             nextk = arcs[iphase].narcs;
  1940.         if (nexti == start) {
  1941.             nextk = 0;
  1942.             if (isDashed) {
  1943.                 iDash = iDashStart;
  1944.                 iphase = iphaseStart;
  1945.                 dashRemaining = dashRemainingStart;
  1946.             }
  1947.         }
  1948.         arcsJoin = narcs > 1 && i != j &&
  1949.                  ISEQUAL (data[i].x1, data[j].x0) &&
  1950.                 ISEQUAL (data[i].y1, data[j].y0) &&
  1951.                 !data[i].selfJoin && !data[j].selfJoin;
  1952.         if (arc)
  1953.         {
  1954.             if (arcsJoin)
  1955.                 arc->render = 0;
  1956.             else
  1957.                 arc->render = 1;
  1958.         }
  1959.         if (arcsJoin &&
  1960.             (prevphase == 0 || isDoubleDash) &&
  1961.             (iphase == 0 || isDoubleDash))
  1962.          {
  1963.             joinphase = iphase;
  1964.             if (isDoubleDash) {
  1965.                 if (nexti == start)
  1966.                     joinphase = iphaseStart;
  1967.                 /*
  1968.                  * if the join is right at the dash,
  1969.                  * draw the join in foreground
  1970.                  * This is because the foreground
  1971.                  * arcs are computed second, the results
  1972.                  * of which are needed to draw the join
  1973.                  */
  1974.                 if (joinphase != prevphase)
  1975.                     joinphase = 0;
  1976.             }
  1977.             if (joinphase == 0 || isDoubleDash) {
  1978.                 addJoin (&arcs[joinphase].joins,
  1979.                       &arcs[joinphase].njoins,
  1980.                       &joinSize[joinphase],
  1981.                       LEFT_END, k, prevphase,
  1982.                       RIGHT_END, nextk, iphase);
  1983.                 arc->join = arcs[prevphase].njoins;
  1984.             }
  1985.         } else {
  1986.             /*
  1987.              * cap the left end of this arc
  1988.              * unless it joins itself
  1989.              */
  1990.             if ((prevphase == 0 || isDoubleDash) &&
  1991.                 !arc->selfJoin)
  1992.             {
  1993.                 addCap (&arcs[prevphase].caps, &arcs[prevphase].ncaps,
  1994.                      &capSize[prevphase], LEFT_END, k);
  1995.                 arc->cap = arcs[prevphase].ncaps;
  1996.             }
  1997.             if (isDashed && !arcsJoin) {
  1998.                 iDash = iDashStart;
  1999.                 iphase = iphaseStart;
  2000.                 dashRemaining = dashRemainingStart;
  2001.             }
  2002.             nextk = arcs[iphase].narcs;
  2003.             if (nexti == start) {
  2004.                 nextk = 0;
  2005.                 iDash = iDashStart;
  2006.                 iphase = iphaseStart;
  2007.                 dashRemaining = dashRemainingStart;
  2008.             }
  2009.             /*
  2010.              * cap the right end of the next arc.  If the
  2011.              * next arc is actually the first arc, only
  2012.              * cap it if it joins with this arc.  This
  2013.              * case will occur when the final dash segment
  2014.              * of an on/off dash is off.  Of course, this
  2015.              * cap will be drawn at a strange time, but that
  2016.              * hardly matters...
  2017.              */
  2018.             if ((iphase == 0 || isDoubleDash) &&
  2019.                 (nexti != start || arcsJoin && isDashed))
  2020.                 addCap (&arcs[iphase].caps, &arcs[iphase].ncaps,
  2021.                      &capSize[iphase], RIGHT_END, nextk);
  2022.         }
  2023.         i = nexti;
  2024.         if (i == start)
  2025.             break;
  2026.     }
  2027.     /*
  2028.      * make sure the last section is rendered
  2029.      */
  2030.     for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++)
  2031.         if (arcs[iphase].narcs > 0) {
  2032.             arcs[iphase].arcs[arcs[iphase].narcs-1].render = 1;
  2033.             arcs[iphase].arcs[arcs[iphase].narcs-1].join =
  2034.                      arcs[iphase].njoins;
  2035.             arcs[iphase].arcs[arcs[iphase].narcs-1].cap =
  2036.                      arcs[iphase].ncaps;
  2037.         }
  2038.     DEALLOCATE_LOCAL(data);
  2039.     return arcs;
  2040. arcfail:
  2041.     miFreeArcs(arcs, pGC);
  2042.     DEALLOCATE_LOCAL(data);
  2043.     return (miPolyArcPtr)NULL;
  2044. }
  2045.  
  2046. static double
  2047. angleToLength (angle, map)
  2048.     int    angle;
  2049.     dashMap    *map;
  2050. {
  2051.     double    len, excesslen, sidelen = map->map[DASH_MAP_SIZE - 1], totallen;
  2052.     int    di;
  2053.     int    excess;
  2054.     Bool    oddSide = FALSE;
  2055.  
  2056.     totallen = 0;
  2057.     if (angle >= 0) {
  2058.         while (angle >= 90 * 64) {
  2059.             angle -= 90 * 64;
  2060.             totallen += sidelen;
  2061.             oddSide = !oddSide;
  2062.         }
  2063.     } else {
  2064.         while (angle < 0) {
  2065.             angle += 90 * 64;
  2066.             totallen -= sidelen;
  2067.             oddSide = !oddSide;
  2068.         }
  2069.     }
  2070.     if (oddSide)
  2071.         angle = 90 * 64 - angle;
  2072.         
  2073.     di = xAngleToDashIndex (angle);
  2074.     excess = angle - dashIndexToXAngle (di);
  2075.  
  2076.     len = map->map[di];
  2077.     /*
  2078.      * linearly interpolate between this point and the next
  2079.      */
  2080.     if (excess > 0) {
  2081.         excesslen = (map->map[di + 1] - map->map[di]) *
  2082.                 ((double) excess) / dashXAngleStep;
  2083.         len += excesslen;
  2084.     }
  2085.     if (oddSide)
  2086.         totallen += (sidelen - len);
  2087.     else
  2088.         totallen += len;
  2089.     return totallen;
  2090. }
  2091.  
  2092. /*
  2093.  * len is along the arc, but may be more than one rotation
  2094.  */
  2095.  
  2096. static int
  2097. lengthToAngle (len, map)
  2098.     double    len;
  2099.     dashMap    *map;
  2100. {
  2101.     double    sidelen = map->map[DASH_MAP_SIZE - 1];
  2102.     int    angle, angleexcess;
  2103.     Bool    oddSide = FALSE;
  2104.     int    a0, a1, a;
  2105.  
  2106.     angle = 0;
  2107.     /*
  2108.      * step around the ellipse, subtracting sidelens and
  2109.      * adding 90 degrees.  oddSide will tell if the
  2110.      * map should be interpolated in reverse
  2111.      */
  2112.     if (len >= 0) {
  2113.         if (sidelen == 0)
  2114.             return 2 * FULLCIRCLE;    /* infinity */
  2115.         while (len >= sidelen) {
  2116.             angle += 90 * 64;
  2117.             len -= sidelen;
  2118.             oddSide = !oddSide;
  2119.         }
  2120.     } else {
  2121.         if (sidelen == 0)
  2122.             return -2 * FULLCIRCLE;    /* infinity */
  2123.         while (len < 0) {
  2124.             angle -= 90 * 64;
  2125.             len += sidelen;
  2126.             oddSide = !oddSide;
  2127.         }
  2128.     }
  2129.     if (oddSide)
  2130.         len = sidelen - len;
  2131.     a0 = 0;
  2132.     a1 = DASH_MAP_SIZE - 1;
  2133.     /*
  2134.      * binary search for the closest pre-computed length
  2135.      */
  2136.     while (a1 - a0 > 1) {
  2137.         a = (a0 + a1) / 2;
  2138.         if (len > map->map[a])
  2139.             a0 = a;
  2140.         else
  2141.             a1 = a;
  2142.     }
  2143.     angleexcess = dashIndexToXAngle (a0);
  2144.     /*
  2145.      * linearly interpolate to the next point
  2146.      */
  2147.     angleexcess += (len - map->map[a0]) /
  2148.             (map->map[a0+1] - map->map[a0]) * dashXAngleStep;
  2149.     if (oddSide)
  2150.         angle += (90 * 64) - angleexcess;
  2151.     else
  2152.         angle += angleexcess;
  2153.     return angle;
  2154. }
  2155.  
  2156. /*
  2157.  * compute the angle of an ellipse which cooresponds to
  2158.  * the given path length.  Note that the correct solution
  2159.  * to this problem is an eliptic integral, we'll punt and
  2160.  * approximate (it's only for dashes anyway).  This
  2161.  * approximation uses a polygon.
  2162.  *
  2163.  * The remaining portion of len is stored in *lenp -
  2164.  * this will be negative if the arc extends beyond
  2165.  * len and positive if len extends beyond the arc.
  2166.  */
  2167.  
  2168. static int
  2169. computeAngleFromPath (startAngle, endAngle, map, lenp, backwards)
  2170.     int    startAngle, endAngle;    /* normalized absolute angles in *64 degrees */
  2171.     dashMap    *map;
  2172.     int    *lenp;
  2173.     int    backwards;
  2174. {
  2175.     int    a0, a1, a;
  2176.     double    len0;
  2177.     int    len;
  2178.  
  2179.     a0 = startAngle;
  2180.     a1 = endAngle;
  2181.     len = *lenp;
  2182.     if (backwards) {
  2183.         /*
  2184.          * flip the problem around to always be
  2185.          * forwards
  2186.          */
  2187.         a0 = FULLCIRCLE - a0;
  2188.         a1 = FULLCIRCLE - a1;
  2189.     }
  2190.     if (a1 < a0)
  2191.         a1 += FULLCIRCLE;
  2192.     len0 = angleToLength (a0, map);
  2193.     a = lengthToAngle (len0 + len, map);
  2194.     if (a > a1) {
  2195.         a = a1;
  2196.         len -= angleToLength (a1, map) - len0;
  2197.     } else
  2198.         len = 0;
  2199.     if (backwards)
  2200.         a = FULLCIRCLE - a;
  2201.     *lenp = len;
  2202.     return a;
  2203. }
  2204.  
  2205. /*
  2206.  * scan convert wide arcs.
  2207.  */
  2208.  
  2209. /*
  2210.  * draw zero width/height arcs
  2211.  */
  2212.  
  2213. static void
  2214. drawZeroArc (pDraw, pGC, tarc, left, right)
  2215.     DrawablePtr   pDraw;
  2216.     GCPtr         pGC;
  2217.     xArc          tarc;
  2218.     miArcFacePtr    right, left;
  2219. {
  2220.     double    x0, y0, x1, y1, w, h, x, y;
  2221.     double    xmax, ymax, xmin, ymin;
  2222.     int    a0, a1;
  2223.     double    a, startAngle, endAngle;
  2224.     double    l, lx, ly;
  2225.  
  2226.     l = pGC->lineWidth;
  2227.     if (l == 0)
  2228.         l = 1;
  2229.     l /= 2;
  2230.     a0 = tarc.angle1;
  2231.     a1 = tarc.angle2;
  2232.     if (a1 > FULLCIRCLE)
  2233.         a1 = FULLCIRCLE;
  2234.     else if (a1 < -FULLCIRCLE)
  2235.         a1 = -FULLCIRCLE;
  2236.     w = tarc.width / 2.0;
  2237.     h = tarc.height / 2.0;
  2238.     /*
  2239.      * play in X coordinates right away
  2240.      */
  2241.     startAngle = - ((double) a0 / 64.0);
  2242.     endAngle = - ((double) (a0 + a1) / 64.0);
  2243.     
  2244.     xmax = -w;
  2245.     xmin = w;
  2246.     ymax = -h;
  2247.     ymin = h;
  2248.     a = startAngle;
  2249.     for (;;)
  2250.     {
  2251.         x = w * miDcos(a);
  2252.         y = h * miDsin(a);
  2253.         if (a == startAngle)
  2254.         {
  2255.             x0 = x;
  2256.             y0 = y;
  2257.         }
  2258.         if (a == endAngle)
  2259.         {
  2260.             x1 = x;
  2261.             y1 = y;
  2262.         }
  2263.         if (x > xmax)
  2264.             xmax = x;
  2265.         if (x < xmin)
  2266.             xmin = x;
  2267.         if (y > ymax)
  2268.             ymax = y;
  2269.         if (y < ymin)
  2270.             ymin = y;
  2271.         if (a == endAngle)
  2272.             break;
  2273.         if (a1 < 0)    /* clockwise */
  2274.         {
  2275.             if (floor (a / 90.0) == floor (endAngle / 90.0))
  2276.                 a = endAngle;
  2277.             else
  2278.                 a = 90 * (floor (a/90.0) + 1);
  2279.         }
  2280.         else
  2281.         {
  2282.             if (ceil (a / 90.0) == ceil (endAngle / 90.0))
  2283.                 a = endAngle;
  2284.             else
  2285.                 a = 90 * (ceil (a/90.0) - 1);
  2286.         }
  2287.     }
  2288.     lx = ly = l;
  2289.     if ((x1 - x0) + (y1 - y0) < 0)
  2290.         lx = ly = -l;
  2291.     if (h)
  2292.         ly = 0.0;
  2293.     else
  2294.         lx = 0.0;
  2295.     if (right)
  2296.     {
  2297.         right->center.x = x0;
  2298.         right->center.y = y0;
  2299.         right->clock.x = x0 - lx;
  2300.         right->clock.y = y0 - ly;
  2301.         right->counterClock.x = x0 + lx;
  2302.         right->counterClock.y = y0 + ly;
  2303.     }
  2304.     if (left)
  2305.      {
  2306.         left->center.x = x1;
  2307.         left->center.y = y1;
  2308.         left->clock.x = x1 + lx;
  2309.         left->clock.y = y1 + ly;
  2310.         left->counterClock.x = x1 - lx;
  2311.         left->counterClock.y = y1 - ly;
  2312.     }
  2313.     
  2314.     x0 = xmin;
  2315.     x1 = xmax;
  2316.     y0 = ymin;
  2317.     y1 = ymax;
  2318.     if (ymin != y1) {
  2319.         xmin = -l;
  2320.         xmax = l;
  2321.     } else {
  2322.         ymin = -l;
  2323.         ymax = l;
  2324.     }
  2325.     if (xmax != xmin && ymax != ymin) {
  2326.         int    minx, maxx, miny, maxy;
  2327.         xRectangle  rect;
  2328.  
  2329.         minx = ICEIL (xmin + w) + tarc.x;
  2330.         maxx = ICEIL (xmax + w) + tarc.x;
  2331.         miny = ICEIL (ymin + h) + tarc.y;
  2332.         maxy = ICEIL (ymax + h) + tarc.y;
  2333.         rect.x = minx;
  2334.         rect.y = miny;
  2335.         rect.width = maxx - minx;
  2336.         rect.height = maxy - miny;
  2337.         (*pGC->ops->PolyFillRect) (pDraw, pGC, 1, &rect);
  2338.     }
  2339. }
  2340.  
  2341. # define BINARY_LIMIT    (0.1)
  2342. # define NEWTON_LIMIT    (0.0000001)
  2343.  
  2344. struct bound {
  2345.     double    min, max;
  2346. };
  2347.  
  2348. struct line {
  2349.     double    m, b;
  2350.     int    valid;
  2351. };
  2352.  
  2353. /*
  2354.  * these are all y value bounds
  2355.  */
  2356.  
  2357. struct arc_bound {
  2358.     struct bound    ellipse;
  2359.     struct bound    inner;
  2360.     struct bound    outer;
  2361.     struct bound    right;
  2362.     struct bound    left;
  2363. };
  2364.  
  2365. # define BINARY_TABLE_SIZE    (512)
  2366.  
  2367. struct accelerators {
  2368.     double        tail_y;
  2369.     double        h2;
  2370.     double        w2;
  2371.     double        h4;
  2372.     double        w4;
  2373.     double        h2mw2;
  2374.     double        wh2mw2;
  2375.     double        wh4;
  2376.     struct line    left, right;
  2377.     double        innerTable[BINARY_TABLE_SIZE+1];
  2378.     double        outerTable[BINARY_TABLE_SIZE+1];
  2379.     char        innerValid[BINARY_TABLE_SIZE+1];
  2380.     char        outerValid[BINARY_TABLE_SIZE+1];
  2381. };
  2382.  
  2383. struct arc_def {
  2384.     double    w, h, l;
  2385.     double    a0, a1;
  2386. };
  2387.  
  2388. #ifdef USE_INLINE
  2389. inline static const double Sqrt (const double x)
  2390. #else
  2391. static double
  2392. Sqrt (x)
  2393. double    x;
  2394. #endif
  2395. {
  2396.     if (x < 0) {
  2397.         if (x > -NEWTON_LIMIT)
  2398.             return 0;
  2399.         else
  2400.             FatalError ("miarc.c: Sqrt of negative number %g\n", x);
  2401.     }
  2402.     return sqrt (x);
  2403. }
  2404.  
  2405. #define boundedLt(value, bounds) \
  2406.     ((bounds).min <= (value) && (value) < (bounds).max)
  2407.  
  2408. #define boundedLe(value, bounds)\
  2409.     ((bounds).min <= (value) && (value) <= (bounds).max)
  2410.  
  2411. /*
  2412.  * this computes the ellipse y value associated with the
  2413.  * bottom of the tail.
  2414.  */
  2415.  
  2416. # define CUBED_ROOT_2    1.2599210498948732038115849718451499938964
  2417. # define CUBED_ROOT_4    1.5874010519681993173435330390930175781250
  2418.  
  2419. static void
  2420. tailEllipseY (def, acc)
  2421.     struct arc_def        *def;
  2422.     struct accelerators    *acc;
  2423. {
  2424.     double        t;
  2425.  
  2426.     acc->tail_y = 0.0;
  2427.     if (def->w == def->h)
  2428.         return;
  2429.     t = def->l * def->w;
  2430.     if (def->w > def->h) {
  2431.         if (t < acc->h2 + acc->h2)
  2432.         return;
  2433.     } else {
  2434.         if (t > acc->h2 + acc->h2)
  2435.         return;
  2436.     }
  2437.     t = def->h * t;
  2438.     t = (CUBED_ROOT_4 * acc->h2 - cbrt(t * t)) / acc->h2mw2;
  2439.     if (t > 0.0)
  2440.         acc->tail_y = def->h / CUBED_ROOT_2 * sqrt(t);
  2441. }
  2442.  
  2443. /*
  2444.  * inverse functions -- compute edge coordinates
  2445.  * from the ellipse
  2446.  */
  2447.  
  2448. static double
  2449. outerXfromXY (x, y, def, acc)
  2450.     double            x, y;
  2451.     struct arc_def        *def;
  2452.     struct accelerators    *acc;
  2453. {
  2454.     return x + (x * acc->h2 * def->l) /
  2455.            (2 * Sqrt (x*x *acc->h4 + y*y * acc->w4));
  2456. }
  2457.  
  2458. static double
  2459. outerXfromY (y, def, acc)
  2460.     double            y;
  2461.     struct arc_def        *def;
  2462.     struct accelerators    *acc;
  2463. {
  2464.     double    x;
  2465.  
  2466.     x = def->w * Sqrt ((acc->h2 - (y*y)) / acc->h2);
  2467.  
  2468.     return x + (x * acc->h2 * def->l) /
  2469.            (2 * Sqrt (x*x *acc->h4 + y*y * acc->w4));
  2470. }
  2471.  
  2472. static double
  2473. outerYfromXY (x, y, def, acc)
  2474.     double        x, y;
  2475.     struct arc_def        *def;
  2476.     struct accelerators    *acc;
  2477. {
  2478.     return y + (y * acc->w2 * def->l) /
  2479.            (2 * Sqrt (x*x * acc->h4 + y*y * acc->w4));
  2480. }
  2481.  
  2482. static double
  2483. outerYfromY (y, def, acc)
  2484.     double    y;
  2485.     struct arc_def        *def;
  2486.     struct accelerators    *acc;
  2487. {
  2488.     double    x;
  2489.  
  2490.     x = def->w * Sqrt ((acc->h2 - (y*y)) / acc->h2);
  2491.  
  2492.     return y + (y * acc->w2 * def->l) /
  2493.            (2 * Sqrt (x*x * acc->h4 + y*y * acc->w4));
  2494. }
  2495.  
  2496. static double
  2497. innerXfromXY (x, y, def, acc)
  2498.     double            x, y;
  2499.     struct arc_def        *def;
  2500.     struct accelerators    *acc;
  2501. {
  2502.     return x - (x * acc->h2 * def->l) /
  2503.            (2 * Sqrt (x*x * acc->h4 + y*y * acc->w4));
  2504. }
  2505.  
  2506. static double
  2507. innerXfromY (y, def, acc)
  2508.     double            y;
  2509.     struct arc_def        *def;
  2510.     struct accelerators    *acc;
  2511. {
  2512.     double    x;
  2513.  
  2514.     x = def->w * Sqrt ((acc->h2 - (y*y)) / acc->h2);
  2515.     
  2516.     return x - (x * acc->h2 * def->l) /
  2517.            (2 * Sqrt (x*x * acc->h4 + y*y * acc->w4));
  2518. }
  2519.  
  2520. static double
  2521. innerYfromXY (x, y, def, acc)
  2522.     double            x, y;
  2523.     struct arc_def        *def;
  2524.     struct accelerators    *acc;
  2525. {
  2526.     return y - (y * acc->w2 * def->l) /
  2527.            (2 * Sqrt (x*x * acc->h4 + y*y * acc->w4));
  2528. }
  2529.  
  2530. static double
  2531. innerYfromY (y, def, acc)
  2532.     double    y;
  2533.     struct arc_def        *def;
  2534.     struct accelerators    *acc;
  2535. {
  2536.     double    x;
  2537.  
  2538.     x = def->w * Sqrt ((acc->h2 - (y*y)) / acc->h2);
  2539.  
  2540.     return y - (y * acc->w2 * def->l) /
  2541.            (2 * Sqrt (x*x * acc->h4 + y*y * acc->w4));
  2542. }
  2543.  
  2544. static void
  2545. computeLine (x1, y1, x2, y2, line)
  2546.     double        x1, y1, x2, y2;
  2547.     struct line    *line;
  2548. {
  2549.     if (y1 == y2)
  2550.         line->valid = 0;
  2551.     else {
  2552.         line->m = (x1 - x2) / (y1 - y2);
  2553.         line->b = x1  - y1 * line->m;
  2554.         line->valid = 1;
  2555.     }
  2556. }
  2557.  
  2558. static double
  2559. intersectLine (y, line)
  2560.     double        y;
  2561.     struct line    *line;
  2562. {
  2563.     return line->m * y + line->b;
  2564. }
  2565.  
  2566. /*
  2567.  * compute various accelerators for an ellipse.  These
  2568.  * are simply values that are used repeatedly in
  2569.  * the computations
  2570.  */
  2571.  
  2572. static void
  2573. computeAcc (def, acc)
  2574.     struct arc_def        *def;
  2575.     struct accelerators    *acc;
  2576. {
  2577.     int    i;
  2578.  
  2579.     acc->h2 = def->h * def->h;
  2580.     acc->w2 = def->w * def->w;
  2581.     acc->h4 = acc->h2 * acc->h2;
  2582.     acc->w4 = acc->w2 * acc->w2;
  2583.     acc->h2mw2 = acc->h2 - acc->w2;
  2584.     acc->wh2mw2 = def->w * acc->h2mw2;
  2585.     acc->wh4 = def->w * acc->h4;
  2586.     tailEllipseY (def, acc);
  2587.     for (i = 0; i <= BINARY_TABLE_SIZE; i++)
  2588.         acc->innerValid[i] = acc->outerValid[i] = 0;
  2589. }
  2590.         
  2591. /*
  2592.  * compute y value bounds of various portions of the arc,
  2593.  * the outer edge, the ellipse and the inner edge.
  2594.  */
  2595.  
  2596. static void
  2597. computeBound (def, bound, acc, right, left)
  2598.     struct arc_def        *def;
  2599.     struct arc_bound    *bound;
  2600.     struct accelerators    *acc;
  2601.     miArcFacePtr        right, left;
  2602. {
  2603.     double        t;
  2604.     double        innerTaily;
  2605.     double        tail_y;
  2606.     struct bound    innerx, outerx;
  2607.     struct bound    ellipsex;
  2608.  
  2609.     bound->ellipse.min = Dsin (def->a0) * def->h;
  2610.     bound->ellipse.max = Dsin (def->a1) * def->h;
  2611.     if (def->a0 == 45 && def->w == def->h)
  2612.         ellipsex.min = bound->ellipse.min;
  2613.     else
  2614.         ellipsex.min = Dcos (def->a0) * def->w;
  2615.     if (def->a1 == 45 && def->w == def->h)
  2616.         ellipsex.max = bound->ellipse.max;
  2617.     else
  2618.         ellipsex.max = Dcos (def->a1) * def->w;
  2619.     bound->outer.min = outerYfromXY (ellipsex.min, bound->ellipse.min, def, acc);
  2620.     bound->outer.max = outerYfromXY (ellipsex.max, bound->ellipse.max, def, acc);
  2621.     bound->inner.min = innerYfromXY (ellipsex.min, bound->ellipse.min, def, acc);
  2622.     bound->inner.max = innerYfromXY (ellipsex.max, bound->ellipse.max, def, acc);
  2623.  
  2624.     outerx.min = outerXfromXY (ellipsex.min, bound->ellipse.min, def, acc);
  2625.     outerx.max = outerXfromXY (ellipsex.max, bound->ellipse.max, def, acc);
  2626.     innerx.min = innerXfromXY (ellipsex.min, bound->ellipse.min, def, acc);
  2627.     innerx.max = innerXfromXY (ellipsex.max, bound->ellipse.max, def, acc);
  2628.     
  2629.     /*
  2630.      * save the line end points for the
  2631.      * cap code to use.  Careful here, these are
  2632.      * in cartesean coordinates (y increasing upwards)
  2633.      * while the cap code uses inverted coordinates
  2634.      * (y increasing downwards)
  2635.      */
  2636.  
  2637.     if (right) {
  2638.         right->counterClock.y = bound->outer.min;
  2639.         right->counterClock.x = outerx.min;
  2640.         right->center.y = bound->ellipse.min;
  2641.         right->center.x = ellipsex.min;
  2642.         right->clock.y = bound->inner.min;
  2643.         right->clock.x = innerx.min;
  2644.     }
  2645.  
  2646.     if (left) {
  2647.         left->clock.y = bound->outer.max;
  2648.         left->clock.x = outerx.max;
  2649.         left->center.y = bound->ellipse.max;
  2650.         left->center.x = ellipsex.max;
  2651.         left->counterClock.y = bound->inner.max;
  2652.         left->counterClock.x = innerx.max;
  2653.     }
  2654.  
  2655.     bound->left.min = bound->inner.max;
  2656.     bound->left.max = bound->outer.max;
  2657.     bound->right.min = bound->inner.min;
  2658.     bound->right.max = bound->outer.min;
  2659.  
  2660.     computeLine (innerx.min, bound->inner.min, outerx.min, bound->outer.min,
  2661.               &acc->right);
  2662.     computeLine (innerx.max, bound->inner.max, outerx.max, bound->outer.max,
  2663.              &acc->left);
  2664.  
  2665.     if (bound->inner.min > bound->inner.max) {
  2666.         t = bound->inner.min;
  2667.         bound->inner.min = bound->inner.max;
  2668.         bound->inner.max = t;
  2669.     }
  2670.     tail_y = acc->tail_y;
  2671.     if (tail_y > bound->ellipse.max)
  2672.         tail_y = bound->ellipse.max;
  2673.     else if (tail_y < bound->ellipse.min)
  2674.         tail_y = bound->ellipse.min;
  2675.     innerTaily = innerYfromY (tail_y, def, acc);
  2676.     if (bound->inner.min > innerTaily)
  2677.         bound->inner.min = innerTaily;
  2678.     if (bound->inner.max < innerTaily)
  2679.         bound->inner.max = innerTaily;
  2680. }
  2681.  
  2682. /*
  2683.  * using newtons method and a binary search, compute the ellipse y value
  2684.  * associated with the given edge value (either outer or
  2685.  * inner).  This is the heart of the scan conversion code and
  2686.  * is generally called three times for each span.  It should
  2687.  * be optimized further.
  2688.  *
  2689.  * the general idea here is to solve the equation:
  2690.  *
  2691.  *                               w^2 * l
  2692.  *   edge_y = y + y * -------------------------------
  2693.  *                    2 * sqrt (x^2 * h^4 + y^2 * w^4)
  2694.  *
  2695.  * for y.  (x, y) is a point on the ellipse, so x can be
  2696.  * found from y:
  2697.  *
  2698.  *                ( h^2 - y^2 )
  2699.  *   x = w * sqrt ( --------- )
  2700.  *                (    h^2    )
  2701.  *
  2702.  * The information given at the start of the search
  2703.  * is two points which are known to bound the desired
  2704.  * solution, a binary search starts with these two points
  2705.  * and converges close to a solution, which is then
  2706.  * refined with newtons method.  Newtons method
  2707.  * cannot be used in isolation as it does not always
  2708.  * converge to the desired solution without a close
  2709.  * starting point, the binary search simply provides
  2710.  * that point.  Increasing the solution interval for
  2711.  * the binary search will certainly speed up the
  2712.  * solution, but may generate a range which causes
  2713.  * the newtons method to fail.  This needs study.
  2714.  */
  2715.  
  2716. # define binaryIndexFromY(y, def)    (((y) / (def)->h) * ((double) BINARY_TABLE_SIZE))
  2717. # define yFromBinaryIndex(i, def)    ((((double) i) / ((double) BINARY_TABLE_SIZE)) * (def)->h)
  2718.  
  2719. #ifdef notdef
  2720.  
  2721. static double
  2722. binaryValue (i, def, acc, valid, table, f)
  2723.     int            i;
  2724.     struct arc_def        *def;
  2725.     struct accelerators    *acc;
  2726.     char            *valid;
  2727.     double            *table;
  2728.     double            (*f)();
  2729. {
  2730.     if (!valid[i]) {
  2731.         valid[i] = 1;
  2732.         table[i] = f (yFromBinaryIndex (i, def), def, acc);
  2733.     }
  2734.     return table[i];
  2735. }
  2736. #else
  2737.  
  2738. # define binaryValue(i, def, acc, valid, table, f)\
  2739.     (valid[i] ? table[i] : (valid[i] = 1, table[i] = f (yFromBinaryIndex (i, def), def, acc)))
  2740. #endif
  2741.  
  2742. static double
  2743. ellipseY (edge_y, def, acc, outer, y0, y1)
  2744.     double            edge_y;
  2745.     struct arc_def        *def;
  2746.     struct accelerators    *acc;
  2747.     register double        y0, y1;
  2748. {
  2749.     register double    w, l, h2, h4, w2, w4, x, y2;
  2750.     double        newtony, binaryy;
  2751.     double        value0, value1;
  2752.     double        newtonvalue, binaryvalue;
  2753.     double        minY, maxY;
  2754.     double        binarylimit;
  2755.     double        (*f)();
  2756.     int        index0, index1, newindex;
  2757.     char        *valid;
  2758.     double        *table;
  2759.     
  2760.     /*
  2761.      * compute some accelerators
  2762.      */
  2763.     w = def->w;
  2764.     if (outer) {
  2765.         f = outerYfromY;
  2766.         l = def->l;
  2767.         table = acc->outerTable;
  2768.         valid = acc->outerValid;
  2769.     } else {
  2770.         f = innerYfromY;
  2771.         l = -def->l;
  2772.         table = acc->innerTable;
  2773.         valid = acc->innerValid;
  2774.     }
  2775.     h2 = acc->h2;
  2776.     h4 = acc->h4;
  2777.     w2 = acc->w2;
  2778.     w4 = acc->w4;
  2779.  
  2780.     /*
  2781.      * make sure the arguments are in the right order
  2782.      */
  2783.     if (y0 > y1) {
  2784.         binaryy = y0;
  2785.         y0 = y1;
  2786.         y1 = binaryy;
  2787.     }
  2788.     maxY = y1;
  2789.     minY = y0;
  2790.  
  2791.     index0 = binaryIndexFromY (y0, def);
  2792.     index1 = binaryIndexFromY (y1, def);
  2793.     if (index0 == index1) {
  2794.         value0 = f (y0, def, acc) - edge_y;
  2795.         if (value0 == 0)
  2796.             return y0;
  2797.         value1 = f (y1, def, acc) - edge_y;
  2798.         if (value1 == 0)
  2799.             return y1;
  2800.         if (value0 > 0 == value1 > 0)
  2801.             return -1.0;
  2802.     } else {
  2803.         /*
  2804.           * round index0 up, index1 down
  2805.           */
  2806.         index0++;
  2807.         value0 = binaryValue (index0, def, acc, valid, table, f) - edge_y;
  2808.         if (value0 == 0)
  2809.             return yFromBinaryIndex (index0, def);
  2810.         value1 = binaryValue (index1, def, acc, valid, table, f) - edge_y;
  2811.         if (value1 == 0)
  2812.             return yFromBinaryIndex (index1, def);
  2813.         /*
  2814.           * make sure the result lies between the restricted end points
  2815.           */
  2816.         if (value0 > 0 == value1 > 0) {
  2817.             if (y0 == y1)
  2818.                 return -1.0;
  2819.             binaryvalue = f(y0, def, acc) - edge_y;
  2820.             if (binaryvalue > 0 != value0 > 0) {
  2821.                 /*
  2822.                   * restrict the search to the small portion at
  2823.                   * the begining
  2824.                   */
  2825.                 index1 = index0;
  2826.                 value1 = value0;
  2827.                 value0 = binaryvalue;
  2828.                 y1 = yFromBinaryIndex (index0, def);
  2829.             } else {
  2830.                 binaryvalue = f(y1, def, acc) - edge_y;
  2831.                 if (binaryvalue > 0 == value1 > 0)
  2832.                     return -1.0;    /* an illegal value */
  2833.                 /*
  2834.                   * restrict the search to the small portion at
  2835.                   * the end
  2836.                   */
  2837.                 index0 = index1;
  2838.                 value0 = value1;
  2839.                 value1 = binaryvalue;
  2840.                 y0 = yFromBinaryIndex (index1, def);
  2841.             }
  2842.         } else {
  2843.             /*
  2844.               * restrict the search to the inside portion
  2845.               */
  2846.             y0 = yFromBinaryIndex (index0, def);
  2847.             y1 = yFromBinaryIndex (index1, def);
  2848.         }
  2849.     }
  2850.     binarylimit = (value1 - value0) / 25.0;
  2851.     binarylimit = fabs (binarylimit);
  2852.     if (binarylimit < BINARY_LIMIT)
  2853.         binarylimit = BINARY_LIMIT;
  2854.     /*
  2855.      * binary search for a while
  2856.      */
  2857.     while (fabs (value1) > binarylimit) {
  2858.         if (y0 == y1 || value0 == value1)
  2859.             return -1.0;
  2860.  
  2861.         if (index1 > index0 + 1) {
  2862.             newindex = (index1 + index0) / 2;
  2863.             binaryy = yFromBinaryIndex (newindex, def);
  2864.             binaryvalue = binaryValue (newindex,
  2865.                 def, acc, valid, table, f) - edge_y;
  2866.         } else {
  2867.             binaryy = (y0 + y1) / 2;
  2868.             /*
  2869.               * inline expansion of the function
  2870.               */
  2871.     
  2872.             y2 = binaryy*binaryy;
  2873.             x = w * Sqrt ((h2 - (y2)) / h2);
  2874.     
  2875.             binaryvalue = ( binaryy + (binaryy * w2 * l) /
  2876.                             (2 * Sqrt (x*x * h4 + y2 * w4))) - edge_y;
  2877.             newindex = -1;
  2878.         }
  2879.         if (binaryvalue > 0 == value0 > 0) {
  2880.             y0 = binaryy;
  2881.             value0 = binaryvalue;
  2882.             if (newindex > 0)
  2883.                 index0 = newindex;
  2884.         } else {
  2885.             y1 = binaryy;
  2886.             value1 = binaryvalue;
  2887.             if (newindex > 0)
  2888.                 index1 = newindex;
  2889.         }
  2890.     }
  2891.  
  2892.     /*
  2893.      * clean up the estimate with newtons method
  2894.      */
  2895.  
  2896.     while (fabs (value1) > NEWTON_LIMIT) {
  2897.         newtony = y1 - value1 * (y1 - y0) / (value1 - value0);
  2898.         if (newtony > maxY)
  2899.             newtony = maxY;
  2900.         if (newtony < minY)
  2901.             newtony = minY;
  2902.         /*
  2903.          * inline expansion of the function
  2904.          */
  2905.  
  2906.         y2 = newtony*newtony;
  2907.         x = w * Sqrt ((h2 - (y2)) / h2);
  2908.  
  2909.         newtonvalue = ( newtony + (newtony * w2 * l) /
  2910.                   (2 * Sqrt (x*x * h4 + y2 * w4))) - edge_y;
  2911.  
  2912.         if (newtonvalue == 0)
  2913.             return newtony;
  2914.         if (fabs (value0) > fabs (value1)) {
  2915.             y0 = newtony;
  2916.             value0 = newtonvalue;
  2917.         } else {
  2918.             y1 = newtony;
  2919.             value1 = newtonvalue;
  2920.         }
  2921.     }
  2922.     return y1;
  2923. }
  2924.  
  2925. #ifdef notdef
  2926. static double
  2927. ellipseX (ellipse_y, def, acc)
  2928.     double            ellipse_y;
  2929.     struct arc_def        *def;
  2930.     struct accelerators    *acc;
  2931. {
  2932.     return def->w / def->h * Sqrt (acc->h2 - ellipse_y * ellipse_y);
  2933. }
  2934. #endif
  2935.  
  2936. static double
  2937. outerX (outer_y, def, bound, acc)
  2938.     register double        outer_y;
  2939.     register struct arc_def    *def;
  2940.     struct arc_bound    *bound;
  2941.     struct accelerators    *acc;
  2942. {
  2943.     double    y;
  2944.  
  2945.     /*
  2946.      * special case for circles
  2947.      */
  2948.     if (def->w == def->h) {
  2949.         register double    x;
  2950.  
  2951.         x = def->w + def->l/2.0;
  2952.         x = Sqrt (x * x - outer_y * outer_y);
  2953.         return x;
  2954.     }
  2955.     if (outer_y == bound->outer.min)
  2956.         y = bound->ellipse.min;
  2957.     if (outer_y == bound->outer.max)
  2958.         y = bound->ellipse.max;
  2959.     else
  2960.         y = ellipseY (outer_y, def, acc, 1,
  2961.                   bound->ellipse.min, bound->ellipse.max);
  2962.     return outerXfromY (y, def, acc);
  2963. }
  2964.  
  2965. /*
  2966.  * this equation has two solutions -- it's not a function
  2967.  */
  2968.  
  2969. static void
  2970. innerXs (inner_y, def, bound, acc, innerX1p, innerX2p)
  2971.     register double        inner_y;
  2972.     struct arc_def        *def;
  2973.     struct arc_bound    *bound;
  2974.     struct accelerators    *acc;
  2975.     double            *innerX1p, *innerX2p;
  2976. {
  2977.     register double    x1, x2;
  2978.     double        xalt, y0, y1, altY, ellipse_y1, ellipse_y2;
  2979.  
  2980.     /*
  2981.      * special case for circles
  2982.      */
  2983.     if (def->w == def->h) {
  2984.         x1 = def->w - def->l/2.0;
  2985.         x2 = Sqrt (x1 * x1 - inner_y * inner_y);
  2986.         if (x1 < 0)
  2987.             x2 = -x2;
  2988.         *innerX1p = *innerX2p = x2;
  2989.         return;
  2990.     }
  2991.     if (boundedLe (acc->tail_y, bound->ellipse)) {
  2992.         if (def->h > def->w) {
  2993.             y0 = bound->ellipse.min;
  2994.             y1 = acc->tail_y;
  2995.             altY = bound->ellipse.max;
  2996.         } else {
  2997.             y0 = bound->ellipse.max;
  2998.             y1 = acc->tail_y;
  2999.             altY = bound->ellipse.min;
  3000.         }
  3001.         ellipse_y1 = ellipseY (inner_y, def, acc, 0, y0, y1);
  3002.         ellipse_y2 = ellipseY (inner_y, def, acc, 0, y1, altY);
  3003.         if (ellipse_y1 == -1.0)
  3004.             ellipse_y1 = ellipse_y2;
  3005.         if (ellipse_y2 == -1.0)
  3006.             ellipse_y2 = ellipse_y1;
  3007.     } else {
  3008.         ellipse_y1 = ellipseY (inner_y, def, acc, 0,
  3009.                        bound->ellipse.min, bound->ellipse.max);
  3010.         ellipse_y2 = ellipse_y1;
  3011.     }
  3012.     x2 = x1 = innerXfromY (ellipse_y1, def, acc);
  3013.     if (ellipse_y1 != ellipse_y2)
  3014.         x2 = innerXfromY (ellipse_y2, def, acc);
  3015.     if (acc->left.valid && boundedLe (inner_y, bound->left)) {
  3016.         xalt = intersectLine (inner_y, &acc->left);
  3017.         if (xalt < x2 && xalt < x1)
  3018.             x2 = xalt;
  3019.         if (xalt < x1)
  3020.             x1 = xalt;
  3021.     }
  3022.     if (acc->right.valid && boundedLe (inner_y, bound->right)) {
  3023.         xalt = intersectLine (inner_y, &acc->right);
  3024.         if (xalt < x2 && xalt < x1)
  3025.             x2 = xalt;
  3026.         if (xalt < x1)
  3027.             x1 = xalt;
  3028.     }
  3029.     *innerX1p = x1;
  3030.     *innerX2p = x2;
  3031. }
  3032.  
  3033. /*
  3034.  * this section computes the x value of the span at y 
  3035.  * intersected with the specified face of the ellipse.
  3036.  *
  3037.  * this is the min/max X value over the set of normal
  3038.  * lines to the entire ellipse,  the equation of the
  3039.  * normal lines is:
  3040.  *
  3041.  *     ellipse_x h^2                   h^2
  3042.  * x = ------------ y + ellipse_x (1 - --- )
  3043.  *     ellipse_y w^2                   w^2
  3044.  *
  3045.  * compute the derivative with-respect-to ellipse_y and solve
  3046.  * for zero:
  3047.  *    
  3048.  *       (w^2 - h^2) ellipse_y^3 + h^4 y
  3049.  * 0 = - ----------------------------------
  3050.  *       h w ellipse_y^2 sqrt (h^2 - ellipse_y^2)
  3051.  *
  3052.  *             (   h^4 y     )
  3053.  * ellipse_y = ( ----------  ) ^ (1/3)
  3054.  *             ( (h^2 - w^2) )
  3055.  *
  3056.  * The other two solutions to the equation are imaginary.
  3057.  *
  3058.  * This gives the position on the ellipse which generates
  3059.  * the normal with the largest/smallest x intersection point.
  3060.  *
  3061.  * Now compute the second derivative to check whether
  3062.  * the intersection is a minimum or maximum:
  3063.  *
  3064.  *    h (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2))
  3065.  * -  -------------------------------------------
  3066.  *          w y0^3 (sqrt (h^2 - y^2)) ^ 3
  3067.  *
  3068.  * as we only care about the sign,
  3069.  *
  3070.  * - (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2))
  3071.  *
  3072.  * or (to use accelerators),
  3073.  *
  3074.  * y0^3 (h^2 - w^2) - h^2 y (3y0^2 - 2h^2) 
  3075.  *
  3076.  */
  3077.  
  3078. /*
  3079.  * computes the position on the ellipse whose normal line
  3080.  * intersects the given scan line maximally
  3081.  */
  3082.  
  3083. static double
  3084. hookEllipseY (scan_y, bound, acc, left)
  3085.     double            scan_y;
  3086.     struct arc_bound    *bound;
  3087.     struct accelerators    *acc;
  3088. {
  3089.     double    ret;
  3090.  
  3091.     if (acc->h2mw2 == 0) {
  3092.         if (scan_y > 0 && !left || scan_y < 0 && left)
  3093.             return bound->ellipse.min;
  3094.         return bound->ellipse.max;
  3095.     }
  3096.     ret = (acc->h4 * scan_y) / (acc->h2mw2);
  3097.     if (ret >= 0)
  3098.         return cbrt (ret);
  3099.     else
  3100.         return -cbrt (-ret);
  3101. }
  3102.  
  3103. /*
  3104.  * computes the X value of the intersection of the
  3105.  * given scan line with the right side of the lower hook
  3106.  */
  3107.  
  3108. static double
  3109. hookX (scan_y, def, bound, acc, left)
  3110.     double            scan_y;
  3111.     struct arc_def        *def;
  3112.     struct arc_bound    *bound;
  3113.     struct accelerators    *acc;
  3114.     int            left;
  3115. {
  3116.     double    ellipse_y, x;
  3117.     double    maxMin;
  3118.  
  3119.     if (def->w != def->h) {
  3120.         ellipse_y = hookEllipseY (scan_y, bound, acc, left);
  3121.         if (boundedLe (ellipse_y, bound->ellipse)) {
  3122.             /*
  3123.               * compute the value of the second
  3124.               * derivative
  3125.               */
  3126.             maxMin = ellipse_y*ellipse_y*ellipse_y * acc->h2mw2 -
  3127.               acc->h2 * scan_y * (3 * ellipse_y*ellipse_y - 2*acc->h2);
  3128.             if ((left && maxMin > 0) || (!left && maxMin < 0)) {
  3129.                 if (ellipse_y == 0)
  3130.                     return def->w + left ? -def->l/2 : def->l/2;
  3131.                 x = (acc->h2 * scan_y - ellipse_y * acc->h2mw2) *
  3132.                     Sqrt (acc->h2 - ellipse_y * ellipse_y) /
  3133.                      (def->h * def->w * ellipse_y);
  3134.                 return x;
  3135.             }
  3136.         }
  3137.     }
  3138.     if (left) {
  3139.         if (acc->left.valid && boundedLe (scan_y, bound->left)) {
  3140.             x = intersectLine (scan_y, &acc->left);
  3141.         } else {
  3142.             if (acc->right.valid)
  3143.                 x = intersectLine (scan_y, &acc->right);
  3144.             else
  3145.                 x = def->w - def->l/2;
  3146.         }
  3147.     } else {
  3148.         if (acc->right.valid && boundedLe (scan_y, bound->right)) {
  3149.             x = intersectLine (scan_y, &acc->right);
  3150.         } else {
  3151.             if (acc->left.valid)
  3152.                 x = intersectLine (scan_y, &acc->left);
  3153.             else
  3154.                 x = def->w - def->l/2;
  3155.         }
  3156.     }
  3157.     return x;
  3158. }
  3159.  
  3160. /*
  3161.  * generate the set of spans with
  3162.  * the given y coordinate
  3163.  */
  3164.  
  3165. static void
  3166. arcSpan (y, def, bounds, acc)
  3167.     double            y;
  3168.     struct arc_def        *def;
  3169.     struct arc_bound    *bounds;
  3170.     struct accelerators    *acc;
  3171. {
  3172.     double    innerx1, innerx2, outerx1, outerx2;
  3173.  
  3174.     if (boundedLe (y, bounds->inner)) {
  3175.         /*
  3176.          * intersection with inner edge
  3177.          */
  3178.         innerXs (y, def, bounds, acc, &innerx1, &innerx2);
  3179.     } else {
  3180.         /*
  3181.          * intersection with left face
  3182.          */
  3183.         innerx2 = innerx1 = hookX (y, def, bounds, acc, 1);
  3184.         if (acc->right.valid && boundedLe (y, bounds->right))
  3185.         {
  3186.             innerx2 = intersectLine (y, &acc->right);
  3187.             if (innerx2 < innerx1)
  3188.                 innerx1 = innerx2;
  3189.         }
  3190.     }
  3191.     if (boundedLe (y, bounds->outer)) {
  3192.         /*
  3193.          * intersection with outer edge
  3194.          */
  3195.         outerx1 = outerx2 = outerX (y, def, bounds, acc);
  3196.     } else {
  3197.         /*
  3198.          * intersection with right face
  3199.          */
  3200.         outerx2 = outerx1 = hookX (y, def, bounds, acc, 0);
  3201.         if (acc->left.valid && boundedLe (y, bounds->left))
  3202.          {
  3203.             outerx2 = intersectLine (y, &acc->left);
  3204.             if (outerx2 < outerx1)
  3205.                 outerx2 = outerx1;
  3206.         }
  3207.     }
  3208.     /*
  3209.      * there are a very few cases when two spans will be
  3210.      * generated.
  3211.      */
  3212.     if (innerx1 <= outerx1 &&
  3213.          outerx1 <  innerx2 &&
  3214.          innerx2 <= outerx2)
  3215.      {
  3216.         span (innerx1, outerx1);
  3217.         span (innerx2, outerx2);
  3218.     } else
  3219.         span (innerx1, outerx2);
  3220. }
  3221.  
  3222. /*
  3223.  * create whole arcs out of pieces.  This code is
  3224.  * very bad.
  3225.  */
  3226.  
  3227. static double    arcXcenter, arcYcenter;
  3228. static int    arcXoffset, arcYoffset;
  3229.  
  3230. static struct finalSpan    **finalSpans = NULL;
  3231. static int        finalMiny = 0, finalMaxy = -1;
  3232. static int        finalSize = 0;
  3233.  
  3234. static int        nspans = 0;    /* total spans, not just y coords */
  3235.  
  3236. struct finalSpan {
  3237.     struct finalSpan    *next;
  3238.     int            min, max;    /* x values */
  3239. };
  3240.  
  3241. static struct finalSpan    *freeFinalSpans, *tmpFinalSpan;
  3242.  
  3243. # define allocFinalSpan()   (freeFinalSpans ?\
  3244.                 ((tmpFinalSpan = freeFinalSpans), \
  3245.                  (freeFinalSpans = freeFinalSpans->next), \
  3246.                  (tmpFinalSpan->next = 0), \
  3247.                  tmpFinalSpan) : \
  3248.                  realAllocSpan ())
  3249.  
  3250. # define SPAN_CHUNK_SIZE    128
  3251.  
  3252. struct finalSpanChunk {
  3253.     struct finalSpan    data[SPAN_CHUNK_SIZE];
  3254.     struct finalSpanChunk    *next;
  3255. };
  3256.  
  3257. static struct finalSpanChunk    *chunks;
  3258.  
  3259. struct finalSpan *
  3260. realAllocSpan ()
  3261. {
  3262.     register struct finalSpanChunk    *newChunk;
  3263.     register struct finalSpan    *span;
  3264.     register int            i;
  3265.  
  3266.     newChunk = (struct finalSpanChunk *) xalloc (sizeof (struct finalSpanChunk));
  3267.     if (!newChunk)
  3268.         return (struct finalSpan *) NULL;
  3269.     newChunk->next = chunks;
  3270.     chunks = newChunk;
  3271.     freeFinalSpans = span = newChunk->data + 1;
  3272.     for (i = 1; i < SPAN_CHUNK_SIZE-1; i++) {
  3273.         span->next = span+1;
  3274.         span++;
  3275.     }
  3276.     span->next = 0;
  3277.     span = newChunk->data;
  3278.     span->next = 0;
  3279.     return span;
  3280. }
  3281.  
  3282. static void
  3283. disposeFinalSpans ()
  3284. {
  3285.     struct finalSpanChunk    *chunk, *next;
  3286.  
  3287.     for (chunk = chunks; chunk; chunk = next) {
  3288.         next = chunk->next;
  3289.         xfree (chunk);
  3290.     }
  3291.     chunks = 0;
  3292.     freeFinalSpans = 0;
  3293.     xfree(finalSpans);
  3294.     finalSpans = 0;
  3295. }
  3296.  
  3297. static void
  3298. fillSpans (pDrawable, pGC)
  3299.     DrawablePtr    pDrawable;
  3300.     GCPtr    pGC;
  3301. {
  3302.     register struct finalSpan    *span;
  3303.     register DDXPointPtr        xSpan;
  3304.     register int            *xWidth;
  3305.     register int            i;
  3306.     register struct finalSpan    **f;
  3307.     register int            spany;
  3308.     DDXPointPtr            xSpans;
  3309.     int                *xWidths;
  3310.  
  3311.     if (nspans == 0)
  3312.         return;
  3313.     xSpan = xSpans = (DDXPointPtr) xalloc (nspans * sizeof (DDXPointRec));
  3314.     xWidth = xWidths = (int *) xalloc (nspans * sizeof (int));
  3315.     if (xSpans && xWidths)
  3316.     {
  3317.         i = 0;
  3318.         f = finalSpans;
  3319.         for (spany = finalMiny; spany <= finalMaxy; spany++, f++) {
  3320.             for (span = *f; span; span=span->next) {
  3321.                 if (span->max <= span->min)
  3322.                     continue;
  3323.                 xSpan->x = span->min;
  3324.                 xSpan->y = spany;
  3325.                 ++xSpan;
  3326.                 *xWidth++ = span->max - span->min;
  3327.                 ++i;
  3328.             }
  3329.         }
  3330.         (*pGC->ops->FillSpans) (pDrawable, pGC, i, xSpans, xWidths, TRUE);
  3331.     }
  3332.     disposeFinalSpans ();
  3333.     xfree (xSpans);
  3334.     xfree (xWidths);
  3335.     finalMiny = 0;
  3336.     finalMaxy = -1;
  3337.     finalSize = 0;
  3338.     nspans = 0;
  3339. }
  3340.  
  3341. # define SPAN_REALLOC    100
  3342.  
  3343. # define findSpan(y) ((finalMiny <= (y) && (y) <= finalMaxy) ? \
  3344.               &finalSpans[(y) - finalMiny] : \
  3345.               realFindSpan (y))
  3346.  
  3347. static struct finalSpan **
  3348. realFindSpan (y)
  3349. {
  3350.     struct finalSpan    **newSpans;
  3351.     int            newSize, newMiny, newMaxy;
  3352.     int            change;
  3353.     int            i;
  3354.  
  3355.     if (y < finalMiny || y > finalMaxy) {
  3356.         if (!finalSize) {
  3357.             finalMaxy = y - (SPAN_REALLOC - 1);
  3358.             finalMiny = finalMaxy + 1;
  3359.         }
  3360.         if (y < finalMiny)
  3361.             change = finalMiny - y;
  3362.         else
  3363.             change = y - finalMaxy;
  3364.         if (change > SPAN_REALLOC)
  3365.             change += SPAN_REALLOC;
  3366.         else
  3367.             change = SPAN_REALLOC;
  3368.         newSize = finalSize + change;
  3369.         newSpans = (struct finalSpan **) xalloc
  3370.                      (newSize * sizeof (struct finalSpan *));
  3371.         if (!newSpans)
  3372.             return (struct finalSpan **)NULL;
  3373.         newMiny = finalMiny;
  3374.         newMaxy = finalMaxy;
  3375.         if (y < finalMiny)
  3376.             newMiny = finalMiny - change;
  3377.         else
  3378.             newMaxy = finalMaxy + change;
  3379.         if (finalSpans) {
  3380.             bcopy ((char *) finalSpans,
  3381.                     ((char *) newSpans) + (finalMiny-newMiny) * sizeof (struct finalSpan *),
  3382.                    finalSize * sizeof (struct finalSpan *));
  3383.             xfree (finalSpans);
  3384.         }
  3385.         if ((i = finalMiny - newMiny) > 0)
  3386.             bzero ((char *)newSpans, i * sizeof (struct finalSpan *));
  3387.         if ((i = newMaxy - finalMaxy) > 0)
  3388.             bzero ((char *)(newSpans + newSize - i),
  3389.                    i * sizeof (struct finalSpan *));
  3390.         finalSpans = newSpans;
  3391.         finalMaxy = newMaxy;
  3392.         finalMiny = newMiny;
  3393.         finalSize = newSize;
  3394.     }
  3395.     return &finalSpans[y - finalMiny];
  3396. }
  3397.  
  3398. static void
  3399. newFinalSpan (y, xmin, xmax)
  3400.     int        y;
  3401.     register int    xmin, xmax;
  3402. {
  3403.     register struct finalSpan    *x;
  3404.     register struct finalSpan    **f;
  3405.     struct finalSpan        *oldx;
  3406.     struct finalSpan        *prev;
  3407.  
  3408.     f = findSpan (y);
  3409.     if (!f)
  3410.         return;
  3411.     oldx = 0;
  3412.     for (;;) {
  3413.         prev = 0;
  3414.         for (x = *f; x; x=x->next) {
  3415.             if (x == oldx) {
  3416.                 prev = x;
  3417.                 continue;
  3418.             }
  3419.             if (x->min <= xmax && xmin <= x->max) {
  3420.                 if (oldx) {
  3421.                     oldx->min = min (x->min, xmin);
  3422.                     oldx->max = max (x->max, xmax);
  3423.                     if (prev)
  3424.                         prev->next = x->next;
  3425.                     else
  3426.                         *f = x->next;
  3427.                     --nspans;
  3428.                 } else {
  3429.                     x->min = min (x->min, xmin);
  3430.                     x->max = max (x->max, xmax);
  3431.                     oldx = x;
  3432.                 }
  3433.                 xmin = oldx->min;
  3434.                 xmax = oldx->max;
  3435.                 break;
  3436.             }
  3437.             prev = x;
  3438.         }
  3439.         if (!x)
  3440.             break;
  3441.     }
  3442.     if (!oldx) {
  3443.         x = allocFinalSpan ();
  3444.         if (x)
  3445.         {
  3446.             x->min = xmin;
  3447.             x->max = xmax;
  3448.             x->next = *f;
  3449.             *f = x;
  3450.             ++nspans;
  3451.         }
  3452.     }
  3453. }
  3454.  
  3455. static void
  3456. deleteFinalSpan (y, xmin, xmax)
  3457.     int        y;
  3458.     register int    xmin, xmax;
  3459. {
  3460.     register struct finalSpan    *x;
  3461.     register struct finalSpan    **f;
  3462.     int                newmax;
  3463.  
  3464.     f = findSpan (y);
  3465.     if (!f)
  3466.         return;
  3467.     for (x = *f; x; x=x->next) {
  3468.         if (x->min <= xmin && xmax <= x->max) {
  3469.         if (x->min == xmin) {
  3470.             x->min = xmax;
  3471.         } else if (x->max == xmax) {
  3472.             x->max = xmin;
  3473.         } else {
  3474.             newmax = x->max;
  3475.             x->max = xmin;
  3476.             newFinalSpan (y, xmax, newmax);
  3477.         }
  3478.         return;
  3479.         } else if (x->min <= xmax && xmin <= x->max) {
  3480.         if (x->min <= xmin) {
  3481.             x->max = xmin;
  3482.         } else {
  3483.             x->min = xmax;
  3484.             if (x->min > x->max)
  3485.             x->min = x->max;
  3486.         }
  3487.         }
  3488.     }
  3489. }
  3490.  
  3491. static void
  3492. mirrorSppPoint (quadrant, sppPoint)
  3493.     int        quadrant;
  3494.     SppPointPtr    sppPoint;
  3495. {
  3496.     switch (quadrant) {
  3497.     case 0:
  3498.         break;
  3499.     case 1:
  3500.         sppPoint->x = -sppPoint->x;
  3501.         break;
  3502.     case 2:
  3503.         sppPoint->x = -sppPoint->x;
  3504.         sppPoint->y = -sppPoint->y;
  3505.         break;
  3506.     case 3:
  3507.         sppPoint->y = -sppPoint->y;
  3508.         break;
  3509.     }
  3510.     /*
  3511.      * and translate to X coordinate system
  3512.      */
  3513.     sppPoint->y = -sppPoint->y;
  3514. }
  3515.  
  3516. static double    spanY;
  3517.  
  3518. static int    quadrantMask;
  3519.  
  3520. static void
  3521. span (left, right)
  3522.     double    left, right;
  3523. {
  3524.     register int    mask = quadrantMask, bit;
  3525.     register double    min, max, y;
  3526.     int    xmin, xmax, spany;
  3527.  
  3528.     while (mask) {
  3529.         bit = lowbit (mask);
  3530.         mask &= ~bit;
  3531.         switch (bit) {
  3532.         case 1:
  3533.             min = left;
  3534.             max = right;
  3535.             y = spanY;
  3536.             break;
  3537.         case 2:
  3538.             min = -right;
  3539.             max = -left;
  3540.             y = spanY;
  3541.             break;
  3542.         case 4:
  3543.             min = -right;
  3544.             max = -left;
  3545.             y = -spanY;
  3546.             break;
  3547.         case 8:
  3548.             min = left;
  3549.             max = right;
  3550.             y = -spanY;
  3551.             break;
  3552.         default:
  3553.             FatalError ("miarc.c: illegal quadrant mask bit %d\n", bit);
  3554.         }
  3555.         xmin = ICEIL (min + arcXcenter) + arcXoffset;
  3556.         xmax = ICEIL (max + arcXcenter) + arcXoffset;
  3557.         spany = ICEIL (arcYcenter - y) + arcYoffset;
  3558.  
  3559.         if (xmax > xmin)
  3560.             newFinalSpan (spany, xmin, xmax);
  3561.     }
  3562. }
  3563.  
  3564. static void
  3565. unspan (left, right)
  3566. double    left, right;
  3567. {
  3568.     register int    mask = quadrantMask, bit;
  3569.     register double    min, max, y;
  3570.     int    xmin, xmax, spany;
  3571.  
  3572.     while (mask) {
  3573.         bit = lowbit (mask);
  3574.         mask &= ~bit;
  3575.         switch (bit) {
  3576.         case 1:
  3577.             min = left;
  3578.             max = right;
  3579.             y = spanY;
  3580.             break;
  3581.         case 2:
  3582.             min = -right;
  3583.             max = -left;
  3584.             y = spanY;
  3585.             break;
  3586.         case 4:
  3587.             min = -right;
  3588.             max = -left;
  3589.             y = -spanY;
  3590.             break;
  3591.         case 8:
  3592.             min = left;
  3593.             max = right;
  3594.             y = -spanY;
  3595.             break;
  3596.         default:
  3597.             FatalError ("miarc.c: illegal quadrant mask bit %d\n", bit);
  3598.         }
  3599.         xmin = ICEIL (min + arcXcenter) + arcXoffset;
  3600.         xmax = ICEIL (max + arcXcenter) + arcXoffset;
  3601.         spany = ICEIL (arcYcenter - y) + arcYoffset;
  3602.  
  3603.         if (xmax > xmin)
  3604.             deleteFinalSpan (spany, xmin, xmax);
  3605.     }
  3606. }
  3607.  
  3608. /*
  3609.  * split an arc into pieces which are scan-converted
  3610.  * in the first-quadrant and mirrored into position.
  3611.  * This is necessary as the scan-conversion code can
  3612.  * only deal with arcs completely contained in the
  3613.  * first quadrant.
  3614.  */
  3615.  
  3616. static void
  3617. drawArc (x0, y0, w, h, l, a0, a1, right, left)
  3618.     int    x0, y0, w, h, l, a0, a1;
  3619.     miArcFacePtr    right, left;    /* save end line points */
  3620. {
  3621.     struct arc_def        def;
  3622.     struct accelerators    acc;
  3623.     int            startq, endq, curq;
  3624.     int            rightq, leftq, righta, lefta;
  3625.     miArcFacePtr        passRight, passLeft;
  3626.     int            q0, q1, mask;
  3627.     struct band {
  3628.         int    a0, a1;
  3629.         int    mask;
  3630.     }    band[5], sweep[20];
  3631.     int            bandno, sweepno;
  3632.     int            i, j;
  3633.     int            flipRight = 0, flipLeft = 0;            
  3634.     int            copyEnd = 0;
  3635.  
  3636.     def.w = ((double) w) / 2;
  3637.     def.h = ((double) h) / 2;
  3638.     arcXoffset = x0;
  3639.     arcYoffset = y0;
  3640.     arcXcenter = def.w;
  3641.     arcYcenter = def.h;
  3642.     def.l = (double) l;
  3643.     if (l == 0)
  3644.         def.l = 1.0;
  3645.     if (a1 < a0)
  3646.         a1 += 360 * 64;
  3647.     startq = a0 / (90 * 64);
  3648.     if (a0 == a1)
  3649.         endq = startq;
  3650.     else
  3651.         endq = (a1-1) / (90 * 64);
  3652.     bandno = 0;
  3653.     curq = startq;
  3654.     for (;;) {
  3655.         switch (curq) {
  3656.         case 0:
  3657.             if (a0 > 90 * 64)
  3658.                 q0 = 0;
  3659.             else
  3660.                 q0 = a0;
  3661.             if (a1 < 360 * 64)
  3662.                 q1 = min (a1, 90 * 64);
  3663.             else
  3664.                 q1 = 90 * 64;
  3665.             if (curq == startq && a0 == q0) {
  3666.                 righta = q0;
  3667.                 rightq = curq;
  3668.             }
  3669.             if (curq == endq && a1 == q1) {
  3670.                 lefta = q1;
  3671.                 leftq = curq;
  3672.             }
  3673.             break;
  3674.         case 1:
  3675.             if (a1 < 90 * 64)
  3676.                 q0 = 0;
  3677.             else
  3678.                 q0 = 180 * 64 - min (a1, 180 * 64);
  3679.             if (a0 > 180 * 64)
  3680.                 q1 = 90 * 64;
  3681.             else
  3682.                 q1 = 180 * 64 - max (a0, 90 * 64);
  3683.             if (curq == startq && 180 * 64 - a0 == q1) {
  3684.                 righta = q1;
  3685.                 rightq = curq;
  3686.             }
  3687.             if (curq == endq && 180 * 64 - a1 == q0) {
  3688.                 lefta = q0;
  3689.                 leftq = curq;
  3690.             }
  3691.             break;
  3692.         case 2:
  3693.             if (a0 > 270 * 64)
  3694.                 q0 = 0;
  3695.             else
  3696.                 q0 = max (a0, 180 * 64) - 180 * 64;
  3697.             if (a1 < 180 * 64)
  3698.                 q1 = 90 * 64;
  3699.             else
  3700.                 q1 = min (a1, 270 * 64) - 180 * 64;
  3701.             if (curq == startq && a0 - 180*64 == q0) {
  3702.                 righta = q0;
  3703.                 rightq = curq;
  3704.             }
  3705.             if (curq == endq && a1 - 180 * 64 == q1) {
  3706.                 lefta = q1;
  3707.                 leftq = curq;
  3708.             }
  3709.             break;
  3710.         case 3:
  3711.             if (a1 < 270 * 64)
  3712.                 q0 = 0;
  3713.             else
  3714.                 q0 = 360 * 64 - min (a1, 360 * 64);
  3715.             q1 = 360 * 64 - max (a0, 270 * 64);
  3716.             if (curq == startq && 360 * 64 - a0 == q1) {
  3717.                 righta = q1;
  3718.                 rightq = curq;
  3719.             }
  3720.             if (curq == endq && 360 * 64 - a1 == q0) {
  3721.                 lefta = q0;
  3722.                 leftq = curq;
  3723.             }
  3724.             break;
  3725.         }
  3726.         band[bandno].a0 = q0;
  3727.         band[bandno].a1 = q1;
  3728.         band[bandno].mask = 1 << curq;
  3729.         bandno++;
  3730.         if (curq == endq)
  3731.             break;
  3732.         curq++;
  3733.         if (curq == 4) {
  3734.             a0 = 0;
  3735.             a1 -= 360 * 64;
  3736.             curq = 0;
  3737.             endq -= 4;
  3738.         }
  3739.     }
  3740.     sweepno = 0;
  3741.     for (;;) {
  3742.         q0 = 90 * 64;
  3743.         mask = 0;
  3744.         /*
  3745.          * find left-most point
  3746.          */
  3747.         for (i = 0; i < bandno; i++)
  3748.             if (band[i].a0 <= q0) {
  3749.                 q0 = band[i].a0;
  3750.                 q1 = band[i].a1;
  3751.                 mask = band[i].mask;
  3752.             }
  3753.         if (!mask)
  3754.             break;
  3755.         /*
  3756.          * locate next point of change
  3757.          */
  3758.         for (i = 0; i < bandno; i++)
  3759.             if (!(mask & band[i].mask)) {
  3760.                 if (band[i].a0 == q0) {
  3761.                     if (band[i].a1 < q1)
  3762.                         q1 = band[i].a1;
  3763.                     mask |= band[i].mask;
  3764.                  } else if (band[i].a0 < q1)
  3765.                     q1 = band[i].a0;
  3766.             }
  3767.         /*
  3768.          * create a new sweep
  3769.          */
  3770.         sweep[sweepno].a0 = q0;
  3771.         sweep[sweepno].a1 = q1;
  3772.         sweep[sweepno].mask = mask;
  3773.         sweepno++;
  3774.         /*
  3775.          * subtract the sweep from the affected bands
  3776.          */
  3777.         for (i = 0; i < bandno; i++)
  3778.             if (band[i].a0 == q0) {
  3779.                 band[i].a0 = q1;
  3780.                 /*
  3781.                  * check if this band is empty
  3782.                  */
  3783.                 if (band[i].a0 == band[i].a1)
  3784.                     band[i].a1 = band[i].a0 = 90 * 64 + 1;
  3785.             }
  3786.     }
  3787.     computeAcc (&def, &acc);
  3788.     for (j = 0; j < sweepno; j++) {
  3789.         mask = sweep[j].mask;
  3790.         passRight = passLeft = 0;
  3791.          if (mask & (1 << rightq)) {
  3792.             if (sweep[j].a0 == righta)
  3793.                 passRight = right;
  3794.             else if (sweep[j].a1 == righta) {
  3795.                 passLeft = right;
  3796.                 flipRight = 1;
  3797.             }
  3798.         }
  3799.         if (mask & (1 << leftq)) {
  3800.             if (sweep[j].a1 == lefta)
  3801.             {
  3802.                 if (passLeft)
  3803.                     copyEnd = 1;
  3804.                 passLeft = left;
  3805.             }
  3806.             else if (sweep[j].a0 == lefta) {
  3807.                 if (passRight)
  3808.                     copyEnd = 1;
  3809.                 passRight = left;
  3810.                 flipLeft = 1;
  3811.             }
  3812.         }
  3813.         drawQuadrant (&def, &acc, sweep[j].a0, sweep[j].a1, mask, 
  3814.                    passRight, passLeft);
  3815.     }
  3816.     /*
  3817.      * when copyEnd is set, both ends of the arc were computed
  3818.      * at the same time; drawQuadrant only takes one end though,
  3819.      * so the left end will be the only one holding the data.  Copy
  3820.      * it from there.
  3821.      */
  3822.     if (copyEnd)
  3823.         *right = *left;
  3824.     /*
  3825.      * mirror the coordinates generated for the
  3826.      * faces of the arc
  3827.      */
  3828.     if (right) {
  3829.         mirrorSppPoint (rightq, &right->clock);
  3830.         mirrorSppPoint (rightq, &right->center);
  3831.         mirrorSppPoint (rightq, &right->counterClock);
  3832.         if (flipRight) {
  3833.             SppPointRec    temp;
  3834.  
  3835.             temp = right->clock;
  3836.             right->clock = right->counterClock;
  3837.             right->counterClock = temp;
  3838.         }
  3839.     }
  3840.     if (left) {
  3841.         mirrorSppPoint (leftq,  &left->counterClock);
  3842.         mirrorSppPoint (leftq,  &left->center);
  3843.         mirrorSppPoint (leftq,  &left->clock);
  3844.         if (flipLeft) {
  3845.             SppPointRec    temp;
  3846.  
  3847.             temp = left->clock;
  3848.             left->clock = left->counterClock;
  3849.             left->counterClock = temp;
  3850.         }
  3851.     }
  3852. }
  3853.  
  3854. static void
  3855. drawQuadrant (def, acc, a0, a1, mask, right, left)
  3856.     struct arc_def        *def;
  3857.     struct accelerators    *acc;
  3858.     int            a0, a1;
  3859.     int            mask;
  3860.     miArcFacePtr        right, left;
  3861. {
  3862.     struct arc_bound    bound;
  3863.     double            miny, maxy, y;
  3864.     int            minIsInteger;
  3865.     double            fromInt;
  3866.  
  3867.     def->a0 = ((double) a0) / 64.0;
  3868.     def->a1 = ((double) a1) / 64.0;
  3869.     fromInt = def->h - floor (def->h);
  3870.     computeBound (def, &bound, acc, right, left);
  3871.     y = fmin (bound.inner.min, bound.outer.min);
  3872.     miny = ICEIL(y - fromInt) + fromInt;
  3873.     minIsInteger = y == miny;
  3874.     y = fmax (bound.inner.max, bound.outer.max);
  3875.     maxy = floor (y - fromInt) + fromInt;
  3876.     for (y = miny; y <= maxy; y = y + 1.0) {
  3877.         if (y == miny && minIsInteger)
  3878.             quadrantMask = mask & 0xc;
  3879.         else
  3880.             quadrantMask = mask;
  3881.         spanY = y;
  3882.         arcSpan (y, def, &bound, acc);
  3883.     }
  3884.     /*
  3885.      * add the pixel at the top of the arc if
  3886.      * this segment terminates exactly at the
  3887.      * top of the arc, and the outside
  3888.      * point is exactly an integer (width
  3889.      * is integral and (line width/2)
  3890.      * is integral)
  3891.      */
  3892.     if (a1 == 90 * 64 && (mask & 1) &&
  3893.         def->w == floor (def->w) &&
  3894.         def->l/2 == floor (def->l/2))
  3895.      {
  3896.         quadrantMask = 1;
  3897.         spanY = def->h + def->l/2;
  3898.         span (0.0, 1.0);
  3899.         spanY = def->h - def->l/2;
  3900.         unspan (0.0, 1.0);
  3901.     }
  3902. }
  3903.