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