miarc.c revision 2f9f5fec
105b261ecSmrg/*********************************************************** 205b261ecSmrg 305b261ecSmrgCopyright 1987, 1998 The Open Group 405b261ecSmrg 505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its 605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that 705b261ecSmrgthe above copyright notice appear in all copies and that both that 805b261ecSmrgcopyright notice and this permission notice appear in supporting 905b261ecSmrgdocumentation. 1005b261ecSmrg 1105b261ecSmrgThe above copyright notice and this permission notice shall be included in 1205b261ecSmrgall copies or substantial portions of the Software. 1305b261ecSmrg 1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1505b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1605b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1705b261ecSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 1805b261ecSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 1905b261ecSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2005b261ecSmrg 2105b261ecSmrgExcept as contained in this notice, the name of The Open Group shall not be 2205b261ecSmrgused in advertising or otherwise to promote the sale, use or other dealings 2305b261ecSmrgin this Software without prior written authorization from The Open Group. 2405b261ecSmrg 2505b261ecSmrg 2605b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 2705b261ecSmrg 2805b261ecSmrg All Rights Reserved 2905b261ecSmrg 3005b261ecSmrgPermission to use, copy, modify, and distribute this software and its 3105b261ecSmrgdocumentation for any purpose and without fee is hereby granted, 3205b261ecSmrgprovided that the above copyright notice appear in all copies and that 3305b261ecSmrgboth that copyright notice and this permission notice appear in 3405b261ecSmrgsupporting documentation, and that the name of Digital not be 3505b261ecSmrgused in advertising or publicity pertaining to distribution of the 3605b261ecSmrgsoftware without specific, written prior permission. 3705b261ecSmrg 3805b261ecSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 3905b261ecSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 4005b261ecSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 4105b261ecSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 4205b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 4305b261ecSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 4405b261ecSmrgSOFTWARE. 4505b261ecSmrg 4605b261ecSmrg******************************************************************/ 4705b261ecSmrg/* Author: Keith Packard and Bob Scheifler */ 4805b261ecSmrg/* Warning: this code is toxic, do not dally very long here. */ 4905b261ecSmrg 5005b261ecSmrg#ifdef HAVE_DIX_CONFIG_H 5105b261ecSmrg#include <dix-config.h> 5205b261ecSmrg#endif 5305b261ecSmrg 5405b261ecSmrg#include <math.h> 5505b261ecSmrg#include <X11/X.h> 5605b261ecSmrg#include <X11/Xprotostr.h> 5705b261ecSmrg#include "misc.h" 5805b261ecSmrg#include "gcstruct.h" 5905b261ecSmrg#include "scrnintstr.h" 6005b261ecSmrg#include "pixmapstr.h" 6105b261ecSmrg#include "windowstr.h" 6205b261ecSmrg#include "mifpoly.h" 6305b261ecSmrg#include "mi.h" 6405b261ecSmrg#include "mifillarc.h" 6505b261ecSmrg#include <X11/Xfuncproto.h> 6605b261ecSmrg 6705b261ecSmrgstatic double miDsin(double a); 6805b261ecSmrgstatic double miDcos(double a); 6905b261ecSmrgstatic double miDasin(double v); 7005b261ecSmrgstatic double miDatan2(double dy, double dx); 7105b261ecSmrg 7205b261ecSmrg#ifndef HAVE_CBRT 7305b261ecSmrgstatic double 7405b261ecSmrgcbrt(double x) 7505b261ecSmrg{ 7605b261ecSmrg if (x > 0.0) 7705b261ecSmrg return pow(x, 1.0/3.0); 7805b261ecSmrg else 7905b261ecSmrg return -pow(-x, 1.0/3.0); 8005b261ecSmrg} 8105b261ecSmrg#endif 8205b261ecSmrg 8305b261ecSmrg/* 8405b261ecSmrg * some interesting sematic interpretation of the protocol: 8505b261ecSmrg * 8605b261ecSmrg * Self intersecting arcs (i.e. those spanning 360 degrees) 8705b261ecSmrg * never join with other arcs, and are drawn without caps 8805b261ecSmrg * (unless on/off dashed, in which case each dash segment 8905b261ecSmrg * is capped, except when the last segment meets the 9005b261ecSmrg * first segment, when no caps are drawn) 9105b261ecSmrg * 9205b261ecSmrg * double dash arcs are drawn in two parts, first the 9305b261ecSmrg * odd dashes (drawn in background) then the even dashes 9405b261ecSmrg * (drawn in foreground). This means that overlapping 9505b261ecSmrg * sections of foreground/background are drawn twice, 9605b261ecSmrg * first in background then in foreground. The double-draw 9705b261ecSmrg * occurs even when the function uses the destination values 9805b261ecSmrg * (e.g. xor mode). This is the same way the wide-line 9905b261ecSmrg * code works and should be "fixed". 10005b261ecSmrg * 10105b261ecSmrg */ 10205b261ecSmrg 10305b261ecSmrg#undef max 10405b261ecSmrg#undef min 10505b261ecSmrg 10605b261ecSmrg_X_INLINE static int max (const int x, const int y) 10705b261ecSmrg{ 10805b261ecSmrg return x>y? x:y; 10905b261ecSmrg} 11005b261ecSmrg 11105b261ecSmrg_X_INLINE static int min (const int x, const int y) 11205b261ecSmrg{ 11305b261ecSmrg return x<y? x:y; 11405b261ecSmrg} 11505b261ecSmrg 11605b261ecSmrgstruct bound { 11705b261ecSmrg double min, max; 11805b261ecSmrg}; 11905b261ecSmrg 12005b261ecSmrgstruct ibound { 12105b261ecSmrg int min, max; 12205b261ecSmrg}; 12305b261ecSmrg 12405b261ecSmrg#define boundedLe(value, bounds)\ 12505b261ecSmrg ((bounds).min <= (value) && (value) <= (bounds).max) 12605b261ecSmrg 12705b261ecSmrgstruct line { 12805b261ecSmrg double m, b; 12905b261ecSmrg int valid; 13005b261ecSmrg}; 13105b261ecSmrg 13205b261ecSmrg#define intersectLine(y,line) (line.m * (y) + line.b) 13305b261ecSmrg 13405b261ecSmrg/* 13505b261ecSmrg * these are all y value bounds 13605b261ecSmrg */ 13705b261ecSmrg 13805b261ecSmrgstruct arc_bound { 13905b261ecSmrg struct bound ellipse; 14005b261ecSmrg struct bound inner; 14105b261ecSmrg struct bound outer; 14205b261ecSmrg struct bound right; 14305b261ecSmrg struct bound left; 14405b261ecSmrg struct ibound inneri; 14505b261ecSmrg struct ibound outeri; 14605b261ecSmrg}; 14705b261ecSmrg 14805b261ecSmrgstruct accelerators { 14905b261ecSmrg double tail_y; 15005b261ecSmrg double h2; 15105b261ecSmrg double w2; 15205b261ecSmrg double h4; 15305b261ecSmrg double w4; 15405b261ecSmrg double h2mw2; 15505b261ecSmrg double h2l; 15605b261ecSmrg double w2l; 15705b261ecSmrg double fromIntX; 15805b261ecSmrg double fromIntY; 15905b261ecSmrg struct line left, right; 16005b261ecSmrg int yorgu; 16105b261ecSmrg int yorgl; 16205b261ecSmrg int xorg; 16305b261ecSmrg}; 16405b261ecSmrg 16505b261ecSmrgstruct arc_def { 16605b261ecSmrg double w, h, l; 16705b261ecSmrg double a0, a1; 16805b261ecSmrg}; 16905b261ecSmrg 17005b261ecSmrg# define todeg(xAngle) (((double) (xAngle)) / 64.0) 17105b261ecSmrg 17205b261ecSmrg# define RIGHT_END 0 17305b261ecSmrg# define LEFT_END 1 17405b261ecSmrg 17505b261ecSmrgtypedef struct _miArcJoin { 17605b261ecSmrg int arcIndex0, arcIndex1; 17705b261ecSmrg int phase0, phase1; 17805b261ecSmrg int end0, end1; 17905b261ecSmrg} miArcJoinRec, *miArcJoinPtr; 18005b261ecSmrg 18105b261ecSmrgtypedef struct _miArcCap { 18205b261ecSmrg int arcIndex; 18305b261ecSmrg int end; 18405b261ecSmrg} miArcCapRec, *miArcCapPtr; 18505b261ecSmrg 18605b261ecSmrgtypedef struct _miArcFace { 18705b261ecSmrg SppPointRec clock; 18805b261ecSmrg SppPointRec center; 18905b261ecSmrg SppPointRec counterClock; 19005b261ecSmrg} miArcFaceRec, *miArcFacePtr; 19105b261ecSmrg 19205b261ecSmrgtypedef struct _miArcData { 19305b261ecSmrg xArc arc; 19405b261ecSmrg int render; /* non-zero means render after drawing */ 19505b261ecSmrg int join; /* related join */ 19605b261ecSmrg int cap; /* related cap */ 19705b261ecSmrg int selfJoin; /* final dash meets first dash */ 19805b261ecSmrg miArcFaceRec bounds[2]; 19905b261ecSmrg double x0, y0, x1, y1; 20005b261ecSmrg} miArcDataRec, *miArcDataPtr; 20105b261ecSmrg 20205b261ecSmrg/* 20305b261ecSmrg * This is an entire sequence of arcs, computed and categorized according 20405b261ecSmrg * to operation. miDashArcs generates either one or two of these. 20505b261ecSmrg */ 20605b261ecSmrg 20705b261ecSmrgtypedef struct _miPolyArc { 20805b261ecSmrg int narcs; 20905b261ecSmrg miArcDataPtr arcs; 21005b261ecSmrg int ncaps; 21105b261ecSmrg miArcCapPtr caps; 21205b261ecSmrg int njoins; 21305b261ecSmrg miArcJoinPtr joins; 21405b261ecSmrg} miPolyArcRec, *miPolyArcPtr; 21505b261ecSmrg 21605b261ecSmrgstatic void fillSpans(DrawablePtr pDrawable, GCPtr pGC); 21705b261ecSmrgstatic void newFinalSpan(int y, int xmin, int xmax); 21805b261ecSmrgstatic void drawArc(xArc *tarc, int l, int a0, int a1, miArcFacePtr right, 21905b261ecSmrg miArcFacePtr left); 22005b261ecSmrgstatic void drawZeroArc(DrawablePtr pDraw, GCPtr pGC, xArc *tarc, int lw, 22105b261ecSmrg miArcFacePtr left, miArcFacePtr right); 22205b261ecSmrgstatic void miArcJoin(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pLeft, 22305b261ecSmrg miArcFacePtr pRight, int xOrgLeft, int yOrgLeft, 22405b261ecSmrg double xFtransLeft, double yFtransLeft, 22505b261ecSmrg int xOrgRight, int yOrgRight, 22605b261ecSmrg double xFtransRight, double yFtransRight); 22705b261ecSmrgstatic void miArcCap(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pFace, 22805b261ecSmrg int end, int xOrg, int yOrg, double xFtrans, 22905b261ecSmrg double yFtrans); 23005b261ecSmrgstatic void miRoundCap(DrawablePtr pDraw, GCPtr pGC, SppPointRec pCenter, 23105b261ecSmrg SppPointRec pEnd, SppPointRec pCorner, 23205b261ecSmrg SppPointRec pOtherCorner, int fLineEnd, 23305b261ecSmrg int xOrg, int yOrg, double xFtrans, double yFtrans); 23405b261ecSmrgstatic void miFreeArcs(miPolyArcPtr arcs, GCPtr pGC); 23505b261ecSmrgstatic miPolyArcPtr miComputeArcs(xArc *parcs, int narcs, GCPtr pGC); 23605b261ecSmrgstatic int miGetArcPts(SppArcPtr parc, int cpt, SppPointPtr *ppPts); 23705b261ecSmrg 23805b261ecSmrg# define CUBED_ROOT_2 1.2599210498948732038115849718451499938964 23905b261ecSmrg# define CUBED_ROOT_4 1.5874010519681993173435330390930175781250 24005b261ecSmrg 24105b261ecSmrg/* 24205b261ecSmrg * draw one segment of the arc using the arc spans generation routines 24305b261ecSmrg */ 24405b261ecSmrg 24505b261ecSmrgstatic void 24605b261ecSmrgmiArcSegment( 24705b261ecSmrg DrawablePtr pDraw, 24805b261ecSmrg GCPtr pGC, 24905b261ecSmrg xArc tarc, 25005b261ecSmrg miArcFacePtr right, 25105b261ecSmrg miArcFacePtr left) 25205b261ecSmrg{ 25305b261ecSmrg int l = pGC->lineWidth; 25405b261ecSmrg int a0, a1, startAngle, endAngle; 25505b261ecSmrg miArcFacePtr temp; 25605b261ecSmrg 25705b261ecSmrg if (!l) 25805b261ecSmrg l = 1; 25905b261ecSmrg 26005b261ecSmrg if (tarc.width == 0 || tarc.height == 0) { 26105b261ecSmrg drawZeroArc (pDraw, pGC, &tarc, l, left, right); 26205b261ecSmrg return; 26305b261ecSmrg } 26405b261ecSmrg 26505b261ecSmrg if (pGC->miTranslate) { 26605b261ecSmrg tarc.x += pDraw->x; 26705b261ecSmrg tarc.y += pDraw->y; 26805b261ecSmrg } 26905b261ecSmrg 27005b261ecSmrg a0 = tarc.angle1; 27105b261ecSmrg a1 = tarc.angle2; 27205b261ecSmrg if (a1 > FULLCIRCLE) 27305b261ecSmrg a1 = FULLCIRCLE; 27405b261ecSmrg else if (a1 < -FULLCIRCLE) 27505b261ecSmrg a1 = -FULLCIRCLE; 27605b261ecSmrg if (a1 < 0) { 27705b261ecSmrg startAngle = a0 + a1; 27805b261ecSmrg endAngle = a0; 27905b261ecSmrg temp = right; 28005b261ecSmrg right = left; 28105b261ecSmrg left = temp; 28205b261ecSmrg } else { 28305b261ecSmrg startAngle = a0; 28405b261ecSmrg endAngle = a0 + a1; 28505b261ecSmrg } 28605b261ecSmrg /* 28705b261ecSmrg * bounds check the two angles 28805b261ecSmrg */ 28905b261ecSmrg if (startAngle < 0) 29005b261ecSmrg startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE; 29105b261ecSmrg if (startAngle >= FULLCIRCLE) 29205b261ecSmrg startAngle = startAngle % FULLCIRCLE; 29305b261ecSmrg if (endAngle < 0) 29405b261ecSmrg endAngle = FULLCIRCLE - (-endAngle) % FULLCIRCLE; 29505b261ecSmrg if (endAngle > FULLCIRCLE) 29605b261ecSmrg endAngle = (endAngle-1) % FULLCIRCLE + 1; 29705b261ecSmrg if ((startAngle == endAngle) && a1) { 29805b261ecSmrg startAngle = 0; 29905b261ecSmrg endAngle = FULLCIRCLE; 30005b261ecSmrg } 30105b261ecSmrg 30205b261ecSmrg drawArc (&tarc, l, startAngle, endAngle, right, left); 30305b261ecSmrg} 30405b261ecSmrg 30505b261ecSmrg/* 30605b261ecSmrg 30705b261ecSmrgThree equations combine to describe the boundaries of the arc 30805b261ecSmrg 30905b261ecSmrgx^2/w^2 + y^2/h^2 = 1 ellipse itself 31005b261ecSmrg(X-x)^2 + (Y-y)^2 = r^2 circle at (x, y) on the ellipse 31105b261ecSmrg(Y-y) = (X-x)*w^2*y/(h^2*x) normal at (x, y) on the ellipse 31205b261ecSmrg 31305b261ecSmrgThese lead to a quartic relating Y and y 31405b261ecSmrg 31505b261ecSmrgy^4 - (2Y)y^3 + (Y^2 + (h^4 - w^2*r^2)/(w^2 - h^2))y^2 31605b261ecSmrg - (2Y*h^4/(w^2 - h^2))y + (Y^2*h^4)/(w^2 - h^2) = 0 31705b261ecSmrg 31805b261ecSmrgThe reducible cubic obtained from this quartic is 31905b261ecSmrg 32005b261ecSmrgz^3 - (3N)z^2 - 2V = 0 32105b261ecSmrg 32205b261ecSmrgwhere 32305b261ecSmrg 32405b261ecSmrgN = (Y^2 + (h^4 - w^2*r^2/(w^2 - h^2)))/6 32505b261ecSmrgV = w^2*r^2*Y^2*h^4/(4 *(w^2 - h^2)^2) 32605b261ecSmrg 32705b261ecSmrgLet 32805b261ecSmrg 32905b261ecSmrgt = z - N 33005b261ecSmrgp = -N^2 33105b261ecSmrgq = -N^3 - V 33205b261ecSmrg 33305b261ecSmrgThen we get 33405b261ecSmrg 33505b261ecSmrgt^3 + 3pt + 2q = 0 33605b261ecSmrg 33705b261ecSmrgThe discriminant of this cubic is 33805b261ecSmrg 33905b261ecSmrgD = q^2 + p^3 34005b261ecSmrg 34105b261ecSmrgWhen D > 0, a real root is obtained as 34205b261ecSmrg 34305b261ecSmrgz = N + cbrt(-q+sqrt(D)) + cbrt(-q-sqrt(D)) 34405b261ecSmrg 34505b261ecSmrgWhen D < 0, a real root is obtained as 34605b261ecSmrg 34705b261ecSmrgz = N - 2m*cos(acos(-q/m^3)/3) 34805b261ecSmrg 34905b261ecSmrgwhere 35005b261ecSmrg 35105b261ecSmrgm = sqrt(|p|) * sign(q) 35205b261ecSmrg 35305b261ecSmrgGiven a real root Z of the cubic, the roots of the quartic are the roots 35405b261ecSmrgof the two quadratics 35505b261ecSmrg 35605b261ecSmrgy^2 + ((b+A)/2)y + (Z + (bZ - d)/A) = 0 35705b261ecSmrg 35805b261ecSmrgwhere 35905b261ecSmrg 36005b261ecSmrgA = +/- sqrt(8Z + b^2 - 4c) 36105b261ecSmrgb, c, d are the cubic, quadratic, and linear coefficients of the quartic 36205b261ecSmrg 36305b261ecSmrgSome experimentation is then required to determine which solutions 36405b261ecSmrgcorrespond to the inner and outer boundaries. 36505b261ecSmrg 36605b261ecSmrg*/ 36705b261ecSmrg 36805b261ecSmrgtypedef struct { 36905b261ecSmrg short lx, lw, rx, rw; 37005b261ecSmrg} miArcSpan; 37105b261ecSmrg 37205b261ecSmrgtypedef struct { 37305b261ecSmrg miArcSpan *spans; 37405b261ecSmrg int count1, count2, k; 37505b261ecSmrg char top, bot, hole; 37605b261ecSmrg} miArcSpanData; 37705b261ecSmrg 37805b261ecSmrgstatic void drawQuadrant(struct arc_def *def, struct accelerators *acc, 37905b261ecSmrg int a0, int a1, int mask, miArcFacePtr right, 38005b261ecSmrg miArcFacePtr left, miArcSpanData *spdata); 38105b261ecSmrg 38205b261ecSmrgstatic void 38305b261ecSmrgmiComputeCircleSpans( 38405b261ecSmrg int lw, 38505b261ecSmrg xArc *parc, 38605b261ecSmrg miArcSpanData *spdata) 38705b261ecSmrg{ 38805b261ecSmrg miArcSpan *span; 38905b261ecSmrg int doinner; 39005b261ecSmrg int x, y, e; 39105b261ecSmrg int xk, yk, xm, ym, dx, dy; 39205b261ecSmrg int slw, inslw; 39305b261ecSmrg int inx = 0, iny, ine = 0; 39405b261ecSmrg int inxk = 0, inyk = 0, inxm = 0, inym = 0; 39505b261ecSmrg 39605b261ecSmrg doinner = -lw; 39705b261ecSmrg slw = parc->width - doinner; 39805b261ecSmrg y = parc->height >> 1; 39905b261ecSmrg dy = parc->height & 1; 40005b261ecSmrg dx = 1 - dy; 40105b261ecSmrg MIWIDEARCSETUP(x, y, dy, slw, e, xk, xm, yk, ym); 40205b261ecSmrg inslw = parc->width + doinner; 40305b261ecSmrg if (inslw > 0) 40405b261ecSmrg { 40505b261ecSmrg spdata->hole = spdata->top; 40605b261ecSmrg MIWIDEARCSETUP(inx, iny, dy, inslw, ine, inxk, inxm, inyk, inym); 40705b261ecSmrg } 40805b261ecSmrg else 40905b261ecSmrg { 41005b261ecSmrg spdata->hole = FALSE; 41105b261ecSmrg doinner = -y; 41205b261ecSmrg } 41305b261ecSmrg spdata->count1 = -doinner - spdata->top; 41405b261ecSmrg spdata->count2 = y + doinner; 41505b261ecSmrg span = spdata->spans; 41605b261ecSmrg while (y) 41705b261ecSmrg { 41805b261ecSmrg MIFILLARCSTEP(slw); 41905b261ecSmrg span->lx = dy - x; 42005b261ecSmrg if (++doinner <= 0) 42105b261ecSmrg { 42205b261ecSmrg span->lw = slw; 42305b261ecSmrg span->rx = 0; 42405b261ecSmrg span->rw = span->lx + slw; 42505b261ecSmrg } 42605b261ecSmrg else 42705b261ecSmrg { 42805b261ecSmrg MIFILLINARCSTEP(inslw); 42905b261ecSmrg span->lw = x - inx; 43005b261ecSmrg span->rx = dy - inx + inslw; 43105b261ecSmrg span->rw = inx - x + slw - inslw; 43205b261ecSmrg } 43305b261ecSmrg span++; 43405b261ecSmrg } 43505b261ecSmrg if (spdata->bot) 43605b261ecSmrg { 43705b261ecSmrg if (spdata->count2) 43805b261ecSmrg spdata->count2--; 43905b261ecSmrg else 44005b261ecSmrg { 44105b261ecSmrg if (lw > (int)parc->height) 44205b261ecSmrg span[-1].rx = span[-1].rw = -((lw - (int)parc->height) >> 1); 44305b261ecSmrg else 44405b261ecSmrg span[-1].rw = 0; 44505b261ecSmrg spdata->count1--; 44605b261ecSmrg } 44705b261ecSmrg } 44805b261ecSmrg} 44905b261ecSmrg 45005b261ecSmrgstatic void 45105b261ecSmrgmiComputeEllipseSpans( 45205b261ecSmrg int lw, 45305b261ecSmrg xArc *parc, 45405b261ecSmrg miArcSpanData *spdata) 45505b261ecSmrg{ 45605b261ecSmrg miArcSpan *span; 45705b261ecSmrg double w, h, r, xorg; 45805b261ecSmrg double Hs, Hf, WH, K, Vk, Nk, Fk, Vr, N, Nc, Z, rs; 45905b261ecSmrg double A, T, b, d, x, y, t, inx, outx = 0.0, hepp, hepm; 46005b261ecSmrg int flip, solution; 46105b261ecSmrg 46205b261ecSmrg w = (double)parc->width / 2.0; 46305b261ecSmrg h = (double)parc->height / 2.0; 46405b261ecSmrg r = lw / 2.0; 46505b261ecSmrg rs = r * r; 46605b261ecSmrg Hs = h * h; 46705b261ecSmrg WH = w * w - Hs; 46805b261ecSmrg Nk = w * r; 46905b261ecSmrg Vk = (Nk * Hs) / (WH + WH); 47005b261ecSmrg Hf = Hs * Hs; 47105b261ecSmrg Nk = (Hf - Nk * Nk) / WH; 47205b261ecSmrg Fk = Hf / WH; 47305b261ecSmrg hepp = h + EPSILON; 47405b261ecSmrg hepm = h - EPSILON; 47505b261ecSmrg K = h + ((lw - 1) >> 1); 47605b261ecSmrg span = spdata->spans; 47705b261ecSmrg if (parc->width & 1) 47805b261ecSmrg xorg = .5; 47905b261ecSmrg else 48005b261ecSmrg xorg = 0.0; 48105b261ecSmrg if (spdata->top) 48205b261ecSmrg { 48305b261ecSmrg span->lx = 0; 48405b261ecSmrg span->lw = 1; 48505b261ecSmrg span++; 48605b261ecSmrg } 48705b261ecSmrg spdata->count1 = 0; 48805b261ecSmrg spdata->count2 = 0; 48905b261ecSmrg spdata->hole = (spdata->top && 49005b261ecSmrg (int)parc->height * lw <= (int)(parc->width * parc->width) && 49105b261ecSmrg lw < (int)parc->height); 49205b261ecSmrg for (; K > 0.0; K -= 1.0) 49305b261ecSmrg { 49405b261ecSmrg N = (K * K + Nk) / 6.0; 49505b261ecSmrg Nc = N * N * N; 49605b261ecSmrg Vr = Vk * K; 49705b261ecSmrg t = Nc + Vr * Vr; 49805b261ecSmrg d = Nc + t; 49905b261ecSmrg if (d < 0.0) { 50005b261ecSmrg d = Nc; 50105b261ecSmrg b = N; 50205b261ecSmrg if ( (b < 0.0) == (t < 0.0) ) 50305b261ecSmrg { 50405b261ecSmrg b = -b; 50505b261ecSmrg d = -d; 50605b261ecSmrg } 50705b261ecSmrg Z = N - 2.0 * b * cos(acos(-t / d) / 3.0); 50805b261ecSmrg if ( (Z < 0.0) == (Vr < 0.0) ) 50905b261ecSmrg flip = 2; 51005b261ecSmrg else 51105b261ecSmrg flip = 1; 51205b261ecSmrg } 51305b261ecSmrg else 51405b261ecSmrg { 51505b261ecSmrg d = Vr * sqrt(d); 51605b261ecSmrg Z = N + cbrt(t + d) + cbrt(t - d); 51705b261ecSmrg flip = 0; 51805b261ecSmrg } 51905b261ecSmrg A = sqrt((Z + Z) - Nk); 52005b261ecSmrg T = (Fk - Z) * K / A; 52105b261ecSmrg inx = 0.0; 52205b261ecSmrg solution = FALSE; 52305b261ecSmrg b = -A + K; 52405b261ecSmrg d = b * b - 4 * (Z + T); 52505b261ecSmrg if (d >= 0) 52605b261ecSmrg { 52705b261ecSmrg d = sqrt(d); 52805b261ecSmrg y = (b + d) / 2; 52905b261ecSmrg if ((y >= 0.0) && (y < hepp)) 53005b261ecSmrg { 53105b261ecSmrg solution = TRUE; 53205b261ecSmrg if (y > hepm) 53305b261ecSmrg y = h; 53405b261ecSmrg t = y / h; 53505b261ecSmrg x = w * sqrt(1 - (t * t)); 53605b261ecSmrg t = K - y; 53705b261ecSmrg if (rs - (t * t) >= 0) 53805b261ecSmrg t = sqrt(rs - (t * t)); 53905b261ecSmrg else 54005b261ecSmrg t = 0; 54105b261ecSmrg if (flip == 2) 54205b261ecSmrg inx = x - t; 54305b261ecSmrg else 54405b261ecSmrg outx = x + t; 54505b261ecSmrg } 54605b261ecSmrg } 54705b261ecSmrg b = A + K; 54805b261ecSmrg d = b * b - 4 * (Z - T); 54905b261ecSmrg /* Because of the large magnitudes involved, we lose enough precision 55005b261ecSmrg * that sometimes we end up with a negative value near the axis, when 55105b261ecSmrg * it should be positive. This is a workaround. 55205b261ecSmrg */ 55305b261ecSmrg if (d < 0 && !solution) 55405b261ecSmrg d = 0.0; 55505b261ecSmrg if (d >= 0) { 55605b261ecSmrg d = sqrt(d); 55705b261ecSmrg y = (b + d) / 2; 55805b261ecSmrg if (y < hepp) 55905b261ecSmrg { 56005b261ecSmrg if (y > hepm) 56105b261ecSmrg y = h; 56205b261ecSmrg t = y / h; 56305b261ecSmrg x = w * sqrt(1 - (t * t)); 56405b261ecSmrg t = K - y; 56505b261ecSmrg if (rs - (t * t) >= 0) 56605b261ecSmrg inx = x - sqrt(rs - (t * t)); 56705b261ecSmrg else 56805b261ecSmrg inx = x; 56905b261ecSmrg } 57005b261ecSmrg y = (b - d) / 2; 57105b261ecSmrg if (y >= 0.0) 57205b261ecSmrg { 57305b261ecSmrg if (y > hepm) 57405b261ecSmrg y = h; 57505b261ecSmrg t = y / h; 57605b261ecSmrg x = w * sqrt(1 - (t * t)); 57705b261ecSmrg t = K - y; 57805b261ecSmrg if (rs - (t * t) >= 0) 57905b261ecSmrg t = sqrt(rs - (t * t)); 58005b261ecSmrg else 58105b261ecSmrg t = 0; 58205b261ecSmrg if (flip == 1) 58305b261ecSmrg inx = x - t; 58405b261ecSmrg else 58505b261ecSmrg outx = x + t; 58605b261ecSmrg } 58705b261ecSmrg } 58805b261ecSmrg span->lx = ICEIL(xorg - outx); 58905b261ecSmrg if (inx <= 0.0) 59005b261ecSmrg { 59105b261ecSmrg spdata->count1++; 59205b261ecSmrg span->lw = ICEIL(xorg + outx) - span->lx; 59305b261ecSmrg span->rx = ICEIL(xorg + inx); 59405b261ecSmrg span->rw = -ICEIL(xorg - inx); 59505b261ecSmrg } 59605b261ecSmrg else 59705b261ecSmrg { 59805b261ecSmrg spdata->count2++; 59905b261ecSmrg span->lw = ICEIL(xorg - inx) - span->lx; 60005b261ecSmrg span->rx = ICEIL(xorg + inx); 60105b261ecSmrg span->rw = ICEIL(xorg + outx) - span->rx; 60205b261ecSmrg } 60305b261ecSmrg span++; 60405b261ecSmrg } 60505b261ecSmrg if (spdata->bot) 60605b261ecSmrg { 60705b261ecSmrg outx = w + r; 60805b261ecSmrg if (r >= h && r <= w) 60905b261ecSmrg inx = 0.0; 61005b261ecSmrg else if (Nk < 0.0 && -Nk < Hs) 61105b261ecSmrg { 61205b261ecSmrg inx = w * sqrt(1 + Nk / Hs) - sqrt(rs + Nk); 61305b261ecSmrg if (inx > w - r) 61405b261ecSmrg inx = w - r; 61505b261ecSmrg } 61605b261ecSmrg else 61705b261ecSmrg inx = w - r; 61805b261ecSmrg span->lx = ICEIL(xorg - outx); 61905b261ecSmrg if (inx <= 0.0) 62005b261ecSmrg { 62105b261ecSmrg span->lw = ICEIL(xorg + outx) - span->lx; 62205b261ecSmrg span->rx = ICEIL(xorg + inx); 62305b261ecSmrg span->rw = -ICEIL(xorg - inx); 62405b261ecSmrg } 62505b261ecSmrg else 62605b261ecSmrg { 62705b261ecSmrg span->lw = ICEIL(xorg - inx) - span->lx; 62805b261ecSmrg span->rx = ICEIL(xorg + inx); 62905b261ecSmrg span->rw = ICEIL(xorg + outx) - span->rx; 63005b261ecSmrg } 63105b261ecSmrg } 63205b261ecSmrg if (spdata->hole) 63305b261ecSmrg { 63405b261ecSmrg span = &spdata->spans[spdata->count1]; 63505b261ecSmrg span->lw = -span->lx; 63605b261ecSmrg span->rx = 1; 63705b261ecSmrg span->rw = span->lw; 63805b261ecSmrg spdata->count1--; 63905b261ecSmrg spdata->count2++; 64005b261ecSmrg } 64105b261ecSmrg} 64205b261ecSmrg 64305b261ecSmrgstatic double 64405b261ecSmrgtailX( 64505b261ecSmrg double K, 64605b261ecSmrg struct arc_def *def, 64705b261ecSmrg struct arc_bound *bounds, 64805b261ecSmrg struct accelerators *acc) 64905b261ecSmrg{ 65005b261ecSmrg double w, h, r; 65105b261ecSmrg double Hs, Hf, WH, Vk, Nk, Fk, Vr, N, Nc, Z, rs; 65205b261ecSmrg double A, T, b, d, x, y, t, hepp, hepm; 65305b261ecSmrg int flip, solution; 65405b261ecSmrg double xs[2]; 65505b261ecSmrg double *xp; 65605b261ecSmrg 65705b261ecSmrg w = def->w; 65805b261ecSmrg h = def->h; 65905b261ecSmrg r = def->l; 66005b261ecSmrg rs = r * r; 66105b261ecSmrg Hs = acc->h2; 66205b261ecSmrg WH = -acc->h2mw2; 66305b261ecSmrg Nk = def->w * r; 66405b261ecSmrg Vk = (Nk * Hs) / (WH + WH); 66505b261ecSmrg Hf = acc->h4; 66605b261ecSmrg Nk = (Hf - Nk * Nk) / WH; 66705b261ecSmrg if (K == 0.0) { 66805b261ecSmrg if (Nk < 0.0 && -Nk < Hs) { 66905b261ecSmrg xs[0] = w * sqrt(1 + Nk / Hs) - sqrt(rs + Nk); 67005b261ecSmrg xs[1] = w - r; 67105b261ecSmrg if (acc->left.valid && boundedLe(K, bounds->left) && 67205b261ecSmrg !boundedLe(K, bounds->outer) && xs[0] >= 0.0 && xs[1] >= 0.0) 67305b261ecSmrg return xs[1]; 67405b261ecSmrg if (acc->right.valid && boundedLe(K, bounds->right) && 67505b261ecSmrg !boundedLe(K, bounds->inner) && xs[0] <= 0.0 && xs[1] <= 0.0) 67605b261ecSmrg return xs[1]; 67705b261ecSmrg return xs[0]; 67805b261ecSmrg } 67905b261ecSmrg return w - r; 68005b261ecSmrg } 68105b261ecSmrg Fk = Hf / WH; 68205b261ecSmrg hepp = h + EPSILON; 68305b261ecSmrg hepm = h - EPSILON; 68405b261ecSmrg N = (K * K + Nk) / 6.0; 68505b261ecSmrg Nc = N * N * N; 68605b261ecSmrg Vr = Vk * K; 68705b261ecSmrg xp = xs; 68805b261ecSmrg xs[0] = 0.0; 68905b261ecSmrg t = Nc + Vr * Vr; 69005b261ecSmrg d = Nc + t; 69105b261ecSmrg if (d < 0.0) { 69205b261ecSmrg d = Nc; 69305b261ecSmrg b = N; 69405b261ecSmrg if ( (b < 0.0) == (t < 0.0) ) 69505b261ecSmrg { 69605b261ecSmrg b = -b; 69705b261ecSmrg d = -d; 69805b261ecSmrg } 69905b261ecSmrg Z = N - 2.0 * b * cos(acos(-t / d) / 3.0); 70005b261ecSmrg if ( (Z < 0.0) == (Vr < 0.0) ) 70105b261ecSmrg flip = 2; 70205b261ecSmrg else 70305b261ecSmrg flip = 1; 70405b261ecSmrg } 70505b261ecSmrg else 70605b261ecSmrg { 70705b261ecSmrg d = Vr * sqrt(d); 70805b261ecSmrg Z = N + cbrt(t + d) + cbrt(t - d); 70905b261ecSmrg flip = 0; 71005b261ecSmrg } 71105b261ecSmrg A = sqrt((Z + Z) - Nk); 71205b261ecSmrg T = (Fk - Z) * K / A; 71305b261ecSmrg solution = FALSE; 71405b261ecSmrg b = -A + K; 71505b261ecSmrg d = b * b - 4 * (Z + T); 71605b261ecSmrg if (d >= 0 && flip == 2) 71705b261ecSmrg { 71805b261ecSmrg d = sqrt(d); 71905b261ecSmrg y = (b + d) / 2; 72005b261ecSmrg if ((y >= 0.0) && (y < hepp)) 72105b261ecSmrg { 72205b261ecSmrg solution = TRUE; 72305b261ecSmrg if (y > hepm) 72405b261ecSmrg y = h; 72505b261ecSmrg t = y / h; 72605b261ecSmrg x = w * sqrt(1 - (t * t)); 72705b261ecSmrg t = K - y; 72805b261ecSmrg if (rs - (t * t) >= 0) 72905b261ecSmrg t = sqrt(rs - (t * t)); 73005b261ecSmrg else 73105b261ecSmrg t = 0; 73205b261ecSmrg *xp++ = x - t; 73305b261ecSmrg } 73405b261ecSmrg } 73505b261ecSmrg b = A + K; 73605b261ecSmrg d = b * b - 4 * (Z - T); 73705b261ecSmrg /* Because of the large magnitudes involved, we lose enough precision 73805b261ecSmrg * that sometimes we end up with a negative value near the axis, when 73905b261ecSmrg * it should be positive. This is a workaround. 74005b261ecSmrg */ 74105b261ecSmrg if (d < 0 && !solution) 74205b261ecSmrg d = 0.0; 74305b261ecSmrg if (d >= 0) { 74405b261ecSmrg d = sqrt(d); 74505b261ecSmrg y = (b + d) / 2; 74605b261ecSmrg if (y < hepp) 74705b261ecSmrg { 74805b261ecSmrg if (y > hepm) 74905b261ecSmrg y = h; 75005b261ecSmrg t = y / h; 75105b261ecSmrg x = w * sqrt(1 - (t * t)); 75205b261ecSmrg t = K - y; 75305b261ecSmrg if (rs - (t * t) >= 0) 75405b261ecSmrg *xp++ = x - sqrt(rs - (t * t)); 75505b261ecSmrg else 75605b261ecSmrg *xp++ = x; 75705b261ecSmrg } 75805b261ecSmrg y = (b - d) / 2; 75905b261ecSmrg if (y >= 0.0 && flip == 1) 76005b261ecSmrg { 76105b261ecSmrg if (y > hepm) 76205b261ecSmrg y = h; 76305b261ecSmrg t = y / h; 76405b261ecSmrg x = w * sqrt(1 - (t * t)); 76505b261ecSmrg t = K - y; 76605b261ecSmrg if (rs - (t * t) >= 0) 76705b261ecSmrg t = sqrt(rs - (t * t)); 76805b261ecSmrg else 76905b261ecSmrg t = 0; 77005b261ecSmrg *xp++ = x - t; 77105b261ecSmrg } 77205b261ecSmrg } 77305b261ecSmrg if (xp > &xs[1]) { 77405b261ecSmrg if (acc->left.valid && boundedLe(K, bounds->left) && 77505b261ecSmrg !boundedLe(K, bounds->outer) && xs[0] >= 0.0 && xs[1] >= 0.0) 77605b261ecSmrg return xs[1]; 77705b261ecSmrg if (acc->right.valid && boundedLe(K, bounds->right) && 77805b261ecSmrg !boundedLe(K, bounds->inner) && xs[0] <= 0.0 && xs[1] <= 0.0) 77905b261ecSmrg return xs[1]; 78005b261ecSmrg } 78105b261ecSmrg return xs[0]; 78205b261ecSmrg} 78305b261ecSmrg 78405b261ecSmrgstatic miArcSpanData * 7856747b715SmrgmiComputeWideEllipse(int lw, xArc *parc) 78605b261ecSmrg{ 7876747b715Smrg miArcSpanData *spdata = NULL; 78805b261ecSmrg int k; 78905b261ecSmrg 79005b261ecSmrg if (!lw) 79105b261ecSmrg lw = 1; 79205b261ecSmrg k = (parc->height >> 1) + ((lw - 1) >> 1); 7936747b715Smrg spdata = malloc(sizeof(miArcSpanData) + sizeof(miArcSpan) * (k + 2)); 7946747b715Smrg if (!spdata) 7956747b715Smrg return NULL; 7966747b715Smrg spdata->spans = (miArcSpan *)(spdata + 1); 7976747b715Smrg spdata->k = k; 79805b261ecSmrg spdata->top = !(lw & 1) && !(parc->width & 1); 79905b261ecSmrg spdata->bot = !(parc->height & 1); 80005b261ecSmrg if (parc->width == parc->height) 80105b261ecSmrg miComputeCircleSpans(lw, parc, spdata); 80205b261ecSmrg else 80305b261ecSmrg miComputeEllipseSpans(lw, parc, spdata); 80405b261ecSmrg return spdata; 80505b261ecSmrg} 80605b261ecSmrg 80705b261ecSmrgstatic void 80805b261ecSmrgmiFillWideEllipse( 80905b261ecSmrg DrawablePtr pDraw, 81005b261ecSmrg GCPtr pGC, 81105b261ecSmrg xArc *parc) 81205b261ecSmrg{ 81305b261ecSmrg DDXPointPtr points; 81405b261ecSmrg DDXPointPtr pts; 81505b261ecSmrg int *widths; 81605b261ecSmrg int *wids; 81705b261ecSmrg miArcSpanData *spdata; 81805b261ecSmrg miArcSpan *span; 81905b261ecSmrg int xorg, yorgu, yorgl; 82005b261ecSmrg int n; 82105b261ecSmrg 82205b261ecSmrg yorgu = parc->height + pGC->lineWidth; 82305b261ecSmrg n = (sizeof(int) * 2) * yorgu; 8246747b715Smrg widths = malloc(n + (sizeof(DDXPointRec) * 2) * yorgu); 82505b261ecSmrg if (!widths) 82605b261ecSmrg return; 82705b261ecSmrg points = (DDXPointPtr)((char *)widths + n); 8286747b715Smrg spdata = miComputeWideEllipse((int)pGC->lineWidth, parc); 82905b261ecSmrg if (!spdata) 83005b261ecSmrg { 8316747b715Smrg free(widths); 83205b261ecSmrg return; 83305b261ecSmrg } 83405b261ecSmrg pts = points; 83505b261ecSmrg wids = widths; 83605b261ecSmrg span = spdata->spans; 83705b261ecSmrg xorg = parc->x + (parc->width >> 1); 83805b261ecSmrg yorgu = parc->y + (parc->height >> 1); 83905b261ecSmrg yorgl = yorgu + (parc->height & 1); 84005b261ecSmrg if (pGC->miTranslate) 84105b261ecSmrg { 84205b261ecSmrg xorg += pDraw->x; 84305b261ecSmrg yorgu += pDraw->y; 84405b261ecSmrg yorgl += pDraw->y; 84505b261ecSmrg } 84605b261ecSmrg yorgu -= spdata->k; 84705b261ecSmrg yorgl += spdata->k; 84805b261ecSmrg if (spdata->top) 84905b261ecSmrg { 85005b261ecSmrg pts->x = xorg; 85105b261ecSmrg pts->y = yorgu - 1; 85205b261ecSmrg pts++; 85305b261ecSmrg *wids++ = 1; 85405b261ecSmrg span++; 85505b261ecSmrg } 85605b261ecSmrg for (n = spdata->count1; --n >= 0; ) 85705b261ecSmrg { 85805b261ecSmrg pts[0].x = xorg + span->lx; 85905b261ecSmrg pts[0].y = yorgu; 86005b261ecSmrg wids[0] = span->lw; 86105b261ecSmrg pts[1].x = pts[0].x; 86205b261ecSmrg pts[1].y = yorgl; 86305b261ecSmrg wids[1] = wids[0]; 86405b261ecSmrg yorgu++; 86505b261ecSmrg yorgl--; 86605b261ecSmrg pts += 2; 86705b261ecSmrg wids += 2; 86805b261ecSmrg span++; 86905b261ecSmrg } 87005b261ecSmrg if (spdata->hole) 87105b261ecSmrg { 87205b261ecSmrg pts[0].x = xorg; 87305b261ecSmrg pts[0].y = yorgl; 87405b261ecSmrg wids[0] = 1; 87505b261ecSmrg pts++; 87605b261ecSmrg wids++; 87705b261ecSmrg } 87805b261ecSmrg for (n = spdata->count2; --n >= 0; ) 87905b261ecSmrg { 88005b261ecSmrg pts[0].x = xorg + span->lx; 88105b261ecSmrg pts[0].y = yorgu; 88205b261ecSmrg wids[0] = span->lw; 88305b261ecSmrg pts[1].x = xorg + span->rx; 88405b261ecSmrg pts[1].y = pts[0].y; 88505b261ecSmrg wids[1] = span->rw; 88605b261ecSmrg pts[2].x = pts[0].x; 88705b261ecSmrg pts[2].y = yorgl; 88805b261ecSmrg wids[2] = wids[0]; 88905b261ecSmrg pts[3].x = pts[1].x; 89005b261ecSmrg pts[3].y = pts[2].y; 89105b261ecSmrg wids[3] = wids[1]; 89205b261ecSmrg yorgu++; 89305b261ecSmrg yorgl--; 89405b261ecSmrg pts += 4; 89505b261ecSmrg wids += 4; 89605b261ecSmrg span++; 89705b261ecSmrg } 89805b261ecSmrg if (spdata->bot) 89905b261ecSmrg { 90005b261ecSmrg if (span->rw <= 0) 90105b261ecSmrg { 90205b261ecSmrg pts[0].x = xorg + span->lx; 90305b261ecSmrg pts[0].y = yorgu; 90405b261ecSmrg wids[0] = span->lw; 90505b261ecSmrg pts++; 90605b261ecSmrg wids++; 90705b261ecSmrg } 90805b261ecSmrg else 90905b261ecSmrg { 91005b261ecSmrg pts[0].x = xorg + span->lx; 91105b261ecSmrg pts[0].y = yorgu; 91205b261ecSmrg wids[0] = span->lw; 91305b261ecSmrg pts[1].x = xorg + span->rx; 91405b261ecSmrg pts[1].y = pts[0].y; 91505b261ecSmrg wids[1] = span->rw; 91605b261ecSmrg pts += 2; 91705b261ecSmrg wids += 2; 91805b261ecSmrg } 91905b261ecSmrg } 9206747b715Smrg free(spdata); 92105b261ecSmrg (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE); 92205b261ecSmrg 9236747b715Smrg free(widths); 92405b261ecSmrg} 92505b261ecSmrg 92605b261ecSmrg/* 92705b261ecSmrg * miPolyArc strategy: 92805b261ecSmrg * 92905b261ecSmrg * If arc is zero width and solid, we don't have to worry about the rasterop 93005b261ecSmrg * or join styles. For wide solid circles, we use a fast integer algorithm. 93105b261ecSmrg * For wide solid ellipses, we use special case floating point code. 93205b261ecSmrg * Otherwise, we set up pDrawTo and pGCTo according to the rasterop, then 93305b261ecSmrg * draw using pGCTo and pDrawTo. If the raster-op was "tricky," that is, 93405b261ecSmrg * if it involves the destination, then we use PushPixels to move the bits 93505b261ecSmrg * from the scratch drawable to pDraw. (See the wide line code for a 93605b261ecSmrg * fuller explanation of this.) 93705b261ecSmrg */ 93805b261ecSmrg 9396747b715Smrgvoid 9404642e01fSmrgmiPolyArc(DrawablePtr pDraw, GCPtr pGC, int narcs, xArc *parcs) 94105b261ecSmrg{ 94205b261ecSmrg int i; 94305b261ecSmrg xArc *parc; 94405b261ecSmrg int xMin, xMax, yMin, yMax; 94505b261ecSmrg int pixmapWidth = 0, pixmapHeight = 0; 94605b261ecSmrg int xOrg = 0, yOrg = 0; 94705b261ecSmrg int width; 94805b261ecSmrg Bool fTricky; 94905b261ecSmrg DrawablePtr pDrawTo; 95005b261ecSmrg CARD32 fg, bg; 95105b261ecSmrg GCPtr pGCTo; 95205b261ecSmrg miPolyArcPtr polyArcs; 95305b261ecSmrg int cap[2], join[2]; 95405b261ecSmrg int iphase; 95505b261ecSmrg int halfWidth; 95605b261ecSmrg 95705b261ecSmrg width = pGC->lineWidth; 95805b261ecSmrg if(width == 0 && pGC->lineStyle == LineSolid) 95905b261ecSmrg { 96005b261ecSmrg for(i = narcs, parc = parcs; --i >= 0; parc++) 96105b261ecSmrg miArcSegment( pDraw, pGC, *parc, 96205b261ecSmrg (miArcFacePtr) 0, (miArcFacePtr) 0 ); 96305b261ecSmrg fillSpans (pDraw, pGC); 96405b261ecSmrg } 96505b261ecSmrg else 96605b261ecSmrg { 96705b261ecSmrg if ((pGC->lineStyle == LineSolid) && narcs) 96805b261ecSmrg { 96905b261ecSmrg while (parcs->width && parcs->height && 97005b261ecSmrg (parcs->angle2 >= FULLCIRCLE || 97105b261ecSmrg parcs->angle2 <= -FULLCIRCLE)) 97205b261ecSmrg { 97305b261ecSmrg miFillWideEllipse(pDraw, pGC, parcs); 97405b261ecSmrg if (!--narcs) 97505b261ecSmrg return; 97605b261ecSmrg parcs++; 97705b261ecSmrg } 97805b261ecSmrg } 97905b261ecSmrg 98005b261ecSmrg /* Set up pDrawTo and pGCTo based on the rasterop */ 98105b261ecSmrg switch(pGC->alu) 98205b261ecSmrg { 98305b261ecSmrg case GXclear: /* 0 */ 98405b261ecSmrg case GXcopy: /* src */ 98505b261ecSmrg case GXcopyInverted: /* NOT src */ 98605b261ecSmrg case GXset: /* 1 */ 98705b261ecSmrg fTricky = FALSE; 98805b261ecSmrg pDrawTo = pDraw; 98905b261ecSmrg pGCTo = pGC; 99005b261ecSmrg break; 99105b261ecSmrg default: 99205b261ecSmrg fTricky = TRUE; 99305b261ecSmrg 99405b261ecSmrg /* find bounding box around arcs */ 99505b261ecSmrg xMin = yMin = MAXSHORT; 99605b261ecSmrg xMax = yMax = MINSHORT; 99705b261ecSmrg 99805b261ecSmrg for(i = narcs, parc = parcs; --i >= 0; parc++) 99905b261ecSmrg { 100005b261ecSmrg xMin = min (xMin, parc->x); 100105b261ecSmrg yMin = min (yMin, parc->y); 100205b261ecSmrg xMax = max (xMax, (parc->x + (int) parc->width)); 100305b261ecSmrg yMax = max (yMax, (parc->y + (int) parc->height)); 100405b261ecSmrg } 100505b261ecSmrg 100605b261ecSmrg /* expand box to deal with line widths */ 100705b261ecSmrg halfWidth = (width + 1)/2; 100805b261ecSmrg xMin -= halfWidth; 100905b261ecSmrg yMin -= halfWidth; 101005b261ecSmrg xMax += halfWidth; 101105b261ecSmrg yMax += halfWidth; 101205b261ecSmrg 101305b261ecSmrg /* compute pixmap size; limit it to size of drawable */ 101405b261ecSmrg xOrg = max(xMin, 0); 101505b261ecSmrg yOrg = max(yMin, 0); 101605b261ecSmrg pixmapWidth = min(xMax, pDraw->width) - xOrg; 101705b261ecSmrg pixmapHeight = min(yMax, pDraw->height) - yOrg; 101805b261ecSmrg 101905b261ecSmrg /* if nothing left, return */ 102005b261ecSmrg if ( (pixmapWidth <= 0) || (pixmapHeight <= 0) ) return; 102105b261ecSmrg 102205b261ecSmrg for(i = narcs, parc = parcs; --i >= 0; parc++) 102305b261ecSmrg { 102405b261ecSmrg parc->x -= xOrg; 102505b261ecSmrg parc->y -= yOrg; 102605b261ecSmrg } 102705b261ecSmrg if (pGC->miTranslate) 102805b261ecSmrg { 102905b261ecSmrg xOrg += pDraw->x; 103005b261ecSmrg yOrg += pDraw->y; 103105b261ecSmrg } 103205b261ecSmrg 103305b261ecSmrg /* set up scratch GC */ 103405b261ecSmrg 103505b261ecSmrg pGCTo = GetScratchGC(1, pDraw->pScreen); 103605b261ecSmrg if (!pGCTo) 103705b261ecSmrg return; 10386747b715Smrg { 10396747b715Smrg ChangeGCVal gcvals[6]; 10406747b715Smrg gcvals[0].val = GXcopy; 10416747b715Smrg gcvals[1].val = 1; 10426747b715Smrg gcvals[2].val = 0; 10436747b715Smrg gcvals[3].val = pGC->lineWidth; 10446747b715Smrg gcvals[4].val = pGC->capStyle; 10456747b715Smrg gcvals[5].val = pGC->joinStyle; 10466747b715Smrg ChangeGC(NullClient, pGCTo, GCFunction | 10476747b715Smrg GCForeground | GCBackground | GCLineWidth | 10486747b715Smrg GCCapStyle | GCJoinStyle, gcvals); 10496747b715Smrg } 105005b261ecSmrg 105105b261ecSmrg /* allocate a 1 bit deep pixmap of the appropriate size, and 105205b261ecSmrg * validate it */ 105305b261ecSmrg pDrawTo = (DrawablePtr)(*pDraw->pScreen->CreatePixmap) 10544642e01fSmrg (pDraw->pScreen, pixmapWidth, pixmapHeight, 1, 10554642e01fSmrg CREATE_PIXMAP_USAGE_SCRATCH); 105605b261ecSmrg if (!pDrawTo) 105705b261ecSmrg { 105805b261ecSmrg FreeScratchGC(pGCTo); 105905b261ecSmrg return; 106005b261ecSmrg } 106105b261ecSmrg ValidateGC(pDrawTo, pGCTo); 106205b261ecSmrg miClearDrawable(pDrawTo, pGCTo); 106305b261ecSmrg } 106405b261ecSmrg 106505b261ecSmrg fg = pGC->fgPixel; 106605b261ecSmrg bg = pGC->bgPixel; 106705b261ecSmrg if ((pGC->fillStyle == FillTiled) || 106805b261ecSmrg (pGC->fillStyle == FillOpaqueStippled)) 106905b261ecSmrg bg = fg; /* the protocol sez these don't cause color changes */ 107005b261ecSmrg 107105b261ecSmrg polyArcs = miComputeArcs (parcs, narcs, pGC); 107205b261ecSmrg 107305b261ecSmrg if (!polyArcs) 107405b261ecSmrg { 107505b261ecSmrg if (fTricky) { 107605b261ecSmrg (*pDraw->pScreen->DestroyPixmap) ((PixmapPtr)pDrawTo); 107705b261ecSmrg FreeScratchGC (pGCTo); 107805b261ecSmrg } 107905b261ecSmrg return; 108005b261ecSmrg } 108105b261ecSmrg 108205b261ecSmrg cap[0] = cap[1] = 0; 108305b261ecSmrg join[0] = join[1] = 0; 108405b261ecSmrg for (iphase = ((pGC->lineStyle == LineDoubleDash) ? 1 : 0); 108505b261ecSmrg iphase >= 0; 108605b261ecSmrg iphase--) 108705b261ecSmrg { 10886747b715Smrg ChangeGCVal gcval; 108905b261ecSmrg if (iphase == 1) { 10906747b715Smrg gcval.val = bg; 10916747b715Smrg ChangeGC (NullClient, pGC, GCForeground, &gcval); 109205b261ecSmrg ValidateGC (pDraw, pGC); 109305b261ecSmrg } else if (pGC->lineStyle == LineDoubleDash) { 10946747b715Smrg gcval.val = fg; 10956747b715Smrg ChangeGC (NullClient, pGC, GCForeground, &gcval); 109605b261ecSmrg ValidateGC (pDraw, pGC); 109705b261ecSmrg } 109805b261ecSmrg for (i = 0; i < polyArcs[iphase].narcs; i++) { 109905b261ecSmrg miArcDataPtr arcData; 110005b261ecSmrg 110105b261ecSmrg arcData = &polyArcs[iphase].arcs[i]; 110205b261ecSmrg miArcSegment(pDrawTo, pGCTo, arcData->arc, 110305b261ecSmrg &arcData->bounds[RIGHT_END], 110405b261ecSmrg &arcData->bounds[LEFT_END]); 110505b261ecSmrg if (polyArcs[iphase].arcs[i].render) { 110605b261ecSmrg fillSpans (pDrawTo, pGCTo); 110705b261ecSmrg /* 110805b261ecSmrg * don't cap self-joining arcs 110905b261ecSmrg */ 111005b261ecSmrg if (polyArcs[iphase].arcs[i].selfJoin && 111105b261ecSmrg cap[iphase] < polyArcs[iphase].arcs[i].cap) 111205b261ecSmrg cap[iphase]++; 111305b261ecSmrg while (cap[iphase] < polyArcs[iphase].arcs[i].cap) { 111405b261ecSmrg int arcIndex, end; 111505b261ecSmrg miArcDataPtr arcData0; 111605b261ecSmrg 111705b261ecSmrg arcIndex = polyArcs[iphase].caps[cap[iphase]].arcIndex; 111805b261ecSmrg end = polyArcs[iphase].caps[cap[iphase]].end; 111905b261ecSmrg arcData0 = &polyArcs[iphase].arcs[arcIndex]; 112005b261ecSmrg miArcCap (pDrawTo, pGCTo, 112105b261ecSmrg &arcData0->bounds[end], end, 112205b261ecSmrg arcData0->arc.x, arcData0->arc.y, 112305b261ecSmrg (double) arcData0->arc.width / 2.0, 112405b261ecSmrg (double) arcData0->arc.height / 2.0); 112505b261ecSmrg ++cap[iphase]; 112605b261ecSmrg } 112705b261ecSmrg while (join[iphase] < polyArcs[iphase].arcs[i].join) { 112805b261ecSmrg int arcIndex0, arcIndex1, end0, end1; 112905b261ecSmrg int phase0, phase1; 113005b261ecSmrg miArcDataPtr arcData0, arcData1; 113105b261ecSmrg miArcJoinPtr joinp; 113205b261ecSmrg 113305b261ecSmrg joinp = &polyArcs[iphase].joins[join[iphase]]; 113405b261ecSmrg arcIndex0 = joinp->arcIndex0; 113505b261ecSmrg end0 = joinp->end0; 113605b261ecSmrg arcIndex1 = joinp->arcIndex1; 113705b261ecSmrg end1 = joinp->end1; 113805b261ecSmrg phase0 = joinp->phase0; 113905b261ecSmrg phase1 = joinp->phase1; 114005b261ecSmrg arcData0 = &polyArcs[phase0].arcs[arcIndex0]; 114105b261ecSmrg arcData1 = &polyArcs[phase1].arcs[arcIndex1]; 114205b261ecSmrg miArcJoin (pDrawTo, pGCTo, 114305b261ecSmrg &arcData0->bounds[end0], 114405b261ecSmrg &arcData1->bounds[end1], 114505b261ecSmrg arcData0->arc.x, arcData0->arc.y, 114605b261ecSmrg (double) arcData0->arc.width / 2.0, 114705b261ecSmrg (double) arcData0->arc.height / 2.0, 114805b261ecSmrg arcData1->arc.x, arcData1->arc.y, 114905b261ecSmrg (double) arcData1->arc.width / 2.0, 115005b261ecSmrg (double) arcData1->arc.height / 2.0); 115105b261ecSmrg ++join[iphase]; 115205b261ecSmrg } 115305b261ecSmrg if (fTricky) { 115405b261ecSmrg if (pGC->serialNumber != pDraw->serialNumber) 115505b261ecSmrg ValidateGC (pDraw, pGC); 115605b261ecSmrg (*pGC->ops->PushPixels) (pGC, (PixmapPtr)pDrawTo, 115705b261ecSmrg pDraw, pixmapWidth, pixmapHeight, xOrg, yOrg); 115805b261ecSmrg miClearDrawable ((DrawablePtr) pDrawTo, pGCTo); 115905b261ecSmrg } 116005b261ecSmrg } 116105b261ecSmrg } 116205b261ecSmrg } 116305b261ecSmrg miFreeArcs(polyArcs, pGC); 116405b261ecSmrg 116505b261ecSmrg if(fTricky) 116605b261ecSmrg { 116705b261ecSmrg (*pGCTo->pScreen->DestroyPixmap)((PixmapPtr)pDrawTo); 116805b261ecSmrg FreeScratchGC(pGCTo); 116905b261ecSmrg } 117005b261ecSmrg } 117105b261ecSmrg} 117205b261ecSmrg 117305b261ecSmrgstatic double 117405b261ecSmrgangleBetween (SppPointRec center, SppPointRec point1, SppPointRec point2) 117505b261ecSmrg{ 117605b261ecSmrg double a1, a2, a; 117705b261ecSmrg 117805b261ecSmrg /* 117905b261ecSmrg * reflect from X coordinates back to ellipse 118005b261ecSmrg * coordinates -- y increasing upwards 118105b261ecSmrg */ 118205b261ecSmrg a1 = miDatan2 (- (point1.y - center.y), point1.x - center.x); 118305b261ecSmrg a2 = miDatan2 (- (point2.y - center.y), point2.x - center.x); 118405b261ecSmrg a = a2 - a1; 118505b261ecSmrg if (a <= -180.0) 118605b261ecSmrg a += 360.0; 118705b261ecSmrg else if (a > 180.0) 118805b261ecSmrg a -= 360.0; 118905b261ecSmrg return a; 119005b261ecSmrg} 119105b261ecSmrg 119205b261ecSmrgstatic void 119305b261ecSmrgtranslateBounds ( 119405b261ecSmrg miArcFacePtr b, 119505b261ecSmrg int x, 119605b261ecSmrg int y, 119705b261ecSmrg double fx, 119805b261ecSmrg double fy) 119905b261ecSmrg{ 120005b261ecSmrg fx += x; 120105b261ecSmrg fy += y; 120205b261ecSmrg b->clock.x -= fx; 120305b261ecSmrg b->clock.y -= fy; 120405b261ecSmrg b->center.x -= fx; 120505b261ecSmrg b->center.y -= fy; 120605b261ecSmrg b->counterClock.x -= fx; 120705b261ecSmrg b->counterClock.y -= fy; 120805b261ecSmrg} 120905b261ecSmrg 121005b261ecSmrgstatic void 121105b261ecSmrgmiArcJoin(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pLeft, 121205b261ecSmrg miArcFacePtr pRight, int xOrgLeft, int yOrgLeft, 121305b261ecSmrg double xFtransLeft, double yFtransLeft, 121405b261ecSmrg int xOrgRight, int yOrgRight, 121505b261ecSmrg double xFtransRight, double yFtransRight) 121605b261ecSmrg{ 121705b261ecSmrg SppPointRec center, corner, otherCorner; 121805b261ecSmrg SppPointRec poly[5], e; 121905b261ecSmrg SppPointPtr pArcPts; 122005b261ecSmrg int cpt; 122105b261ecSmrg SppArcRec arc; 122205b261ecSmrg miArcFaceRec Right, Left; 122305b261ecSmrg int polyLen = 0; 122405b261ecSmrg int xOrg, yOrg; 122505b261ecSmrg double xFtrans, yFtrans; 122605b261ecSmrg double a; 122705b261ecSmrg double ae, ac2, ec2, bc2, de; 122805b261ecSmrg double width; 122905b261ecSmrg 123005b261ecSmrg xOrg = (xOrgRight + xOrgLeft) / 2; 123105b261ecSmrg yOrg = (yOrgRight + yOrgLeft) / 2; 123205b261ecSmrg xFtrans = (xFtransLeft + xFtransRight) / 2; 123305b261ecSmrg yFtrans = (yFtransLeft + yFtransRight) / 2; 123405b261ecSmrg Right = *pRight; 123505b261ecSmrg translateBounds (&Right, xOrg - xOrgRight, yOrg - yOrgRight, 123605b261ecSmrg xFtrans - xFtransRight, yFtrans - yFtransRight); 123705b261ecSmrg Left = *pLeft; 123805b261ecSmrg translateBounds (&Left, xOrg - xOrgLeft, yOrg - yOrgLeft, 123905b261ecSmrg xFtrans - xFtransLeft, yFtrans - yFtransLeft); 124005b261ecSmrg pRight = &Right; 124105b261ecSmrg pLeft = &Left; 124205b261ecSmrg 124305b261ecSmrg if (pRight->clock.x == pLeft->counterClock.x && 124405b261ecSmrg pRight->clock.y == pLeft->counterClock.y) 124505b261ecSmrg return; 124605b261ecSmrg center = pRight->center; 124705b261ecSmrg if (0 <= (a = angleBetween (center, pRight->clock, pLeft->counterClock)) 124805b261ecSmrg && a <= 180.0) 124905b261ecSmrg { 125005b261ecSmrg corner = pRight->clock; 125105b261ecSmrg otherCorner = pLeft->counterClock; 125205b261ecSmrg } else { 125305b261ecSmrg a = angleBetween (center, pLeft->clock, pRight->counterClock); 125405b261ecSmrg corner = pLeft->clock; 125505b261ecSmrg otherCorner = pRight->counterClock; 125605b261ecSmrg } 125705b261ecSmrg switch (pGC->joinStyle) { 125805b261ecSmrg case JoinRound: 125905b261ecSmrg width = (pGC->lineWidth ? (double)pGC->lineWidth : (double)1); 126005b261ecSmrg 126105b261ecSmrg arc.x = center.x - width/2; 126205b261ecSmrg arc.y = center.y - width/2; 126305b261ecSmrg arc.width = width; 126405b261ecSmrg arc.height = width; 126505b261ecSmrg arc.angle1 = -miDatan2 (corner.y - center.y, corner.x - center.x); 126605b261ecSmrg arc.angle2 = a; 12676747b715Smrg pArcPts = malloc(3 * sizeof (SppPointRec)); 126805b261ecSmrg if (!pArcPts) 126905b261ecSmrg return; 127005b261ecSmrg pArcPts[0].x = otherCorner.x; 127105b261ecSmrg pArcPts[0].y = otherCorner.y; 127205b261ecSmrg pArcPts[1].x = center.x; 127305b261ecSmrg pArcPts[1].y = center.y; 127405b261ecSmrg pArcPts[2].x = corner.x; 127505b261ecSmrg pArcPts[2].y = corner.y; 127605b261ecSmrg if( (cpt = miGetArcPts(&arc, 3, &pArcPts)) ) 127705b261ecSmrg { 127805b261ecSmrg /* by drawing with miFillSppPoly and setting the endpoints of the arc 127905b261ecSmrg * to be the corners, we assure that the cap will meet up with the 128005b261ecSmrg * rest of the line */ 128105b261ecSmrg miFillSppPoly(pDraw, pGC, cpt, pArcPts, xOrg, yOrg, xFtrans, yFtrans); 128205b261ecSmrg } 12836747b715Smrg free(pArcPts); 128405b261ecSmrg return; 128505b261ecSmrg case JoinMiter: 128605b261ecSmrg /* 128705b261ecSmrg * don't miter arcs with less than 11 degrees between them 128805b261ecSmrg */ 128905b261ecSmrg if (a < 169.0) { 129005b261ecSmrg poly[0] = corner; 129105b261ecSmrg poly[1] = center; 129205b261ecSmrg poly[2] = otherCorner; 129305b261ecSmrg bc2 = (corner.x - otherCorner.x) * (corner.x - otherCorner.x) + 129405b261ecSmrg (corner.y - otherCorner.y) * (corner.y - otherCorner.y); 129505b261ecSmrg ec2 = bc2 / 4; 129605b261ecSmrg ac2 = (corner.x - center.x) * (corner.x - center.x) + 129705b261ecSmrg (corner.y - center.y) * (corner.y - center.y); 129805b261ecSmrg ae = sqrt (ac2 - ec2); 129905b261ecSmrg de = ec2 / ae; 130005b261ecSmrg e.x = (corner.x + otherCorner.x) / 2; 130105b261ecSmrg e.y = (corner.y + otherCorner.y) / 2; 130205b261ecSmrg poly[3].x = e.x + de * (e.x - center.x) / ae; 130305b261ecSmrg poly[3].y = e.y + de * (e.y - center.y) / ae; 130405b261ecSmrg poly[4] = corner; 130505b261ecSmrg polyLen = 5; 130605b261ecSmrg break; 130705b261ecSmrg } 130805b261ecSmrg case JoinBevel: 130905b261ecSmrg poly[0] = corner; 131005b261ecSmrg poly[1] = center; 131105b261ecSmrg poly[2] = otherCorner; 131205b261ecSmrg poly[3] = corner; 131305b261ecSmrg polyLen = 4; 131405b261ecSmrg break; 131505b261ecSmrg } 131605b261ecSmrg miFillSppPoly (pDraw, pGC, polyLen, poly, xOrg, yOrg, xFtrans, yFtrans); 131705b261ecSmrg} 131805b261ecSmrg 131905b261ecSmrg/*ARGSUSED*/ 132005b261ecSmrgstatic void 132105b261ecSmrgmiArcCap ( 132205b261ecSmrg DrawablePtr pDraw, 132305b261ecSmrg GCPtr pGC, 132405b261ecSmrg miArcFacePtr pFace, 132505b261ecSmrg int end, 132605b261ecSmrg int xOrg, 132705b261ecSmrg int yOrg, 132805b261ecSmrg double xFtrans, 132905b261ecSmrg double yFtrans) 133005b261ecSmrg{ 133105b261ecSmrg SppPointRec corner, otherCorner, center, endPoint, poly[5]; 133205b261ecSmrg 133305b261ecSmrg corner = pFace->clock; 133405b261ecSmrg otherCorner = pFace->counterClock; 133505b261ecSmrg center = pFace->center; 133605b261ecSmrg switch (pGC->capStyle) { 133705b261ecSmrg case CapProjecting: 133805b261ecSmrg poly[0].x = otherCorner.x; 133905b261ecSmrg poly[0].y = otherCorner.y; 134005b261ecSmrg poly[1].x = corner.x; 134105b261ecSmrg poly[1].y = corner.y; 134205b261ecSmrg poly[2].x = corner.x - 134305b261ecSmrg (center.y - corner.y); 134405b261ecSmrg poly[2].y = corner.y + 134505b261ecSmrg (center.x - corner.x); 134605b261ecSmrg poly[3].x = otherCorner.x - 134705b261ecSmrg (otherCorner.y - center.y); 134805b261ecSmrg poly[3].y = otherCorner.y + 134905b261ecSmrg (otherCorner.x - center.x); 135005b261ecSmrg poly[4].x = otherCorner.x; 135105b261ecSmrg poly[4].y = otherCorner.y; 135205b261ecSmrg miFillSppPoly (pDraw, pGC, 5, poly, xOrg, yOrg, xFtrans, yFtrans); 135305b261ecSmrg break; 135405b261ecSmrg case CapRound: 135505b261ecSmrg /* 135605b261ecSmrg * miRoundCap just needs these to be unequal. 135705b261ecSmrg */ 135805b261ecSmrg endPoint = center; 135905b261ecSmrg endPoint.x = endPoint.x + 100; 136005b261ecSmrg miRoundCap (pDraw, pGC, center, endPoint, corner, otherCorner, 0, 136105b261ecSmrg -xOrg, -yOrg, xFtrans, yFtrans); 136205b261ecSmrg break; 136305b261ecSmrg } 136405b261ecSmrg} 136505b261ecSmrg 136605b261ecSmrg/* MIROUNDCAP -- a private helper function 136705b261ecSmrg * Put Rounded cap on end. pCenter is the center of this end of the line 136805b261ecSmrg * pEnd is the center of the other end of the line. pCorner is one of the 136905b261ecSmrg * two corners at this end of the line. 137005b261ecSmrg * NOTE: pOtherCorner must be counter-clockwise from pCorner. 137105b261ecSmrg */ 137205b261ecSmrg/*ARGSUSED*/ 137305b261ecSmrgstatic void 137405b261ecSmrgmiRoundCap( 137505b261ecSmrg DrawablePtr pDraw, 137605b261ecSmrg GCPtr pGC, 137705b261ecSmrg SppPointRec pCenter, 137805b261ecSmrg SppPointRec pEnd, 137905b261ecSmrg SppPointRec pCorner, 138005b261ecSmrg SppPointRec pOtherCorner, 138105b261ecSmrg int fLineEnd, 138205b261ecSmrg int xOrg, 138305b261ecSmrg int yOrg, 138405b261ecSmrg double xFtrans, 138505b261ecSmrg double yFtrans) 138605b261ecSmrg{ 138705b261ecSmrg int cpt; 138805b261ecSmrg double width; 138905b261ecSmrg SppArcRec arc; 139005b261ecSmrg SppPointPtr pArcPts; 139105b261ecSmrg 139205b261ecSmrg width = (pGC->lineWidth ? (double)pGC->lineWidth : (double)1); 139305b261ecSmrg 139405b261ecSmrg arc.x = pCenter.x - width/2; 139505b261ecSmrg arc.y = pCenter.y - width/2; 139605b261ecSmrg arc.width = width; 139705b261ecSmrg arc.height = width; 139805b261ecSmrg arc.angle1 = -miDatan2 (pCorner.y - pCenter.y, pCorner.x - pCenter.x); 139905b261ecSmrg if(PTISEQUAL(pCenter, pEnd)) 140005b261ecSmrg arc.angle2 = - 180.0; 140105b261ecSmrg else { 140205b261ecSmrg arc.angle2 = -miDatan2 (pOtherCorner.y - pCenter.y, pOtherCorner.x - pCenter.x) - arc.angle1; 140305b261ecSmrg if (arc.angle2 < 0) 140405b261ecSmrg arc.angle2 += 360.0; 140505b261ecSmrg } 140605b261ecSmrg pArcPts = (SppPointPtr) NULL; 140705b261ecSmrg if( (cpt = miGetArcPts(&arc, 0, &pArcPts)) ) 140805b261ecSmrg { 140905b261ecSmrg /* by drawing with miFillSppPoly and setting the endpoints of the arc 141005b261ecSmrg * to be the corners, we assure that the cap will meet up with the 141105b261ecSmrg * rest of the line */ 141205b261ecSmrg miFillSppPoly(pDraw, pGC, cpt, pArcPts, -xOrg, -yOrg, xFtrans, yFtrans); 141305b261ecSmrg } 14146747b715Smrg free(pArcPts); 141505b261ecSmrg} 141605b261ecSmrg 141705b261ecSmrg/* 141805b261ecSmrg * To avoid inaccuracy at the cardinal points, use trig functions 141905b261ecSmrg * which are exact for those angles 142005b261ecSmrg */ 142105b261ecSmrg 142205b261ecSmrg#ifndef M_PI 142305b261ecSmrg#define M_PI 3.14159265358979323846 142405b261ecSmrg#endif 142505b261ecSmrg#ifndef M_PI_2 142605b261ecSmrg#define M_PI_2 1.57079632679489661923 142705b261ecSmrg#endif 142805b261ecSmrg 142905b261ecSmrg# define Dsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0))) 143005b261ecSmrg# define Dcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0))) 14316747b715Smrg# define mod(a,b) ((a) >= 0 ? (a) % (b) : (b) - (-(a)) % (b)) 143205b261ecSmrg 143305b261ecSmrgstatic double 143405b261ecSmrgmiDcos (double a) 143505b261ecSmrg{ 143605b261ecSmrg int i; 143705b261ecSmrg 143805b261ecSmrg if (floor (a/90) == a/90) { 143905b261ecSmrg i = (int) (a/90.0); 144005b261ecSmrg switch (mod (i, 4)) { 144105b261ecSmrg case 0: return 1; 144205b261ecSmrg case 1: return 0; 144305b261ecSmrg case 2: return -1; 144405b261ecSmrg case 3: return 0; 144505b261ecSmrg } 144605b261ecSmrg } 144705b261ecSmrg return cos (a * M_PI / 180.0); 144805b261ecSmrg} 144905b261ecSmrg 145005b261ecSmrgstatic double 145105b261ecSmrgmiDsin (double a) 145205b261ecSmrg{ 145305b261ecSmrg int i; 145405b261ecSmrg 145505b261ecSmrg if (floor (a/90) == a/90) { 145605b261ecSmrg i = (int) (a/90.0); 145705b261ecSmrg switch (mod (i, 4)) { 145805b261ecSmrg case 0: return 0; 145905b261ecSmrg case 1: return 1; 146005b261ecSmrg case 2: return 0; 146105b261ecSmrg case 3: return -1; 146205b261ecSmrg } 146305b261ecSmrg } 146405b261ecSmrg return sin (a * M_PI / 180.0); 146505b261ecSmrg} 146605b261ecSmrg 146705b261ecSmrgstatic double 146805b261ecSmrgmiDasin (double v) 146905b261ecSmrg{ 147005b261ecSmrg if (v == 0) 147105b261ecSmrg return 0.0; 147205b261ecSmrg if (v == 1.0) 147305b261ecSmrg return 90.0; 147405b261ecSmrg if (v == -1.0) 147505b261ecSmrg return -90.0; 147605b261ecSmrg return asin(v) * (180.0 / M_PI); 147705b261ecSmrg} 147805b261ecSmrg 147905b261ecSmrgstatic double 148005b261ecSmrgmiDatan2 (double dy, double dx) 148105b261ecSmrg{ 148205b261ecSmrg if (dy == 0) { 148305b261ecSmrg if (dx >= 0) 148405b261ecSmrg return 0.0; 148505b261ecSmrg return 180.0; 148605b261ecSmrg } else if (dx == 0) { 148705b261ecSmrg if (dy > 0) 148805b261ecSmrg return 90.0; 148905b261ecSmrg return -90.0; 149005b261ecSmrg } else if (Fabs (dy) == Fabs (dx)) { 149105b261ecSmrg if (dy > 0) { 149205b261ecSmrg if (dx > 0) 149305b261ecSmrg return 45.0; 149405b261ecSmrg return 135.0; 149505b261ecSmrg } else { 149605b261ecSmrg if (dx > 0) 149705b261ecSmrg return 315.0; 149805b261ecSmrg return 225.0; 149905b261ecSmrg } 150005b261ecSmrg } else { 150105b261ecSmrg return atan2 (dy, dx) * (180.0 / M_PI); 150205b261ecSmrg } 150305b261ecSmrg} 150405b261ecSmrg 150505b261ecSmrg/* MIGETARCPTS -- Converts an arc into a set of line segments -- a helper 150605b261ecSmrg * routine for filled arc and line (round cap) code. 150705b261ecSmrg * Returns the number of points in the arc. Note that it takes a pointer 150805b261ecSmrg * to a pointer to where it should put the points and an index (cpt). 150905b261ecSmrg * This procedure allocates the space necessary to fit the arc points. 151005b261ecSmrg * Sometimes it's convenient for those points to be at the end of an existing 151105b261ecSmrg * array. (For example, if we want to leave a spare point to make sectors 15126747b715Smrg * instead of segments.) So we pass in the malloc()ed chunk that contains the 151305b261ecSmrg * array and an index saying where we should start stashing the points. 151405b261ecSmrg * If there isn't an array already, we just pass in a null pointer and 15156747b715Smrg * count on realloc() to handle the null pointer correctly. 151605b261ecSmrg */ 151705b261ecSmrgstatic int 151805b261ecSmrgmiGetArcPts( 151905b261ecSmrg SppArcPtr parc, /* points to an arc */ 152005b261ecSmrg int cpt, /* number of points already in arc list */ 152105b261ecSmrg SppPointPtr *ppPts) /* pointer to pointer to arc-list -- modified */ 152205b261ecSmrg{ 152305b261ecSmrg double st, /* Start Theta, start angle */ 152405b261ecSmrg et, /* End Theta, offset from start theta */ 152505b261ecSmrg dt, /* Delta Theta, angle to sweep ellipse */ 152605b261ecSmrg cdt, /* Cos Delta Theta, actually 2 cos(dt) */ 152705b261ecSmrg x0, y0, /* the recurrence formula needs two points to start */ 152805b261ecSmrg x1, y1, 152905b261ecSmrg x2, y2, /* this will be the new point generated */ 153005b261ecSmrg xc, yc; /* the center point */ 153105b261ecSmrg int count, i; 153205b261ecSmrg SppPointPtr poly; 153305b261ecSmrg 153405b261ecSmrg /* The spec says that positive angles indicate counterclockwise motion. 153505b261ecSmrg * Given our coordinate system (with 0,0 in the upper left corner), 153605b261ecSmrg * the screen appears flipped in Y. The easiest fix is to negate the 153705b261ecSmrg * angles given */ 153805b261ecSmrg 153905b261ecSmrg st = - parc->angle1; 154005b261ecSmrg 154105b261ecSmrg et = - parc->angle2; 154205b261ecSmrg 154305b261ecSmrg /* Try to get a delta theta that is within 1/2 pixel. Then adjust it 154405b261ecSmrg * so that it divides evenly into the total. 154505b261ecSmrg * I'm just using cdt 'cause I'm lazy. 154605b261ecSmrg */ 154705b261ecSmrg cdt = parc->width; 154805b261ecSmrg if (parc->height > cdt) 154905b261ecSmrg cdt = parc->height; 155005b261ecSmrg cdt /= 2.0; 155105b261ecSmrg if(cdt <= 0) 155205b261ecSmrg return 0; 155305b261ecSmrg if (cdt < 1.0) 155405b261ecSmrg cdt = 1.0; 155505b261ecSmrg dt = miDasin ( 1.0 / cdt ); /* minimum step necessary */ 155605b261ecSmrg count = et/dt; 155705b261ecSmrg count = abs(count) + 1; 155805b261ecSmrg dt = et/count; 155905b261ecSmrg count++; 156005b261ecSmrg 156105b261ecSmrg cdt = 2 * miDcos(dt); 15626747b715Smrg if (!(poly = (SppPointPtr) realloc((pointer)*ppPts, 156305b261ecSmrg (cpt + count) * sizeof(SppPointRec)))) 15646747b715Smrg return 0; 156505b261ecSmrg *ppPts = poly; 156605b261ecSmrg 156705b261ecSmrg xc = parc->width/2.0; /* store half width and half height */ 156805b261ecSmrg yc = parc->height/2.0; 156905b261ecSmrg 157005b261ecSmrg x0 = xc * miDcos(st); 157105b261ecSmrg y0 = yc * miDsin(st); 157205b261ecSmrg x1 = xc * miDcos(st + dt); 157305b261ecSmrg y1 = yc * miDsin(st + dt); 157405b261ecSmrg xc += parc->x; /* by adding initial point, these become */ 157505b261ecSmrg yc += parc->y; /* the center point */ 157605b261ecSmrg 157705b261ecSmrg poly[cpt].x = (xc + x0); 157805b261ecSmrg poly[cpt].y = (yc + y0); 157905b261ecSmrg poly[cpt + 1].x = (xc + x1); 158005b261ecSmrg poly[cpt + 1].y = (yc + y1); 158105b261ecSmrg 158205b261ecSmrg for(i = 2; i < count; i++) 158305b261ecSmrg { 158405b261ecSmrg x2 = cdt * x1 - x0; 158505b261ecSmrg y2 = cdt * y1 - y0; 158605b261ecSmrg 158705b261ecSmrg poly[cpt + i].x = (xc + x2); 158805b261ecSmrg poly[cpt + i].y = (yc + y2); 158905b261ecSmrg 159005b261ecSmrg x0 = x1; y0 = y1; 159105b261ecSmrg x1 = x2; y1 = y2; 159205b261ecSmrg } 159305b261ecSmrg /* adjust the last point */ 15942f9f5fecSjoerg if (fabs(parc->angle2) >= 360.0) 159505b261ecSmrg poly[cpt +i -1] = poly[0]; 159605b261ecSmrg else { 159705b261ecSmrg poly[cpt +i -1].x = (miDcos(st + et) * parc->width/2.0 + xc); 159805b261ecSmrg poly[cpt +i -1].y = (miDsin(st + et) * parc->height/2.0 + yc); 159905b261ecSmrg } 160005b261ecSmrg 16016747b715Smrg return count; 160205b261ecSmrg} 160305b261ecSmrg 160405b261ecSmrgstruct arcData { 160505b261ecSmrg double x0, y0, x1, y1; 160605b261ecSmrg int selfJoin; 160705b261ecSmrg}; 160805b261ecSmrg 160905b261ecSmrg# define ADD_REALLOC_STEP 20 161005b261ecSmrg 161105b261ecSmrgstatic void 161205b261ecSmrgaddCap ( 161305b261ecSmrg miArcCapPtr *capsp, 161405b261ecSmrg int *ncapsp, 161505b261ecSmrg int *sizep, 161605b261ecSmrg int end, 161705b261ecSmrg int arcIndex) 161805b261ecSmrg{ 161905b261ecSmrg int newsize; 162005b261ecSmrg miArcCapPtr cap; 162105b261ecSmrg 162205b261ecSmrg if (*ncapsp == *sizep) 162305b261ecSmrg { 162405b261ecSmrg newsize = *sizep + ADD_REALLOC_STEP; 16256747b715Smrg cap = (miArcCapPtr) realloc(*capsp, 162605b261ecSmrg newsize * sizeof (**capsp)); 162705b261ecSmrg if (!cap) 162805b261ecSmrg return; 162905b261ecSmrg *sizep = newsize; 163005b261ecSmrg *capsp = cap; 163105b261ecSmrg } 163205b261ecSmrg cap = &(*capsp)[*ncapsp]; 163305b261ecSmrg cap->end = end; 163405b261ecSmrg cap->arcIndex = arcIndex; 163505b261ecSmrg ++*ncapsp; 163605b261ecSmrg} 163705b261ecSmrg 163805b261ecSmrgstatic void 163905b261ecSmrgaddJoin ( 164005b261ecSmrg miArcJoinPtr *joinsp, 164105b261ecSmrg int *njoinsp, 164205b261ecSmrg int *sizep, 164305b261ecSmrg int end0, 164405b261ecSmrg int index0, 164505b261ecSmrg int phase0, 164605b261ecSmrg int end1, 164705b261ecSmrg int index1, 164805b261ecSmrg int phase1) 164905b261ecSmrg{ 165005b261ecSmrg int newsize; 165105b261ecSmrg miArcJoinPtr join; 165205b261ecSmrg 165305b261ecSmrg if (*njoinsp == *sizep) 165405b261ecSmrg { 165505b261ecSmrg newsize = *sizep + ADD_REALLOC_STEP; 16566747b715Smrg join = (miArcJoinPtr) realloc(*joinsp, 165705b261ecSmrg newsize * sizeof (**joinsp)); 165805b261ecSmrg if (!join) 165905b261ecSmrg return; 166005b261ecSmrg *sizep = newsize; 166105b261ecSmrg *joinsp = join; 166205b261ecSmrg } 166305b261ecSmrg join = &(*joinsp)[*njoinsp]; 166405b261ecSmrg join->end0 = end0; 166505b261ecSmrg join->arcIndex0 = index0; 166605b261ecSmrg join->phase0 = phase0; 166705b261ecSmrg join->end1 = end1; 166805b261ecSmrg join->arcIndex1 = index1; 166905b261ecSmrg join->phase1 = phase1; 167005b261ecSmrg ++*njoinsp; 167105b261ecSmrg} 167205b261ecSmrg 167305b261ecSmrgstatic miArcDataPtr 167405b261ecSmrgaddArc ( 167505b261ecSmrg miArcDataPtr *arcsp, 167605b261ecSmrg int *narcsp, 167705b261ecSmrg int *sizep, 167805b261ecSmrg xArc *xarc) 167905b261ecSmrg{ 168005b261ecSmrg int newsize; 168105b261ecSmrg miArcDataPtr arc; 168205b261ecSmrg 168305b261ecSmrg if (*narcsp == *sizep) 168405b261ecSmrg { 168505b261ecSmrg newsize = *sizep + ADD_REALLOC_STEP; 16866747b715Smrg arc = (miArcDataPtr) realloc(*arcsp, 168705b261ecSmrg newsize * sizeof (**arcsp)); 168805b261ecSmrg if (!arc) 16896747b715Smrg return NULL; 169005b261ecSmrg *sizep = newsize; 169105b261ecSmrg *arcsp = arc; 169205b261ecSmrg } 169305b261ecSmrg arc = &(*arcsp)[*narcsp]; 169405b261ecSmrg arc->arc = *xarc; 169505b261ecSmrg ++*narcsp; 169605b261ecSmrg return arc; 169705b261ecSmrg} 169805b261ecSmrg 169905b261ecSmrgstatic void 170005b261ecSmrgmiFreeArcs( 170105b261ecSmrg miPolyArcPtr arcs, 170205b261ecSmrg GCPtr pGC) 170305b261ecSmrg{ 170405b261ecSmrg int iphase; 170505b261ecSmrg 170605b261ecSmrg for (iphase = ((pGC->lineStyle == LineDoubleDash) ? 1 : 0); 170705b261ecSmrg iphase >= 0; 170805b261ecSmrg iphase--) 170905b261ecSmrg { 171005b261ecSmrg if (arcs[iphase].narcs > 0) 17116747b715Smrg free(arcs[iphase].arcs); 171205b261ecSmrg if (arcs[iphase].njoins > 0) 17136747b715Smrg free(arcs[iphase].joins); 171405b261ecSmrg if (arcs[iphase].ncaps > 0) 17156747b715Smrg free(arcs[iphase].caps); 171605b261ecSmrg } 17176747b715Smrg free(arcs); 171805b261ecSmrg} 171905b261ecSmrg 172005b261ecSmrg/* 172105b261ecSmrg * map angles to radial distance. This only deals with the first quadrant 172205b261ecSmrg */ 172305b261ecSmrg 172405b261ecSmrg/* 172505b261ecSmrg * a polygonal approximation to the arc for computing arc lengths 172605b261ecSmrg */ 172705b261ecSmrg 172805b261ecSmrg# define DASH_MAP_SIZE 91 172905b261ecSmrg 173005b261ecSmrg# define dashIndexToAngle(di) ((((double) (di)) * 90.0) / ((double) DASH_MAP_SIZE - 1)) 173105b261ecSmrg# define xAngleToDashIndex(xa) ((((long) (xa)) * (DASH_MAP_SIZE - 1)) / (90 * 64)) 173205b261ecSmrg# define dashIndexToXAngle(di) ((((long) (di)) * (90 * 64)) / (DASH_MAP_SIZE - 1)) 173305b261ecSmrg# define dashXAngleStep (((double) (90 * 64)) / ((double) (DASH_MAP_SIZE - 1))) 173405b261ecSmrg 173505b261ecSmrgtypedef struct { 173605b261ecSmrg double map[DASH_MAP_SIZE]; 173705b261ecSmrg} dashMap; 173805b261ecSmrg 173905b261ecSmrgstatic int computeAngleFromPath(int startAngle, int endAngle, dashMap *map, 174005b261ecSmrg int *lenp, int backwards); 174105b261ecSmrg 174205b261ecSmrgstatic void 174305b261ecSmrgcomputeDashMap ( 174405b261ecSmrg xArc *arcp, 174505b261ecSmrg dashMap *map) 174605b261ecSmrg{ 174705b261ecSmrg int di; 174805b261ecSmrg double a, x, y, prevx = 0.0, prevy = 0.0, dist; 174905b261ecSmrg 175005b261ecSmrg for (di = 0; di < DASH_MAP_SIZE; di++) { 175105b261ecSmrg a = dashIndexToAngle (di); 175205b261ecSmrg x = ((double) arcp->width / 2.0) * miDcos (a); 175305b261ecSmrg y = ((double) arcp->height / 2.0) * miDsin (a); 175405b261ecSmrg if (di == 0) { 175505b261ecSmrg map->map[di] = 0.0; 175605b261ecSmrg } else { 175705b261ecSmrg dist = hypot (x - prevx, y - prevy); 175805b261ecSmrg map->map[di] = map->map[di - 1] + dist; 175905b261ecSmrg } 176005b261ecSmrg prevx = x; 176105b261ecSmrg prevy = y; 176205b261ecSmrg } 176305b261ecSmrg} 176405b261ecSmrg 176505b261ecSmrgtypedef enum {HORIZONTAL, VERTICAL, OTHER} arcTypes; 176605b261ecSmrg 176705b261ecSmrg/* this routine is a bit gory */ 176805b261ecSmrg 176905b261ecSmrgstatic miPolyArcPtr 177005b261ecSmrgmiComputeArcs ( 177105b261ecSmrg xArc *parcs, 177205b261ecSmrg int narcs, 177305b261ecSmrg GCPtr pGC) 177405b261ecSmrg{ 177505b261ecSmrg int isDashed, isDoubleDash; 177605b261ecSmrg int dashOffset; 177705b261ecSmrg miPolyArcPtr arcs; 177805b261ecSmrg int start, i, j, k = 0, nexti, nextk = 0; 177905b261ecSmrg int joinSize[2]; 178005b261ecSmrg int capSize[2]; 178105b261ecSmrg int arcSize[2]; 178205b261ecSmrg int angle2; 178305b261ecSmrg double a0, a1; 178405b261ecSmrg struct arcData *data; 178505b261ecSmrg miArcDataPtr arc; 178605b261ecSmrg xArc xarc; 178705b261ecSmrg int iphase, prevphase = 0, joinphase; 178805b261ecSmrg int arcsJoin; 178905b261ecSmrg int selfJoin; 179005b261ecSmrg 17916747b715Smrg int iDash = 0, dashRemaining = 0; 179205b261ecSmrg int iDashStart = 0, dashRemainingStart = 0, iphaseStart; 179305b261ecSmrg int startAngle, spanAngle, endAngle, backwards = 0; 179405b261ecSmrg int prevDashAngle, dashAngle; 179505b261ecSmrg dashMap map; 179605b261ecSmrg 179705b261ecSmrg isDashed = !(pGC->lineStyle == LineSolid); 179805b261ecSmrg isDoubleDash = (pGC->lineStyle == LineDoubleDash); 179905b261ecSmrg dashOffset = pGC->dashOffset; 180005b261ecSmrg 18016747b715Smrg data = malloc(narcs * sizeof (struct arcData)); 180205b261ecSmrg if (!data) 18036747b715Smrg return NULL; 18046747b715Smrg arcs = malloc(sizeof (*arcs) * (isDoubleDash ? 2 : 1)); 180505b261ecSmrg if (!arcs) 180605b261ecSmrg { 18076747b715Smrg free(data); 18086747b715Smrg return NULL; 180905b261ecSmrg } 181005b261ecSmrg for (i = 0; i < narcs; i++) { 181105b261ecSmrg a0 = todeg (parcs[i].angle1); 181205b261ecSmrg angle2 = parcs[i].angle2; 181305b261ecSmrg if (angle2 > FULLCIRCLE) 181405b261ecSmrg angle2 = FULLCIRCLE; 181505b261ecSmrg else if (angle2 < -FULLCIRCLE) 181605b261ecSmrg angle2 = -FULLCIRCLE; 181705b261ecSmrg data[i].selfJoin = angle2 == FULLCIRCLE || angle2 == -FULLCIRCLE; 181805b261ecSmrg a1 = todeg (parcs[i].angle1 + angle2); 181905b261ecSmrg data[i].x0 = parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos (a0)); 182005b261ecSmrg data[i].y0 = parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin (a0)); 182105b261ecSmrg data[i].x1 = parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos (a1)); 182205b261ecSmrg data[i].y1 = parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin (a1)); 182305b261ecSmrg } 182405b261ecSmrg 182505b261ecSmrg for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++) { 182605b261ecSmrg arcs[iphase].njoins = 0; 182705b261ecSmrg arcs[iphase].joins = 0; 182805b261ecSmrg joinSize[iphase] = 0; 182905b261ecSmrg 183005b261ecSmrg arcs[iphase].ncaps = 0; 183105b261ecSmrg arcs[iphase].caps = 0; 183205b261ecSmrg capSize[iphase] = 0; 183305b261ecSmrg 183405b261ecSmrg arcs[iphase].narcs = 0; 183505b261ecSmrg arcs[iphase].arcs = 0; 183605b261ecSmrg arcSize[iphase] = 0; 183705b261ecSmrg } 183805b261ecSmrg 183905b261ecSmrg iphase = 0; 184005b261ecSmrg if (isDashed) { 184105b261ecSmrg iDash = 0; 184205b261ecSmrg dashRemaining = pGC->dash[0]; 184305b261ecSmrg while (dashOffset > 0) { 184405b261ecSmrg if (dashOffset >= dashRemaining) { 184505b261ecSmrg dashOffset -= dashRemaining; 184605b261ecSmrg iphase = iphase ? 0 : 1; 184705b261ecSmrg iDash++; 184805b261ecSmrg if (iDash == pGC->numInDashList) 184905b261ecSmrg iDash = 0; 185005b261ecSmrg dashRemaining = pGC->dash[iDash]; 185105b261ecSmrg } else { 185205b261ecSmrg dashRemaining -= dashOffset; 185305b261ecSmrg dashOffset = 0; 185405b261ecSmrg } 185505b261ecSmrg } 185605b261ecSmrg iDashStart = iDash; 185705b261ecSmrg dashRemainingStart = dashRemaining; 185805b261ecSmrg } 185905b261ecSmrg iphaseStart = iphase; 186005b261ecSmrg 186105b261ecSmrg for (i = narcs - 1; i >= 0; i--) { 186205b261ecSmrg j = i + 1; 186305b261ecSmrg if (j == narcs) 186405b261ecSmrg j = 0; 186505b261ecSmrg if (data[i].selfJoin || i == j || 186605b261ecSmrg (UNEQUAL (data[i].x1, data[j].x0) || 186705b261ecSmrg UNEQUAL (data[i].y1, data[j].y0))) 186805b261ecSmrg { 186905b261ecSmrg if (iphase == 0 || isDoubleDash) 187005b261ecSmrg addCap (&arcs[iphase].caps, &arcs[iphase].ncaps, 187105b261ecSmrg &capSize[iphase], RIGHT_END, 0); 187205b261ecSmrg break; 187305b261ecSmrg } 187405b261ecSmrg } 187505b261ecSmrg start = i + 1; 187605b261ecSmrg if (start == narcs) 187705b261ecSmrg start = 0; 187805b261ecSmrg i = start; 187905b261ecSmrg for (;;) { 188005b261ecSmrg j = i + 1; 188105b261ecSmrg if (j == narcs) 188205b261ecSmrg j = 0; 188305b261ecSmrg nexti = i+1; 188405b261ecSmrg if (nexti == narcs) 188505b261ecSmrg nexti = 0; 188605b261ecSmrg if (isDashed) { 188705b261ecSmrg /* 188805b261ecSmrg ** deal with dashed arcs. Use special rules for certain 0 area arcs. 188905b261ecSmrg ** Presumably, the other 0 area arcs still aren't done right. 189005b261ecSmrg */ 189105b261ecSmrg arcTypes arcType = OTHER; 189205b261ecSmrg CARD16 thisLength; 189305b261ecSmrg 189405b261ecSmrg if (parcs[i].height == 0 189505b261ecSmrg && (parcs[i].angle1 % FULLCIRCLE) == 0x2d00 189605b261ecSmrg && parcs[i].angle2 == 0x2d00) 189705b261ecSmrg arcType = HORIZONTAL; 189805b261ecSmrg else if (parcs[i].width == 0 189905b261ecSmrg && (parcs[i].angle1 % FULLCIRCLE) == 0x1680 190005b261ecSmrg && parcs[i].angle2 == 0x2d00) 190105b261ecSmrg arcType = VERTICAL; 190205b261ecSmrg if (arcType == OTHER) { 190305b261ecSmrg /* 190405b261ecSmrg * precompute an approximation map 190505b261ecSmrg */ 190605b261ecSmrg computeDashMap (&parcs[i], &map); 190705b261ecSmrg /* 190805b261ecSmrg * compute each individual dash segment using the path 190905b261ecSmrg * length function 191005b261ecSmrg */ 191105b261ecSmrg startAngle = parcs[i].angle1; 191205b261ecSmrg spanAngle = parcs[i].angle2; 191305b261ecSmrg if (spanAngle > FULLCIRCLE) 191405b261ecSmrg spanAngle = FULLCIRCLE; 191505b261ecSmrg else if (spanAngle < -FULLCIRCLE) 191605b261ecSmrg spanAngle = -FULLCIRCLE; 191705b261ecSmrg if (startAngle < 0) 191805b261ecSmrg startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE; 191905b261ecSmrg if (startAngle >= FULLCIRCLE) 192005b261ecSmrg startAngle = startAngle % FULLCIRCLE; 192105b261ecSmrg endAngle = startAngle + spanAngle; 192205b261ecSmrg backwards = spanAngle < 0; 192305b261ecSmrg } else { 192405b261ecSmrg xarc = parcs[i]; 192505b261ecSmrg if (arcType == VERTICAL) { 192605b261ecSmrg xarc.angle1 = 0x1680; 192705b261ecSmrg startAngle = parcs[i].y; 192805b261ecSmrg endAngle = startAngle + parcs[i].height; 192905b261ecSmrg } else { 193005b261ecSmrg xarc.angle1 = 0x2d00; 193105b261ecSmrg startAngle = parcs[i].x; 193205b261ecSmrg endAngle = startAngle + parcs[i].width; 193305b261ecSmrg } 193405b261ecSmrg } 193505b261ecSmrg dashAngle = startAngle; 193605b261ecSmrg selfJoin = data[i].selfJoin && 193705b261ecSmrg (iphase == 0 || isDoubleDash); 193805b261ecSmrg /* 193905b261ecSmrg * add dashed arcs to each bucket 194005b261ecSmrg */ 194105b261ecSmrg arc = 0; 194205b261ecSmrg while (dashAngle != endAngle) { 194305b261ecSmrg prevDashAngle = dashAngle; 194405b261ecSmrg if (arcType == OTHER) { 194505b261ecSmrg dashAngle = computeAngleFromPath (prevDashAngle, endAngle, 194605b261ecSmrg &map, &dashRemaining, backwards); 194705b261ecSmrg /* avoid troubles with huge arcs and small dashes */ 194805b261ecSmrg if (dashAngle == prevDashAngle) { 194905b261ecSmrg if (backwards) 195005b261ecSmrg dashAngle--; 195105b261ecSmrg else 195205b261ecSmrg dashAngle++; 195305b261ecSmrg } 195405b261ecSmrg } else { 195505b261ecSmrg thisLength = (dashAngle + dashRemaining <= endAngle) ? 195605b261ecSmrg dashRemaining : endAngle - dashAngle; 195705b261ecSmrg if (arcType == VERTICAL) { 195805b261ecSmrg xarc.y = dashAngle; 195905b261ecSmrg xarc.height = thisLength; 196005b261ecSmrg } else { 196105b261ecSmrg xarc.x = dashAngle; 196205b261ecSmrg xarc.width = thisLength; 196305b261ecSmrg } 196405b261ecSmrg dashAngle += thisLength; 196505b261ecSmrg dashRemaining -= thisLength; 196605b261ecSmrg } 196705b261ecSmrg if (iphase == 0 || isDoubleDash) { 196805b261ecSmrg if (arcType == OTHER) { 196905b261ecSmrg xarc = parcs[i]; 197005b261ecSmrg spanAngle = prevDashAngle; 197105b261ecSmrg if (spanAngle < 0) 197205b261ecSmrg spanAngle = FULLCIRCLE - (-spanAngle) % FULLCIRCLE; 197305b261ecSmrg if (spanAngle >= FULLCIRCLE) 197405b261ecSmrg spanAngle = spanAngle % FULLCIRCLE; 197505b261ecSmrg xarc.angle1 = spanAngle; 197605b261ecSmrg spanAngle = dashAngle - prevDashAngle; 197705b261ecSmrg if (backwards) { 197805b261ecSmrg if (dashAngle > prevDashAngle) 197905b261ecSmrg spanAngle = - FULLCIRCLE + spanAngle; 198005b261ecSmrg } else { 198105b261ecSmrg if (dashAngle < prevDashAngle) 198205b261ecSmrg spanAngle = FULLCIRCLE + spanAngle; 198305b261ecSmrg } 198405b261ecSmrg if (spanAngle > FULLCIRCLE) 198505b261ecSmrg spanAngle = FULLCIRCLE; 198605b261ecSmrg if (spanAngle < -FULLCIRCLE) 198705b261ecSmrg spanAngle = -FULLCIRCLE; 198805b261ecSmrg xarc.angle2 = spanAngle; 198905b261ecSmrg } 199005b261ecSmrg arc = addArc (&arcs[iphase].arcs, &arcs[iphase].narcs, 199105b261ecSmrg &arcSize[iphase], &xarc); 199205b261ecSmrg if (!arc) 199305b261ecSmrg goto arcfail; 199405b261ecSmrg /* 199505b261ecSmrg * cap each end of an on/off dash 199605b261ecSmrg */ 199705b261ecSmrg if (!isDoubleDash) { 199805b261ecSmrg if (prevDashAngle != startAngle) { 199905b261ecSmrg addCap (&arcs[iphase].caps, 200005b261ecSmrg &arcs[iphase].ncaps, 200105b261ecSmrg &capSize[iphase], RIGHT_END, 200205b261ecSmrg arc - arcs[iphase].arcs); 200305b261ecSmrg 200405b261ecSmrg } 200505b261ecSmrg if (dashAngle != endAngle) { 200605b261ecSmrg addCap (&arcs[iphase].caps, 200705b261ecSmrg &arcs[iphase].ncaps, 200805b261ecSmrg &capSize[iphase], LEFT_END, 200905b261ecSmrg arc - arcs[iphase].arcs); 201005b261ecSmrg } 201105b261ecSmrg } 201205b261ecSmrg arc->cap = arcs[iphase].ncaps; 201305b261ecSmrg arc->join = arcs[iphase].njoins; 201405b261ecSmrg arc->render = 0; 201505b261ecSmrg arc->selfJoin = 0; 201605b261ecSmrg if (dashAngle == endAngle) 201705b261ecSmrg arc->selfJoin = selfJoin; 201805b261ecSmrg } 201905b261ecSmrg prevphase = iphase; 202005b261ecSmrg if (dashRemaining <= 0) { 202105b261ecSmrg ++iDash; 202205b261ecSmrg if (iDash == pGC->numInDashList) 202305b261ecSmrg iDash = 0; 202405b261ecSmrg iphase = iphase ? 0:1; 202505b261ecSmrg dashRemaining = pGC->dash[iDash]; 202605b261ecSmrg } 202705b261ecSmrg } 202805b261ecSmrg /* 202905b261ecSmrg * make sure a place exists for the position data when 203005b261ecSmrg * drawing a zero-length arc 203105b261ecSmrg */ 203205b261ecSmrg if (startAngle == endAngle) { 203305b261ecSmrg prevphase = iphase; 203405b261ecSmrg if (!isDoubleDash && iphase == 1) 203505b261ecSmrg prevphase = 0; 203605b261ecSmrg arc = addArc (&arcs[prevphase].arcs, &arcs[prevphase].narcs, 203705b261ecSmrg &arcSize[prevphase], &parcs[i]); 203805b261ecSmrg if (!arc) 203905b261ecSmrg goto arcfail; 204005b261ecSmrg arc->join = arcs[prevphase].njoins; 204105b261ecSmrg arc->cap = arcs[prevphase].ncaps; 204205b261ecSmrg arc->selfJoin = data[i].selfJoin; 204305b261ecSmrg } 204405b261ecSmrg } else { 204505b261ecSmrg arc = addArc (&arcs[iphase].arcs, &arcs[iphase].narcs, 204605b261ecSmrg &arcSize[iphase], &parcs[i]); 204705b261ecSmrg if (!arc) 204805b261ecSmrg goto arcfail; 204905b261ecSmrg arc->join = arcs[iphase].njoins; 205005b261ecSmrg arc->cap = arcs[iphase].ncaps; 205105b261ecSmrg arc->selfJoin = data[i].selfJoin; 205205b261ecSmrg prevphase = iphase; 205305b261ecSmrg } 205405b261ecSmrg if (prevphase == 0 || isDoubleDash) 205505b261ecSmrg k = arcs[prevphase].narcs - 1; 205605b261ecSmrg if (iphase == 0 || isDoubleDash) 205705b261ecSmrg nextk = arcs[iphase].narcs; 205805b261ecSmrg if (nexti == start) { 205905b261ecSmrg nextk = 0; 206005b261ecSmrg if (isDashed) { 206105b261ecSmrg iDash = iDashStart; 206205b261ecSmrg iphase = iphaseStart; 206305b261ecSmrg dashRemaining = dashRemainingStart; 206405b261ecSmrg } 206505b261ecSmrg } 206605b261ecSmrg arcsJoin = narcs > 1 && i != j && 206705b261ecSmrg ISEQUAL (data[i].x1, data[j].x0) && 206805b261ecSmrg ISEQUAL (data[i].y1, data[j].y0) && 206905b261ecSmrg !data[i].selfJoin && !data[j].selfJoin; 207005b261ecSmrg if (arc) 207105b261ecSmrg { 207205b261ecSmrg if (arcsJoin) 207305b261ecSmrg arc->render = 0; 207405b261ecSmrg else 207505b261ecSmrg arc->render = 1; 207605b261ecSmrg } 207705b261ecSmrg if (arcsJoin && 207805b261ecSmrg (prevphase == 0 || isDoubleDash) && 207905b261ecSmrg (iphase == 0 || isDoubleDash)) 208005b261ecSmrg { 208105b261ecSmrg joinphase = iphase; 208205b261ecSmrg if (isDoubleDash) { 208305b261ecSmrg if (nexti == start) 208405b261ecSmrg joinphase = iphaseStart; 208505b261ecSmrg /* 208605b261ecSmrg * if the join is right at the dash, 208705b261ecSmrg * draw the join in foreground 208805b261ecSmrg * This is because the foreground 208905b261ecSmrg * arcs are computed second, the results 209005b261ecSmrg * of which are needed to draw the join 209105b261ecSmrg */ 209205b261ecSmrg if (joinphase != prevphase) 209305b261ecSmrg joinphase = 0; 209405b261ecSmrg } 209505b261ecSmrg if (joinphase == 0 || isDoubleDash) { 209605b261ecSmrg addJoin (&arcs[joinphase].joins, 209705b261ecSmrg &arcs[joinphase].njoins, 209805b261ecSmrg &joinSize[joinphase], 209905b261ecSmrg LEFT_END, k, prevphase, 210005b261ecSmrg RIGHT_END, nextk, iphase); 210105b261ecSmrg arc->join = arcs[prevphase].njoins; 210205b261ecSmrg } 210305b261ecSmrg } else { 210405b261ecSmrg /* 210505b261ecSmrg * cap the left end of this arc 210605b261ecSmrg * unless it joins itself 210705b261ecSmrg */ 210805b261ecSmrg if ((prevphase == 0 || isDoubleDash) && 210905b261ecSmrg !arc->selfJoin) 211005b261ecSmrg { 211105b261ecSmrg addCap (&arcs[prevphase].caps, &arcs[prevphase].ncaps, 211205b261ecSmrg &capSize[prevphase], LEFT_END, k); 211305b261ecSmrg arc->cap = arcs[prevphase].ncaps; 211405b261ecSmrg } 211505b261ecSmrg if (isDashed && !arcsJoin) { 211605b261ecSmrg iDash = iDashStart; 211705b261ecSmrg iphase = iphaseStart; 211805b261ecSmrg dashRemaining = dashRemainingStart; 211905b261ecSmrg } 212005b261ecSmrg nextk = arcs[iphase].narcs; 212105b261ecSmrg if (nexti == start) { 212205b261ecSmrg nextk = 0; 212305b261ecSmrg iDash = iDashStart; 212405b261ecSmrg iphase = iphaseStart; 212505b261ecSmrg dashRemaining = dashRemainingStart; 212605b261ecSmrg } 212705b261ecSmrg /* 212805b261ecSmrg * cap the right end of the next arc. If the 212905b261ecSmrg * next arc is actually the first arc, only 213005b261ecSmrg * cap it if it joins with this arc. This 213105b261ecSmrg * case will occur when the final dash segment 213205b261ecSmrg * of an on/off dash is off. Of course, this 213305b261ecSmrg * cap will be drawn at a strange time, but that 213405b261ecSmrg * hardly matters... 213505b261ecSmrg */ 213605b261ecSmrg if ((iphase == 0 || isDoubleDash) && 213705b261ecSmrg (nexti != start || (arcsJoin && isDashed))) 213805b261ecSmrg addCap (&arcs[iphase].caps, &arcs[iphase].ncaps, 213905b261ecSmrg &capSize[iphase], RIGHT_END, nextk); 214005b261ecSmrg } 214105b261ecSmrg i = nexti; 214205b261ecSmrg if (i == start) 214305b261ecSmrg break; 214405b261ecSmrg } 214505b261ecSmrg /* 214605b261ecSmrg * make sure the last section is rendered 214705b261ecSmrg */ 214805b261ecSmrg for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++) 214905b261ecSmrg if (arcs[iphase].narcs > 0) { 215005b261ecSmrg arcs[iphase].arcs[arcs[iphase].narcs-1].render = 1; 215105b261ecSmrg arcs[iphase].arcs[arcs[iphase].narcs-1].join = 215205b261ecSmrg arcs[iphase].njoins; 215305b261ecSmrg arcs[iphase].arcs[arcs[iphase].narcs-1].cap = 215405b261ecSmrg arcs[iphase].ncaps; 215505b261ecSmrg } 21566747b715Smrg free(data); 215705b261ecSmrg return arcs; 215805b261ecSmrgarcfail: 215905b261ecSmrg miFreeArcs(arcs, pGC); 21606747b715Smrg free(data); 21616747b715Smrg return NULL; 216205b261ecSmrg} 216305b261ecSmrg 216405b261ecSmrgstatic double 216505b261ecSmrgangleToLength ( 216605b261ecSmrg int angle, 216705b261ecSmrg dashMap *map) 216805b261ecSmrg{ 216905b261ecSmrg double len, excesslen, sidelen = map->map[DASH_MAP_SIZE - 1], totallen; 217005b261ecSmrg int di; 217105b261ecSmrg int excess; 217205b261ecSmrg Bool oddSide = FALSE; 217305b261ecSmrg 217405b261ecSmrg totallen = 0; 217505b261ecSmrg if (angle >= 0) { 217605b261ecSmrg while (angle >= 90 * 64) { 217705b261ecSmrg angle -= 90 * 64; 217805b261ecSmrg totallen += sidelen; 217905b261ecSmrg oddSide = !oddSide; 218005b261ecSmrg } 218105b261ecSmrg } else { 218205b261ecSmrg while (angle < 0) { 218305b261ecSmrg angle += 90 * 64; 218405b261ecSmrg totallen -= sidelen; 218505b261ecSmrg oddSide = !oddSide; 218605b261ecSmrg } 218705b261ecSmrg } 218805b261ecSmrg if (oddSide) 218905b261ecSmrg angle = 90 * 64 - angle; 219005b261ecSmrg 219105b261ecSmrg di = xAngleToDashIndex (angle); 219205b261ecSmrg excess = angle - dashIndexToXAngle (di); 219305b261ecSmrg 219405b261ecSmrg len = map->map[di]; 219505b261ecSmrg /* 219605b261ecSmrg * linearly interpolate between this point and the next 219705b261ecSmrg */ 219805b261ecSmrg if (excess > 0) { 219905b261ecSmrg excesslen = (map->map[di + 1] - map->map[di]) * 220005b261ecSmrg ((double) excess) / dashXAngleStep; 220105b261ecSmrg len += excesslen; 220205b261ecSmrg } 220305b261ecSmrg if (oddSide) 220405b261ecSmrg totallen += (sidelen - len); 220505b261ecSmrg else 220605b261ecSmrg totallen += len; 220705b261ecSmrg return totallen; 220805b261ecSmrg} 220905b261ecSmrg 221005b261ecSmrg/* 221105b261ecSmrg * len is along the arc, but may be more than one rotation 221205b261ecSmrg */ 221305b261ecSmrg 221405b261ecSmrgstatic int 221505b261ecSmrglengthToAngle ( 221605b261ecSmrg double len, 221705b261ecSmrg dashMap *map) 221805b261ecSmrg{ 221905b261ecSmrg double sidelen = map->map[DASH_MAP_SIZE - 1]; 222005b261ecSmrg int angle, angleexcess; 222105b261ecSmrg Bool oddSide = FALSE; 222205b261ecSmrg int a0, a1, a; 222305b261ecSmrg 222405b261ecSmrg angle = 0; 222505b261ecSmrg /* 222605b261ecSmrg * step around the ellipse, subtracting sidelens and 222705b261ecSmrg * adding 90 degrees. oddSide will tell if the 222805b261ecSmrg * map should be interpolated in reverse 222905b261ecSmrg */ 223005b261ecSmrg if (len >= 0) { 223105b261ecSmrg if (sidelen == 0) 223205b261ecSmrg return 2 * FULLCIRCLE; /* infinity */ 223305b261ecSmrg while (len >= sidelen) { 223405b261ecSmrg angle += 90 * 64; 223505b261ecSmrg len -= sidelen; 223605b261ecSmrg oddSide = !oddSide; 223705b261ecSmrg } 223805b261ecSmrg } else { 223905b261ecSmrg if (sidelen == 0) 224005b261ecSmrg return -2 * FULLCIRCLE; /* infinity */ 224105b261ecSmrg while (len < 0) { 224205b261ecSmrg angle -= 90 * 64; 224305b261ecSmrg len += sidelen; 224405b261ecSmrg oddSide = !oddSide; 224505b261ecSmrg } 224605b261ecSmrg } 224705b261ecSmrg if (oddSide) 224805b261ecSmrg len = sidelen - len; 224905b261ecSmrg a0 = 0; 225005b261ecSmrg a1 = DASH_MAP_SIZE - 1; 225105b261ecSmrg /* 225205b261ecSmrg * binary search for the closest pre-computed length 225305b261ecSmrg */ 225405b261ecSmrg while (a1 - a0 > 1) { 225505b261ecSmrg a = (a0 + a1) / 2; 225605b261ecSmrg if (len > map->map[a]) 225705b261ecSmrg a0 = a; 225805b261ecSmrg else 225905b261ecSmrg a1 = a; 226005b261ecSmrg } 226105b261ecSmrg angleexcess = dashIndexToXAngle (a0); 226205b261ecSmrg /* 226305b261ecSmrg * linearly interpolate to the next point 226405b261ecSmrg */ 226505b261ecSmrg angleexcess += (len - map->map[a0]) / 226605b261ecSmrg (map->map[a0+1] - map->map[a0]) * dashXAngleStep; 226705b261ecSmrg if (oddSide) 226805b261ecSmrg angle += (90 * 64) - angleexcess; 226905b261ecSmrg else 227005b261ecSmrg angle += angleexcess; 227105b261ecSmrg return angle; 227205b261ecSmrg} 227305b261ecSmrg 227405b261ecSmrg/* 227505b261ecSmrg * compute the angle of an ellipse which cooresponds to 227605b261ecSmrg * the given path length. Note that the correct solution 227705b261ecSmrg * to this problem is an eliptic integral, we'll punt and 227805b261ecSmrg * approximate (it's only for dashes anyway). This 227905b261ecSmrg * approximation uses a polygon. 228005b261ecSmrg * 228105b261ecSmrg * The remaining portion of len is stored in *lenp - 228205b261ecSmrg * this will be negative if the arc extends beyond 228305b261ecSmrg * len and positive if len extends beyond the arc. 228405b261ecSmrg */ 228505b261ecSmrg 228605b261ecSmrgstatic int 228705b261ecSmrgcomputeAngleFromPath ( 228805b261ecSmrg int startAngle, 228905b261ecSmrg int endAngle, /* normalized absolute angles in *64 degrees */ 229005b261ecSmrg dashMap *map, 229105b261ecSmrg int *lenp, 229205b261ecSmrg int backwards) 229305b261ecSmrg{ 229405b261ecSmrg int a0, a1, a; 229505b261ecSmrg double len0; 229605b261ecSmrg int len; 229705b261ecSmrg 229805b261ecSmrg a0 = startAngle; 229905b261ecSmrg a1 = endAngle; 230005b261ecSmrg len = *lenp; 230105b261ecSmrg if (backwards) { 230205b261ecSmrg /* 230305b261ecSmrg * flip the problem around to always be 230405b261ecSmrg * forwards 230505b261ecSmrg */ 230605b261ecSmrg a0 = FULLCIRCLE - a0; 230705b261ecSmrg a1 = FULLCIRCLE - a1; 230805b261ecSmrg } 230905b261ecSmrg if (a1 < a0) 231005b261ecSmrg a1 += FULLCIRCLE; 231105b261ecSmrg len0 = angleToLength (a0, map); 231205b261ecSmrg a = lengthToAngle (len0 + len, map); 231305b261ecSmrg if (a > a1) { 231405b261ecSmrg a = a1; 231505b261ecSmrg len -= angleToLength (a1, map) - len0; 231605b261ecSmrg } else 231705b261ecSmrg len = 0; 231805b261ecSmrg if (backwards) 231905b261ecSmrg a = FULLCIRCLE - a; 232005b261ecSmrg *lenp = len; 232105b261ecSmrg return a; 232205b261ecSmrg} 232305b261ecSmrg 232405b261ecSmrg/* 232505b261ecSmrg * scan convert wide arcs. 232605b261ecSmrg */ 232705b261ecSmrg 232805b261ecSmrg/* 232905b261ecSmrg * draw zero width/height arcs 233005b261ecSmrg */ 233105b261ecSmrg 233205b261ecSmrgstatic void 233305b261ecSmrgdrawZeroArc ( 233405b261ecSmrg DrawablePtr pDraw, 233505b261ecSmrg GCPtr pGC, 233605b261ecSmrg xArc *tarc, 233705b261ecSmrg int lw, 233805b261ecSmrg miArcFacePtr left, 233905b261ecSmrg miArcFacePtr right) 234005b261ecSmrg{ 234105b261ecSmrg double x0 = 0.0, y0 = 0.0, x1 = 0.0, y1 = 0.0, w, h, x, y; 234205b261ecSmrg double xmax, ymax, xmin, ymin; 234305b261ecSmrg int a0, a1; 234405b261ecSmrg double a, startAngle, endAngle; 234505b261ecSmrg double l, lx, ly; 234605b261ecSmrg 234705b261ecSmrg l = lw / 2.0; 234805b261ecSmrg a0 = tarc->angle1; 234905b261ecSmrg a1 = tarc->angle2; 235005b261ecSmrg if (a1 > FULLCIRCLE) 235105b261ecSmrg a1 = FULLCIRCLE; 235205b261ecSmrg else if (a1 < -FULLCIRCLE) 235305b261ecSmrg a1 = -FULLCIRCLE; 235405b261ecSmrg w = (double)tarc->width / 2.0; 235505b261ecSmrg h = (double)tarc->height / 2.0; 235605b261ecSmrg /* 235705b261ecSmrg * play in X coordinates right away 235805b261ecSmrg */ 235905b261ecSmrg startAngle = - ((double) a0 / 64.0); 236005b261ecSmrg endAngle = - ((double) (a0 + a1) / 64.0); 236105b261ecSmrg 236205b261ecSmrg xmax = -w; 236305b261ecSmrg xmin = w; 236405b261ecSmrg ymax = -h; 236505b261ecSmrg ymin = h; 236605b261ecSmrg a = startAngle; 236705b261ecSmrg for (;;) 236805b261ecSmrg { 236905b261ecSmrg x = w * miDcos(a); 237005b261ecSmrg y = h * miDsin(a); 237105b261ecSmrg if (a == startAngle) 237205b261ecSmrg { 237305b261ecSmrg x0 = x; 237405b261ecSmrg y0 = y; 237505b261ecSmrg } 237605b261ecSmrg if (a == endAngle) 237705b261ecSmrg { 237805b261ecSmrg x1 = x; 237905b261ecSmrg y1 = y; 238005b261ecSmrg } 238105b261ecSmrg if (x > xmax) 238205b261ecSmrg xmax = x; 238305b261ecSmrg if (x < xmin) 238405b261ecSmrg xmin = x; 238505b261ecSmrg if (y > ymax) 238605b261ecSmrg ymax = y; 238705b261ecSmrg if (y < ymin) 238805b261ecSmrg ymin = y; 238905b261ecSmrg if (a == endAngle) 239005b261ecSmrg break; 239105b261ecSmrg if (a1 < 0) /* clockwise */ 239205b261ecSmrg { 239305b261ecSmrg if (floor (a / 90.0) == floor (endAngle / 90.0)) 239405b261ecSmrg a = endAngle; 239505b261ecSmrg else 239605b261ecSmrg a = 90 * (floor (a/90.0) + 1); 239705b261ecSmrg } 239805b261ecSmrg else 239905b261ecSmrg { 240005b261ecSmrg if (ceil (a / 90.0) == ceil (endAngle / 90.0)) 240105b261ecSmrg a = endAngle; 240205b261ecSmrg else 240305b261ecSmrg a = 90 * (ceil (a/90.0) - 1); 240405b261ecSmrg } 240505b261ecSmrg } 240605b261ecSmrg lx = ly = l; 240705b261ecSmrg if ((x1 - x0) + (y1 - y0) < 0) 240805b261ecSmrg lx = ly = -l; 240905b261ecSmrg if (h) 241005b261ecSmrg { 241105b261ecSmrg ly = 0.0; 241205b261ecSmrg lx = -lx; 241305b261ecSmrg } 241405b261ecSmrg else 241505b261ecSmrg lx = 0.0; 241605b261ecSmrg if (right) 241705b261ecSmrg { 241805b261ecSmrg right->center.x = x0; 241905b261ecSmrg right->center.y = y0; 242005b261ecSmrg right->clock.x = x0 - lx; 242105b261ecSmrg right->clock.y = y0 - ly; 242205b261ecSmrg right->counterClock.x = x0 + lx; 242305b261ecSmrg right->counterClock.y = y0 + ly; 242405b261ecSmrg } 242505b261ecSmrg if (left) 242605b261ecSmrg { 242705b261ecSmrg left->center.x = x1; 242805b261ecSmrg left->center.y = y1; 242905b261ecSmrg left->clock.x = x1 + lx; 243005b261ecSmrg left->clock.y = y1 + ly; 243105b261ecSmrg left->counterClock.x = x1 - lx; 243205b261ecSmrg left->counterClock.y = y1 - ly; 243305b261ecSmrg } 243405b261ecSmrg 243505b261ecSmrg x0 = xmin; 243605b261ecSmrg x1 = xmax; 243705b261ecSmrg y0 = ymin; 243805b261ecSmrg y1 = ymax; 243905b261ecSmrg if (ymin != y1) { 244005b261ecSmrg xmin = -l; 244105b261ecSmrg xmax = l; 244205b261ecSmrg } else { 244305b261ecSmrg ymin = -l; 244405b261ecSmrg ymax = l; 244505b261ecSmrg } 244605b261ecSmrg if (xmax != xmin && ymax != ymin) { 244705b261ecSmrg int minx, maxx, miny, maxy; 244805b261ecSmrg xRectangle rect; 244905b261ecSmrg 245005b261ecSmrg minx = ICEIL (xmin + w) + tarc->x; 245105b261ecSmrg maxx = ICEIL (xmax + w) + tarc->x; 245205b261ecSmrg miny = ICEIL (ymin + h) + tarc->y; 245305b261ecSmrg maxy = ICEIL (ymax + h) + tarc->y; 245405b261ecSmrg rect.x = minx; 245505b261ecSmrg rect.y = miny; 245605b261ecSmrg rect.width = maxx - minx; 245705b261ecSmrg rect.height = maxy - miny; 245805b261ecSmrg (*pGC->ops->PolyFillRect) (pDraw, pGC, 1, &rect); 245905b261ecSmrg } 246005b261ecSmrg} 246105b261ecSmrg 246205b261ecSmrg/* 246305b261ecSmrg * this computes the ellipse y value associated with the 246405b261ecSmrg * bottom of the tail. 246505b261ecSmrg */ 246605b261ecSmrg 246705b261ecSmrgstatic void 246805b261ecSmrgtailEllipseY ( 246905b261ecSmrg struct arc_def *def, 247005b261ecSmrg struct accelerators *acc) 247105b261ecSmrg{ 247205b261ecSmrg double t; 247305b261ecSmrg 247405b261ecSmrg acc->tail_y = 0.0; 247505b261ecSmrg if (def->w == def->h) 247605b261ecSmrg return; 247705b261ecSmrg t = def->l * def->w; 247805b261ecSmrg if (def->w > def->h) { 247905b261ecSmrg if (t < acc->h2) 248005b261ecSmrg return; 248105b261ecSmrg } else { 248205b261ecSmrg if (t > acc->h2) 248305b261ecSmrg return; 248405b261ecSmrg } 248505b261ecSmrg t = 2.0 * def->h * t; 248605b261ecSmrg t = (CUBED_ROOT_4 * acc->h2 - cbrt(t * t)) / acc->h2mw2; 248705b261ecSmrg if (t > 0.0) 248805b261ecSmrg acc->tail_y = def->h / CUBED_ROOT_2 * sqrt(t); 248905b261ecSmrg} 249005b261ecSmrg 249105b261ecSmrg/* 249205b261ecSmrg * inverse functions -- compute edge coordinates 249305b261ecSmrg * from the ellipse 249405b261ecSmrg */ 249505b261ecSmrg 249605b261ecSmrgstatic double 249705b261ecSmrgouterXfromXY ( 249805b261ecSmrg double x, 249905b261ecSmrg double y, 250005b261ecSmrg struct arc_def *def, 250105b261ecSmrg struct accelerators *acc) 250205b261ecSmrg{ 250305b261ecSmrg return x + (x * acc->h2l) / sqrt (x*x * acc->h4 + y*y * acc->w4); 250405b261ecSmrg} 250505b261ecSmrg 250605b261ecSmrgstatic double 250705b261ecSmrgouterYfromXY ( 250805b261ecSmrg double x, 250905b261ecSmrg double y, 251005b261ecSmrg struct arc_def *def, 251105b261ecSmrg struct accelerators *acc) 251205b261ecSmrg{ 251305b261ecSmrg return y + (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4); 251405b261ecSmrg} 251505b261ecSmrg 251605b261ecSmrgstatic double 251705b261ecSmrginnerXfromXY ( 251805b261ecSmrg double x, 251905b261ecSmrg double y, 252005b261ecSmrg struct arc_def *def, 252105b261ecSmrg struct accelerators *acc) 252205b261ecSmrg{ 252305b261ecSmrg return x - (x * acc->h2l) / sqrt (x*x * acc->h4 + y*y * acc->w4); 252405b261ecSmrg} 252505b261ecSmrg 252605b261ecSmrgstatic double 252705b261ecSmrginnerYfromXY ( 252805b261ecSmrg double x, 252905b261ecSmrg double y, 253005b261ecSmrg struct arc_def *def, 253105b261ecSmrg struct accelerators *acc) 253205b261ecSmrg{ 253305b261ecSmrg return y - (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4); 253405b261ecSmrg} 253505b261ecSmrg 253605b261ecSmrgstatic double 253705b261ecSmrginnerYfromY ( 253805b261ecSmrg double y, 253905b261ecSmrg struct arc_def *def, 254005b261ecSmrg struct accelerators *acc) 254105b261ecSmrg{ 254205b261ecSmrg double x; 254305b261ecSmrg 254405b261ecSmrg x = (def->w / def->h) * sqrt (acc->h2 - y*y); 254505b261ecSmrg 254605b261ecSmrg return y - (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4); 254705b261ecSmrg} 254805b261ecSmrg 254905b261ecSmrgstatic void 255005b261ecSmrgcomputeLine ( 255105b261ecSmrg double x1, 255205b261ecSmrg double y1, 255305b261ecSmrg double x2, 255405b261ecSmrg double y2, 255505b261ecSmrg struct line *line) 255605b261ecSmrg{ 255705b261ecSmrg if (y1 == y2) 255805b261ecSmrg line->valid = 0; 255905b261ecSmrg else { 256005b261ecSmrg line->m = (x1 - x2) / (y1 - y2); 256105b261ecSmrg line->b = x1 - y1 * line->m; 256205b261ecSmrg line->valid = 1; 256305b261ecSmrg } 256405b261ecSmrg} 256505b261ecSmrg 256605b261ecSmrg/* 256705b261ecSmrg * compute various accelerators for an ellipse. These 256805b261ecSmrg * are simply values that are used repeatedly in 256905b261ecSmrg * the computations 257005b261ecSmrg */ 257105b261ecSmrg 257205b261ecSmrgstatic void 257305b261ecSmrgcomputeAcc ( 257405b261ecSmrg xArc *tarc, 257505b261ecSmrg int lw, 257605b261ecSmrg struct arc_def *def, 257705b261ecSmrg struct accelerators *acc) 257805b261ecSmrg{ 257905b261ecSmrg def->w = ((double) tarc->width) / 2.0; 258005b261ecSmrg def->h = ((double) tarc->height) / 2.0; 258105b261ecSmrg def->l = ((double) lw) / 2.0; 258205b261ecSmrg acc->h2 = def->h * def->h; 258305b261ecSmrg acc->w2 = def->w * def->w; 258405b261ecSmrg acc->h4 = acc->h2 * acc->h2; 258505b261ecSmrg acc->w4 = acc->w2 * acc->w2; 258605b261ecSmrg acc->h2l = acc->h2 * def->l; 258705b261ecSmrg acc->w2l = acc->w2 * def->l; 258805b261ecSmrg acc->h2mw2 = acc->h2 - acc->w2; 258905b261ecSmrg acc->fromIntX = (tarc->width & 1) ? 0.5 : 0.0; 259005b261ecSmrg acc->fromIntY = (tarc->height & 1) ? 0.5 : 0.0; 259105b261ecSmrg acc->xorg = tarc->x + (tarc->width >> 1); 259205b261ecSmrg acc->yorgu = tarc->y + (tarc->height >> 1); 259305b261ecSmrg acc->yorgl = acc->yorgu + (tarc->height & 1); 259405b261ecSmrg tailEllipseY (def, acc); 259505b261ecSmrg} 259605b261ecSmrg 259705b261ecSmrg/* 259805b261ecSmrg * compute y value bounds of various portions of the arc, 259905b261ecSmrg * the outer edge, the ellipse and the inner edge. 260005b261ecSmrg */ 260105b261ecSmrg 260205b261ecSmrgstatic void 260305b261ecSmrgcomputeBound ( 260405b261ecSmrg struct arc_def *def, 260505b261ecSmrg struct arc_bound *bound, 260605b261ecSmrg struct accelerators *acc, 260705b261ecSmrg miArcFacePtr right, 260805b261ecSmrg miArcFacePtr left) 260905b261ecSmrg{ 261005b261ecSmrg double t; 261105b261ecSmrg double innerTaily; 261205b261ecSmrg double tail_y; 261305b261ecSmrg struct bound innerx, outerx; 261405b261ecSmrg struct bound ellipsex; 261505b261ecSmrg 261605b261ecSmrg bound->ellipse.min = Dsin (def->a0) * def->h; 261705b261ecSmrg bound->ellipse.max = Dsin (def->a1) * def->h; 261805b261ecSmrg if (def->a0 == 45 && def->w == def->h) 261905b261ecSmrg ellipsex.min = bound->ellipse.min; 262005b261ecSmrg else 262105b261ecSmrg ellipsex.min = Dcos (def->a0) * def->w; 262205b261ecSmrg if (def->a1 == 45 && def->w == def->h) 262305b261ecSmrg ellipsex.max = bound->ellipse.max; 262405b261ecSmrg else 262505b261ecSmrg ellipsex.max = Dcos (def->a1) * def->w; 262605b261ecSmrg bound->outer.min = outerYfromXY (ellipsex.min, bound->ellipse.min, def, acc); 262705b261ecSmrg bound->outer.max = outerYfromXY (ellipsex.max, bound->ellipse.max, def, acc); 262805b261ecSmrg bound->inner.min = innerYfromXY (ellipsex.min, bound->ellipse.min, def, acc); 262905b261ecSmrg bound->inner.max = innerYfromXY (ellipsex.max, bound->ellipse.max, def, acc); 263005b261ecSmrg 263105b261ecSmrg outerx.min = outerXfromXY (ellipsex.min, bound->ellipse.min, def, acc); 263205b261ecSmrg outerx.max = outerXfromXY (ellipsex.max, bound->ellipse.max, def, acc); 263305b261ecSmrg innerx.min = innerXfromXY (ellipsex.min, bound->ellipse.min, def, acc); 263405b261ecSmrg innerx.max = innerXfromXY (ellipsex.max, bound->ellipse.max, def, acc); 263505b261ecSmrg 263605b261ecSmrg /* 263705b261ecSmrg * save the line end points for the 263805b261ecSmrg * cap code to use. Careful here, these are 263905b261ecSmrg * in cartesean coordinates (y increasing upwards) 264005b261ecSmrg * while the cap code uses inverted coordinates 264105b261ecSmrg * (y increasing downwards) 264205b261ecSmrg */ 264305b261ecSmrg 264405b261ecSmrg if (right) { 264505b261ecSmrg right->counterClock.y = bound->outer.min; 264605b261ecSmrg right->counterClock.x = outerx.min; 264705b261ecSmrg right->center.y = bound->ellipse.min; 264805b261ecSmrg right->center.x = ellipsex.min; 264905b261ecSmrg right->clock.y = bound->inner.min; 265005b261ecSmrg right->clock.x = innerx.min; 265105b261ecSmrg } 265205b261ecSmrg 265305b261ecSmrg if (left) { 265405b261ecSmrg left->clock.y = bound->outer.max; 265505b261ecSmrg left->clock.x = outerx.max; 265605b261ecSmrg left->center.y = bound->ellipse.max; 265705b261ecSmrg left->center.x = ellipsex.max; 265805b261ecSmrg left->counterClock.y = bound->inner.max; 265905b261ecSmrg left->counterClock.x = innerx.max; 266005b261ecSmrg } 266105b261ecSmrg 266205b261ecSmrg bound->left.min = bound->inner.max; 266305b261ecSmrg bound->left.max = bound->outer.max; 266405b261ecSmrg bound->right.min = bound->inner.min; 266505b261ecSmrg bound->right.max = bound->outer.min; 266605b261ecSmrg 266705b261ecSmrg computeLine (innerx.min, bound->inner.min, outerx.min, bound->outer.min, 266805b261ecSmrg &acc->right); 266905b261ecSmrg computeLine (innerx.max, bound->inner.max, outerx.max, bound->outer.max, 267005b261ecSmrg &acc->left); 267105b261ecSmrg 267205b261ecSmrg if (bound->inner.min > bound->inner.max) { 267305b261ecSmrg t = bound->inner.min; 267405b261ecSmrg bound->inner.min = bound->inner.max; 267505b261ecSmrg bound->inner.max = t; 267605b261ecSmrg } 267705b261ecSmrg tail_y = acc->tail_y; 267805b261ecSmrg if (tail_y > bound->ellipse.max) 267905b261ecSmrg tail_y = bound->ellipse.max; 268005b261ecSmrg else if (tail_y < bound->ellipse.min) 268105b261ecSmrg tail_y = bound->ellipse.min; 268205b261ecSmrg innerTaily = innerYfromY (tail_y, def, acc); 268305b261ecSmrg if (bound->inner.min > innerTaily) 268405b261ecSmrg bound->inner.min = innerTaily; 268505b261ecSmrg if (bound->inner.max < innerTaily) 268605b261ecSmrg bound->inner.max = innerTaily; 268705b261ecSmrg bound->inneri.min = ICEIL(bound->inner.min - acc->fromIntY); 268805b261ecSmrg bound->inneri.max = floor(bound->inner.max - acc->fromIntY); 268905b261ecSmrg bound->outeri.min = ICEIL(bound->outer.min - acc->fromIntY); 269005b261ecSmrg bound->outeri.max = floor(bound->outer.max - acc->fromIntY); 269105b261ecSmrg} 269205b261ecSmrg 269305b261ecSmrg/* 269405b261ecSmrg * this section computes the x value of the span at y 269505b261ecSmrg * intersected with the specified face of the ellipse. 269605b261ecSmrg * 269705b261ecSmrg * this is the min/max X value over the set of normal 269805b261ecSmrg * lines to the entire ellipse, the equation of the 269905b261ecSmrg * normal lines is: 270005b261ecSmrg * 270105b261ecSmrg * ellipse_x h^2 h^2 270205b261ecSmrg * x = ------------ y + ellipse_x (1 - --- ) 270305b261ecSmrg * ellipse_y w^2 w^2 270405b261ecSmrg * 270505b261ecSmrg * compute the derivative with-respect-to ellipse_y and solve 270605b261ecSmrg * for zero: 270705b261ecSmrg * 270805b261ecSmrg * (w^2 - h^2) ellipse_y^3 + h^4 y 270905b261ecSmrg * 0 = - ---------------------------------- 271005b261ecSmrg * h w ellipse_y^2 sqrt (h^2 - ellipse_y^2) 271105b261ecSmrg * 271205b261ecSmrg * ( h^4 y ) 271305b261ecSmrg * ellipse_y = ( ---------- ) ^ (1/3) 271405b261ecSmrg * ( (h^2 - w^2) ) 271505b261ecSmrg * 271605b261ecSmrg * The other two solutions to the equation are imaginary. 271705b261ecSmrg * 271805b261ecSmrg * This gives the position on the ellipse which generates 271905b261ecSmrg * the normal with the largest/smallest x intersection point. 272005b261ecSmrg * 272105b261ecSmrg * Now compute the second derivative to check whether 272205b261ecSmrg * the intersection is a minimum or maximum: 272305b261ecSmrg * 272405b261ecSmrg * h (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2)) 272505b261ecSmrg * - ------------------------------------------- 272605b261ecSmrg * w y0^3 (sqrt (h^2 - y^2)) ^ 3 272705b261ecSmrg * 272805b261ecSmrg * as we only care about the sign, 272905b261ecSmrg * 273005b261ecSmrg * - (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2)) 273105b261ecSmrg * 273205b261ecSmrg * or (to use accelerators), 273305b261ecSmrg * 273405b261ecSmrg * y0^3 (h^2 - w^2) - h^2 y (3y0^2 - 2h^2) 273505b261ecSmrg * 273605b261ecSmrg */ 273705b261ecSmrg 273805b261ecSmrg/* 273905b261ecSmrg * computes the position on the ellipse whose normal line 274005b261ecSmrg * intersects the given scan line maximally 274105b261ecSmrg */ 274205b261ecSmrg 274305b261ecSmrgstatic double 274405b261ecSmrghookEllipseY ( 274505b261ecSmrg double scan_y, 274605b261ecSmrg struct arc_bound *bound, 274705b261ecSmrg struct accelerators *acc, 274805b261ecSmrg int left) 274905b261ecSmrg{ 275005b261ecSmrg double ret; 275105b261ecSmrg 275205b261ecSmrg if (acc->h2mw2 == 0) { 275305b261ecSmrg if ( (scan_y > 0 && !left) || (scan_y < 0 && left) ) 275405b261ecSmrg return bound->ellipse.min; 275505b261ecSmrg return bound->ellipse.max; 275605b261ecSmrg } 275705b261ecSmrg ret = (acc->h4 * scan_y) / (acc->h2mw2); 275805b261ecSmrg if (ret >= 0) 275905b261ecSmrg return cbrt (ret); 276005b261ecSmrg else 276105b261ecSmrg return -cbrt (-ret); 276205b261ecSmrg} 276305b261ecSmrg 276405b261ecSmrg/* 276505b261ecSmrg * computes the X value of the intersection of the 276605b261ecSmrg * given scan line with the right side of the lower hook 276705b261ecSmrg */ 276805b261ecSmrg 276905b261ecSmrgstatic double 277005b261ecSmrghookX ( 277105b261ecSmrg double scan_y, 277205b261ecSmrg struct arc_def *def, 277305b261ecSmrg struct arc_bound *bound, 277405b261ecSmrg struct accelerators *acc, 277505b261ecSmrg int left) 277605b261ecSmrg{ 277705b261ecSmrg double ellipse_y, x; 277805b261ecSmrg double maxMin; 277905b261ecSmrg 278005b261ecSmrg if (def->w != def->h) { 278105b261ecSmrg ellipse_y = hookEllipseY (scan_y, bound, acc, left); 278205b261ecSmrg if (boundedLe (ellipse_y, bound->ellipse)) { 278305b261ecSmrg /* 278405b261ecSmrg * compute the value of the second 278505b261ecSmrg * derivative 278605b261ecSmrg */ 278705b261ecSmrg maxMin = ellipse_y*ellipse_y*ellipse_y * acc->h2mw2 - 278805b261ecSmrg acc->h2 * scan_y * (3 * ellipse_y*ellipse_y - 2*acc->h2); 278905b261ecSmrg if ((left && maxMin > 0) || (!left && maxMin < 0)) { 279005b261ecSmrg if (ellipse_y == 0) 279105b261ecSmrg return def->w + left ? -def->l : def->l; 279205b261ecSmrg x = (acc->h2 * scan_y - ellipse_y * acc->h2mw2) * 279305b261ecSmrg sqrt (acc->h2 - ellipse_y * ellipse_y) / 279405b261ecSmrg (def->h * def->w * ellipse_y); 279505b261ecSmrg return x; 279605b261ecSmrg } 279705b261ecSmrg } 279805b261ecSmrg } 279905b261ecSmrg if (left) { 280005b261ecSmrg if (acc->left.valid && boundedLe (scan_y, bound->left)) { 280105b261ecSmrg x = intersectLine (scan_y, acc->left); 280205b261ecSmrg } else { 280305b261ecSmrg if (acc->right.valid) 280405b261ecSmrg x = intersectLine (scan_y, acc->right); 280505b261ecSmrg else 280605b261ecSmrg x = def->w - def->l; 280705b261ecSmrg } 280805b261ecSmrg } else { 280905b261ecSmrg if (acc->right.valid && boundedLe (scan_y, bound->right)) { 281005b261ecSmrg x = intersectLine (scan_y, acc->right); 281105b261ecSmrg } else { 281205b261ecSmrg if (acc->left.valid) 281305b261ecSmrg x = intersectLine (scan_y, acc->left); 281405b261ecSmrg else 281505b261ecSmrg x = def->w - def->l; 281605b261ecSmrg } 281705b261ecSmrg } 281805b261ecSmrg return x; 281905b261ecSmrg} 282005b261ecSmrg 282105b261ecSmrg/* 282205b261ecSmrg * generate the set of spans with 282305b261ecSmrg * the given y coordinate 282405b261ecSmrg */ 282505b261ecSmrg 282605b261ecSmrgstatic void 282705b261ecSmrgarcSpan ( 282805b261ecSmrg int y, 282905b261ecSmrg int lx, 283005b261ecSmrg int lw, 283105b261ecSmrg int rx, 283205b261ecSmrg int rw, 283305b261ecSmrg struct arc_def *def, 283405b261ecSmrg struct arc_bound *bounds, 283505b261ecSmrg struct accelerators *acc, 283605b261ecSmrg int mask) 283705b261ecSmrg{ 283805b261ecSmrg int linx, loutx, rinx, routx; 283905b261ecSmrg double x, altx; 284005b261ecSmrg 284105b261ecSmrg if (boundedLe (y, bounds->inneri)) { 284205b261ecSmrg linx = -(lx + lw); 284305b261ecSmrg rinx = rx; 284405b261ecSmrg } else { 284505b261ecSmrg /* 284605b261ecSmrg * intersection with left face 284705b261ecSmrg */ 284805b261ecSmrg x = hookX (y + acc->fromIntY, def, bounds, acc, 1); 284905b261ecSmrg if (acc->right.valid && 285005b261ecSmrg boundedLe (y + acc->fromIntY, bounds->right)) 285105b261ecSmrg { 285205b261ecSmrg altx = intersectLine (y + acc->fromIntY, acc->right); 285305b261ecSmrg if (altx < x) 285405b261ecSmrg x = altx; 285505b261ecSmrg } 285605b261ecSmrg linx = -ICEIL(acc->fromIntX - x); 285705b261ecSmrg rinx = ICEIL(acc->fromIntX + x); 285805b261ecSmrg } 285905b261ecSmrg if (boundedLe (y, bounds->outeri)) { 286005b261ecSmrg loutx = -lx; 286105b261ecSmrg routx = rx + rw; 286205b261ecSmrg } else { 286305b261ecSmrg /* 286405b261ecSmrg * intersection with right face 286505b261ecSmrg */ 286605b261ecSmrg x = hookX (y + acc->fromIntY, def, bounds, acc, 0); 286705b261ecSmrg if (acc->left.valid && 286805b261ecSmrg boundedLe (y + acc->fromIntY, bounds->left)) 286905b261ecSmrg { 287005b261ecSmrg altx = x; 287105b261ecSmrg x = intersectLine (y + acc->fromIntY, acc->left); 287205b261ecSmrg if (x < altx) 287305b261ecSmrg x = altx; 287405b261ecSmrg } 287505b261ecSmrg loutx = -ICEIL(acc->fromIntX - x); 287605b261ecSmrg routx = ICEIL(acc->fromIntX + x); 287705b261ecSmrg } 287805b261ecSmrg if (routx > rinx) { 287905b261ecSmrg if (mask & 1) 288005b261ecSmrg newFinalSpan (acc->yorgu - y, 288105b261ecSmrg acc->xorg + rinx, acc->xorg + routx); 288205b261ecSmrg if (mask & 8) 288305b261ecSmrg newFinalSpan (acc->yorgl + y, 288405b261ecSmrg acc->xorg + rinx, acc->xorg + routx); 288505b261ecSmrg } 288605b261ecSmrg if (loutx > linx) { 288705b261ecSmrg if (mask & 2) 288805b261ecSmrg newFinalSpan (acc->yorgu - y, 288905b261ecSmrg acc->xorg - loutx, acc->xorg - linx); 289005b261ecSmrg if (mask & 4) 289105b261ecSmrg newFinalSpan (acc->yorgl + y, 289205b261ecSmrg acc->xorg - loutx, acc->xorg - linx); 289305b261ecSmrg } 289405b261ecSmrg} 289505b261ecSmrg 289605b261ecSmrgstatic void 289705b261ecSmrgarcSpan0 ( 289805b261ecSmrg int lx, 289905b261ecSmrg int lw, 290005b261ecSmrg int rx, 290105b261ecSmrg int rw, 290205b261ecSmrg struct arc_def *def, 290305b261ecSmrg struct arc_bound *bounds, 290405b261ecSmrg struct accelerators *acc, 290505b261ecSmrg int mask) 290605b261ecSmrg{ 290705b261ecSmrg double x; 290805b261ecSmrg 290905b261ecSmrg if (boundedLe (0, bounds->inneri) && 291005b261ecSmrg acc->left.valid && boundedLe (0, bounds->left) && 291105b261ecSmrg acc->left.b > 0) 291205b261ecSmrg { 291305b261ecSmrg x = def->w - def->l; 291405b261ecSmrg if (acc->left.b < x) 291505b261ecSmrg x = acc->left.b; 291605b261ecSmrg lw = ICEIL(acc->fromIntX - x) - lx; 291705b261ecSmrg rw += rx; 291805b261ecSmrg rx = ICEIL(acc->fromIntX + x); 291905b261ecSmrg rw -= rx; 292005b261ecSmrg } 292105b261ecSmrg arcSpan (0, lx, lw, rx, rw, def, bounds, acc, mask); 292205b261ecSmrg} 292305b261ecSmrg 292405b261ecSmrgstatic void 292505b261ecSmrgtailSpan ( 292605b261ecSmrg int y, 292705b261ecSmrg int lw, 292805b261ecSmrg int rw, 292905b261ecSmrg struct arc_def *def, 293005b261ecSmrg struct arc_bound *bounds, 293105b261ecSmrg struct accelerators *acc, 293205b261ecSmrg int mask) 293305b261ecSmrg{ 293405b261ecSmrg double yy, xalt, x, lx, rx; 293505b261ecSmrg int n; 293605b261ecSmrg 293705b261ecSmrg if (boundedLe(y, bounds->outeri)) 293805b261ecSmrg arcSpan (y, 0, lw, -rw, rw, def, bounds, acc, mask); 293905b261ecSmrg else if (def->w != def->h) { 294005b261ecSmrg yy = y + acc->fromIntY; 294105b261ecSmrg x = tailX(yy, def, bounds, acc); 294205b261ecSmrg if (yy == 0.0 && x == -rw - acc->fromIntX) 294305b261ecSmrg return; 294405b261ecSmrg if (acc->right.valid && boundedLe (yy, bounds->right)) { 294505b261ecSmrg rx = x; 294605b261ecSmrg lx = -x; 294705b261ecSmrg xalt = intersectLine (yy, acc->right); 294805b261ecSmrg if (xalt >= -rw - acc->fromIntX && xalt <= rx) 294905b261ecSmrg rx = xalt; 295005b261ecSmrg n = ICEIL(acc->fromIntX + lx); 295105b261ecSmrg if (lw > n) { 295205b261ecSmrg if (mask & 2) 295305b261ecSmrg newFinalSpan (acc->yorgu - y, 295405b261ecSmrg acc->xorg + n, acc->xorg + lw); 295505b261ecSmrg if (mask & 4) 295605b261ecSmrg newFinalSpan (acc->yorgl + y, 295705b261ecSmrg acc->xorg + n, acc->xorg + lw); 295805b261ecSmrg } 295905b261ecSmrg n = ICEIL(acc->fromIntX + rx); 296005b261ecSmrg if (n > -rw) { 296105b261ecSmrg if (mask & 1) 296205b261ecSmrg newFinalSpan (acc->yorgu - y, 296305b261ecSmrg acc->xorg - rw, acc->xorg + n); 296405b261ecSmrg if (mask & 8) 296505b261ecSmrg newFinalSpan (acc->yorgl + y, 296605b261ecSmrg acc->xorg - rw, acc->xorg + n); 296705b261ecSmrg } 296805b261ecSmrg } 296905b261ecSmrg arcSpan (y, 297005b261ecSmrg ICEIL(acc->fromIntX - x), 0, 297105b261ecSmrg ICEIL(acc->fromIntX + x), 0, 297205b261ecSmrg def, bounds, acc, mask); 297305b261ecSmrg } 297405b261ecSmrg} 297505b261ecSmrg 297605b261ecSmrg/* 297705b261ecSmrg * create whole arcs out of pieces. This code is 297805b261ecSmrg * very bad. 297905b261ecSmrg */ 298005b261ecSmrg 298105b261ecSmrgstatic struct finalSpan **finalSpans = NULL; 298205b261ecSmrgstatic int finalMiny = 0, finalMaxy = -1; 298305b261ecSmrgstatic int finalSize = 0; 298405b261ecSmrg 298505b261ecSmrgstatic int nspans = 0; /* total spans, not just y coords */ 298605b261ecSmrg 298705b261ecSmrgstruct finalSpan { 298805b261ecSmrg struct finalSpan *next; 298905b261ecSmrg int min, max; /* x values */ 299005b261ecSmrg}; 299105b261ecSmrg 299205b261ecSmrgstatic struct finalSpan *freeFinalSpans, *tmpFinalSpan; 299305b261ecSmrg 299405b261ecSmrg# define allocFinalSpan() (freeFinalSpans ?\ 299505b261ecSmrg ((tmpFinalSpan = freeFinalSpans), \ 299605b261ecSmrg (freeFinalSpans = freeFinalSpans->next), \ 299705b261ecSmrg (tmpFinalSpan->next = 0), \ 299805b261ecSmrg tmpFinalSpan) : \ 299905b261ecSmrg realAllocSpan ()) 300005b261ecSmrg 300105b261ecSmrg# define SPAN_CHUNK_SIZE 128 300205b261ecSmrg 300305b261ecSmrgstruct finalSpanChunk { 300405b261ecSmrg struct finalSpan data[SPAN_CHUNK_SIZE]; 300505b261ecSmrg struct finalSpanChunk *next; 300605b261ecSmrg}; 300705b261ecSmrg 300805b261ecSmrgstatic struct finalSpanChunk *chunks; 300905b261ecSmrg 301005b261ecSmrgstatic struct finalSpan * 301105b261ecSmrgrealAllocSpan (void) 301205b261ecSmrg{ 301305b261ecSmrg struct finalSpanChunk *newChunk; 301405b261ecSmrg struct finalSpan *span; 301505b261ecSmrg int i; 301605b261ecSmrg 30176747b715Smrg newChunk = malloc(sizeof (struct finalSpanChunk)); 301805b261ecSmrg if (!newChunk) 301905b261ecSmrg return (struct finalSpan *) NULL; 302005b261ecSmrg newChunk->next = chunks; 302105b261ecSmrg chunks = newChunk; 302205b261ecSmrg freeFinalSpans = span = newChunk->data + 1; 302305b261ecSmrg for (i = 1; i < SPAN_CHUNK_SIZE-1; i++) { 302405b261ecSmrg span->next = span+1; 302505b261ecSmrg span++; 302605b261ecSmrg } 302705b261ecSmrg span->next = 0; 302805b261ecSmrg span = newChunk->data; 302905b261ecSmrg span->next = 0; 303005b261ecSmrg return span; 303105b261ecSmrg} 303205b261ecSmrg 303305b261ecSmrgstatic void 303405b261ecSmrgdisposeFinalSpans (void) 303505b261ecSmrg{ 303605b261ecSmrg struct finalSpanChunk *chunk, *next; 303705b261ecSmrg 303805b261ecSmrg for (chunk = chunks; chunk; chunk = next) { 303905b261ecSmrg next = chunk->next; 30406747b715Smrg free(chunk); 304105b261ecSmrg } 304205b261ecSmrg chunks = 0; 304305b261ecSmrg freeFinalSpans = 0; 30446747b715Smrg free(finalSpans); 304505b261ecSmrg finalSpans = 0; 304605b261ecSmrg} 304705b261ecSmrg 304805b261ecSmrgstatic void 304905b261ecSmrgfillSpans ( 305005b261ecSmrg DrawablePtr pDrawable, 305105b261ecSmrg GCPtr pGC) 305205b261ecSmrg{ 305305b261ecSmrg struct finalSpan *span; 305405b261ecSmrg DDXPointPtr xSpan; 305505b261ecSmrg int *xWidth; 305605b261ecSmrg int i; 305705b261ecSmrg struct finalSpan **f; 305805b261ecSmrg int spany; 305905b261ecSmrg DDXPointPtr xSpans; 306005b261ecSmrg int *xWidths; 306105b261ecSmrg 306205b261ecSmrg if (nspans == 0) 306305b261ecSmrg return; 30646747b715Smrg xSpan = xSpans = malloc(nspans * sizeof (DDXPointRec)); 30656747b715Smrg xWidth = xWidths = malloc(nspans * sizeof (int)); 306605b261ecSmrg if (xSpans && xWidths) 306705b261ecSmrg { 306805b261ecSmrg i = 0; 306905b261ecSmrg f = finalSpans; 307005b261ecSmrg for (spany = finalMiny; spany <= finalMaxy; spany++, f++) { 307105b261ecSmrg for (span = *f; span; span=span->next) { 307205b261ecSmrg if (span->max <= span->min) 307305b261ecSmrg continue; 307405b261ecSmrg xSpan->x = span->min; 307505b261ecSmrg xSpan->y = spany; 307605b261ecSmrg ++xSpan; 307705b261ecSmrg *xWidth++ = span->max - span->min; 307805b261ecSmrg ++i; 307905b261ecSmrg } 308005b261ecSmrg } 308105b261ecSmrg (*pGC->ops->FillSpans) (pDrawable, pGC, i, xSpans, xWidths, TRUE); 308205b261ecSmrg } 308305b261ecSmrg disposeFinalSpans (); 30846747b715Smrg free(xSpans); 30856747b715Smrg free(xWidths); 308605b261ecSmrg finalMiny = 0; 308705b261ecSmrg finalMaxy = -1; 308805b261ecSmrg finalSize = 0; 308905b261ecSmrg nspans = 0; 309005b261ecSmrg} 309105b261ecSmrg 309205b261ecSmrg# define SPAN_REALLOC 100 309305b261ecSmrg 309405b261ecSmrg# define findSpan(y) ((finalMiny <= (y) && (y) <= finalMaxy) ? \ 309505b261ecSmrg &finalSpans[(y) - finalMiny] : \ 309605b261ecSmrg realFindSpan (y)) 309705b261ecSmrg 309805b261ecSmrgstatic struct finalSpan ** 309905b261ecSmrgrealFindSpan (int y) 310005b261ecSmrg{ 310105b261ecSmrg struct finalSpan **newSpans; 310205b261ecSmrg int newSize, newMiny, newMaxy; 310305b261ecSmrg int change; 310405b261ecSmrg int i; 310505b261ecSmrg 310605b261ecSmrg if (y < finalMiny || y > finalMaxy) { 310705b261ecSmrg if (!finalSize) { 310805b261ecSmrg finalMiny = y; 310905b261ecSmrg finalMaxy = y - 1; 311005b261ecSmrg } 311105b261ecSmrg if (y < finalMiny) 311205b261ecSmrg change = finalMiny - y; 311305b261ecSmrg else 311405b261ecSmrg change = y - finalMaxy; 311505b261ecSmrg if (change >= SPAN_REALLOC) 311605b261ecSmrg change += SPAN_REALLOC; 311705b261ecSmrg else 311805b261ecSmrg change = SPAN_REALLOC; 311905b261ecSmrg newSize = finalSize + change; 31206747b715Smrg newSpans = malloc(newSize * sizeof (struct finalSpan *)); 312105b261ecSmrg if (!newSpans) 31226747b715Smrg return NULL; 312305b261ecSmrg newMiny = finalMiny; 312405b261ecSmrg newMaxy = finalMaxy; 312505b261ecSmrg if (y < finalMiny) 312605b261ecSmrg newMiny = finalMiny - change; 312705b261ecSmrg else 312805b261ecSmrg newMaxy = finalMaxy + change; 312905b261ecSmrg if (finalSpans) { 313005b261ecSmrg memmove(((char *) newSpans) + (finalMiny-newMiny) * sizeof (struct finalSpan *), 313105b261ecSmrg (char *) finalSpans, 313205b261ecSmrg finalSize * sizeof (struct finalSpan *)); 31336747b715Smrg free(finalSpans); 313405b261ecSmrg } 313505b261ecSmrg if ((i = finalMiny - newMiny) > 0) 31366747b715Smrg memset((char *)newSpans, 0, i * sizeof (struct finalSpan *)); 313705b261ecSmrg if ((i = newMaxy - finalMaxy) > 0) 31386747b715Smrg memset((char *)(newSpans + newSize - i), 0, 313905b261ecSmrg i * sizeof (struct finalSpan *)); 314005b261ecSmrg finalSpans = newSpans; 314105b261ecSmrg finalMaxy = newMaxy; 314205b261ecSmrg finalMiny = newMiny; 314305b261ecSmrg finalSize = newSize; 314405b261ecSmrg } 314505b261ecSmrg return &finalSpans[y - finalMiny]; 314605b261ecSmrg} 314705b261ecSmrg 314805b261ecSmrgstatic void 314905b261ecSmrgnewFinalSpan ( 315005b261ecSmrg int y, 315105b261ecSmrg int xmin, 315205b261ecSmrg int xmax) 315305b261ecSmrg{ 315405b261ecSmrg struct finalSpan *x; 315505b261ecSmrg struct finalSpan **f; 315605b261ecSmrg struct finalSpan *oldx; 315705b261ecSmrg struct finalSpan *prev; 315805b261ecSmrg 315905b261ecSmrg f = findSpan (y); 316005b261ecSmrg if (!f) 316105b261ecSmrg return; 316205b261ecSmrg oldx = 0; 316305b261ecSmrg for (;;) { 316405b261ecSmrg prev = 0; 316505b261ecSmrg for (x = *f; x; x=x->next) { 316605b261ecSmrg if (x == oldx) { 316705b261ecSmrg prev = x; 316805b261ecSmrg continue; 316905b261ecSmrg } 317005b261ecSmrg if (x->min <= xmax && xmin <= x->max) { 317105b261ecSmrg if (oldx) { 317205b261ecSmrg oldx->min = min (x->min, xmin); 317305b261ecSmrg oldx->max = max (x->max, xmax); 317405b261ecSmrg if (prev) 317505b261ecSmrg prev->next = x->next; 317605b261ecSmrg else 317705b261ecSmrg *f = x->next; 317805b261ecSmrg --nspans; 317905b261ecSmrg } else { 318005b261ecSmrg x->min = min (x->min, xmin); 318105b261ecSmrg x->max = max (x->max, xmax); 318205b261ecSmrg oldx = x; 318305b261ecSmrg } 318405b261ecSmrg xmin = oldx->min; 318505b261ecSmrg xmax = oldx->max; 318605b261ecSmrg break; 318705b261ecSmrg } 318805b261ecSmrg prev = x; 318905b261ecSmrg } 319005b261ecSmrg if (!x) 319105b261ecSmrg break; 319205b261ecSmrg } 319305b261ecSmrg if (!oldx) { 319405b261ecSmrg x = allocFinalSpan (); 319505b261ecSmrg if (x) 319605b261ecSmrg { 319705b261ecSmrg x->min = xmin; 319805b261ecSmrg x->max = xmax; 319905b261ecSmrg x->next = *f; 320005b261ecSmrg *f = x; 320105b261ecSmrg ++nspans; 320205b261ecSmrg } 320305b261ecSmrg } 320405b261ecSmrg} 320505b261ecSmrg 320605b261ecSmrgstatic void 320705b261ecSmrgmirrorSppPoint ( 320805b261ecSmrg int quadrant, 320905b261ecSmrg SppPointPtr sppPoint) 321005b261ecSmrg{ 321105b261ecSmrg switch (quadrant) { 321205b261ecSmrg case 0: 321305b261ecSmrg break; 321405b261ecSmrg case 1: 321505b261ecSmrg sppPoint->x = -sppPoint->x; 321605b261ecSmrg break; 321705b261ecSmrg case 2: 321805b261ecSmrg sppPoint->x = -sppPoint->x; 321905b261ecSmrg sppPoint->y = -sppPoint->y; 322005b261ecSmrg break; 322105b261ecSmrg case 3: 322205b261ecSmrg sppPoint->y = -sppPoint->y; 322305b261ecSmrg break; 322405b261ecSmrg } 322505b261ecSmrg /* 322605b261ecSmrg * and translate to X coordinate system 322705b261ecSmrg */ 322805b261ecSmrg sppPoint->y = -sppPoint->y; 322905b261ecSmrg} 323005b261ecSmrg 323105b261ecSmrg/* 323205b261ecSmrg * split an arc into pieces which are scan-converted 323305b261ecSmrg * in the first-quadrant and mirrored into position. 323405b261ecSmrg * This is necessary as the scan-conversion code can 323505b261ecSmrg * only deal with arcs completely contained in the 323605b261ecSmrg * first quadrant. 323705b261ecSmrg */ 323805b261ecSmrg 323905b261ecSmrgstatic void 324005b261ecSmrgdrawArc ( 324105b261ecSmrg xArc *tarc, 324205b261ecSmrg int l, 324305b261ecSmrg int a0, 324405b261ecSmrg int a1, 324505b261ecSmrg miArcFacePtr right, 324605b261ecSmrg miArcFacePtr left) /* save end line points */ 324705b261ecSmrg{ 324805b261ecSmrg struct arc_def def; 324905b261ecSmrg struct accelerators acc; 325005b261ecSmrg int startq, endq, curq; 325105b261ecSmrg int rightq, leftq = 0, righta = 0, lefta = 0; 325205b261ecSmrg miArcFacePtr passRight, passLeft; 325305b261ecSmrg int q0 = 0, q1 = 0, mask; 325405b261ecSmrg struct band { 325505b261ecSmrg int a0, a1; 325605b261ecSmrg int mask; 325705b261ecSmrg } band[5], sweep[20]; 325805b261ecSmrg int bandno, sweepno; 325905b261ecSmrg int i, j; 326005b261ecSmrg int flipRight = 0, flipLeft = 0; 326105b261ecSmrg int copyEnd = 0; 326205b261ecSmrg miArcSpanData *spdata; 326305b261ecSmrg 32646747b715Smrg spdata = miComputeWideEllipse(l, tarc); 326505b261ecSmrg if (!spdata) 326605b261ecSmrg return; 326705b261ecSmrg 326805b261ecSmrg if (a1 < a0) 326905b261ecSmrg a1 += 360 * 64; 327005b261ecSmrg startq = a0 / (90 * 64); 327105b261ecSmrg if (a0 == a1) 327205b261ecSmrg endq = startq; 327305b261ecSmrg else 327405b261ecSmrg endq = (a1-1) / (90 * 64); 327505b261ecSmrg bandno = 0; 327605b261ecSmrg curq = startq; 327705b261ecSmrg rightq = -1; 327805b261ecSmrg for (;;) { 327905b261ecSmrg switch (curq) { 328005b261ecSmrg case 0: 328105b261ecSmrg if (a0 > 90 * 64) 328205b261ecSmrg q0 = 0; 328305b261ecSmrg else 328405b261ecSmrg q0 = a0; 328505b261ecSmrg if (a1 < 360 * 64) 328605b261ecSmrg q1 = min (a1, 90 * 64); 328705b261ecSmrg else 328805b261ecSmrg q1 = 90 * 64; 328905b261ecSmrg if (curq == startq && a0 == q0 && rightq < 0) { 329005b261ecSmrg righta = q0; 329105b261ecSmrg rightq = curq; 329205b261ecSmrg } 329305b261ecSmrg if (curq == endq && a1 == q1) { 329405b261ecSmrg lefta = q1; 329505b261ecSmrg leftq = curq; 329605b261ecSmrg } 329705b261ecSmrg break; 329805b261ecSmrg case 1: 329905b261ecSmrg if (a1 < 90 * 64) 330005b261ecSmrg q0 = 0; 330105b261ecSmrg else 330205b261ecSmrg q0 = 180 * 64 - min (a1, 180 * 64); 330305b261ecSmrg if (a0 > 180 * 64) 330405b261ecSmrg q1 = 90 * 64; 330505b261ecSmrg else 330605b261ecSmrg q1 = 180 * 64 - max (a0, 90 * 64); 330705b261ecSmrg if (curq == startq && 180 * 64 - a0 == q1) { 330805b261ecSmrg righta = q1; 330905b261ecSmrg rightq = curq; 331005b261ecSmrg } 331105b261ecSmrg if (curq == endq && 180 * 64 - a1 == q0) { 331205b261ecSmrg lefta = q0; 331305b261ecSmrg leftq = curq; 331405b261ecSmrg } 331505b261ecSmrg break; 331605b261ecSmrg case 2: 331705b261ecSmrg if (a0 > 270 * 64) 331805b261ecSmrg q0 = 0; 331905b261ecSmrg else 332005b261ecSmrg q0 = max (a0, 180 * 64) - 180 * 64; 332105b261ecSmrg if (a1 < 180 * 64) 332205b261ecSmrg q1 = 90 * 64; 332305b261ecSmrg else 332405b261ecSmrg q1 = min (a1, 270 * 64) - 180 * 64; 332505b261ecSmrg if (curq == startq && a0 - 180*64 == q0) { 332605b261ecSmrg righta = q0; 332705b261ecSmrg rightq = curq; 332805b261ecSmrg } 332905b261ecSmrg if (curq == endq && a1 - 180 * 64 == q1) { 333005b261ecSmrg lefta = q1; 333105b261ecSmrg leftq = curq; 333205b261ecSmrg } 333305b261ecSmrg break; 333405b261ecSmrg case 3: 333505b261ecSmrg if (a1 < 270 * 64) 333605b261ecSmrg q0 = 0; 333705b261ecSmrg else 333805b261ecSmrg q0 = 360 * 64 - min (a1, 360 * 64); 333905b261ecSmrg q1 = 360 * 64 - max (a0, 270 * 64); 334005b261ecSmrg if (curq == startq && 360 * 64 - a0 == q1) { 334105b261ecSmrg righta = q1; 334205b261ecSmrg rightq = curq; 334305b261ecSmrg } 334405b261ecSmrg if (curq == endq && 360 * 64 - a1 == q0) { 334505b261ecSmrg lefta = q0; 334605b261ecSmrg leftq = curq; 334705b261ecSmrg } 334805b261ecSmrg break; 334905b261ecSmrg } 335005b261ecSmrg band[bandno].a0 = q0; 335105b261ecSmrg band[bandno].a1 = q1; 335205b261ecSmrg band[bandno].mask = 1 << curq; 335305b261ecSmrg bandno++; 335405b261ecSmrg if (curq == endq) 335505b261ecSmrg break; 335605b261ecSmrg curq++; 335705b261ecSmrg if (curq == 4) { 335805b261ecSmrg a0 = 0; 335905b261ecSmrg a1 -= 360 * 64; 336005b261ecSmrg curq = 0; 336105b261ecSmrg endq -= 4; 336205b261ecSmrg } 336305b261ecSmrg } 336405b261ecSmrg sweepno = 0; 336505b261ecSmrg for (;;) { 336605b261ecSmrg q0 = 90 * 64; 336705b261ecSmrg mask = 0; 336805b261ecSmrg /* 336905b261ecSmrg * find left-most point 337005b261ecSmrg */ 337105b261ecSmrg for (i = 0; i < bandno; i++) 337205b261ecSmrg if (band[i].a0 <= q0) { 337305b261ecSmrg q0 = band[i].a0; 337405b261ecSmrg q1 = band[i].a1; 337505b261ecSmrg mask = band[i].mask; 337605b261ecSmrg } 337705b261ecSmrg if (!mask) 337805b261ecSmrg break; 337905b261ecSmrg /* 338005b261ecSmrg * locate next point of change 338105b261ecSmrg */ 338205b261ecSmrg for (i = 0; i < bandno; i++) 338305b261ecSmrg if (!(mask & band[i].mask)) { 338405b261ecSmrg if (band[i].a0 == q0) { 338505b261ecSmrg if (band[i].a1 < q1) 338605b261ecSmrg q1 = band[i].a1; 338705b261ecSmrg mask |= band[i].mask; 338805b261ecSmrg } else if (band[i].a0 < q1) 338905b261ecSmrg q1 = band[i].a0; 339005b261ecSmrg } 339105b261ecSmrg /* 339205b261ecSmrg * create a new sweep 339305b261ecSmrg */ 339405b261ecSmrg sweep[sweepno].a0 = q0; 339505b261ecSmrg sweep[sweepno].a1 = q1; 339605b261ecSmrg sweep[sweepno].mask = mask; 339705b261ecSmrg sweepno++; 339805b261ecSmrg /* 339905b261ecSmrg * subtract the sweep from the affected bands 340005b261ecSmrg */ 340105b261ecSmrg for (i = 0; i < bandno; i++) 340205b261ecSmrg if (band[i].a0 == q0) { 340305b261ecSmrg band[i].a0 = q1; 340405b261ecSmrg /* 340505b261ecSmrg * check if this band is empty 340605b261ecSmrg */ 340705b261ecSmrg if (band[i].a0 == band[i].a1) 340805b261ecSmrg band[i].a1 = band[i].a0 = 90 * 64 + 1; 340905b261ecSmrg } 341005b261ecSmrg } 341105b261ecSmrg computeAcc (tarc, l, &def, &acc); 341205b261ecSmrg for (j = 0; j < sweepno; j++) { 341305b261ecSmrg mask = sweep[j].mask; 341405b261ecSmrg passRight = passLeft = 0; 341505b261ecSmrg if (mask & (1 << rightq)) { 341605b261ecSmrg if (sweep[j].a0 == righta) 341705b261ecSmrg passRight = right; 341805b261ecSmrg else if (sweep[j].a1 == righta) { 341905b261ecSmrg passLeft = right; 342005b261ecSmrg flipRight = 1; 342105b261ecSmrg } 342205b261ecSmrg } 342305b261ecSmrg if (mask & (1 << leftq)) { 342405b261ecSmrg if (sweep[j].a1 == lefta) 342505b261ecSmrg { 342605b261ecSmrg if (passLeft) 342705b261ecSmrg copyEnd = 1; 342805b261ecSmrg passLeft = left; 342905b261ecSmrg } 343005b261ecSmrg else if (sweep[j].a0 == lefta) { 343105b261ecSmrg if (passRight) 343205b261ecSmrg copyEnd = 1; 343305b261ecSmrg passRight = left; 343405b261ecSmrg flipLeft = 1; 343505b261ecSmrg } 343605b261ecSmrg } 343705b261ecSmrg drawQuadrant (&def, &acc, sweep[j].a0, sweep[j].a1, mask, 343805b261ecSmrg passRight, passLeft, spdata); 343905b261ecSmrg } 344005b261ecSmrg /* 344105b261ecSmrg * when copyEnd is set, both ends of the arc were computed 344205b261ecSmrg * at the same time; drawQuadrant only takes one end though, 344305b261ecSmrg * so the left end will be the only one holding the data. Copy 344405b261ecSmrg * it from there. 344505b261ecSmrg */ 344605b261ecSmrg if (copyEnd) 344705b261ecSmrg *right = *left; 344805b261ecSmrg /* 344905b261ecSmrg * mirror the coordinates generated for the 345005b261ecSmrg * faces of the arc 345105b261ecSmrg */ 345205b261ecSmrg if (right) { 345305b261ecSmrg mirrorSppPoint (rightq, &right->clock); 345405b261ecSmrg mirrorSppPoint (rightq, &right->center); 345505b261ecSmrg mirrorSppPoint (rightq, &right->counterClock); 345605b261ecSmrg if (flipRight) { 345705b261ecSmrg SppPointRec temp; 345805b261ecSmrg 345905b261ecSmrg temp = right->clock; 346005b261ecSmrg right->clock = right->counterClock; 346105b261ecSmrg right->counterClock = temp; 346205b261ecSmrg } 346305b261ecSmrg } 346405b261ecSmrg if (left) { 346505b261ecSmrg mirrorSppPoint (leftq, &left->counterClock); 346605b261ecSmrg mirrorSppPoint (leftq, &left->center); 346705b261ecSmrg mirrorSppPoint (leftq, &left->clock); 346805b261ecSmrg if (flipLeft) { 346905b261ecSmrg SppPointRec temp; 347005b261ecSmrg 347105b261ecSmrg temp = left->clock; 347205b261ecSmrg left->clock = left->counterClock; 347305b261ecSmrg left->counterClock = temp; 347405b261ecSmrg } 347505b261ecSmrg } 34766747b715Smrg free(spdata); 347705b261ecSmrg} 347805b261ecSmrg 347905b261ecSmrgstatic void 348005b261ecSmrgdrawQuadrant ( 348105b261ecSmrg struct arc_def *def, 348205b261ecSmrg struct accelerators *acc, 348305b261ecSmrg int a0, 348405b261ecSmrg int a1, 348505b261ecSmrg int mask, 348605b261ecSmrg miArcFacePtr right, 348705b261ecSmrg miArcFacePtr left, 348805b261ecSmrg miArcSpanData *spdata) 348905b261ecSmrg{ 349005b261ecSmrg struct arc_bound bound; 349105b261ecSmrg double yy, x, xalt; 349205b261ecSmrg int y, miny, maxy; 349305b261ecSmrg int n; 349405b261ecSmrg miArcSpan *span; 349505b261ecSmrg 349605b261ecSmrg def->a0 = ((double) a0) / 64.0; 349705b261ecSmrg def->a1 = ((double) a1) / 64.0; 349805b261ecSmrg computeBound (def, &bound, acc, right, left); 349905b261ecSmrg yy = bound.inner.min; 350005b261ecSmrg if (bound.outer.min < yy) 350105b261ecSmrg yy = bound.outer.min; 350205b261ecSmrg miny = ICEIL(yy - acc->fromIntY); 350305b261ecSmrg yy = bound.inner.max; 350405b261ecSmrg if (bound.outer.max > yy) 350505b261ecSmrg yy = bound.outer.max; 350605b261ecSmrg maxy = floor(yy - acc->fromIntY); 350705b261ecSmrg y = spdata->k; 350805b261ecSmrg span = spdata->spans; 350905b261ecSmrg if (spdata->top) 351005b261ecSmrg { 351105b261ecSmrg if (a1 == 90 * 64 && (mask & 1)) 351205b261ecSmrg newFinalSpan (acc->yorgu - y - 1, acc->xorg, acc->xorg + 1); 351305b261ecSmrg span++; 351405b261ecSmrg } 351505b261ecSmrg for (n = spdata->count1; --n >= 0; ) 351605b261ecSmrg { 351705b261ecSmrg if (y < miny) 351805b261ecSmrg return; 351905b261ecSmrg if (y <= maxy) { 352005b261ecSmrg arcSpan (y, 352105b261ecSmrg span->lx, -span->lx, 0, span->lx + span->lw, 352205b261ecSmrg def, &bound, acc, mask); 352305b261ecSmrg if (span->rw + span->rx) 352405b261ecSmrg tailSpan (y, -span->rw, -span->rx, def, &bound, acc, mask); 352505b261ecSmrg } 352605b261ecSmrg y--; 352705b261ecSmrg span++; 352805b261ecSmrg } 352905b261ecSmrg if (y < miny) 353005b261ecSmrg return; 353105b261ecSmrg if (spdata->hole) 353205b261ecSmrg { 353305b261ecSmrg if (y <= maxy) 353405b261ecSmrg arcSpan (y, 0, 0, 0, 1, def, &bound, acc, mask & 0xc); 353505b261ecSmrg } 353605b261ecSmrg for (n = spdata->count2; --n >= 0; ) 353705b261ecSmrg { 353805b261ecSmrg if (y < miny) 353905b261ecSmrg return; 354005b261ecSmrg if (y <= maxy) 354105b261ecSmrg arcSpan (y, span->lx, span->lw, span->rx, span->rw, 354205b261ecSmrg def, &bound, acc, mask); 354305b261ecSmrg y--; 354405b261ecSmrg span++; 354505b261ecSmrg } 354605b261ecSmrg if (spdata->bot && miny <= y && y <= maxy) 354705b261ecSmrg { 354805b261ecSmrg n = mask; 354905b261ecSmrg if (y == miny) 355005b261ecSmrg n &= 0xc; 355105b261ecSmrg if (span->rw <= 0) { 355205b261ecSmrg arcSpan0 (span->lx, -span->lx, 0, span->lx + span->lw, 355305b261ecSmrg def, &bound, acc, n); 355405b261ecSmrg if (span->rw + span->rx) 355505b261ecSmrg tailSpan (y, -span->rw, -span->rx, def, &bound, acc, n); 355605b261ecSmrg } 355705b261ecSmrg else 355805b261ecSmrg arcSpan0 (span->lx, span->lw, span->rx, span->rw, 355905b261ecSmrg def, &bound, acc, n); 356005b261ecSmrg y--; 356105b261ecSmrg } 356205b261ecSmrg while (y >= miny) { 356305b261ecSmrg yy = y + acc->fromIntY; 356405b261ecSmrg if (def->w == def->h) { 356505b261ecSmrg xalt = def->w - def->l; 356605b261ecSmrg x = -sqrt(xalt * xalt - yy * yy); 356705b261ecSmrg } else { 356805b261ecSmrg x = tailX(yy, def, &bound, acc); 356905b261ecSmrg if (acc->left.valid && boundedLe (yy, bound.left)) { 357005b261ecSmrg xalt = intersectLine (yy, acc->left); 357105b261ecSmrg if (xalt < x) 357205b261ecSmrg x = xalt; 357305b261ecSmrg } 357405b261ecSmrg if (acc->right.valid && boundedLe (yy, bound.right)) { 357505b261ecSmrg xalt = intersectLine (yy, acc->right); 357605b261ecSmrg if (xalt < x) 357705b261ecSmrg x = xalt; 357805b261ecSmrg } 357905b261ecSmrg } 358005b261ecSmrg arcSpan (y, 358105b261ecSmrg ICEIL(acc->fromIntX - x), 0, 358205b261ecSmrg ICEIL(acc->fromIntX + x), 0, 358305b261ecSmrg def, &bound, acc, mask); 358405b261ecSmrg y--; 358505b261ecSmrg } 358605b261ecSmrg} 3587