1706f2543Smrg/*********************************************************** 2706f2543Smrg 3706f2543SmrgCopyright 1987, 1998 The Open Group 4706f2543Smrg 5706f2543SmrgPermission to use, copy, modify, distribute, and sell this software and its 6706f2543Smrgdocumentation for any purpose is hereby granted without fee, provided that 7706f2543Smrgthe above copyright notice appear in all copies and that both that 8706f2543Smrgcopyright notice and this permission notice appear in supporting 9706f2543Smrgdocumentation. 10706f2543Smrg 11706f2543SmrgThe above copyright notice and this permission notice shall be included in 12706f2543Smrgall copies or substantial portions of the Software. 13706f2543Smrg 14706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15706f2543SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16706f2543SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17706f2543SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18706f2543SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19706f2543SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20706f2543Smrg 21706f2543SmrgExcept as contained in this notice, the name of The Open Group shall not be 22706f2543Smrgused in advertising or otherwise to promote the sale, use or other dealings 23706f2543Smrgin this Software without prior written authorization from The Open Group. 24706f2543Smrg 25706f2543Smrg 26706f2543SmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 27706f2543Smrg 28706f2543Smrg All Rights Reserved 29706f2543Smrg 30706f2543SmrgPermission to use, copy, modify, and distribute this software and its 31706f2543Smrgdocumentation for any purpose and without fee is hereby granted, 32706f2543Smrgprovided that the above copyright notice appear in all copies and that 33706f2543Smrgboth that copyright notice and this permission notice appear in 34706f2543Smrgsupporting documentation, and that the name of Digital not be 35706f2543Smrgused in advertising or publicity pertaining to distribution of the 36706f2543Smrgsoftware without specific, written prior permission. 37706f2543Smrg 38706f2543SmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 39706f2543SmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 40706f2543SmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 41706f2543SmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 42706f2543SmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 43706f2543SmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 44706f2543SmrgSOFTWARE. 45706f2543Smrg 46706f2543Smrg******************************************************************/ 47706f2543Smrg/* Author: Keith Packard and Bob Scheifler */ 48706f2543Smrg/* Warning: this code is toxic, do not dally very long here. */ 49706f2543Smrg 50706f2543Smrg#ifdef HAVE_DIX_CONFIG_H 51706f2543Smrg#include <dix-config.h> 52706f2543Smrg#endif 53706f2543Smrg 54706f2543Smrg#include <math.h> 55706f2543Smrg#include <X11/X.h> 56706f2543Smrg#include <X11/Xprotostr.h> 57706f2543Smrg#include "misc.h" 58706f2543Smrg#include "gcstruct.h" 59706f2543Smrg#include "scrnintstr.h" 60706f2543Smrg#include "pixmapstr.h" 61706f2543Smrg#include "windowstr.h" 62706f2543Smrg#include "mifpoly.h" 63706f2543Smrg#include "mi.h" 64706f2543Smrg#include "mifillarc.h" 65706f2543Smrg#include <X11/Xfuncproto.h> 66706f2543Smrg 67706f2543Smrgstatic double miDsin(double a); 68706f2543Smrgstatic double miDcos(double a); 69706f2543Smrgstatic double miDasin(double v); 70706f2543Smrgstatic double miDatan2(double dy, double dx); 71706f2543Smrg 72706f2543Smrg#ifndef HAVE_CBRT 73706f2543Smrgstatic double 74706f2543Smrgcbrt(double x) 75706f2543Smrg{ 76706f2543Smrg if (x > 0.0) 77706f2543Smrg return pow(x, 1.0/3.0); 78706f2543Smrg else 79706f2543Smrg return -pow(-x, 1.0/3.0); 80706f2543Smrg} 81706f2543Smrg#endif 82706f2543Smrg 83706f2543Smrg/* 84706f2543Smrg * some interesting sematic interpretation of the protocol: 85706f2543Smrg * 86706f2543Smrg * Self intersecting arcs (i.e. those spanning 360 degrees) 87706f2543Smrg * never join with other arcs, and are drawn without caps 88706f2543Smrg * (unless on/off dashed, in which case each dash segment 89706f2543Smrg * is capped, except when the last segment meets the 90706f2543Smrg * first segment, when no caps are drawn) 91706f2543Smrg * 92706f2543Smrg * double dash arcs are drawn in two parts, first the 93706f2543Smrg * odd dashes (drawn in background) then the even dashes 94706f2543Smrg * (drawn in foreground). This means that overlapping 95706f2543Smrg * sections of foreground/background are drawn twice, 96706f2543Smrg * first in background then in foreground. The double-draw 97706f2543Smrg * occurs even when the function uses the destination values 98706f2543Smrg * (e.g. xor mode). This is the same way the wide-line 99706f2543Smrg * code works and should be "fixed". 100706f2543Smrg * 101706f2543Smrg */ 102706f2543Smrg 103706f2543Smrg#undef max 104706f2543Smrg#undef min 105706f2543Smrg 106706f2543Smrg_X_INLINE static int max (const int x, const int y) 107706f2543Smrg{ 108706f2543Smrg return x>y? x:y; 109706f2543Smrg} 110706f2543Smrg 111706f2543Smrg_X_INLINE static int min (const int x, const int y) 112706f2543Smrg{ 113706f2543Smrg return x<y? x:y; 114706f2543Smrg} 115706f2543Smrg 116706f2543Smrgstruct bound { 117706f2543Smrg double min, max; 118706f2543Smrg}; 119706f2543Smrg 120706f2543Smrgstruct ibound { 121706f2543Smrg int min, max; 122706f2543Smrg}; 123706f2543Smrg 124706f2543Smrg#define boundedLe(value, bounds)\ 125706f2543Smrg ((bounds).min <= (value) && (value) <= (bounds).max) 126706f2543Smrg 127706f2543Smrgstruct line { 128706f2543Smrg double m, b; 129706f2543Smrg int valid; 130706f2543Smrg}; 131706f2543Smrg 132706f2543Smrg#define intersectLine(y,line) (line.m * (y) + line.b) 133706f2543Smrg 134706f2543Smrg/* 135706f2543Smrg * these are all y value bounds 136706f2543Smrg */ 137706f2543Smrg 138706f2543Smrgstruct arc_bound { 139706f2543Smrg struct bound ellipse; 140706f2543Smrg struct bound inner; 141706f2543Smrg struct bound outer; 142706f2543Smrg struct bound right; 143706f2543Smrg struct bound left; 144706f2543Smrg struct ibound inneri; 145706f2543Smrg struct ibound outeri; 146706f2543Smrg}; 147706f2543Smrg 148706f2543Smrgstruct accelerators { 149706f2543Smrg double tail_y; 150706f2543Smrg double h2; 151706f2543Smrg double w2; 152706f2543Smrg double h4; 153706f2543Smrg double w4; 154706f2543Smrg double h2mw2; 155706f2543Smrg double h2l; 156706f2543Smrg double w2l; 157706f2543Smrg double fromIntX; 158706f2543Smrg double fromIntY; 159706f2543Smrg struct line left, right; 160706f2543Smrg int yorgu; 161706f2543Smrg int yorgl; 162706f2543Smrg int xorg; 163706f2543Smrg}; 164706f2543Smrg 165706f2543Smrgstruct arc_def { 166706f2543Smrg double w, h, l; 167706f2543Smrg double a0, a1; 168706f2543Smrg}; 169706f2543Smrg 170706f2543Smrg# define todeg(xAngle) (((double) (xAngle)) / 64.0) 171706f2543Smrg 172706f2543Smrg# define RIGHT_END 0 173706f2543Smrg# define LEFT_END 1 174706f2543Smrg 175706f2543Smrgtypedef struct _miArcJoin { 176706f2543Smrg int arcIndex0, arcIndex1; 177706f2543Smrg int phase0, phase1; 178706f2543Smrg int end0, end1; 179706f2543Smrg} miArcJoinRec, *miArcJoinPtr; 180706f2543Smrg 181706f2543Smrgtypedef struct _miArcCap { 182706f2543Smrg int arcIndex; 183706f2543Smrg int end; 184706f2543Smrg} miArcCapRec, *miArcCapPtr; 185706f2543Smrg 186706f2543Smrgtypedef struct _miArcFace { 187706f2543Smrg SppPointRec clock; 188706f2543Smrg SppPointRec center; 189706f2543Smrg SppPointRec counterClock; 190706f2543Smrg} miArcFaceRec, *miArcFacePtr; 191706f2543Smrg 192706f2543Smrgtypedef struct _miArcData { 193706f2543Smrg xArc arc; 194706f2543Smrg int render; /* non-zero means render after drawing */ 195706f2543Smrg int join; /* related join */ 196706f2543Smrg int cap; /* related cap */ 197706f2543Smrg int selfJoin; /* final dash meets first dash */ 198706f2543Smrg miArcFaceRec bounds[2]; 199706f2543Smrg double x0, y0, x1, y1; 200706f2543Smrg} miArcDataRec, *miArcDataPtr; 201706f2543Smrg 202706f2543Smrg/* 203706f2543Smrg * This is an entire sequence of arcs, computed and categorized according 204706f2543Smrg * to operation. miDashArcs generates either one or two of these. 205706f2543Smrg */ 206706f2543Smrg 207706f2543Smrgtypedef struct _miPolyArc { 208706f2543Smrg int narcs; 209706f2543Smrg miArcDataPtr arcs; 210706f2543Smrg int ncaps; 211706f2543Smrg miArcCapPtr caps; 212706f2543Smrg int njoins; 213706f2543Smrg miArcJoinPtr joins; 214706f2543Smrg} miPolyArcRec, *miPolyArcPtr; 215706f2543Smrg 216706f2543Smrgstatic void fillSpans(DrawablePtr pDrawable, GCPtr pGC); 217706f2543Smrgstatic void newFinalSpan(int y, int xmin, int xmax); 218706f2543Smrgstatic void drawArc(xArc *tarc, int l, int a0, int a1, miArcFacePtr right, 219706f2543Smrg miArcFacePtr left); 220706f2543Smrgstatic void drawZeroArc(DrawablePtr pDraw, GCPtr pGC, xArc *tarc, int lw, 221706f2543Smrg miArcFacePtr left, miArcFacePtr right); 222706f2543Smrgstatic void miArcJoin(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pLeft, 223706f2543Smrg miArcFacePtr pRight, int xOrgLeft, int yOrgLeft, 224706f2543Smrg double xFtransLeft, double yFtransLeft, 225706f2543Smrg int xOrgRight, int yOrgRight, 226706f2543Smrg double xFtransRight, double yFtransRight); 227706f2543Smrgstatic void miArcCap(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pFace, 228706f2543Smrg int end, int xOrg, int yOrg, double xFtrans, 229706f2543Smrg double yFtrans); 230706f2543Smrgstatic void miRoundCap(DrawablePtr pDraw, GCPtr pGC, SppPointRec pCenter, 231706f2543Smrg SppPointRec pEnd, SppPointRec pCorner, 232706f2543Smrg SppPointRec pOtherCorner, int fLineEnd, 233706f2543Smrg int xOrg, int yOrg, double xFtrans, double yFtrans); 234706f2543Smrgstatic void miFreeArcs(miPolyArcPtr arcs, GCPtr pGC); 235706f2543Smrgstatic miPolyArcPtr miComputeArcs(xArc *parcs, int narcs, GCPtr pGC); 236706f2543Smrgstatic int miGetArcPts(SppArcPtr parc, int cpt, SppPointPtr *ppPts); 237706f2543Smrg 238706f2543Smrg# define CUBED_ROOT_2 1.2599210498948732038115849718451499938964 239706f2543Smrg# define CUBED_ROOT_4 1.5874010519681993173435330390930175781250 240706f2543Smrg 241706f2543Smrg/* 242706f2543Smrg * draw one segment of the arc using the arc spans generation routines 243706f2543Smrg */ 244706f2543Smrg 245706f2543Smrgstatic void 246706f2543SmrgmiArcSegment( 247706f2543Smrg DrawablePtr pDraw, 248706f2543Smrg GCPtr pGC, 249706f2543Smrg xArc tarc, 250706f2543Smrg miArcFacePtr right, 251706f2543Smrg miArcFacePtr left) 252706f2543Smrg{ 253706f2543Smrg int l = pGC->lineWidth; 254706f2543Smrg int a0, a1, startAngle, endAngle; 255706f2543Smrg miArcFacePtr temp; 256706f2543Smrg 257706f2543Smrg if (!l) 258706f2543Smrg l = 1; 259706f2543Smrg 260706f2543Smrg if (tarc.width == 0 || tarc.height == 0) { 261706f2543Smrg drawZeroArc (pDraw, pGC, &tarc, l, left, right); 262706f2543Smrg return; 263706f2543Smrg } 264706f2543Smrg 265706f2543Smrg if (pGC->miTranslate) { 266706f2543Smrg tarc.x += pDraw->x; 267706f2543Smrg tarc.y += pDraw->y; 268706f2543Smrg } 269706f2543Smrg 270706f2543Smrg a0 = tarc.angle1; 271706f2543Smrg a1 = tarc.angle2; 272706f2543Smrg if (a1 > FULLCIRCLE) 273706f2543Smrg a1 = FULLCIRCLE; 274706f2543Smrg else if (a1 < -FULLCIRCLE) 275706f2543Smrg a1 = -FULLCIRCLE; 276706f2543Smrg if (a1 < 0) { 277706f2543Smrg startAngle = a0 + a1; 278706f2543Smrg endAngle = a0; 279706f2543Smrg temp = right; 280706f2543Smrg right = left; 281706f2543Smrg left = temp; 282706f2543Smrg } else { 283706f2543Smrg startAngle = a0; 284706f2543Smrg endAngle = a0 + a1; 285706f2543Smrg } 286706f2543Smrg /* 287706f2543Smrg * bounds check the two angles 288706f2543Smrg */ 289706f2543Smrg if (startAngle < 0) 290706f2543Smrg startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE; 291706f2543Smrg if (startAngle >= FULLCIRCLE) 292706f2543Smrg startAngle = startAngle % FULLCIRCLE; 293706f2543Smrg if (endAngle < 0) 294706f2543Smrg endAngle = FULLCIRCLE - (-endAngle) % FULLCIRCLE; 295706f2543Smrg if (endAngle > FULLCIRCLE) 296706f2543Smrg endAngle = (endAngle-1) % FULLCIRCLE + 1; 297706f2543Smrg if ((startAngle == endAngle) && a1) { 298706f2543Smrg startAngle = 0; 299706f2543Smrg endAngle = FULLCIRCLE; 300706f2543Smrg } 301706f2543Smrg 302706f2543Smrg drawArc (&tarc, l, startAngle, endAngle, right, left); 303706f2543Smrg} 304706f2543Smrg 305706f2543Smrg/* 306706f2543Smrg 307706f2543SmrgThree equations combine to describe the boundaries of the arc 308706f2543Smrg 309706f2543Smrgx^2/w^2 + y^2/h^2 = 1 ellipse itself 310706f2543Smrg(X-x)^2 + (Y-y)^2 = r^2 circle at (x, y) on the ellipse 311706f2543Smrg(Y-y) = (X-x)*w^2*y/(h^2*x) normal at (x, y) on the ellipse 312706f2543Smrg 313706f2543SmrgThese lead to a quartic relating Y and y 314706f2543Smrg 315706f2543Smrgy^4 - (2Y)y^3 + (Y^2 + (h^4 - w^2*r^2)/(w^2 - h^2))y^2 316706f2543Smrg - (2Y*h^4/(w^2 - h^2))y + (Y^2*h^4)/(w^2 - h^2) = 0 317706f2543Smrg 318706f2543SmrgThe reducible cubic obtained from this quartic is 319706f2543Smrg 320706f2543Smrgz^3 - (3N)z^2 - 2V = 0 321706f2543Smrg 322706f2543Smrgwhere 323706f2543Smrg 324706f2543SmrgN = (Y^2 + (h^4 - w^2*r^2/(w^2 - h^2)))/6 325706f2543SmrgV = w^2*r^2*Y^2*h^4/(4 *(w^2 - h^2)^2) 326706f2543Smrg 327706f2543SmrgLet 328706f2543Smrg 329706f2543Smrgt = z - N 330706f2543Smrgp = -N^2 331706f2543Smrgq = -N^3 - V 332706f2543Smrg 333706f2543SmrgThen we get 334706f2543Smrg 335706f2543Smrgt^3 + 3pt + 2q = 0 336706f2543Smrg 337706f2543SmrgThe discriminant of this cubic is 338706f2543Smrg 339706f2543SmrgD = q^2 + p^3 340706f2543Smrg 341706f2543SmrgWhen D > 0, a real root is obtained as 342706f2543Smrg 343706f2543Smrgz = N + cbrt(-q+sqrt(D)) + cbrt(-q-sqrt(D)) 344706f2543Smrg 345706f2543SmrgWhen D < 0, a real root is obtained as 346706f2543Smrg 347706f2543Smrgz = N - 2m*cos(acos(-q/m^3)/3) 348706f2543Smrg 349706f2543Smrgwhere 350706f2543Smrg 351706f2543Smrgm = sqrt(|p|) * sign(q) 352706f2543Smrg 353706f2543SmrgGiven a real root Z of the cubic, the roots of the quartic are the roots 354706f2543Smrgof the two quadratics 355706f2543Smrg 356706f2543Smrgy^2 + ((b+A)/2)y + (Z + (bZ - d)/A) = 0 357706f2543Smrg 358706f2543Smrgwhere 359706f2543Smrg 360706f2543SmrgA = +/- sqrt(8Z + b^2 - 4c) 361706f2543Smrgb, c, d are the cubic, quadratic, and linear coefficients of the quartic 362706f2543Smrg 363706f2543SmrgSome experimentation is then required to determine which solutions 364706f2543Smrgcorrespond to the inner and outer boundaries. 365706f2543Smrg 366706f2543Smrg*/ 367706f2543Smrg 368706f2543Smrgtypedef struct { 369706f2543Smrg short lx, lw, rx, rw; 370706f2543Smrg} miArcSpan; 371706f2543Smrg 372706f2543Smrgtypedef struct { 373706f2543Smrg miArcSpan *spans; 374706f2543Smrg int count1, count2, k; 375706f2543Smrg char top, bot, hole; 376706f2543Smrg} miArcSpanData; 377706f2543Smrg 378706f2543Smrgstatic void drawQuadrant(struct arc_def *def, struct accelerators *acc, 379706f2543Smrg int a0, int a1, int mask, miArcFacePtr right, 380706f2543Smrg miArcFacePtr left, miArcSpanData *spdata); 381706f2543Smrg 382706f2543Smrgstatic void 383706f2543SmrgmiComputeCircleSpans( 384706f2543Smrg int lw, 385706f2543Smrg xArc *parc, 386706f2543Smrg miArcSpanData *spdata) 387706f2543Smrg{ 388706f2543Smrg miArcSpan *span; 389706f2543Smrg int doinner; 390706f2543Smrg int x, y, e; 391706f2543Smrg int xk, yk, xm, ym, dx, dy; 392706f2543Smrg int slw, inslw; 393706f2543Smrg int inx = 0, iny, ine = 0; 394706f2543Smrg int inxk = 0, inyk = 0, inxm = 0, inym = 0; 395706f2543Smrg 396706f2543Smrg doinner = -lw; 397706f2543Smrg slw = parc->width - doinner; 398706f2543Smrg y = parc->height >> 1; 399706f2543Smrg dy = parc->height & 1; 400706f2543Smrg dx = 1 - dy; 401706f2543Smrg MIWIDEARCSETUP(x, y, dy, slw, e, xk, xm, yk, ym); 402706f2543Smrg inslw = parc->width + doinner; 403706f2543Smrg if (inslw > 0) 404706f2543Smrg { 405706f2543Smrg spdata->hole = spdata->top; 406706f2543Smrg MIWIDEARCSETUP(inx, iny, dy, inslw, ine, inxk, inxm, inyk, inym); 407706f2543Smrg } 408706f2543Smrg else 409706f2543Smrg { 410706f2543Smrg spdata->hole = FALSE; 411706f2543Smrg doinner = -y; 412706f2543Smrg } 413706f2543Smrg spdata->count1 = -doinner - spdata->top; 414706f2543Smrg spdata->count2 = y + doinner; 415706f2543Smrg span = spdata->spans; 416706f2543Smrg while (y) 417706f2543Smrg { 418706f2543Smrg MIFILLARCSTEP(slw); 419706f2543Smrg span->lx = dy - x; 420706f2543Smrg if (++doinner <= 0) 421706f2543Smrg { 422706f2543Smrg span->lw = slw; 423706f2543Smrg span->rx = 0; 424706f2543Smrg span->rw = span->lx + slw; 425706f2543Smrg } 426706f2543Smrg else 427706f2543Smrg { 428706f2543Smrg MIFILLINARCSTEP(inslw); 429706f2543Smrg span->lw = x - inx; 430706f2543Smrg span->rx = dy - inx + inslw; 431706f2543Smrg span->rw = inx - x + slw - inslw; 432706f2543Smrg } 433706f2543Smrg span++; 434706f2543Smrg } 435706f2543Smrg if (spdata->bot) 436706f2543Smrg { 437706f2543Smrg if (spdata->count2) 438706f2543Smrg spdata->count2--; 439706f2543Smrg else 440706f2543Smrg { 441706f2543Smrg if (lw > (int)parc->height) 442706f2543Smrg span[-1].rx = span[-1].rw = -((lw - (int)parc->height) >> 1); 443706f2543Smrg else 444706f2543Smrg span[-1].rw = 0; 445706f2543Smrg spdata->count1--; 446706f2543Smrg } 447706f2543Smrg } 448706f2543Smrg} 449706f2543Smrg 450706f2543Smrgstatic void 451706f2543SmrgmiComputeEllipseSpans( 452706f2543Smrg int lw, 453706f2543Smrg xArc *parc, 454706f2543Smrg miArcSpanData *spdata) 455706f2543Smrg{ 456706f2543Smrg miArcSpan *span; 457706f2543Smrg double w, h, r, xorg; 458706f2543Smrg double Hs, Hf, WH, K, Vk, Nk, Fk, Vr, N, Nc, Z, rs; 459706f2543Smrg double A, T, b, d, x, y, t, inx, outx = 0.0, hepp, hepm; 460706f2543Smrg int flip, solution; 461706f2543Smrg 462706f2543Smrg w = (double)parc->width / 2.0; 463706f2543Smrg h = (double)parc->height / 2.0; 464706f2543Smrg r = lw / 2.0; 465706f2543Smrg rs = r * r; 466706f2543Smrg Hs = h * h; 467706f2543Smrg WH = w * w - Hs; 468706f2543Smrg Nk = w * r; 469706f2543Smrg Vk = (Nk * Hs) / (WH + WH); 470706f2543Smrg Hf = Hs * Hs; 471706f2543Smrg Nk = (Hf - Nk * Nk) / WH; 472706f2543Smrg Fk = Hf / WH; 473706f2543Smrg hepp = h + EPSILON; 474706f2543Smrg hepm = h - EPSILON; 475706f2543Smrg K = h + ((lw - 1) >> 1); 476706f2543Smrg span = spdata->spans; 477706f2543Smrg if (parc->width & 1) 478706f2543Smrg xorg = .5; 479706f2543Smrg else 480706f2543Smrg xorg = 0.0; 481706f2543Smrg if (spdata->top) 482706f2543Smrg { 483706f2543Smrg span->lx = 0; 484706f2543Smrg span->lw = 1; 485706f2543Smrg span++; 486706f2543Smrg } 487706f2543Smrg spdata->count1 = 0; 488706f2543Smrg spdata->count2 = 0; 489706f2543Smrg spdata->hole = (spdata->top && 490706f2543Smrg (int)parc->height * lw <= (int)(parc->width * parc->width) && 491706f2543Smrg lw < (int)parc->height); 492706f2543Smrg for (; K > 0.0; K -= 1.0) 493706f2543Smrg { 494706f2543Smrg N = (K * K + Nk) / 6.0; 495706f2543Smrg Nc = N * N * N; 496706f2543Smrg Vr = Vk * K; 497706f2543Smrg t = Nc + Vr * Vr; 498706f2543Smrg d = Nc + t; 499706f2543Smrg if (d < 0.0) { 500706f2543Smrg d = Nc; 501706f2543Smrg b = N; 502706f2543Smrg if ( (b < 0.0) == (t < 0.0) ) 503706f2543Smrg { 504706f2543Smrg b = -b; 505706f2543Smrg d = -d; 506706f2543Smrg } 507706f2543Smrg Z = N - 2.0 * b * cos(acos(-t / d) / 3.0); 508706f2543Smrg if ( (Z < 0.0) == (Vr < 0.0) ) 509706f2543Smrg flip = 2; 510706f2543Smrg else 511706f2543Smrg flip = 1; 512706f2543Smrg } 513706f2543Smrg else 514706f2543Smrg { 515706f2543Smrg d = Vr * sqrt(d); 516706f2543Smrg Z = N + cbrt(t + d) + cbrt(t - d); 517706f2543Smrg flip = 0; 518706f2543Smrg } 519706f2543Smrg A = sqrt((Z + Z) - Nk); 520706f2543Smrg T = (Fk - Z) * K / A; 521706f2543Smrg inx = 0.0; 522706f2543Smrg solution = FALSE; 523706f2543Smrg b = -A + K; 524706f2543Smrg d = b * b - 4 * (Z + T); 525706f2543Smrg if (d >= 0) 526706f2543Smrg { 527706f2543Smrg d = sqrt(d); 528706f2543Smrg y = (b + d) / 2; 529706f2543Smrg if ((y >= 0.0) && (y < hepp)) 530706f2543Smrg { 531706f2543Smrg solution = TRUE; 532706f2543Smrg if (y > hepm) 533706f2543Smrg y = h; 534706f2543Smrg t = y / h; 535706f2543Smrg x = w * sqrt(1 - (t * t)); 536706f2543Smrg t = K - y; 537706f2543Smrg if (rs - (t * t) >= 0) 538706f2543Smrg t = sqrt(rs - (t * t)); 539706f2543Smrg else 540706f2543Smrg t = 0; 541706f2543Smrg if (flip == 2) 542706f2543Smrg inx = x - t; 543706f2543Smrg else 544706f2543Smrg outx = x + t; 545706f2543Smrg } 546706f2543Smrg } 547706f2543Smrg b = A + K; 548706f2543Smrg d = b * b - 4 * (Z - T); 549706f2543Smrg /* Because of the large magnitudes involved, we lose enough precision 550706f2543Smrg * that sometimes we end up with a negative value near the axis, when 551706f2543Smrg * it should be positive. This is a workaround. 552706f2543Smrg */ 553706f2543Smrg if (d < 0 && !solution) 554706f2543Smrg d = 0.0; 555706f2543Smrg if (d >= 0) { 556706f2543Smrg d = sqrt(d); 557706f2543Smrg y = (b + d) / 2; 558706f2543Smrg if (y < hepp) 559706f2543Smrg { 560706f2543Smrg if (y > hepm) 561706f2543Smrg y = h; 562706f2543Smrg t = y / h; 563706f2543Smrg x = w * sqrt(1 - (t * t)); 564706f2543Smrg t = K - y; 565706f2543Smrg if (rs - (t * t) >= 0) 566706f2543Smrg inx = x - sqrt(rs - (t * t)); 567706f2543Smrg else 568706f2543Smrg inx = x; 569706f2543Smrg } 570706f2543Smrg y = (b - d) / 2; 571706f2543Smrg if (y >= 0.0) 572706f2543Smrg { 573706f2543Smrg if (y > hepm) 574706f2543Smrg y = h; 575706f2543Smrg t = y / h; 576706f2543Smrg x = w * sqrt(1 - (t * t)); 577706f2543Smrg t = K - y; 578706f2543Smrg if (rs - (t * t) >= 0) 579706f2543Smrg t = sqrt(rs - (t * t)); 580706f2543Smrg else 581706f2543Smrg t = 0; 582706f2543Smrg if (flip == 1) 583706f2543Smrg inx = x - t; 584706f2543Smrg else 585706f2543Smrg outx = x + t; 586706f2543Smrg } 587706f2543Smrg } 588706f2543Smrg span->lx = ICEIL(xorg - outx); 589706f2543Smrg if (inx <= 0.0) 590706f2543Smrg { 591706f2543Smrg spdata->count1++; 592706f2543Smrg span->lw = ICEIL(xorg + outx) - span->lx; 593706f2543Smrg span->rx = ICEIL(xorg + inx); 594706f2543Smrg span->rw = -ICEIL(xorg - inx); 595706f2543Smrg } 596706f2543Smrg else 597706f2543Smrg { 598706f2543Smrg spdata->count2++; 599706f2543Smrg span->lw = ICEIL(xorg - inx) - span->lx; 600706f2543Smrg span->rx = ICEIL(xorg + inx); 601706f2543Smrg span->rw = ICEIL(xorg + outx) - span->rx; 602706f2543Smrg } 603706f2543Smrg span++; 604706f2543Smrg } 605706f2543Smrg if (spdata->bot) 606706f2543Smrg { 607706f2543Smrg outx = w + r; 608706f2543Smrg if (r >= h && r <= w) 609706f2543Smrg inx = 0.0; 610706f2543Smrg else if (Nk < 0.0 && -Nk < Hs) 611706f2543Smrg { 612706f2543Smrg inx = w * sqrt(1 + Nk / Hs) - sqrt(rs + Nk); 613706f2543Smrg if (inx > w - r) 614706f2543Smrg inx = w - r; 615706f2543Smrg } 616706f2543Smrg else 617706f2543Smrg inx = w - r; 618706f2543Smrg span->lx = ICEIL(xorg - outx); 619706f2543Smrg if (inx <= 0.0) 620706f2543Smrg { 621706f2543Smrg span->lw = ICEIL(xorg + outx) - span->lx; 622706f2543Smrg span->rx = ICEIL(xorg + inx); 623706f2543Smrg span->rw = -ICEIL(xorg - inx); 624706f2543Smrg } 625706f2543Smrg else 626706f2543Smrg { 627706f2543Smrg span->lw = ICEIL(xorg - inx) - span->lx; 628706f2543Smrg span->rx = ICEIL(xorg + inx); 629706f2543Smrg span->rw = ICEIL(xorg + outx) - span->rx; 630706f2543Smrg } 631706f2543Smrg } 632706f2543Smrg if (spdata->hole) 633706f2543Smrg { 634706f2543Smrg span = &spdata->spans[spdata->count1]; 635706f2543Smrg span->lw = -span->lx; 636706f2543Smrg span->rx = 1; 637706f2543Smrg span->rw = span->lw; 638706f2543Smrg spdata->count1--; 639706f2543Smrg spdata->count2++; 640706f2543Smrg } 641706f2543Smrg} 642706f2543Smrg 643706f2543Smrgstatic double 644706f2543SmrgtailX( 645706f2543Smrg double K, 646706f2543Smrg struct arc_def *def, 647706f2543Smrg struct arc_bound *bounds, 648706f2543Smrg struct accelerators *acc) 649706f2543Smrg{ 650706f2543Smrg double w, h, r; 651706f2543Smrg double Hs, Hf, WH, Vk, Nk, Fk, Vr, N, Nc, Z, rs; 652706f2543Smrg double A, T, b, d, x, y, t, hepp, hepm; 653706f2543Smrg int flip, solution; 654706f2543Smrg double xs[2]; 655706f2543Smrg double *xp; 656706f2543Smrg 657706f2543Smrg w = def->w; 658706f2543Smrg h = def->h; 659706f2543Smrg r = def->l; 660706f2543Smrg rs = r * r; 661706f2543Smrg Hs = acc->h2; 662706f2543Smrg WH = -acc->h2mw2; 663706f2543Smrg Nk = def->w * r; 664706f2543Smrg Vk = (Nk * Hs) / (WH + WH); 665706f2543Smrg Hf = acc->h4; 666706f2543Smrg Nk = (Hf - Nk * Nk) / WH; 667706f2543Smrg if (K == 0.0) { 668706f2543Smrg if (Nk < 0.0 && -Nk < Hs) { 669706f2543Smrg xs[0] = w * sqrt(1 + Nk / Hs) - sqrt(rs + Nk); 670706f2543Smrg xs[1] = w - r; 671706f2543Smrg if (acc->left.valid && boundedLe(K, bounds->left) && 672706f2543Smrg !boundedLe(K, bounds->outer) && xs[0] >= 0.0 && xs[1] >= 0.0) 673706f2543Smrg return xs[1]; 674706f2543Smrg if (acc->right.valid && boundedLe(K, bounds->right) && 675706f2543Smrg !boundedLe(K, bounds->inner) && xs[0] <= 0.0 && xs[1] <= 0.0) 676706f2543Smrg return xs[1]; 677706f2543Smrg return xs[0]; 678706f2543Smrg } 679706f2543Smrg return w - r; 680706f2543Smrg } 681706f2543Smrg Fk = Hf / WH; 682706f2543Smrg hepp = h + EPSILON; 683706f2543Smrg hepm = h - EPSILON; 684706f2543Smrg N = (K * K + Nk) / 6.0; 685706f2543Smrg Nc = N * N * N; 686706f2543Smrg Vr = Vk * K; 687706f2543Smrg xp = xs; 688706f2543Smrg xs[0] = 0.0; 689706f2543Smrg t = Nc + Vr * Vr; 690706f2543Smrg d = Nc + t; 691706f2543Smrg if (d < 0.0) { 692706f2543Smrg d = Nc; 693706f2543Smrg b = N; 694706f2543Smrg if ( (b < 0.0) == (t < 0.0) ) 695706f2543Smrg { 696706f2543Smrg b = -b; 697706f2543Smrg d = -d; 698706f2543Smrg } 699706f2543Smrg Z = N - 2.0 * b * cos(acos(-t / d) / 3.0); 700706f2543Smrg if ( (Z < 0.0) == (Vr < 0.0) ) 701706f2543Smrg flip = 2; 702706f2543Smrg else 703706f2543Smrg flip = 1; 704706f2543Smrg } 705706f2543Smrg else 706706f2543Smrg { 707706f2543Smrg d = Vr * sqrt(d); 708706f2543Smrg Z = N + cbrt(t + d) + cbrt(t - d); 709706f2543Smrg flip = 0; 710706f2543Smrg } 711706f2543Smrg A = sqrt((Z + Z) - Nk); 712706f2543Smrg T = (Fk - Z) * K / A; 713706f2543Smrg solution = FALSE; 714706f2543Smrg b = -A + K; 715706f2543Smrg d = b * b - 4 * (Z + T); 716706f2543Smrg if (d >= 0 && flip == 2) 717706f2543Smrg { 718706f2543Smrg d = sqrt(d); 719706f2543Smrg y = (b + d) / 2; 720706f2543Smrg if ((y >= 0.0) && (y < hepp)) 721706f2543Smrg { 722706f2543Smrg solution = TRUE; 723706f2543Smrg if (y > hepm) 724706f2543Smrg y = h; 725706f2543Smrg t = y / h; 726706f2543Smrg x = w * sqrt(1 - (t * t)); 727706f2543Smrg t = K - y; 728706f2543Smrg if (rs - (t * t) >= 0) 729706f2543Smrg t = sqrt(rs - (t * t)); 730706f2543Smrg else 731706f2543Smrg t = 0; 732706f2543Smrg *xp++ = x - t; 733706f2543Smrg } 734706f2543Smrg } 735706f2543Smrg b = A + K; 736706f2543Smrg d = b * b - 4 * (Z - T); 737706f2543Smrg /* Because of the large magnitudes involved, we lose enough precision 738706f2543Smrg * that sometimes we end up with a negative value near the axis, when 739706f2543Smrg * it should be positive. This is a workaround. 740706f2543Smrg */ 741706f2543Smrg if (d < 0 && !solution) 742706f2543Smrg d = 0.0; 743706f2543Smrg if (d >= 0) { 744706f2543Smrg d = sqrt(d); 745706f2543Smrg y = (b + d) / 2; 746706f2543Smrg if (y < hepp) 747706f2543Smrg { 748706f2543Smrg if (y > hepm) 749706f2543Smrg y = h; 750706f2543Smrg t = y / h; 751706f2543Smrg x = w * sqrt(1 - (t * t)); 752706f2543Smrg t = K - y; 753706f2543Smrg if (rs - (t * t) >= 0) 754706f2543Smrg *xp++ = x - sqrt(rs - (t * t)); 755706f2543Smrg else 756706f2543Smrg *xp++ = x; 757706f2543Smrg } 758706f2543Smrg y = (b - d) / 2; 759706f2543Smrg if (y >= 0.0 && flip == 1) 760706f2543Smrg { 761706f2543Smrg if (y > hepm) 762706f2543Smrg y = h; 763706f2543Smrg t = y / h; 764706f2543Smrg x = w * sqrt(1 - (t * t)); 765706f2543Smrg t = K - y; 766706f2543Smrg if (rs - (t * t) >= 0) 767706f2543Smrg t = sqrt(rs - (t * t)); 768706f2543Smrg else 769706f2543Smrg t = 0; 770706f2543Smrg *xp++ = x - t; 771706f2543Smrg } 772706f2543Smrg } 773706f2543Smrg if (xp > &xs[1]) { 774706f2543Smrg if (acc->left.valid && boundedLe(K, bounds->left) && 775706f2543Smrg !boundedLe(K, bounds->outer) && xs[0] >= 0.0 && xs[1] >= 0.0) 776706f2543Smrg return xs[1]; 777706f2543Smrg if (acc->right.valid && boundedLe(K, bounds->right) && 778706f2543Smrg !boundedLe(K, bounds->inner) && xs[0] <= 0.0 && xs[1] <= 0.0) 779706f2543Smrg return xs[1]; 780706f2543Smrg } 781706f2543Smrg return xs[0]; 782706f2543Smrg} 783706f2543Smrg 784706f2543Smrgstatic miArcSpanData * 785706f2543SmrgmiComputeWideEllipse(int lw, xArc *parc) 786706f2543Smrg{ 787706f2543Smrg miArcSpanData *spdata = NULL; 788706f2543Smrg int k; 789706f2543Smrg 790706f2543Smrg if (!lw) 791706f2543Smrg lw = 1; 792706f2543Smrg k = (parc->height >> 1) + ((lw - 1) >> 1); 793706f2543Smrg spdata = malloc(sizeof(miArcSpanData) + sizeof(miArcSpan) * (k + 2)); 794706f2543Smrg if (!spdata) 795706f2543Smrg return NULL; 796706f2543Smrg spdata->spans = (miArcSpan *)(spdata + 1); 797706f2543Smrg spdata->k = k; 798706f2543Smrg spdata->top = !(lw & 1) && !(parc->width & 1); 799706f2543Smrg spdata->bot = !(parc->height & 1); 800706f2543Smrg if (parc->width == parc->height) 801706f2543Smrg miComputeCircleSpans(lw, parc, spdata); 802706f2543Smrg else 803706f2543Smrg miComputeEllipseSpans(lw, parc, spdata); 804706f2543Smrg return spdata; 805706f2543Smrg} 806706f2543Smrg 807706f2543Smrgstatic void 808706f2543SmrgmiFillWideEllipse( 809706f2543Smrg DrawablePtr pDraw, 810706f2543Smrg GCPtr pGC, 811706f2543Smrg xArc *parc) 812706f2543Smrg{ 813706f2543Smrg DDXPointPtr points; 814706f2543Smrg DDXPointPtr pts; 815706f2543Smrg int *widths; 816706f2543Smrg int *wids; 817706f2543Smrg miArcSpanData *spdata; 818706f2543Smrg miArcSpan *span; 819706f2543Smrg int xorg, yorgu, yorgl; 820706f2543Smrg int n; 821706f2543Smrg 822706f2543Smrg yorgu = parc->height + pGC->lineWidth; 823706f2543Smrg n = (sizeof(int) * 2) * yorgu; 824706f2543Smrg widths = malloc(n + (sizeof(DDXPointRec) * 2) * yorgu); 825706f2543Smrg if (!widths) 826706f2543Smrg return; 827706f2543Smrg points = (DDXPointPtr)((char *)widths + n); 828706f2543Smrg spdata = miComputeWideEllipse((int)pGC->lineWidth, parc); 829706f2543Smrg if (!spdata) 830706f2543Smrg { 831706f2543Smrg free(widths); 832706f2543Smrg return; 833706f2543Smrg } 834706f2543Smrg pts = points; 835706f2543Smrg wids = widths; 836706f2543Smrg span = spdata->spans; 837706f2543Smrg xorg = parc->x + (parc->width >> 1); 838706f2543Smrg yorgu = parc->y + (parc->height >> 1); 839706f2543Smrg yorgl = yorgu + (parc->height & 1); 840706f2543Smrg if (pGC->miTranslate) 841706f2543Smrg { 842706f2543Smrg xorg += pDraw->x; 843706f2543Smrg yorgu += pDraw->y; 844706f2543Smrg yorgl += pDraw->y; 845706f2543Smrg } 846706f2543Smrg yorgu -= spdata->k; 847706f2543Smrg yorgl += spdata->k; 848706f2543Smrg if (spdata->top) 849706f2543Smrg { 850706f2543Smrg pts->x = xorg; 851706f2543Smrg pts->y = yorgu - 1; 852706f2543Smrg pts++; 853706f2543Smrg *wids++ = 1; 854706f2543Smrg span++; 855706f2543Smrg } 856706f2543Smrg for (n = spdata->count1; --n >= 0; ) 857706f2543Smrg { 858706f2543Smrg pts[0].x = xorg + span->lx; 859706f2543Smrg pts[0].y = yorgu; 860706f2543Smrg wids[0] = span->lw; 861706f2543Smrg pts[1].x = pts[0].x; 862706f2543Smrg pts[1].y = yorgl; 863706f2543Smrg wids[1] = wids[0]; 864706f2543Smrg yorgu++; 865706f2543Smrg yorgl--; 866706f2543Smrg pts += 2; 867706f2543Smrg wids += 2; 868706f2543Smrg span++; 869706f2543Smrg } 870706f2543Smrg if (spdata->hole) 871706f2543Smrg { 872706f2543Smrg pts[0].x = xorg; 873706f2543Smrg pts[0].y = yorgl; 874706f2543Smrg wids[0] = 1; 875706f2543Smrg pts++; 876706f2543Smrg wids++; 877706f2543Smrg } 878706f2543Smrg for (n = spdata->count2; --n >= 0; ) 879706f2543Smrg { 880706f2543Smrg pts[0].x = xorg + span->lx; 881706f2543Smrg pts[0].y = yorgu; 882706f2543Smrg wids[0] = span->lw; 883706f2543Smrg pts[1].x = xorg + span->rx; 884706f2543Smrg pts[1].y = pts[0].y; 885706f2543Smrg wids[1] = span->rw; 886706f2543Smrg pts[2].x = pts[0].x; 887706f2543Smrg pts[2].y = yorgl; 888706f2543Smrg wids[2] = wids[0]; 889706f2543Smrg pts[3].x = pts[1].x; 890706f2543Smrg pts[3].y = pts[2].y; 891706f2543Smrg wids[3] = wids[1]; 892706f2543Smrg yorgu++; 893706f2543Smrg yorgl--; 894706f2543Smrg pts += 4; 895706f2543Smrg wids += 4; 896706f2543Smrg span++; 897706f2543Smrg } 898706f2543Smrg if (spdata->bot) 899706f2543Smrg { 900706f2543Smrg if (span->rw <= 0) 901706f2543Smrg { 902706f2543Smrg pts[0].x = xorg + span->lx; 903706f2543Smrg pts[0].y = yorgu; 904706f2543Smrg wids[0] = span->lw; 905706f2543Smrg pts++; 906706f2543Smrg wids++; 907706f2543Smrg } 908706f2543Smrg else 909706f2543Smrg { 910706f2543Smrg pts[0].x = xorg + span->lx; 911706f2543Smrg pts[0].y = yorgu; 912706f2543Smrg wids[0] = span->lw; 913706f2543Smrg pts[1].x = xorg + span->rx; 914706f2543Smrg pts[1].y = pts[0].y; 915706f2543Smrg wids[1] = span->rw; 916706f2543Smrg pts += 2; 917706f2543Smrg wids += 2; 918706f2543Smrg } 919706f2543Smrg } 920706f2543Smrg free(spdata); 921706f2543Smrg (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE); 922706f2543Smrg 923706f2543Smrg free(widths); 924706f2543Smrg} 925706f2543Smrg 926706f2543Smrg/* 927706f2543Smrg * miPolyArc strategy: 928706f2543Smrg * 929706f2543Smrg * If arc is zero width and solid, we don't have to worry about the rasterop 930706f2543Smrg * or join styles. For wide solid circles, we use a fast integer algorithm. 931706f2543Smrg * For wide solid ellipses, we use special case floating point code. 932706f2543Smrg * Otherwise, we set up pDrawTo and pGCTo according to the rasterop, then 933706f2543Smrg * draw using pGCTo and pDrawTo. If the raster-op was "tricky," that is, 934706f2543Smrg * if it involves the destination, then we use PushPixels to move the bits 935706f2543Smrg * from the scratch drawable to pDraw. (See the wide line code for a 936706f2543Smrg * fuller explanation of this.) 937706f2543Smrg */ 938706f2543Smrg 939706f2543Smrgvoid 940706f2543SmrgmiPolyArc(DrawablePtr pDraw, GCPtr pGC, int narcs, xArc *parcs) 941706f2543Smrg{ 942706f2543Smrg int i; 943706f2543Smrg xArc *parc; 944706f2543Smrg int xMin, xMax, yMin, yMax; 945706f2543Smrg int pixmapWidth = 0, pixmapHeight = 0; 946706f2543Smrg int xOrg = 0, yOrg = 0; 947706f2543Smrg int width; 948706f2543Smrg Bool fTricky; 949706f2543Smrg DrawablePtr pDrawTo; 950706f2543Smrg CARD32 fg, bg; 951706f2543Smrg GCPtr pGCTo; 952706f2543Smrg miPolyArcPtr polyArcs; 953706f2543Smrg int cap[2], join[2]; 954706f2543Smrg int iphase; 955706f2543Smrg int halfWidth; 956706f2543Smrg 957706f2543Smrg width = pGC->lineWidth; 958706f2543Smrg if(width == 0 && pGC->lineStyle == LineSolid) 959706f2543Smrg { 960706f2543Smrg for(i = narcs, parc = parcs; --i >= 0; parc++) 961706f2543Smrg miArcSegment( pDraw, pGC, *parc, 962706f2543Smrg (miArcFacePtr) 0, (miArcFacePtr) 0 ); 963706f2543Smrg fillSpans (pDraw, pGC); 964706f2543Smrg } 965706f2543Smrg else 966706f2543Smrg { 967706f2543Smrg if ((pGC->lineStyle == LineSolid) && narcs) 968706f2543Smrg { 969706f2543Smrg while (parcs->width && parcs->height && 970706f2543Smrg (parcs->angle2 >= FULLCIRCLE || 971706f2543Smrg parcs->angle2 <= -FULLCIRCLE)) 972706f2543Smrg { 973706f2543Smrg miFillWideEllipse(pDraw, pGC, parcs); 974706f2543Smrg if (!--narcs) 975706f2543Smrg return; 976706f2543Smrg parcs++; 977706f2543Smrg } 978706f2543Smrg } 979706f2543Smrg 980706f2543Smrg /* Set up pDrawTo and pGCTo based on the rasterop */ 981706f2543Smrg switch(pGC->alu) 982706f2543Smrg { 983706f2543Smrg case GXclear: /* 0 */ 984706f2543Smrg case GXcopy: /* src */ 985706f2543Smrg case GXcopyInverted: /* NOT src */ 986706f2543Smrg case GXset: /* 1 */ 987706f2543Smrg fTricky = FALSE; 988706f2543Smrg pDrawTo = pDraw; 989706f2543Smrg pGCTo = pGC; 990706f2543Smrg break; 991706f2543Smrg default: 992706f2543Smrg fTricky = TRUE; 993706f2543Smrg 994706f2543Smrg /* find bounding box around arcs */ 995706f2543Smrg xMin = yMin = MAXSHORT; 996706f2543Smrg xMax = yMax = MINSHORT; 997706f2543Smrg 998706f2543Smrg for(i = narcs, parc = parcs; --i >= 0; parc++) 999706f2543Smrg { 1000706f2543Smrg xMin = min (xMin, parc->x); 1001706f2543Smrg yMin = min (yMin, parc->y); 1002706f2543Smrg xMax = max (xMax, (parc->x + (int) parc->width)); 1003706f2543Smrg yMax = max (yMax, (parc->y + (int) parc->height)); 1004706f2543Smrg } 1005706f2543Smrg 1006706f2543Smrg /* expand box to deal with line widths */ 1007706f2543Smrg halfWidth = (width + 1)/2; 1008706f2543Smrg xMin -= halfWidth; 1009706f2543Smrg yMin -= halfWidth; 1010706f2543Smrg xMax += halfWidth; 1011706f2543Smrg yMax += halfWidth; 1012706f2543Smrg 1013706f2543Smrg /* compute pixmap size; limit it to size of drawable */ 1014706f2543Smrg xOrg = max(xMin, 0); 1015706f2543Smrg yOrg = max(yMin, 0); 1016706f2543Smrg pixmapWidth = min(xMax, pDraw->width) - xOrg; 1017706f2543Smrg pixmapHeight = min(yMax, pDraw->height) - yOrg; 1018706f2543Smrg 1019706f2543Smrg /* if nothing left, return */ 1020706f2543Smrg if ( (pixmapWidth <= 0) || (pixmapHeight <= 0) ) return; 1021706f2543Smrg 1022706f2543Smrg for(i = narcs, parc = parcs; --i >= 0; parc++) 1023706f2543Smrg { 1024706f2543Smrg parc->x -= xOrg; 1025706f2543Smrg parc->y -= yOrg; 1026706f2543Smrg } 1027706f2543Smrg if (pGC->miTranslate) 1028706f2543Smrg { 1029706f2543Smrg xOrg += pDraw->x; 1030706f2543Smrg yOrg += pDraw->y; 1031706f2543Smrg } 1032706f2543Smrg 1033706f2543Smrg /* set up scratch GC */ 1034706f2543Smrg 1035706f2543Smrg pGCTo = GetScratchGC(1, pDraw->pScreen); 1036706f2543Smrg if (!pGCTo) 1037706f2543Smrg return; 1038706f2543Smrg { 1039706f2543Smrg ChangeGCVal gcvals[6]; 1040706f2543Smrg gcvals[0].val = GXcopy; 1041706f2543Smrg gcvals[1].val = 1; 1042706f2543Smrg gcvals[2].val = 0; 1043706f2543Smrg gcvals[3].val = pGC->lineWidth; 1044706f2543Smrg gcvals[4].val = pGC->capStyle; 1045706f2543Smrg gcvals[5].val = pGC->joinStyle; 1046706f2543Smrg ChangeGC(NullClient, pGCTo, GCFunction | 1047706f2543Smrg GCForeground | GCBackground | GCLineWidth | 1048706f2543Smrg GCCapStyle | GCJoinStyle, gcvals); 1049706f2543Smrg } 1050706f2543Smrg 1051706f2543Smrg /* allocate a 1 bit deep pixmap of the appropriate size, and 1052706f2543Smrg * validate it */ 1053706f2543Smrg pDrawTo = (DrawablePtr)(*pDraw->pScreen->CreatePixmap) 1054706f2543Smrg (pDraw->pScreen, pixmapWidth, pixmapHeight, 1, 1055706f2543Smrg CREATE_PIXMAP_USAGE_SCRATCH); 1056706f2543Smrg if (!pDrawTo) 1057706f2543Smrg { 1058706f2543Smrg FreeScratchGC(pGCTo); 1059706f2543Smrg return; 1060706f2543Smrg } 1061706f2543Smrg ValidateGC(pDrawTo, pGCTo); 1062706f2543Smrg miClearDrawable(pDrawTo, pGCTo); 1063706f2543Smrg } 1064706f2543Smrg 1065706f2543Smrg fg = pGC->fgPixel; 1066706f2543Smrg bg = pGC->bgPixel; 1067706f2543Smrg if ((pGC->fillStyle == FillTiled) || 1068706f2543Smrg (pGC->fillStyle == FillOpaqueStippled)) 1069706f2543Smrg bg = fg; /* the protocol sez these don't cause color changes */ 1070706f2543Smrg 1071706f2543Smrg polyArcs = miComputeArcs (parcs, narcs, pGC); 1072706f2543Smrg 1073706f2543Smrg if (!polyArcs) 1074706f2543Smrg { 1075706f2543Smrg if (fTricky) { 1076706f2543Smrg (*pDraw->pScreen->DestroyPixmap) ((PixmapPtr)pDrawTo); 1077706f2543Smrg FreeScratchGC (pGCTo); 1078706f2543Smrg } 1079706f2543Smrg return; 1080706f2543Smrg } 1081706f2543Smrg 1082706f2543Smrg cap[0] = cap[1] = 0; 1083706f2543Smrg join[0] = join[1] = 0; 1084706f2543Smrg for (iphase = ((pGC->lineStyle == LineDoubleDash) ? 1 : 0); 1085706f2543Smrg iphase >= 0; 1086706f2543Smrg iphase--) 1087706f2543Smrg { 1088706f2543Smrg ChangeGCVal gcval; 1089706f2543Smrg if (iphase == 1) { 1090706f2543Smrg gcval.val = bg; 1091706f2543Smrg ChangeGC (NullClient, pGC, GCForeground, &gcval); 1092706f2543Smrg ValidateGC (pDraw, pGC); 1093706f2543Smrg } else if (pGC->lineStyle == LineDoubleDash) { 1094706f2543Smrg gcval.val = fg; 1095706f2543Smrg ChangeGC (NullClient, pGC, GCForeground, &gcval); 1096706f2543Smrg ValidateGC (pDraw, pGC); 1097706f2543Smrg } 1098706f2543Smrg for (i = 0; i < polyArcs[iphase].narcs; i++) { 1099706f2543Smrg miArcDataPtr arcData; 1100706f2543Smrg 1101706f2543Smrg arcData = &polyArcs[iphase].arcs[i]; 1102706f2543Smrg miArcSegment(pDrawTo, pGCTo, arcData->arc, 1103706f2543Smrg &arcData->bounds[RIGHT_END], 1104706f2543Smrg &arcData->bounds[LEFT_END]); 1105706f2543Smrg if (polyArcs[iphase].arcs[i].render) { 1106706f2543Smrg fillSpans (pDrawTo, pGCTo); 1107706f2543Smrg /* 1108706f2543Smrg * don't cap self-joining arcs 1109706f2543Smrg */ 1110706f2543Smrg if (polyArcs[iphase].arcs[i].selfJoin && 1111706f2543Smrg cap[iphase] < polyArcs[iphase].arcs[i].cap) 1112706f2543Smrg cap[iphase]++; 1113706f2543Smrg while (cap[iphase] < polyArcs[iphase].arcs[i].cap) { 1114706f2543Smrg int arcIndex, end; 1115706f2543Smrg miArcDataPtr arcData0; 1116706f2543Smrg 1117706f2543Smrg arcIndex = polyArcs[iphase].caps[cap[iphase]].arcIndex; 1118706f2543Smrg end = polyArcs[iphase].caps[cap[iphase]].end; 1119706f2543Smrg arcData0 = &polyArcs[iphase].arcs[arcIndex]; 1120706f2543Smrg miArcCap (pDrawTo, pGCTo, 1121706f2543Smrg &arcData0->bounds[end], end, 1122706f2543Smrg arcData0->arc.x, arcData0->arc.y, 1123706f2543Smrg (double) arcData0->arc.width / 2.0, 1124706f2543Smrg (double) arcData0->arc.height / 2.0); 1125706f2543Smrg ++cap[iphase]; 1126706f2543Smrg } 1127706f2543Smrg while (join[iphase] < polyArcs[iphase].arcs[i].join) { 1128706f2543Smrg int arcIndex0, arcIndex1, end0, end1; 1129706f2543Smrg int phase0, phase1; 1130706f2543Smrg miArcDataPtr arcData0, arcData1; 1131706f2543Smrg miArcJoinPtr joinp; 1132706f2543Smrg 1133706f2543Smrg joinp = &polyArcs[iphase].joins[join[iphase]]; 1134706f2543Smrg arcIndex0 = joinp->arcIndex0; 1135706f2543Smrg end0 = joinp->end0; 1136706f2543Smrg arcIndex1 = joinp->arcIndex1; 1137706f2543Smrg end1 = joinp->end1; 1138706f2543Smrg phase0 = joinp->phase0; 1139706f2543Smrg phase1 = joinp->phase1; 1140706f2543Smrg arcData0 = &polyArcs[phase0].arcs[arcIndex0]; 1141706f2543Smrg arcData1 = &polyArcs[phase1].arcs[arcIndex1]; 1142706f2543Smrg miArcJoin (pDrawTo, pGCTo, 1143706f2543Smrg &arcData0->bounds[end0], 1144706f2543Smrg &arcData1->bounds[end1], 1145706f2543Smrg arcData0->arc.x, arcData0->arc.y, 1146706f2543Smrg (double) arcData0->arc.width / 2.0, 1147706f2543Smrg (double) arcData0->arc.height / 2.0, 1148706f2543Smrg arcData1->arc.x, arcData1->arc.y, 1149706f2543Smrg (double) arcData1->arc.width / 2.0, 1150706f2543Smrg (double) arcData1->arc.height / 2.0); 1151706f2543Smrg ++join[iphase]; 1152706f2543Smrg } 1153706f2543Smrg if (fTricky) { 1154706f2543Smrg if (pGC->serialNumber != pDraw->serialNumber) 1155706f2543Smrg ValidateGC (pDraw, pGC); 1156706f2543Smrg (*pGC->ops->PushPixels) (pGC, (PixmapPtr)pDrawTo, 1157706f2543Smrg pDraw, pixmapWidth, pixmapHeight, xOrg, yOrg); 1158706f2543Smrg miClearDrawable ((DrawablePtr) pDrawTo, pGCTo); 1159706f2543Smrg } 1160706f2543Smrg } 1161706f2543Smrg } 1162706f2543Smrg } 1163706f2543Smrg miFreeArcs(polyArcs, pGC); 1164706f2543Smrg 1165706f2543Smrg if(fTricky) 1166706f2543Smrg { 1167706f2543Smrg (*pGCTo->pScreen->DestroyPixmap)((PixmapPtr)pDrawTo); 1168706f2543Smrg FreeScratchGC(pGCTo); 1169706f2543Smrg } 1170706f2543Smrg } 1171706f2543Smrg} 1172706f2543Smrg 1173706f2543Smrgstatic double 1174706f2543SmrgangleBetween (SppPointRec center, SppPointRec point1, SppPointRec point2) 1175706f2543Smrg{ 1176706f2543Smrg double a1, a2, a; 1177706f2543Smrg 1178706f2543Smrg /* 1179706f2543Smrg * reflect from X coordinates back to ellipse 1180706f2543Smrg * coordinates -- y increasing upwards 1181706f2543Smrg */ 1182706f2543Smrg a1 = miDatan2 (- (point1.y - center.y), point1.x - center.x); 1183706f2543Smrg a2 = miDatan2 (- (point2.y - center.y), point2.x - center.x); 1184706f2543Smrg a = a2 - a1; 1185706f2543Smrg if (a <= -180.0) 1186706f2543Smrg a += 360.0; 1187706f2543Smrg else if (a > 180.0) 1188706f2543Smrg a -= 360.0; 1189706f2543Smrg return a; 1190706f2543Smrg} 1191706f2543Smrg 1192706f2543Smrgstatic void 1193706f2543SmrgtranslateBounds ( 1194706f2543Smrg miArcFacePtr b, 1195706f2543Smrg int x, 1196706f2543Smrg int y, 1197706f2543Smrg double fx, 1198706f2543Smrg double fy) 1199706f2543Smrg{ 1200706f2543Smrg fx += x; 1201706f2543Smrg fy += y; 1202706f2543Smrg b->clock.x -= fx; 1203706f2543Smrg b->clock.y -= fy; 1204706f2543Smrg b->center.x -= fx; 1205706f2543Smrg b->center.y -= fy; 1206706f2543Smrg b->counterClock.x -= fx; 1207706f2543Smrg b->counterClock.y -= fy; 1208706f2543Smrg} 1209706f2543Smrg 1210706f2543Smrgstatic void 1211706f2543SmrgmiArcJoin(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pLeft, 1212706f2543Smrg miArcFacePtr pRight, int xOrgLeft, int yOrgLeft, 1213706f2543Smrg double xFtransLeft, double yFtransLeft, 1214706f2543Smrg int xOrgRight, int yOrgRight, 1215706f2543Smrg double xFtransRight, double yFtransRight) 1216706f2543Smrg{ 1217706f2543Smrg SppPointRec center, corner, otherCorner; 1218706f2543Smrg SppPointRec poly[5], e; 1219706f2543Smrg SppPointPtr pArcPts; 1220706f2543Smrg int cpt; 1221706f2543Smrg SppArcRec arc; 1222706f2543Smrg miArcFaceRec Right, Left; 1223706f2543Smrg int polyLen = 0; 1224706f2543Smrg int xOrg, yOrg; 1225706f2543Smrg double xFtrans, yFtrans; 1226706f2543Smrg double a; 1227706f2543Smrg double ae, ac2, ec2, bc2, de; 1228706f2543Smrg double width; 1229706f2543Smrg 1230706f2543Smrg xOrg = (xOrgRight + xOrgLeft) / 2; 1231706f2543Smrg yOrg = (yOrgRight + yOrgLeft) / 2; 1232706f2543Smrg xFtrans = (xFtransLeft + xFtransRight) / 2; 1233706f2543Smrg yFtrans = (yFtransLeft + yFtransRight) / 2; 1234706f2543Smrg Right = *pRight; 1235706f2543Smrg translateBounds (&Right, xOrg - xOrgRight, yOrg - yOrgRight, 1236706f2543Smrg xFtrans - xFtransRight, yFtrans - yFtransRight); 1237706f2543Smrg Left = *pLeft; 1238706f2543Smrg translateBounds (&Left, xOrg - xOrgLeft, yOrg - yOrgLeft, 1239706f2543Smrg xFtrans - xFtransLeft, yFtrans - yFtransLeft); 1240706f2543Smrg pRight = &Right; 1241706f2543Smrg pLeft = &Left; 1242706f2543Smrg 1243706f2543Smrg if (pRight->clock.x == pLeft->counterClock.x && 1244706f2543Smrg pRight->clock.y == pLeft->counterClock.y) 1245706f2543Smrg return; 1246706f2543Smrg center = pRight->center; 1247706f2543Smrg if (0 <= (a = angleBetween (center, pRight->clock, pLeft->counterClock)) 1248706f2543Smrg && a <= 180.0) 1249706f2543Smrg { 1250706f2543Smrg corner = pRight->clock; 1251706f2543Smrg otherCorner = pLeft->counterClock; 1252706f2543Smrg } else { 1253706f2543Smrg a = angleBetween (center, pLeft->clock, pRight->counterClock); 1254706f2543Smrg corner = pLeft->clock; 1255706f2543Smrg otherCorner = pRight->counterClock; 1256706f2543Smrg } 1257706f2543Smrg switch (pGC->joinStyle) { 1258706f2543Smrg case JoinRound: 1259706f2543Smrg width = (pGC->lineWidth ? (double)pGC->lineWidth : (double)1); 1260706f2543Smrg 1261706f2543Smrg arc.x = center.x - width/2; 1262706f2543Smrg arc.y = center.y - width/2; 1263706f2543Smrg arc.width = width; 1264706f2543Smrg arc.height = width; 1265706f2543Smrg arc.angle1 = -miDatan2 (corner.y - center.y, corner.x - center.x); 1266706f2543Smrg arc.angle2 = a; 1267706f2543Smrg pArcPts = malloc(3 * sizeof (SppPointRec)); 1268706f2543Smrg if (!pArcPts) 1269706f2543Smrg return; 1270706f2543Smrg pArcPts[0].x = otherCorner.x; 1271706f2543Smrg pArcPts[0].y = otherCorner.y; 1272706f2543Smrg pArcPts[1].x = center.x; 1273706f2543Smrg pArcPts[1].y = center.y; 1274706f2543Smrg pArcPts[2].x = corner.x; 1275706f2543Smrg pArcPts[2].y = corner.y; 1276706f2543Smrg if( (cpt = miGetArcPts(&arc, 3, &pArcPts)) ) 1277706f2543Smrg { 1278706f2543Smrg /* by drawing with miFillSppPoly and setting the endpoints of the arc 1279706f2543Smrg * to be the corners, we assure that the cap will meet up with the 1280706f2543Smrg * rest of the line */ 1281706f2543Smrg miFillSppPoly(pDraw, pGC, cpt, pArcPts, xOrg, yOrg, xFtrans, yFtrans); 1282706f2543Smrg } 1283706f2543Smrg free(pArcPts); 1284706f2543Smrg return; 1285706f2543Smrg case JoinMiter: 1286706f2543Smrg /* 1287706f2543Smrg * don't miter arcs with less than 11 degrees between them 1288706f2543Smrg */ 1289706f2543Smrg if (a < 169.0) { 1290706f2543Smrg poly[0] = corner; 1291706f2543Smrg poly[1] = center; 1292706f2543Smrg poly[2] = otherCorner; 1293706f2543Smrg bc2 = (corner.x - otherCorner.x) * (corner.x - otherCorner.x) + 1294706f2543Smrg (corner.y - otherCorner.y) * (corner.y - otherCorner.y); 1295706f2543Smrg ec2 = bc2 / 4; 1296706f2543Smrg ac2 = (corner.x - center.x) * (corner.x - center.x) + 1297706f2543Smrg (corner.y - center.y) * (corner.y - center.y); 1298706f2543Smrg ae = sqrt (ac2 - ec2); 1299706f2543Smrg de = ec2 / ae; 1300706f2543Smrg e.x = (corner.x + otherCorner.x) / 2; 1301706f2543Smrg e.y = (corner.y + otherCorner.y) / 2; 1302706f2543Smrg poly[3].x = e.x + de * (e.x - center.x) / ae; 1303706f2543Smrg poly[3].y = e.y + de * (e.y - center.y) / ae; 1304706f2543Smrg poly[4] = corner; 1305706f2543Smrg polyLen = 5; 1306706f2543Smrg break; 1307706f2543Smrg } 1308706f2543Smrg case JoinBevel: 1309706f2543Smrg poly[0] = corner; 1310706f2543Smrg poly[1] = center; 1311706f2543Smrg poly[2] = otherCorner; 1312706f2543Smrg poly[3] = corner; 1313706f2543Smrg polyLen = 4; 1314706f2543Smrg break; 1315706f2543Smrg } 1316706f2543Smrg miFillSppPoly (pDraw, pGC, polyLen, poly, xOrg, yOrg, xFtrans, yFtrans); 1317706f2543Smrg} 1318706f2543Smrg 1319706f2543Smrg/*ARGSUSED*/ 1320706f2543Smrgstatic void 1321706f2543SmrgmiArcCap ( 1322706f2543Smrg DrawablePtr pDraw, 1323706f2543Smrg GCPtr pGC, 1324706f2543Smrg miArcFacePtr pFace, 1325706f2543Smrg int end, 1326706f2543Smrg int xOrg, 1327706f2543Smrg int yOrg, 1328706f2543Smrg double xFtrans, 1329706f2543Smrg double yFtrans) 1330706f2543Smrg{ 1331706f2543Smrg SppPointRec corner, otherCorner, center, endPoint, poly[5]; 1332706f2543Smrg 1333706f2543Smrg corner = pFace->clock; 1334706f2543Smrg otherCorner = pFace->counterClock; 1335706f2543Smrg center = pFace->center; 1336706f2543Smrg switch (pGC->capStyle) { 1337706f2543Smrg case CapProjecting: 1338706f2543Smrg poly[0].x = otherCorner.x; 1339706f2543Smrg poly[0].y = otherCorner.y; 1340706f2543Smrg poly[1].x = corner.x; 1341706f2543Smrg poly[1].y = corner.y; 1342706f2543Smrg poly[2].x = corner.x - 1343706f2543Smrg (center.y - corner.y); 1344706f2543Smrg poly[2].y = corner.y + 1345706f2543Smrg (center.x - corner.x); 1346706f2543Smrg poly[3].x = otherCorner.x - 1347706f2543Smrg (otherCorner.y - center.y); 1348706f2543Smrg poly[3].y = otherCorner.y + 1349706f2543Smrg (otherCorner.x - center.x); 1350706f2543Smrg poly[4].x = otherCorner.x; 1351706f2543Smrg poly[4].y = otherCorner.y; 1352706f2543Smrg miFillSppPoly (pDraw, pGC, 5, poly, xOrg, yOrg, xFtrans, yFtrans); 1353706f2543Smrg break; 1354706f2543Smrg case CapRound: 1355706f2543Smrg /* 1356706f2543Smrg * miRoundCap just needs these to be unequal. 1357706f2543Smrg */ 1358706f2543Smrg endPoint = center; 1359706f2543Smrg endPoint.x = endPoint.x + 100; 1360706f2543Smrg miRoundCap (pDraw, pGC, center, endPoint, corner, otherCorner, 0, 1361706f2543Smrg -xOrg, -yOrg, xFtrans, yFtrans); 1362706f2543Smrg break; 1363706f2543Smrg } 1364706f2543Smrg} 1365706f2543Smrg 1366706f2543Smrg/* MIROUNDCAP -- a private helper function 1367706f2543Smrg * Put Rounded cap on end. pCenter is the center of this end of the line 1368706f2543Smrg * pEnd is the center of the other end of the line. pCorner is one of the 1369706f2543Smrg * two corners at this end of the line. 1370706f2543Smrg * NOTE: pOtherCorner must be counter-clockwise from pCorner. 1371706f2543Smrg */ 1372706f2543Smrg/*ARGSUSED*/ 1373706f2543Smrgstatic void 1374706f2543SmrgmiRoundCap( 1375706f2543Smrg DrawablePtr pDraw, 1376706f2543Smrg GCPtr pGC, 1377706f2543Smrg SppPointRec pCenter, 1378706f2543Smrg SppPointRec pEnd, 1379706f2543Smrg SppPointRec pCorner, 1380706f2543Smrg SppPointRec pOtherCorner, 1381706f2543Smrg int fLineEnd, 1382706f2543Smrg int xOrg, 1383706f2543Smrg int yOrg, 1384706f2543Smrg double xFtrans, 1385706f2543Smrg double yFtrans) 1386706f2543Smrg{ 1387706f2543Smrg int cpt; 1388706f2543Smrg double width; 1389706f2543Smrg SppArcRec arc; 1390706f2543Smrg SppPointPtr pArcPts; 1391706f2543Smrg 1392706f2543Smrg width = (pGC->lineWidth ? (double)pGC->lineWidth : (double)1); 1393706f2543Smrg 1394706f2543Smrg arc.x = pCenter.x - width/2; 1395706f2543Smrg arc.y = pCenter.y - width/2; 1396706f2543Smrg arc.width = width; 1397706f2543Smrg arc.height = width; 1398706f2543Smrg arc.angle1 = -miDatan2 (pCorner.y - pCenter.y, pCorner.x - pCenter.x); 1399706f2543Smrg if(PTISEQUAL(pCenter, pEnd)) 1400706f2543Smrg arc.angle2 = - 180.0; 1401706f2543Smrg else { 1402706f2543Smrg arc.angle2 = -miDatan2 (pOtherCorner.y - pCenter.y, pOtherCorner.x - pCenter.x) - arc.angle1; 1403706f2543Smrg if (arc.angle2 < 0) 1404706f2543Smrg arc.angle2 += 360.0; 1405706f2543Smrg } 1406706f2543Smrg pArcPts = (SppPointPtr) NULL; 1407706f2543Smrg if( (cpt = miGetArcPts(&arc, 0, &pArcPts)) ) 1408706f2543Smrg { 1409706f2543Smrg /* by drawing with miFillSppPoly and setting the endpoints of the arc 1410706f2543Smrg * to be the corners, we assure that the cap will meet up with the 1411706f2543Smrg * rest of the line */ 1412706f2543Smrg miFillSppPoly(pDraw, pGC, cpt, pArcPts, -xOrg, -yOrg, xFtrans, yFtrans); 1413706f2543Smrg } 1414706f2543Smrg free(pArcPts); 1415706f2543Smrg} 1416706f2543Smrg 1417706f2543Smrg/* 1418706f2543Smrg * To avoid inaccuracy at the cardinal points, use trig functions 1419706f2543Smrg * which are exact for those angles 1420706f2543Smrg */ 1421706f2543Smrg 1422706f2543Smrg#ifndef M_PI 1423706f2543Smrg#define M_PI 3.14159265358979323846 1424706f2543Smrg#endif 1425706f2543Smrg#ifndef M_PI_2 1426706f2543Smrg#define M_PI_2 1.57079632679489661923 1427706f2543Smrg#endif 1428706f2543Smrg 1429706f2543Smrg# define Dsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0))) 1430706f2543Smrg# define Dcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0))) 1431706f2543Smrg# define mod(a,b) ((a) >= 0 ? (a) % (b) : (b) - (-(a)) % (b)) 1432706f2543Smrg 1433706f2543Smrgstatic double 1434706f2543SmrgmiDcos (double a) 1435706f2543Smrg{ 1436706f2543Smrg int i; 1437706f2543Smrg 1438706f2543Smrg if (floor (a/90) == a/90) { 1439706f2543Smrg i = (int) (a/90.0); 1440706f2543Smrg switch (mod (i, 4)) { 1441706f2543Smrg case 0: return 1; 1442706f2543Smrg case 1: return 0; 1443706f2543Smrg case 2: return -1; 1444706f2543Smrg case 3: return 0; 1445706f2543Smrg } 1446706f2543Smrg } 1447706f2543Smrg return cos (a * M_PI / 180.0); 1448706f2543Smrg} 1449706f2543Smrg 1450706f2543Smrgstatic double 1451706f2543SmrgmiDsin (double a) 1452706f2543Smrg{ 1453706f2543Smrg int i; 1454706f2543Smrg 1455706f2543Smrg if (floor (a/90) == a/90) { 1456706f2543Smrg i = (int) (a/90.0); 1457706f2543Smrg switch (mod (i, 4)) { 1458706f2543Smrg case 0: return 0; 1459706f2543Smrg case 1: return 1; 1460706f2543Smrg case 2: return 0; 1461706f2543Smrg case 3: return -1; 1462706f2543Smrg } 1463706f2543Smrg } 1464706f2543Smrg return sin (a * M_PI / 180.0); 1465706f2543Smrg} 1466706f2543Smrg 1467706f2543Smrgstatic double 1468706f2543SmrgmiDasin (double v) 1469706f2543Smrg{ 1470706f2543Smrg if (v == 0) 1471706f2543Smrg return 0.0; 1472706f2543Smrg if (v == 1.0) 1473706f2543Smrg return 90.0; 1474706f2543Smrg if (v == -1.0) 1475706f2543Smrg return -90.0; 1476706f2543Smrg return asin(v) * (180.0 / M_PI); 1477706f2543Smrg} 1478706f2543Smrg 1479706f2543Smrgstatic double 1480706f2543SmrgmiDatan2 (double dy, double dx) 1481706f2543Smrg{ 1482706f2543Smrg if (dy == 0) { 1483706f2543Smrg if (dx >= 0) 1484706f2543Smrg return 0.0; 1485706f2543Smrg return 180.0; 1486706f2543Smrg } else if (dx == 0) { 1487706f2543Smrg if (dy > 0) 1488706f2543Smrg return 90.0; 1489706f2543Smrg return -90.0; 1490706f2543Smrg } else if (Fabs (dy) == Fabs (dx)) { 1491706f2543Smrg if (dy > 0) { 1492706f2543Smrg if (dx > 0) 1493706f2543Smrg return 45.0; 1494706f2543Smrg return 135.0; 1495706f2543Smrg } else { 1496706f2543Smrg if (dx > 0) 1497706f2543Smrg return 315.0; 1498706f2543Smrg return 225.0; 1499706f2543Smrg } 1500706f2543Smrg } else { 1501706f2543Smrg return atan2 (dy, dx) * (180.0 / M_PI); 1502706f2543Smrg } 1503706f2543Smrg} 1504706f2543Smrg 1505706f2543Smrg/* MIGETARCPTS -- Converts an arc into a set of line segments -- a helper 1506706f2543Smrg * routine for filled arc and line (round cap) code. 1507706f2543Smrg * Returns the number of points in the arc. Note that it takes a pointer 1508706f2543Smrg * to a pointer to where it should put the points and an index (cpt). 1509706f2543Smrg * This procedure allocates the space necessary to fit the arc points. 1510706f2543Smrg * Sometimes it's convenient for those points to be at the end of an existing 1511706f2543Smrg * array. (For example, if we want to leave a spare point to make sectors 1512706f2543Smrg * instead of segments.) So we pass in the malloc()ed chunk that contains the 1513706f2543Smrg * array and an index saying where we should start stashing the points. 1514706f2543Smrg * If there isn't an array already, we just pass in a null pointer and 1515706f2543Smrg * count on realloc() to handle the null pointer correctly. 1516706f2543Smrg */ 1517706f2543Smrgstatic int 1518706f2543SmrgmiGetArcPts( 1519706f2543Smrg SppArcPtr parc, /* points to an arc */ 1520706f2543Smrg int cpt, /* number of points already in arc list */ 1521706f2543Smrg SppPointPtr *ppPts) /* pointer to pointer to arc-list -- modified */ 1522706f2543Smrg{ 1523706f2543Smrg double st, /* Start Theta, start angle */ 1524706f2543Smrg et, /* End Theta, offset from start theta */ 1525706f2543Smrg dt, /* Delta Theta, angle to sweep ellipse */ 1526706f2543Smrg cdt, /* Cos Delta Theta, actually 2 cos(dt) */ 1527706f2543Smrg x0, y0, /* the recurrence formula needs two points to start */ 1528706f2543Smrg x1, y1, 1529706f2543Smrg x2, y2, /* this will be the new point generated */ 1530706f2543Smrg xc, yc; /* the center point */ 1531706f2543Smrg int count, i; 1532706f2543Smrg SppPointPtr poly; 1533706f2543Smrg 1534706f2543Smrg /* The spec says that positive angles indicate counterclockwise motion. 1535706f2543Smrg * Given our coordinate system (with 0,0 in the upper left corner), 1536706f2543Smrg * the screen appears flipped in Y. The easiest fix is to negate the 1537706f2543Smrg * angles given */ 1538706f2543Smrg 1539706f2543Smrg st = - parc->angle1; 1540706f2543Smrg 1541706f2543Smrg et = - parc->angle2; 1542706f2543Smrg 1543706f2543Smrg /* Try to get a delta theta that is within 1/2 pixel. Then adjust it 1544706f2543Smrg * so that it divides evenly into the total. 1545706f2543Smrg * I'm just using cdt 'cause I'm lazy. 1546706f2543Smrg */ 1547706f2543Smrg cdt = parc->width; 1548706f2543Smrg if (parc->height > cdt) 1549706f2543Smrg cdt = parc->height; 1550706f2543Smrg cdt /= 2.0; 1551706f2543Smrg if(cdt <= 0) 1552706f2543Smrg return 0; 1553706f2543Smrg if (cdt < 1.0) 1554706f2543Smrg cdt = 1.0; 1555706f2543Smrg dt = miDasin ( 1.0 / cdt ); /* minimum step necessary */ 1556706f2543Smrg count = et/dt; 1557706f2543Smrg count = abs(count) + 1; 1558706f2543Smrg dt = et/count; 1559706f2543Smrg count++; 1560706f2543Smrg 1561706f2543Smrg cdt = 2 * miDcos(dt); 1562706f2543Smrg if (!(poly = (SppPointPtr) realloc((pointer)*ppPts, 1563706f2543Smrg (cpt + count) * sizeof(SppPointRec)))) 1564706f2543Smrg return 0; 1565706f2543Smrg *ppPts = poly; 1566706f2543Smrg 1567706f2543Smrg xc = parc->width/2.0; /* store half width and half height */ 1568706f2543Smrg yc = parc->height/2.0; 1569706f2543Smrg 1570706f2543Smrg x0 = xc * miDcos(st); 1571706f2543Smrg y0 = yc * miDsin(st); 1572706f2543Smrg x1 = xc * miDcos(st + dt); 1573706f2543Smrg y1 = yc * miDsin(st + dt); 1574706f2543Smrg xc += parc->x; /* by adding initial point, these become */ 1575706f2543Smrg yc += parc->y; /* the center point */ 1576706f2543Smrg 1577706f2543Smrg poly[cpt].x = (xc + x0); 1578706f2543Smrg poly[cpt].y = (yc + y0); 1579706f2543Smrg poly[cpt + 1].x = (xc + x1); 1580706f2543Smrg poly[cpt + 1].y = (yc + y1); 1581706f2543Smrg 1582706f2543Smrg for(i = 2; i < count; i++) 1583706f2543Smrg { 1584706f2543Smrg x2 = cdt * x1 - x0; 1585706f2543Smrg y2 = cdt * y1 - y0; 1586706f2543Smrg 1587706f2543Smrg poly[cpt + i].x = (xc + x2); 1588706f2543Smrg poly[cpt + i].y = (yc + y2); 1589706f2543Smrg 1590706f2543Smrg x0 = x1; y0 = y1; 1591706f2543Smrg x1 = x2; y1 = y2; 1592706f2543Smrg } 1593706f2543Smrg /* adjust the last point */ 1594706f2543Smrg if (fabs(parc->angle2) >= 360.0) 1595706f2543Smrg poly[cpt +i -1] = poly[0]; 1596706f2543Smrg else { 1597706f2543Smrg poly[cpt +i -1].x = (miDcos(st + et) * parc->width/2.0 + xc); 1598706f2543Smrg poly[cpt +i -1].y = (miDsin(st + et) * parc->height/2.0 + yc); 1599706f2543Smrg } 1600706f2543Smrg 1601706f2543Smrg return count; 1602706f2543Smrg} 1603706f2543Smrg 1604706f2543Smrgstruct arcData { 1605706f2543Smrg double x0, y0, x1, y1; 1606706f2543Smrg int selfJoin; 1607706f2543Smrg}; 1608706f2543Smrg 1609706f2543Smrg# define ADD_REALLOC_STEP 20 1610706f2543Smrg 1611706f2543Smrgstatic void 1612706f2543SmrgaddCap ( 1613706f2543Smrg miArcCapPtr *capsp, 1614706f2543Smrg int *ncapsp, 1615706f2543Smrg int *sizep, 1616706f2543Smrg int end, 1617706f2543Smrg int arcIndex) 1618706f2543Smrg{ 1619706f2543Smrg int newsize; 1620706f2543Smrg miArcCapPtr cap; 1621706f2543Smrg 1622706f2543Smrg if (*ncapsp == *sizep) 1623706f2543Smrg { 1624706f2543Smrg newsize = *sizep + ADD_REALLOC_STEP; 1625706f2543Smrg cap = (miArcCapPtr) realloc(*capsp, 1626706f2543Smrg newsize * sizeof (**capsp)); 1627706f2543Smrg if (!cap) 1628706f2543Smrg return; 1629706f2543Smrg *sizep = newsize; 1630706f2543Smrg *capsp = cap; 1631706f2543Smrg } 1632706f2543Smrg cap = &(*capsp)[*ncapsp]; 1633706f2543Smrg cap->end = end; 1634706f2543Smrg cap->arcIndex = arcIndex; 1635706f2543Smrg ++*ncapsp; 1636706f2543Smrg} 1637706f2543Smrg 1638706f2543Smrgstatic void 1639706f2543SmrgaddJoin ( 1640706f2543Smrg miArcJoinPtr *joinsp, 1641706f2543Smrg int *njoinsp, 1642706f2543Smrg int *sizep, 1643706f2543Smrg int end0, 1644706f2543Smrg int index0, 1645706f2543Smrg int phase0, 1646706f2543Smrg int end1, 1647706f2543Smrg int index1, 1648706f2543Smrg int phase1) 1649706f2543Smrg{ 1650706f2543Smrg int newsize; 1651706f2543Smrg miArcJoinPtr join; 1652706f2543Smrg 1653706f2543Smrg if (*njoinsp == *sizep) 1654706f2543Smrg { 1655706f2543Smrg newsize = *sizep + ADD_REALLOC_STEP; 1656706f2543Smrg join = (miArcJoinPtr) realloc(*joinsp, 1657706f2543Smrg newsize * sizeof (**joinsp)); 1658706f2543Smrg if (!join) 1659706f2543Smrg return; 1660706f2543Smrg *sizep = newsize; 1661706f2543Smrg *joinsp = join; 1662706f2543Smrg } 1663706f2543Smrg join = &(*joinsp)[*njoinsp]; 1664706f2543Smrg join->end0 = end0; 1665706f2543Smrg join->arcIndex0 = index0; 1666706f2543Smrg join->phase0 = phase0; 1667706f2543Smrg join->end1 = end1; 1668706f2543Smrg join->arcIndex1 = index1; 1669706f2543Smrg join->phase1 = phase1; 1670706f2543Smrg ++*njoinsp; 1671706f2543Smrg} 1672706f2543Smrg 1673706f2543Smrgstatic miArcDataPtr 1674706f2543SmrgaddArc ( 1675706f2543Smrg miArcDataPtr *arcsp, 1676706f2543Smrg int *narcsp, 1677706f2543Smrg int *sizep, 1678706f2543Smrg xArc *xarc) 1679706f2543Smrg{ 1680706f2543Smrg int newsize; 1681706f2543Smrg miArcDataPtr arc; 1682706f2543Smrg 1683706f2543Smrg if (*narcsp == *sizep) 1684706f2543Smrg { 1685706f2543Smrg newsize = *sizep + ADD_REALLOC_STEP; 1686706f2543Smrg arc = (miArcDataPtr) realloc(*arcsp, 1687706f2543Smrg newsize * sizeof (**arcsp)); 1688706f2543Smrg if (!arc) 1689706f2543Smrg return NULL; 1690706f2543Smrg *sizep = newsize; 1691706f2543Smrg *arcsp = arc; 1692706f2543Smrg } 1693706f2543Smrg arc = &(*arcsp)[*narcsp]; 1694706f2543Smrg arc->arc = *xarc; 1695706f2543Smrg ++*narcsp; 1696706f2543Smrg return arc; 1697706f2543Smrg} 1698706f2543Smrg 1699706f2543Smrgstatic void 1700706f2543SmrgmiFreeArcs( 1701706f2543Smrg miPolyArcPtr arcs, 1702706f2543Smrg GCPtr pGC) 1703706f2543Smrg{ 1704706f2543Smrg int iphase; 1705706f2543Smrg 1706706f2543Smrg for (iphase = ((pGC->lineStyle == LineDoubleDash) ? 1 : 0); 1707706f2543Smrg iphase >= 0; 1708706f2543Smrg iphase--) 1709706f2543Smrg { 1710706f2543Smrg if (arcs[iphase].narcs > 0) 1711706f2543Smrg free(arcs[iphase].arcs); 1712706f2543Smrg if (arcs[iphase].njoins > 0) 1713706f2543Smrg free(arcs[iphase].joins); 1714706f2543Smrg if (arcs[iphase].ncaps > 0) 1715706f2543Smrg free(arcs[iphase].caps); 1716706f2543Smrg } 1717706f2543Smrg free(arcs); 1718706f2543Smrg} 1719706f2543Smrg 1720706f2543Smrg/* 1721706f2543Smrg * map angles to radial distance. This only deals with the first quadrant 1722706f2543Smrg */ 1723706f2543Smrg 1724706f2543Smrg/* 1725706f2543Smrg * a polygonal approximation to the arc for computing arc lengths 1726706f2543Smrg */ 1727706f2543Smrg 1728706f2543Smrg# define DASH_MAP_SIZE 91 1729706f2543Smrg 1730706f2543Smrg# define dashIndexToAngle(di) ((((double) (di)) * 90.0) / ((double) DASH_MAP_SIZE - 1)) 1731706f2543Smrg# define xAngleToDashIndex(xa) ((((long) (xa)) * (DASH_MAP_SIZE - 1)) / (90 * 64)) 1732706f2543Smrg# define dashIndexToXAngle(di) ((((long) (di)) * (90 * 64)) / (DASH_MAP_SIZE - 1)) 1733706f2543Smrg# define dashXAngleStep (((double) (90 * 64)) / ((double) (DASH_MAP_SIZE - 1))) 1734706f2543Smrg 1735706f2543Smrgtypedef struct { 1736706f2543Smrg double map[DASH_MAP_SIZE]; 1737706f2543Smrg} dashMap; 1738706f2543Smrg 1739706f2543Smrgstatic int computeAngleFromPath(int startAngle, int endAngle, dashMap *map, 1740706f2543Smrg int *lenp, int backwards); 1741706f2543Smrg 1742706f2543Smrgstatic void 1743706f2543SmrgcomputeDashMap ( 1744706f2543Smrg xArc *arcp, 1745706f2543Smrg dashMap *map) 1746706f2543Smrg{ 1747706f2543Smrg int di; 1748706f2543Smrg double a, x, y, prevx = 0.0, prevy = 0.0, dist; 1749706f2543Smrg 1750706f2543Smrg for (di = 0; di < DASH_MAP_SIZE; di++) { 1751706f2543Smrg a = dashIndexToAngle (di); 1752706f2543Smrg x = ((double) arcp->width / 2.0) * miDcos (a); 1753706f2543Smrg y = ((double) arcp->height / 2.0) * miDsin (a); 1754706f2543Smrg if (di == 0) { 1755706f2543Smrg map->map[di] = 0.0; 1756706f2543Smrg } else { 1757706f2543Smrg dist = hypot (x - prevx, y - prevy); 1758706f2543Smrg map->map[di] = map->map[di - 1] + dist; 1759706f2543Smrg } 1760706f2543Smrg prevx = x; 1761706f2543Smrg prevy = y; 1762706f2543Smrg } 1763706f2543Smrg} 1764706f2543Smrg 1765706f2543Smrgtypedef enum {HORIZONTAL, VERTICAL, OTHER} arcTypes; 1766706f2543Smrg 1767706f2543Smrg/* this routine is a bit gory */ 1768706f2543Smrg 1769706f2543Smrgstatic miPolyArcPtr 1770706f2543SmrgmiComputeArcs ( 1771706f2543Smrg xArc *parcs, 1772706f2543Smrg int narcs, 1773706f2543Smrg GCPtr pGC) 1774706f2543Smrg{ 1775706f2543Smrg int isDashed, isDoubleDash; 1776706f2543Smrg int dashOffset; 1777706f2543Smrg miPolyArcPtr arcs; 1778706f2543Smrg int start, i, j, k = 0, nexti, nextk = 0; 1779706f2543Smrg int joinSize[2]; 1780706f2543Smrg int capSize[2]; 1781706f2543Smrg int arcSize[2]; 1782706f2543Smrg int angle2; 1783706f2543Smrg double a0, a1; 1784706f2543Smrg struct arcData *data; 1785706f2543Smrg miArcDataPtr arc; 1786706f2543Smrg xArc xarc; 1787706f2543Smrg int iphase, prevphase = 0, joinphase; 1788706f2543Smrg int arcsJoin; 1789706f2543Smrg int selfJoin; 1790706f2543Smrg 1791706f2543Smrg int iDash = 0, dashRemaining = 0; 1792706f2543Smrg int iDashStart = 0, dashRemainingStart = 0, iphaseStart; 1793706f2543Smrg int startAngle, spanAngle, endAngle, backwards = 0; 1794706f2543Smrg int prevDashAngle, dashAngle; 1795706f2543Smrg dashMap map; 1796706f2543Smrg 1797706f2543Smrg isDashed = !(pGC->lineStyle == LineSolid); 1798706f2543Smrg isDoubleDash = (pGC->lineStyle == LineDoubleDash); 1799706f2543Smrg dashOffset = pGC->dashOffset; 1800706f2543Smrg 1801706f2543Smrg data = malloc(narcs * sizeof (struct arcData)); 1802706f2543Smrg if (!data) 1803706f2543Smrg return NULL; 1804706f2543Smrg arcs = malloc(sizeof (*arcs) * (isDoubleDash ? 2 : 1)); 1805706f2543Smrg if (!arcs) 1806706f2543Smrg { 1807706f2543Smrg free(data); 1808706f2543Smrg return NULL; 1809706f2543Smrg } 1810706f2543Smrg for (i = 0; i < narcs; i++) { 1811706f2543Smrg a0 = todeg (parcs[i].angle1); 1812706f2543Smrg angle2 = parcs[i].angle2; 1813706f2543Smrg if (angle2 > FULLCIRCLE) 1814706f2543Smrg angle2 = FULLCIRCLE; 1815706f2543Smrg else if (angle2 < -FULLCIRCLE) 1816706f2543Smrg angle2 = -FULLCIRCLE; 1817706f2543Smrg data[i].selfJoin = angle2 == FULLCIRCLE || angle2 == -FULLCIRCLE; 1818706f2543Smrg a1 = todeg (parcs[i].angle1 + angle2); 1819706f2543Smrg data[i].x0 = parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos (a0)); 1820706f2543Smrg data[i].y0 = parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin (a0)); 1821706f2543Smrg data[i].x1 = parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos (a1)); 1822706f2543Smrg data[i].y1 = parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin (a1)); 1823706f2543Smrg } 1824706f2543Smrg 1825706f2543Smrg for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++) { 1826706f2543Smrg arcs[iphase].njoins = 0; 1827706f2543Smrg arcs[iphase].joins = 0; 1828706f2543Smrg joinSize[iphase] = 0; 1829706f2543Smrg 1830706f2543Smrg arcs[iphase].ncaps = 0; 1831706f2543Smrg arcs[iphase].caps = 0; 1832706f2543Smrg capSize[iphase] = 0; 1833706f2543Smrg 1834706f2543Smrg arcs[iphase].narcs = 0; 1835706f2543Smrg arcs[iphase].arcs = 0; 1836706f2543Smrg arcSize[iphase] = 0; 1837706f2543Smrg } 1838706f2543Smrg 1839706f2543Smrg iphase = 0; 1840706f2543Smrg if (isDashed) { 1841706f2543Smrg iDash = 0; 1842706f2543Smrg dashRemaining = pGC->dash[0]; 1843706f2543Smrg while (dashOffset > 0) { 1844706f2543Smrg if (dashOffset >= dashRemaining) { 1845706f2543Smrg dashOffset -= dashRemaining; 1846706f2543Smrg iphase = iphase ? 0 : 1; 1847706f2543Smrg iDash++; 1848706f2543Smrg if (iDash == pGC->numInDashList) 1849706f2543Smrg iDash = 0; 1850706f2543Smrg dashRemaining = pGC->dash[iDash]; 1851706f2543Smrg } else { 1852706f2543Smrg dashRemaining -= dashOffset; 1853706f2543Smrg dashOffset = 0; 1854706f2543Smrg } 1855706f2543Smrg } 1856706f2543Smrg iDashStart = iDash; 1857706f2543Smrg dashRemainingStart = dashRemaining; 1858706f2543Smrg } 1859706f2543Smrg iphaseStart = iphase; 1860706f2543Smrg 1861706f2543Smrg for (i = narcs - 1; i >= 0; i--) { 1862706f2543Smrg j = i + 1; 1863706f2543Smrg if (j == narcs) 1864706f2543Smrg j = 0; 1865706f2543Smrg if (data[i].selfJoin || i == j || 1866706f2543Smrg (UNEQUAL (data[i].x1, data[j].x0) || 1867706f2543Smrg UNEQUAL (data[i].y1, data[j].y0))) 1868706f2543Smrg { 1869706f2543Smrg if (iphase == 0 || isDoubleDash) 1870706f2543Smrg addCap (&arcs[iphase].caps, &arcs[iphase].ncaps, 1871706f2543Smrg &capSize[iphase], RIGHT_END, 0); 1872706f2543Smrg break; 1873706f2543Smrg } 1874706f2543Smrg } 1875706f2543Smrg start = i + 1; 1876706f2543Smrg if (start == narcs) 1877706f2543Smrg start = 0; 1878706f2543Smrg i = start; 1879706f2543Smrg for (;;) { 1880706f2543Smrg j = i + 1; 1881706f2543Smrg if (j == narcs) 1882706f2543Smrg j = 0; 1883706f2543Smrg nexti = i+1; 1884706f2543Smrg if (nexti == narcs) 1885706f2543Smrg nexti = 0; 1886706f2543Smrg if (isDashed) { 1887706f2543Smrg /* 1888706f2543Smrg ** deal with dashed arcs. Use special rules for certain 0 area arcs. 1889706f2543Smrg ** Presumably, the other 0 area arcs still aren't done right. 1890706f2543Smrg */ 1891706f2543Smrg arcTypes arcType = OTHER; 1892706f2543Smrg CARD16 thisLength; 1893706f2543Smrg 1894706f2543Smrg if (parcs[i].height == 0 1895706f2543Smrg && (parcs[i].angle1 % FULLCIRCLE) == 0x2d00 1896706f2543Smrg && parcs[i].angle2 == 0x2d00) 1897706f2543Smrg arcType = HORIZONTAL; 1898706f2543Smrg else if (parcs[i].width == 0 1899706f2543Smrg && (parcs[i].angle1 % FULLCIRCLE) == 0x1680 1900706f2543Smrg && parcs[i].angle2 == 0x2d00) 1901706f2543Smrg arcType = VERTICAL; 1902706f2543Smrg if (arcType == OTHER) { 1903706f2543Smrg /* 1904706f2543Smrg * precompute an approximation map 1905706f2543Smrg */ 1906706f2543Smrg computeDashMap (&parcs[i], &map); 1907706f2543Smrg /* 1908706f2543Smrg * compute each individual dash segment using the path 1909706f2543Smrg * length function 1910706f2543Smrg */ 1911706f2543Smrg startAngle = parcs[i].angle1; 1912706f2543Smrg spanAngle = parcs[i].angle2; 1913706f2543Smrg if (spanAngle > FULLCIRCLE) 1914706f2543Smrg spanAngle = FULLCIRCLE; 1915706f2543Smrg else if (spanAngle < -FULLCIRCLE) 1916706f2543Smrg spanAngle = -FULLCIRCLE; 1917706f2543Smrg if (startAngle < 0) 1918706f2543Smrg startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE; 1919706f2543Smrg if (startAngle >= FULLCIRCLE) 1920706f2543Smrg startAngle = startAngle % FULLCIRCLE; 1921706f2543Smrg endAngle = startAngle + spanAngle; 1922706f2543Smrg backwards = spanAngle < 0; 1923706f2543Smrg } else { 1924706f2543Smrg xarc = parcs[i]; 1925706f2543Smrg if (arcType == VERTICAL) { 1926706f2543Smrg xarc.angle1 = 0x1680; 1927706f2543Smrg startAngle = parcs[i].y; 1928706f2543Smrg endAngle = startAngle + parcs[i].height; 1929706f2543Smrg } else { 1930706f2543Smrg xarc.angle1 = 0x2d00; 1931706f2543Smrg startAngle = parcs[i].x; 1932706f2543Smrg endAngle = startAngle + parcs[i].width; 1933706f2543Smrg } 1934706f2543Smrg } 1935706f2543Smrg dashAngle = startAngle; 1936706f2543Smrg selfJoin = data[i].selfJoin && 1937706f2543Smrg (iphase == 0 || isDoubleDash); 1938706f2543Smrg /* 1939706f2543Smrg * add dashed arcs to each bucket 1940706f2543Smrg */ 1941706f2543Smrg arc = 0; 1942706f2543Smrg while (dashAngle != endAngle) { 1943706f2543Smrg prevDashAngle = dashAngle; 1944706f2543Smrg if (arcType == OTHER) { 1945706f2543Smrg dashAngle = computeAngleFromPath (prevDashAngle, endAngle, 1946706f2543Smrg &map, &dashRemaining, backwards); 1947706f2543Smrg /* avoid troubles with huge arcs and small dashes */ 1948706f2543Smrg if (dashAngle == prevDashAngle) { 1949706f2543Smrg if (backwards) 1950706f2543Smrg dashAngle--; 1951706f2543Smrg else 1952706f2543Smrg dashAngle++; 1953706f2543Smrg } 1954706f2543Smrg } else { 1955706f2543Smrg thisLength = (dashAngle + dashRemaining <= endAngle) ? 1956706f2543Smrg dashRemaining : endAngle - dashAngle; 1957706f2543Smrg if (arcType == VERTICAL) { 1958706f2543Smrg xarc.y = dashAngle; 1959706f2543Smrg xarc.height = thisLength; 1960706f2543Smrg } else { 1961706f2543Smrg xarc.x = dashAngle; 1962706f2543Smrg xarc.width = thisLength; 1963706f2543Smrg } 1964706f2543Smrg dashAngle += thisLength; 1965706f2543Smrg dashRemaining -= thisLength; 1966706f2543Smrg } 1967706f2543Smrg if (iphase == 0 || isDoubleDash) { 1968706f2543Smrg if (arcType == OTHER) { 1969706f2543Smrg xarc = parcs[i]; 1970706f2543Smrg spanAngle = prevDashAngle; 1971706f2543Smrg if (spanAngle < 0) 1972706f2543Smrg spanAngle = FULLCIRCLE - (-spanAngle) % FULLCIRCLE; 1973706f2543Smrg if (spanAngle >= FULLCIRCLE) 1974706f2543Smrg spanAngle = spanAngle % FULLCIRCLE; 1975706f2543Smrg xarc.angle1 = spanAngle; 1976706f2543Smrg spanAngle = dashAngle - prevDashAngle; 1977706f2543Smrg if (backwards) { 1978706f2543Smrg if (dashAngle > prevDashAngle) 1979706f2543Smrg spanAngle = - FULLCIRCLE + spanAngle; 1980706f2543Smrg } else { 1981706f2543Smrg if (dashAngle < prevDashAngle) 1982706f2543Smrg spanAngle = FULLCIRCLE + spanAngle; 1983706f2543Smrg } 1984706f2543Smrg if (spanAngle > FULLCIRCLE) 1985706f2543Smrg spanAngle = FULLCIRCLE; 1986706f2543Smrg if (spanAngle < -FULLCIRCLE) 1987706f2543Smrg spanAngle = -FULLCIRCLE; 1988706f2543Smrg xarc.angle2 = spanAngle; 1989706f2543Smrg } 1990706f2543Smrg arc = addArc (&arcs[iphase].arcs, &arcs[iphase].narcs, 1991706f2543Smrg &arcSize[iphase], &xarc); 1992706f2543Smrg if (!arc) 1993706f2543Smrg goto arcfail; 1994706f2543Smrg /* 1995706f2543Smrg * cap each end of an on/off dash 1996706f2543Smrg */ 1997706f2543Smrg if (!isDoubleDash) { 1998706f2543Smrg if (prevDashAngle != startAngle) { 1999706f2543Smrg addCap (&arcs[iphase].caps, 2000706f2543Smrg &arcs[iphase].ncaps, 2001706f2543Smrg &capSize[iphase], RIGHT_END, 2002706f2543Smrg arc - arcs[iphase].arcs); 2003706f2543Smrg 2004706f2543Smrg } 2005706f2543Smrg if (dashAngle != endAngle) { 2006706f2543Smrg addCap (&arcs[iphase].caps, 2007706f2543Smrg &arcs[iphase].ncaps, 2008706f2543Smrg &capSize[iphase], LEFT_END, 2009706f2543Smrg arc - arcs[iphase].arcs); 2010706f2543Smrg } 2011706f2543Smrg } 2012706f2543Smrg arc->cap = arcs[iphase].ncaps; 2013706f2543Smrg arc->join = arcs[iphase].njoins; 2014706f2543Smrg arc->render = 0; 2015706f2543Smrg arc->selfJoin = 0; 2016706f2543Smrg if (dashAngle == endAngle) 2017706f2543Smrg arc->selfJoin = selfJoin; 2018706f2543Smrg } 2019706f2543Smrg prevphase = iphase; 2020706f2543Smrg if (dashRemaining <= 0) { 2021706f2543Smrg ++iDash; 2022706f2543Smrg if (iDash == pGC->numInDashList) 2023706f2543Smrg iDash = 0; 2024706f2543Smrg iphase = iphase ? 0:1; 2025706f2543Smrg dashRemaining = pGC->dash[iDash]; 2026706f2543Smrg } 2027706f2543Smrg } 2028706f2543Smrg /* 2029706f2543Smrg * make sure a place exists for the position data when 2030706f2543Smrg * drawing a zero-length arc 2031706f2543Smrg */ 2032706f2543Smrg if (startAngle == endAngle) { 2033706f2543Smrg prevphase = iphase; 2034706f2543Smrg if (!isDoubleDash && iphase == 1) 2035706f2543Smrg prevphase = 0; 2036706f2543Smrg arc = addArc (&arcs[prevphase].arcs, &arcs[prevphase].narcs, 2037706f2543Smrg &arcSize[prevphase], &parcs[i]); 2038706f2543Smrg if (!arc) 2039706f2543Smrg goto arcfail; 2040706f2543Smrg arc->join = arcs[prevphase].njoins; 2041706f2543Smrg arc->cap = arcs[prevphase].ncaps; 2042706f2543Smrg arc->selfJoin = data[i].selfJoin; 2043706f2543Smrg } 2044706f2543Smrg } else { 2045706f2543Smrg arc = addArc (&arcs[iphase].arcs, &arcs[iphase].narcs, 2046706f2543Smrg &arcSize[iphase], &parcs[i]); 2047706f2543Smrg if (!arc) 2048706f2543Smrg goto arcfail; 2049706f2543Smrg arc->join = arcs[iphase].njoins; 2050706f2543Smrg arc->cap = arcs[iphase].ncaps; 2051706f2543Smrg arc->selfJoin = data[i].selfJoin; 2052706f2543Smrg prevphase = iphase; 2053706f2543Smrg } 2054706f2543Smrg if (prevphase == 0 || isDoubleDash) 2055706f2543Smrg k = arcs[prevphase].narcs - 1; 2056706f2543Smrg if (iphase == 0 || isDoubleDash) 2057706f2543Smrg nextk = arcs[iphase].narcs; 2058706f2543Smrg if (nexti == start) { 2059706f2543Smrg nextk = 0; 2060706f2543Smrg if (isDashed) { 2061706f2543Smrg iDash = iDashStart; 2062706f2543Smrg iphase = iphaseStart; 2063706f2543Smrg dashRemaining = dashRemainingStart; 2064706f2543Smrg } 2065706f2543Smrg } 2066706f2543Smrg arcsJoin = narcs > 1 && i != j && 2067706f2543Smrg ISEQUAL (data[i].x1, data[j].x0) && 2068706f2543Smrg ISEQUAL (data[i].y1, data[j].y0) && 2069706f2543Smrg !data[i].selfJoin && !data[j].selfJoin; 2070706f2543Smrg if (arc) 2071706f2543Smrg { 2072706f2543Smrg if (arcsJoin) 2073706f2543Smrg arc->render = 0; 2074706f2543Smrg else 2075706f2543Smrg arc->render = 1; 2076706f2543Smrg } 2077706f2543Smrg if (arcsJoin && 2078706f2543Smrg (prevphase == 0 || isDoubleDash) && 2079706f2543Smrg (iphase == 0 || isDoubleDash)) 2080706f2543Smrg { 2081706f2543Smrg joinphase = iphase; 2082706f2543Smrg if (isDoubleDash) { 2083706f2543Smrg if (nexti == start) 2084706f2543Smrg joinphase = iphaseStart; 2085706f2543Smrg /* 2086706f2543Smrg * if the join is right at the dash, 2087706f2543Smrg * draw the join in foreground 2088706f2543Smrg * This is because the foreground 2089706f2543Smrg * arcs are computed second, the results 2090706f2543Smrg * of which are needed to draw the join 2091706f2543Smrg */ 2092706f2543Smrg if (joinphase != prevphase) 2093706f2543Smrg joinphase = 0; 2094706f2543Smrg } 2095706f2543Smrg if (joinphase == 0 || isDoubleDash) { 2096706f2543Smrg addJoin (&arcs[joinphase].joins, 2097706f2543Smrg &arcs[joinphase].njoins, 2098706f2543Smrg &joinSize[joinphase], 2099706f2543Smrg LEFT_END, k, prevphase, 2100706f2543Smrg RIGHT_END, nextk, iphase); 2101706f2543Smrg arc->join = arcs[prevphase].njoins; 2102706f2543Smrg } 2103706f2543Smrg } else { 2104706f2543Smrg /* 2105706f2543Smrg * cap the left end of this arc 2106706f2543Smrg * unless it joins itself 2107706f2543Smrg */ 2108706f2543Smrg if ((prevphase == 0 || isDoubleDash) && 2109706f2543Smrg !arc->selfJoin) 2110706f2543Smrg { 2111706f2543Smrg addCap (&arcs[prevphase].caps, &arcs[prevphase].ncaps, 2112706f2543Smrg &capSize[prevphase], LEFT_END, k); 2113706f2543Smrg arc->cap = arcs[prevphase].ncaps; 2114706f2543Smrg } 2115706f2543Smrg if (isDashed && !arcsJoin) { 2116706f2543Smrg iDash = iDashStart; 2117706f2543Smrg iphase = iphaseStart; 2118706f2543Smrg dashRemaining = dashRemainingStart; 2119706f2543Smrg } 2120706f2543Smrg nextk = arcs[iphase].narcs; 2121706f2543Smrg if (nexti == start) { 2122706f2543Smrg nextk = 0; 2123706f2543Smrg iDash = iDashStart; 2124706f2543Smrg iphase = iphaseStart; 2125706f2543Smrg dashRemaining = dashRemainingStart; 2126706f2543Smrg } 2127706f2543Smrg /* 2128706f2543Smrg * cap the right end of the next arc. If the 2129706f2543Smrg * next arc is actually the first arc, only 2130706f2543Smrg * cap it if it joins with this arc. This 2131706f2543Smrg * case will occur when the final dash segment 2132706f2543Smrg * of an on/off dash is off. Of course, this 2133706f2543Smrg * cap will be drawn at a strange time, but that 2134706f2543Smrg * hardly matters... 2135706f2543Smrg */ 2136706f2543Smrg if ((iphase == 0 || isDoubleDash) && 2137706f2543Smrg (nexti != start || (arcsJoin && isDashed))) 2138706f2543Smrg addCap (&arcs[iphase].caps, &arcs[iphase].ncaps, 2139706f2543Smrg &capSize[iphase], RIGHT_END, nextk); 2140706f2543Smrg } 2141706f2543Smrg i = nexti; 2142706f2543Smrg if (i == start) 2143706f2543Smrg break; 2144706f2543Smrg } 2145706f2543Smrg /* 2146706f2543Smrg * make sure the last section is rendered 2147706f2543Smrg */ 2148706f2543Smrg for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++) 2149706f2543Smrg if (arcs[iphase].narcs > 0) { 2150706f2543Smrg arcs[iphase].arcs[arcs[iphase].narcs-1].render = 1; 2151706f2543Smrg arcs[iphase].arcs[arcs[iphase].narcs-1].join = 2152706f2543Smrg arcs[iphase].njoins; 2153706f2543Smrg arcs[iphase].arcs[arcs[iphase].narcs-1].cap = 2154706f2543Smrg arcs[iphase].ncaps; 2155706f2543Smrg } 2156706f2543Smrg free(data); 2157706f2543Smrg return arcs; 2158706f2543Smrgarcfail: 2159706f2543Smrg miFreeArcs(arcs, pGC); 2160706f2543Smrg free(data); 2161706f2543Smrg return NULL; 2162706f2543Smrg} 2163706f2543Smrg 2164706f2543Smrgstatic double 2165706f2543SmrgangleToLength ( 2166706f2543Smrg int angle, 2167706f2543Smrg dashMap *map) 2168706f2543Smrg{ 2169706f2543Smrg double len, excesslen, sidelen = map->map[DASH_MAP_SIZE - 1], totallen; 2170706f2543Smrg int di; 2171706f2543Smrg int excess; 2172706f2543Smrg Bool oddSide = FALSE; 2173706f2543Smrg 2174706f2543Smrg totallen = 0; 2175706f2543Smrg if (angle >= 0) { 2176706f2543Smrg while (angle >= 90 * 64) { 2177706f2543Smrg angle -= 90 * 64; 2178706f2543Smrg totallen += sidelen; 2179706f2543Smrg oddSide = !oddSide; 2180706f2543Smrg } 2181706f2543Smrg } else { 2182706f2543Smrg while (angle < 0) { 2183706f2543Smrg angle += 90 * 64; 2184706f2543Smrg totallen -= sidelen; 2185706f2543Smrg oddSide = !oddSide; 2186706f2543Smrg } 2187706f2543Smrg } 2188706f2543Smrg if (oddSide) 2189706f2543Smrg angle = 90 * 64 - angle; 2190706f2543Smrg 2191706f2543Smrg di = xAngleToDashIndex (angle); 2192706f2543Smrg excess = angle - dashIndexToXAngle (di); 2193706f2543Smrg 2194706f2543Smrg len = map->map[di]; 2195706f2543Smrg /* 2196706f2543Smrg * linearly interpolate between this point and the next 2197706f2543Smrg */ 2198706f2543Smrg if (excess > 0) { 2199706f2543Smrg excesslen = (map->map[di + 1] - map->map[di]) * 2200706f2543Smrg ((double) excess) / dashXAngleStep; 2201706f2543Smrg len += excesslen; 2202706f2543Smrg } 2203706f2543Smrg if (oddSide) 2204706f2543Smrg totallen += (sidelen - len); 2205706f2543Smrg else 2206706f2543Smrg totallen += len; 2207706f2543Smrg return totallen; 2208706f2543Smrg} 2209706f2543Smrg 2210706f2543Smrg/* 2211706f2543Smrg * len is along the arc, but may be more than one rotation 2212706f2543Smrg */ 2213706f2543Smrg 2214706f2543Smrgstatic int 2215706f2543SmrglengthToAngle ( 2216706f2543Smrg double len, 2217706f2543Smrg dashMap *map) 2218706f2543Smrg{ 2219706f2543Smrg double sidelen = map->map[DASH_MAP_SIZE - 1]; 2220706f2543Smrg int angle, angleexcess; 2221706f2543Smrg Bool oddSide = FALSE; 2222706f2543Smrg int a0, a1, a; 2223706f2543Smrg 2224706f2543Smrg angle = 0; 2225706f2543Smrg /* 2226706f2543Smrg * step around the ellipse, subtracting sidelens and 2227706f2543Smrg * adding 90 degrees. oddSide will tell if the 2228706f2543Smrg * map should be interpolated in reverse 2229706f2543Smrg */ 2230706f2543Smrg if (len >= 0) { 2231706f2543Smrg if (sidelen == 0) 2232706f2543Smrg return 2 * FULLCIRCLE; /* infinity */ 2233706f2543Smrg while (len >= sidelen) { 2234706f2543Smrg angle += 90 * 64; 2235706f2543Smrg len -= sidelen; 2236706f2543Smrg oddSide = !oddSide; 2237706f2543Smrg } 2238706f2543Smrg } else { 2239706f2543Smrg if (sidelen == 0) 2240706f2543Smrg return -2 * FULLCIRCLE; /* infinity */ 2241706f2543Smrg while (len < 0) { 2242706f2543Smrg angle -= 90 * 64; 2243706f2543Smrg len += sidelen; 2244706f2543Smrg oddSide = !oddSide; 2245706f2543Smrg } 2246706f2543Smrg } 2247706f2543Smrg if (oddSide) 2248706f2543Smrg len = sidelen - len; 2249706f2543Smrg a0 = 0; 2250706f2543Smrg a1 = DASH_MAP_SIZE - 1; 2251706f2543Smrg /* 2252706f2543Smrg * binary search for the closest pre-computed length 2253706f2543Smrg */ 2254706f2543Smrg while (a1 - a0 > 1) { 2255706f2543Smrg a = (a0 + a1) / 2; 2256706f2543Smrg if (len > map->map[a]) 2257706f2543Smrg a0 = a; 2258706f2543Smrg else 2259706f2543Smrg a1 = a; 2260706f2543Smrg } 2261706f2543Smrg angleexcess = dashIndexToXAngle (a0); 2262706f2543Smrg /* 2263706f2543Smrg * linearly interpolate to the next point 2264706f2543Smrg */ 2265706f2543Smrg angleexcess += (len - map->map[a0]) / 2266706f2543Smrg (map->map[a0+1] - map->map[a0]) * dashXAngleStep; 2267706f2543Smrg if (oddSide) 2268706f2543Smrg angle += (90 * 64) - angleexcess; 2269706f2543Smrg else 2270706f2543Smrg angle += angleexcess; 2271706f2543Smrg return angle; 2272706f2543Smrg} 2273706f2543Smrg 2274706f2543Smrg/* 2275706f2543Smrg * compute the angle of an ellipse which cooresponds to 2276706f2543Smrg * the given path length. Note that the correct solution 2277706f2543Smrg * to this problem is an eliptic integral, we'll punt and 2278706f2543Smrg * approximate (it's only for dashes anyway). This 2279706f2543Smrg * approximation uses a polygon. 2280706f2543Smrg * 2281706f2543Smrg * The remaining portion of len is stored in *lenp - 2282706f2543Smrg * this will be negative if the arc extends beyond 2283706f2543Smrg * len and positive if len extends beyond the arc. 2284706f2543Smrg */ 2285706f2543Smrg 2286706f2543Smrgstatic int 2287706f2543SmrgcomputeAngleFromPath ( 2288706f2543Smrg int startAngle, 2289706f2543Smrg int endAngle, /* normalized absolute angles in *64 degrees */ 2290706f2543Smrg dashMap *map, 2291706f2543Smrg int *lenp, 2292706f2543Smrg int backwards) 2293706f2543Smrg{ 2294706f2543Smrg int a0, a1, a; 2295706f2543Smrg double len0; 2296706f2543Smrg int len; 2297706f2543Smrg 2298706f2543Smrg a0 = startAngle; 2299706f2543Smrg a1 = endAngle; 2300706f2543Smrg len = *lenp; 2301706f2543Smrg if (backwards) { 2302706f2543Smrg /* 2303706f2543Smrg * flip the problem around to always be 2304706f2543Smrg * forwards 2305706f2543Smrg */ 2306706f2543Smrg a0 = FULLCIRCLE - a0; 2307706f2543Smrg a1 = FULLCIRCLE - a1; 2308706f2543Smrg } 2309706f2543Smrg if (a1 < a0) 2310706f2543Smrg a1 += FULLCIRCLE; 2311706f2543Smrg len0 = angleToLength (a0, map); 2312706f2543Smrg a = lengthToAngle (len0 + len, map); 2313706f2543Smrg if (a > a1) { 2314706f2543Smrg a = a1; 2315706f2543Smrg len -= angleToLength (a1, map) - len0; 2316706f2543Smrg } else 2317706f2543Smrg len = 0; 2318706f2543Smrg if (backwards) 2319706f2543Smrg a = FULLCIRCLE - a; 2320706f2543Smrg *lenp = len; 2321706f2543Smrg return a; 2322706f2543Smrg} 2323706f2543Smrg 2324706f2543Smrg/* 2325706f2543Smrg * scan convert wide arcs. 2326706f2543Smrg */ 2327706f2543Smrg 2328706f2543Smrg/* 2329706f2543Smrg * draw zero width/height arcs 2330706f2543Smrg */ 2331706f2543Smrg 2332706f2543Smrgstatic void 2333706f2543SmrgdrawZeroArc ( 2334706f2543Smrg DrawablePtr pDraw, 2335706f2543Smrg GCPtr pGC, 2336706f2543Smrg xArc *tarc, 2337706f2543Smrg int lw, 2338706f2543Smrg miArcFacePtr left, 2339706f2543Smrg miArcFacePtr right) 2340706f2543Smrg{ 2341706f2543Smrg double x0 = 0.0, y0 = 0.0, x1 = 0.0, y1 = 0.0, w, h, x, y; 2342706f2543Smrg double xmax, ymax, xmin, ymin; 2343706f2543Smrg int a0, a1; 2344706f2543Smrg double a, startAngle, endAngle; 2345706f2543Smrg double l, lx, ly; 2346706f2543Smrg 2347706f2543Smrg l = lw / 2.0; 2348706f2543Smrg a0 = tarc->angle1; 2349706f2543Smrg a1 = tarc->angle2; 2350706f2543Smrg if (a1 > FULLCIRCLE) 2351706f2543Smrg a1 = FULLCIRCLE; 2352706f2543Smrg else if (a1 < -FULLCIRCLE) 2353706f2543Smrg a1 = -FULLCIRCLE; 2354706f2543Smrg w = (double)tarc->width / 2.0; 2355706f2543Smrg h = (double)tarc->height / 2.0; 2356706f2543Smrg /* 2357706f2543Smrg * play in X coordinates right away 2358706f2543Smrg */ 2359706f2543Smrg startAngle = - ((double) a0 / 64.0); 2360706f2543Smrg endAngle = - ((double) (a0 + a1) / 64.0); 2361706f2543Smrg 2362706f2543Smrg xmax = -w; 2363706f2543Smrg xmin = w; 2364706f2543Smrg ymax = -h; 2365706f2543Smrg ymin = h; 2366706f2543Smrg a = startAngle; 2367706f2543Smrg for (;;) 2368706f2543Smrg { 2369706f2543Smrg x = w * miDcos(a); 2370706f2543Smrg y = h * miDsin(a); 2371706f2543Smrg if (a == startAngle) 2372706f2543Smrg { 2373706f2543Smrg x0 = x; 2374706f2543Smrg y0 = y; 2375706f2543Smrg } 2376706f2543Smrg if (a == endAngle) 2377706f2543Smrg { 2378706f2543Smrg x1 = x; 2379706f2543Smrg y1 = y; 2380706f2543Smrg } 2381706f2543Smrg if (x > xmax) 2382706f2543Smrg xmax = x; 2383706f2543Smrg if (x < xmin) 2384706f2543Smrg xmin = x; 2385706f2543Smrg if (y > ymax) 2386706f2543Smrg ymax = y; 2387706f2543Smrg if (y < ymin) 2388706f2543Smrg ymin = y; 2389706f2543Smrg if (a == endAngle) 2390706f2543Smrg break; 2391706f2543Smrg if (a1 < 0) /* clockwise */ 2392706f2543Smrg { 2393706f2543Smrg if (floor (a / 90.0) == floor (endAngle / 90.0)) 2394706f2543Smrg a = endAngle; 2395706f2543Smrg else 2396706f2543Smrg a = 90 * (floor (a/90.0) + 1); 2397706f2543Smrg } 2398706f2543Smrg else 2399706f2543Smrg { 2400706f2543Smrg if (ceil (a / 90.0) == ceil (endAngle / 90.0)) 2401706f2543Smrg a = endAngle; 2402706f2543Smrg else 2403706f2543Smrg a = 90 * (ceil (a/90.0) - 1); 2404706f2543Smrg } 2405706f2543Smrg } 2406706f2543Smrg lx = ly = l; 2407706f2543Smrg if ((x1 - x0) + (y1 - y0) < 0) 2408706f2543Smrg lx = ly = -l; 2409706f2543Smrg if (h) 2410706f2543Smrg { 2411706f2543Smrg ly = 0.0; 2412706f2543Smrg lx = -lx; 2413706f2543Smrg } 2414706f2543Smrg else 2415706f2543Smrg lx = 0.0; 2416706f2543Smrg if (right) 2417706f2543Smrg { 2418706f2543Smrg right->center.x = x0; 2419706f2543Smrg right->center.y = y0; 2420706f2543Smrg right->clock.x = x0 - lx; 2421706f2543Smrg right->clock.y = y0 - ly; 2422706f2543Smrg right->counterClock.x = x0 + lx; 2423706f2543Smrg right->counterClock.y = y0 + ly; 2424706f2543Smrg } 2425706f2543Smrg if (left) 2426706f2543Smrg { 2427706f2543Smrg left->center.x = x1; 2428706f2543Smrg left->center.y = y1; 2429706f2543Smrg left->clock.x = x1 + lx; 2430706f2543Smrg left->clock.y = y1 + ly; 2431706f2543Smrg left->counterClock.x = x1 - lx; 2432706f2543Smrg left->counterClock.y = y1 - ly; 2433706f2543Smrg } 2434706f2543Smrg 2435706f2543Smrg x0 = xmin; 2436706f2543Smrg x1 = xmax; 2437706f2543Smrg y0 = ymin; 2438706f2543Smrg y1 = ymax; 2439706f2543Smrg if (ymin != y1) { 2440706f2543Smrg xmin = -l; 2441706f2543Smrg xmax = l; 2442706f2543Smrg } else { 2443706f2543Smrg ymin = -l; 2444706f2543Smrg ymax = l; 2445706f2543Smrg } 2446706f2543Smrg if (xmax != xmin && ymax != ymin) { 2447706f2543Smrg int minx, maxx, miny, maxy; 2448706f2543Smrg xRectangle rect; 2449706f2543Smrg 2450706f2543Smrg minx = ICEIL (xmin + w) + tarc->x; 2451706f2543Smrg maxx = ICEIL (xmax + w) + tarc->x; 2452706f2543Smrg miny = ICEIL (ymin + h) + tarc->y; 2453706f2543Smrg maxy = ICEIL (ymax + h) + tarc->y; 2454706f2543Smrg rect.x = minx; 2455706f2543Smrg rect.y = miny; 2456706f2543Smrg rect.width = maxx - minx; 2457706f2543Smrg rect.height = maxy - miny; 2458706f2543Smrg (*pGC->ops->PolyFillRect) (pDraw, pGC, 1, &rect); 2459706f2543Smrg } 2460706f2543Smrg} 2461706f2543Smrg 2462706f2543Smrg/* 2463706f2543Smrg * this computes the ellipse y value associated with the 2464706f2543Smrg * bottom of the tail. 2465706f2543Smrg */ 2466706f2543Smrg 2467706f2543Smrgstatic void 2468706f2543SmrgtailEllipseY ( 2469706f2543Smrg struct arc_def *def, 2470706f2543Smrg struct accelerators *acc) 2471706f2543Smrg{ 2472706f2543Smrg double t; 2473706f2543Smrg 2474706f2543Smrg acc->tail_y = 0.0; 2475706f2543Smrg if (def->w == def->h) 2476706f2543Smrg return; 2477706f2543Smrg t = def->l * def->w; 2478706f2543Smrg if (def->w > def->h) { 2479706f2543Smrg if (t < acc->h2) 2480706f2543Smrg return; 2481706f2543Smrg } else { 2482706f2543Smrg if (t > acc->h2) 2483706f2543Smrg return; 2484706f2543Smrg } 2485706f2543Smrg t = 2.0 * def->h * t; 2486706f2543Smrg t = (CUBED_ROOT_4 * acc->h2 - cbrt(t * t)) / acc->h2mw2; 2487706f2543Smrg if (t > 0.0) 2488706f2543Smrg acc->tail_y = def->h / CUBED_ROOT_2 * sqrt(t); 2489706f2543Smrg} 2490706f2543Smrg 2491706f2543Smrg/* 2492706f2543Smrg * inverse functions -- compute edge coordinates 2493706f2543Smrg * from the ellipse 2494706f2543Smrg */ 2495706f2543Smrg 2496706f2543Smrgstatic double 2497706f2543SmrgouterXfromXY ( 2498706f2543Smrg double x, 2499706f2543Smrg double y, 2500706f2543Smrg struct arc_def *def, 2501706f2543Smrg struct accelerators *acc) 2502706f2543Smrg{ 2503706f2543Smrg return x + (x * acc->h2l) / sqrt (x*x * acc->h4 + y*y * acc->w4); 2504706f2543Smrg} 2505706f2543Smrg 2506706f2543Smrgstatic double 2507706f2543SmrgouterYfromXY ( 2508706f2543Smrg double x, 2509706f2543Smrg double y, 2510706f2543Smrg struct arc_def *def, 2511706f2543Smrg struct accelerators *acc) 2512706f2543Smrg{ 2513706f2543Smrg return y + (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4); 2514706f2543Smrg} 2515706f2543Smrg 2516706f2543Smrgstatic double 2517706f2543SmrginnerXfromXY ( 2518706f2543Smrg double x, 2519706f2543Smrg double y, 2520706f2543Smrg struct arc_def *def, 2521706f2543Smrg struct accelerators *acc) 2522706f2543Smrg{ 2523706f2543Smrg return x - (x * acc->h2l) / sqrt (x*x * acc->h4 + y*y * acc->w4); 2524706f2543Smrg} 2525706f2543Smrg 2526706f2543Smrgstatic double 2527706f2543SmrginnerYfromXY ( 2528706f2543Smrg double x, 2529706f2543Smrg double y, 2530706f2543Smrg struct arc_def *def, 2531706f2543Smrg struct accelerators *acc) 2532706f2543Smrg{ 2533706f2543Smrg return y - (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4); 2534706f2543Smrg} 2535706f2543Smrg 2536706f2543Smrgstatic double 2537706f2543SmrginnerYfromY ( 2538706f2543Smrg double y, 2539706f2543Smrg struct arc_def *def, 2540706f2543Smrg struct accelerators *acc) 2541706f2543Smrg{ 2542706f2543Smrg double x; 2543706f2543Smrg 2544706f2543Smrg x = (def->w / def->h) * sqrt (acc->h2 - y*y); 2545706f2543Smrg 2546706f2543Smrg return y - (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4); 2547706f2543Smrg} 2548706f2543Smrg 2549706f2543Smrgstatic void 2550706f2543SmrgcomputeLine ( 2551706f2543Smrg double x1, 2552706f2543Smrg double y1, 2553706f2543Smrg double x2, 2554706f2543Smrg double y2, 2555706f2543Smrg struct line *line) 2556706f2543Smrg{ 2557706f2543Smrg if (y1 == y2) 2558706f2543Smrg line->valid = 0; 2559706f2543Smrg else { 2560706f2543Smrg line->m = (x1 - x2) / (y1 - y2); 2561706f2543Smrg line->b = x1 - y1 * line->m; 2562706f2543Smrg line->valid = 1; 2563706f2543Smrg } 2564706f2543Smrg} 2565706f2543Smrg 2566706f2543Smrg/* 2567706f2543Smrg * compute various accelerators for an ellipse. These 2568706f2543Smrg * are simply values that are used repeatedly in 2569706f2543Smrg * the computations 2570706f2543Smrg */ 2571706f2543Smrg 2572706f2543Smrgstatic void 2573706f2543SmrgcomputeAcc ( 2574706f2543Smrg xArc *tarc, 2575706f2543Smrg int lw, 2576706f2543Smrg struct arc_def *def, 2577706f2543Smrg struct accelerators *acc) 2578706f2543Smrg{ 2579706f2543Smrg def->w = ((double) tarc->width) / 2.0; 2580706f2543Smrg def->h = ((double) tarc->height) / 2.0; 2581706f2543Smrg def->l = ((double) lw) / 2.0; 2582706f2543Smrg acc->h2 = def->h * def->h; 2583706f2543Smrg acc->w2 = def->w * def->w; 2584706f2543Smrg acc->h4 = acc->h2 * acc->h2; 2585706f2543Smrg acc->w4 = acc->w2 * acc->w2; 2586706f2543Smrg acc->h2l = acc->h2 * def->l; 2587706f2543Smrg acc->w2l = acc->w2 * def->l; 2588706f2543Smrg acc->h2mw2 = acc->h2 - acc->w2; 2589706f2543Smrg acc->fromIntX = (tarc->width & 1) ? 0.5 : 0.0; 2590706f2543Smrg acc->fromIntY = (tarc->height & 1) ? 0.5 : 0.0; 2591706f2543Smrg acc->xorg = tarc->x + (tarc->width >> 1); 2592706f2543Smrg acc->yorgu = tarc->y + (tarc->height >> 1); 2593706f2543Smrg acc->yorgl = acc->yorgu + (tarc->height & 1); 2594706f2543Smrg tailEllipseY (def, acc); 2595706f2543Smrg} 2596706f2543Smrg 2597706f2543Smrg/* 2598706f2543Smrg * compute y value bounds of various portions of the arc, 2599706f2543Smrg * the outer edge, the ellipse and the inner edge. 2600706f2543Smrg */ 2601706f2543Smrg 2602706f2543Smrgstatic void 2603706f2543SmrgcomputeBound ( 2604706f2543Smrg struct arc_def *def, 2605706f2543Smrg struct arc_bound *bound, 2606706f2543Smrg struct accelerators *acc, 2607706f2543Smrg miArcFacePtr right, 2608706f2543Smrg miArcFacePtr left) 2609706f2543Smrg{ 2610706f2543Smrg double t; 2611706f2543Smrg double innerTaily; 2612706f2543Smrg double tail_y; 2613706f2543Smrg struct bound innerx, outerx; 2614706f2543Smrg struct bound ellipsex; 2615706f2543Smrg 2616706f2543Smrg bound->ellipse.min = Dsin (def->a0) * def->h; 2617706f2543Smrg bound->ellipse.max = Dsin (def->a1) * def->h; 2618706f2543Smrg if (def->a0 == 45 && def->w == def->h) 2619706f2543Smrg ellipsex.min = bound->ellipse.min; 2620706f2543Smrg else 2621706f2543Smrg ellipsex.min = Dcos (def->a0) * def->w; 2622706f2543Smrg if (def->a1 == 45 && def->w == def->h) 2623706f2543Smrg ellipsex.max = bound->ellipse.max; 2624706f2543Smrg else 2625706f2543Smrg ellipsex.max = Dcos (def->a1) * def->w; 2626706f2543Smrg bound->outer.min = outerYfromXY (ellipsex.min, bound->ellipse.min, def, acc); 2627706f2543Smrg bound->outer.max = outerYfromXY (ellipsex.max, bound->ellipse.max, def, acc); 2628706f2543Smrg bound->inner.min = innerYfromXY (ellipsex.min, bound->ellipse.min, def, acc); 2629706f2543Smrg bound->inner.max = innerYfromXY (ellipsex.max, bound->ellipse.max, def, acc); 2630706f2543Smrg 2631706f2543Smrg outerx.min = outerXfromXY (ellipsex.min, bound->ellipse.min, def, acc); 2632706f2543Smrg outerx.max = outerXfromXY (ellipsex.max, bound->ellipse.max, def, acc); 2633706f2543Smrg innerx.min = innerXfromXY (ellipsex.min, bound->ellipse.min, def, acc); 2634706f2543Smrg innerx.max = innerXfromXY (ellipsex.max, bound->ellipse.max, def, acc); 2635706f2543Smrg 2636706f2543Smrg /* 2637706f2543Smrg * save the line end points for the 2638706f2543Smrg * cap code to use. Careful here, these are 2639706f2543Smrg * in cartesean coordinates (y increasing upwards) 2640706f2543Smrg * while the cap code uses inverted coordinates 2641706f2543Smrg * (y increasing downwards) 2642706f2543Smrg */ 2643706f2543Smrg 2644706f2543Smrg if (right) { 2645706f2543Smrg right->counterClock.y = bound->outer.min; 2646706f2543Smrg right->counterClock.x = outerx.min; 2647706f2543Smrg right->center.y = bound->ellipse.min; 2648706f2543Smrg right->center.x = ellipsex.min; 2649706f2543Smrg right->clock.y = bound->inner.min; 2650706f2543Smrg right->clock.x = innerx.min; 2651706f2543Smrg } 2652706f2543Smrg 2653706f2543Smrg if (left) { 2654706f2543Smrg left->clock.y = bound->outer.max; 2655706f2543Smrg left->clock.x = outerx.max; 2656706f2543Smrg left->center.y = bound->ellipse.max; 2657706f2543Smrg left->center.x = ellipsex.max; 2658706f2543Smrg left->counterClock.y = bound->inner.max; 2659706f2543Smrg left->counterClock.x = innerx.max; 2660706f2543Smrg } 2661706f2543Smrg 2662706f2543Smrg bound->left.min = bound->inner.max; 2663706f2543Smrg bound->left.max = bound->outer.max; 2664706f2543Smrg bound->right.min = bound->inner.min; 2665706f2543Smrg bound->right.max = bound->outer.min; 2666706f2543Smrg 2667706f2543Smrg computeLine (innerx.min, bound->inner.min, outerx.min, bound->outer.min, 2668706f2543Smrg &acc->right); 2669706f2543Smrg computeLine (innerx.max, bound->inner.max, outerx.max, bound->outer.max, 2670706f2543Smrg &acc->left); 2671706f2543Smrg 2672706f2543Smrg if (bound->inner.min > bound->inner.max) { 2673706f2543Smrg t = bound->inner.min; 2674706f2543Smrg bound->inner.min = bound->inner.max; 2675706f2543Smrg bound->inner.max = t; 2676706f2543Smrg } 2677706f2543Smrg tail_y = acc->tail_y; 2678706f2543Smrg if (tail_y > bound->ellipse.max) 2679706f2543Smrg tail_y = bound->ellipse.max; 2680706f2543Smrg else if (tail_y < bound->ellipse.min) 2681706f2543Smrg tail_y = bound->ellipse.min; 2682706f2543Smrg innerTaily = innerYfromY (tail_y, def, acc); 2683706f2543Smrg if (bound->inner.min > innerTaily) 2684706f2543Smrg bound->inner.min = innerTaily; 2685706f2543Smrg if (bound->inner.max < innerTaily) 2686706f2543Smrg bound->inner.max = innerTaily; 2687706f2543Smrg bound->inneri.min = ICEIL(bound->inner.min - acc->fromIntY); 2688706f2543Smrg bound->inneri.max = floor(bound->inner.max - acc->fromIntY); 2689706f2543Smrg bound->outeri.min = ICEIL(bound->outer.min - acc->fromIntY); 2690706f2543Smrg bound->outeri.max = floor(bound->outer.max - acc->fromIntY); 2691706f2543Smrg} 2692706f2543Smrg 2693706f2543Smrg/* 2694706f2543Smrg * this section computes the x value of the span at y 2695706f2543Smrg * intersected with the specified face of the ellipse. 2696706f2543Smrg * 2697706f2543Smrg * this is the min/max X value over the set of normal 2698706f2543Smrg * lines to the entire ellipse, the equation of the 2699706f2543Smrg * normal lines is: 2700706f2543Smrg * 2701706f2543Smrg * ellipse_x h^2 h^2 2702706f2543Smrg * x = ------------ y + ellipse_x (1 - --- ) 2703706f2543Smrg * ellipse_y w^2 w^2 2704706f2543Smrg * 2705706f2543Smrg * compute the derivative with-respect-to ellipse_y and solve 2706706f2543Smrg * for zero: 2707706f2543Smrg * 2708706f2543Smrg * (w^2 - h^2) ellipse_y^3 + h^4 y 2709706f2543Smrg * 0 = - ---------------------------------- 2710706f2543Smrg * h w ellipse_y^2 sqrt (h^2 - ellipse_y^2) 2711706f2543Smrg * 2712706f2543Smrg * ( h^4 y ) 2713706f2543Smrg * ellipse_y = ( ---------- ) ^ (1/3) 2714706f2543Smrg * ( (h^2 - w^2) ) 2715706f2543Smrg * 2716706f2543Smrg * The other two solutions to the equation are imaginary. 2717706f2543Smrg * 2718706f2543Smrg * This gives the position on the ellipse which generates 2719706f2543Smrg * the normal with the largest/smallest x intersection point. 2720706f2543Smrg * 2721706f2543Smrg * Now compute the second derivative to check whether 2722706f2543Smrg * the intersection is a minimum or maximum: 2723706f2543Smrg * 2724706f2543Smrg * h (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2)) 2725706f2543Smrg * - ------------------------------------------- 2726706f2543Smrg * w y0^3 (sqrt (h^2 - y^2)) ^ 3 2727706f2543Smrg * 2728706f2543Smrg * as we only care about the sign, 2729706f2543Smrg * 2730706f2543Smrg * - (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2)) 2731706f2543Smrg * 2732706f2543Smrg * or (to use accelerators), 2733706f2543Smrg * 2734706f2543Smrg * y0^3 (h^2 - w^2) - h^2 y (3y0^2 - 2h^2) 2735706f2543Smrg * 2736706f2543Smrg */ 2737706f2543Smrg 2738706f2543Smrg/* 2739706f2543Smrg * computes the position on the ellipse whose normal line 2740706f2543Smrg * intersects the given scan line maximally 2741706f2543Smrg */ 2742706f2543Smrg 2743706f2543Smrgstatic double 2744706f2543SmrghookEllipseY ( 2745706f2543Smrg double scan_y, 2746706f2543Smrg struct arc_bound *bound, 2747706f2543Smrg struct accelerators *acc, 2748706f2543Smrg int left) 2749706f2543Smrg{ 2750706f2543Smrg double ret; 2751706f2543Smrg 2752706f2543Smrg if (acc->h2mw2 == 0) { 2753706f2543Smrg if ( (scan_y > 0 && !left) || (scan_y < 0 && left) ) 2754706f2543Smrg return bound->ellipse.min; 2755706f2543Smrg return bound->ellipse.max; 2756706f2543Smrg } 2757706f2543Smrg ret = (acc->h4 * scan_y) / (acc->h2mw2); 2758706f2543Smrg if (ret >= 0) 2759706f2543Smrg return cbrt (ret); 2760706f2543Smrg else 2761706f2543Smrg return -cbrt (-ret); 2762706f2543Smrg} 2763706f2543Smrg 2764706f2543Smrg/* 2765706f2543Smrg * computes the X value of the intersection of the 2766706f2543Smrg * given scan line with the right side of the lower hook 2767706f2543Smrg */ 2768706f2543Smrg 2769706f2543Smrgstatic double 2770706f2543SmrghookX ( 2771706f2543Smrg double scan_y, 2772706f2543Smrg struct arc_def *def, 2773706f2543Smrg struct arc_bound *bound, 2774706f2543Smrg struct accelerators *acc, 2775706f2543Smrg int left) 2776706f2543Smrg{ 2777706f2543Smrg double ellipse_y, x; 2778706f2543Smrg double maxMin; 2779706f2543Smrg 2780706f2543Smrg if (def->w != def->h) { 2781706f2543Smrg ellipse_y = hookEllipseY (scan_y, bound, acc, left); 2782706f2543Smrg if (boundedLe (ellipse_y, bound->ellipse)) { 2783706f2543Smrg /* 2784706f2543Smrg * compute the value of the second 2785706f2543Smrg * derivative 2786706f2543Smrg */ 2787706f2543Smrg maxMin = ellipse_y*ellipse_y*ellipse_y * acc->h2mw2 - 2788706f2543Smrg acc->h2 * scan_y * (3 * ellipse_y*ellipse_y - 2*acc->h2); 2789706f2543Smrg if ((left && maxMin > 0) || (!left && maxMin < 0)) { 2790706f2543Smrg if (ellipse_y == 0) 2791706f2543Smrg return def->w + left ? -def->l : def->l; 2792706f2543Smrg x = (acc->h2 * scan_y - ellipse_y * acc->h2mw2) * 2793706f2543Smrg sqrt (acc->h2 - ellipse_y * ellipse_y) / 2794706f2543Smrg (def->h * def->w * ellipse_y); 2795706f2543Smrg return x; 2796706f2543Smrg } 2797706f2543Smrg } 2798706f2543Smrg } 2799706f2543Smrg if (left) { 2800706f2543Smrg if (acc->left.valid && boundedLe (scan_y, bound->left)) { 2801706f2543Smrg x = intersectLine (scan_y, acc->left); 2802706f2543Smrg } else { 2803706f2543Smrg if (acc->right.valid) 2804706f2543Smrg x = intersectLine (scan_y, acc->right); 2805706f2543Smrg else 2806706f2543Smrg x = def->w - def->l; 2807706f2543Smrg } 2808706f2543Smrg } else { 2809706f2543Smrg if (acc->right.valid && boundedLe (scan_y, bound->right)) { 2810706f2543Smrg x = intersectLine (scan_y, acc->right); 2811706f2543Smrg } else { 2812706f2543Smrg if (acc->left.valid) 2813706f2543Smrg x = intersectLine (scan_y, acc->left); 2814706f2543Smrg else 2815706f2543Smrg x = def->w - def->l; 2816706f2543Smrg } 2817706f2543Smrg } 2818706f2543Smrg return x; 2819706f2543Smrg} 2820706f2543Smrg 2821706f2543Smrg/* 2822706f2543Smrg * generate the set of spans with 2823706f2543Smrg * the given y coordinate 2824706f2543Smrg */ 2825706f2543Smrg 2826706f2543Smrgstatic void 2827706f2543SmrgarcSpan ( 2828706f2543Smrg int y, 2829706f2543Smrg int lx, 2830706f2543Smrg int lw, 2831706f2543Smrg int rx, 2832706f2543Smrg int rw, 2833706f2543Smrg struct arc_def *def, 2834706f2543Smrg struct arc_bound *bounds, 2835706f2543Smrg struct accelerators *acc, 2836706f2543Smrg int mask) 2837706f2543Smrg{ 2838706f2543Smrg int linx, loutx, rinx, routx; 2839706f2543Smrg double x, altx; 2840706f2543Smrg 2841706f2543Smrg if (boundedLe (y, bounds->inneri)) { 2842706f2543Smrg linx = -(lx + lw); 2843706f2543Smrg rinx = rx; 2844706f2543Smrg } else { 2845706f2543Smrg /* 2846706f2543Smrg * intersection with left face 2847706f2543Smrg */ 2848706f2543Smrg x = hookX (y + acc->fromIntY, def, bounds, acc, 1); 2849706f2543Smrg if (acc->right.valid && 2850706f2543Smrg boundedLe (y + acc->fromIntY, bounds->right)) 2851706f2543Smrg { 2852706f2543Smrg altx = intersectLine (y + acc->fromIntY, acc->right); 2853706f2543Smrg if (altx < x) 2854706f2543Smrg x = altx; 2855706f2543Smrg } 2856706f2543Smrg linx = -ICEIL(acc->fromIntX - x); 2857706f2543Smrg rinx = ICEIL(acc->fromIntX + x); 2858706f2543Smrg } 2859706f2543Smrg if (boundedLe (y, bounds->outeri)) { 2860706f2543Smrg loutx = -lx; 2861706f2543Smrg routx = rx + rw; 2862706f2543Smrg } else { 2863706f2543Smrg /* 2864706f2543Smrg * intersection with right face 2865706f2543Smrg */ 2866706f2543Smrg x = hookX (y + acc->fromIntY, def, bounds, acc, 0); 2867706f2543Smrg if (acc->left.valid && 2868706f2543Smrg boundedLe (y + acc->fromIntY, bounds->left)) 2869706f2543Smrg { 2870706f2543Smrg altx = x; 2871706f2543Smrg x = intersectLine (y + acc->fromIntY, acc->left); 2872706f2543Smrg if (x < altx) 2873706f2543Smrg x = altx; 2874706f2543Smrg } 2875706f2543Smrg loutx = -ICEIL(acc->fromIntX - x); 2876706f2543Smrg routx = ICEIL(acc->fromIntX + x); 2877706f2543Smrg } 2878706f2543Smrg if (routx > rinx) { 2879706f2543Smrg if (mask & 1) 2880706f2543Smrg newFinalSpan (acc->yorgu - y, 2881706f2543Smrg acc->xorg + rinx, acc->xorg + routx); 2882706f2543Smrg if (mask & 8) 2883706f2543Smrg newFinalSpan (acc->yorgl + y, 2884706f2543Smrg acc->xorg + rinx, acc->xorg + routx); 2885706f2543Smrg } 2886706f2543Smrg if (loutx > linx) { 2887706f2543Smrg if (mask & 2) 2888706f2543Smrg newFinalSpan (acc->yorgu - y, 2889706f2543Smrg acc->xorg - loutx, acc->xorg - linx); 2890706f2543Smrg if (mask & 4) 2891706f2543Smrg newFinalSpan (acc->yorgl + y, 2892706f2543Smrg acc->xorg - loutx, acc->xorg - linx); 2893706f2543Smrg } 2894706f2543Smrg} 2895706f2543Smrg 2896706f2543Smrgstatic void 2897706f2543SmrgarcSpan0 ( 2898706f2543Smrg int lx, 2899706f2543Smrg int lw, 2900706f2543Smrg int rx, 2901706f2543Smrg int rw, 2902706f2543Smrg struct arc_def *def, 2903706f2543Smrg struct arc_bound *bounds, 2904706f2543Smrg struct accelerators *acc, 2905706f2543Smrg int mask) 2906706f2543Smrg{ 2907706f2543Smrg double x; 2908706f2543Smrg 2909706f2543Smrg if (boundedLe (0, bounds->inneri) && 2910706f2543Smrg acc->left.valid && boundedLe (0, bounds->left) && 2911706f2543Smrg acc->left.b > 0) 2912706f2543Smrg { 2913706f2543Smrg x = def->w - def->l; 2914706f2543Smrg if (acc->left.b < x) 2915706f2543Smrg x = acc->left.b; 2916706f2543Smrg lw = ICEIL(acc->fromIntX - x) - lx; 2917706f2543Smrg rw += rx; 2918706f2543Smrg rx = ICEIL(acc->fromIntX + x); 2919706f2543Smrg rw -= rx; 2920706f2543Smrg } 2921706f2543Smrg arcSpan (0, lx, lw, rx, rw, def, bounds, acc, mask); 2922706f2543Smrg} 2923706f2543Smrg 2924706f2543Smrgstatic void 2925706f2543SmrgtailSpan ( 2926706f2543Smrg int y, 2927706f2543Smrg int lw, 2928706f2543Smrg int rw, 2929706f2543Smrg struct arc_def *def, 2930706f2543Smrg struct arc_bound *bounds, 2931706f2543Smrg struct accelerators *acc, 2932706f2543Smrg int mask) 2933706f2543Smrg{ 2934706f2543Smrg double yy, xalt, x, lx, rx; 2935706f2543Smrg int n; 2936706f2543Smrg 2937706f2543Smrg if (boundedLe(y, bounds->outeri)) 2938706f2543Smrg arcSpan (y, 0, lw, -rw, rw, def, bounds, acc, mask); 2939706f2543Smrg else if (def->w != def->h) { 2940706f2543Smrg yy = y + acc->fromIntY; 2941706f2543Smrg x = tailX(yy, def, bounds, acc); 2942706f2543Smrg if (yy == 0.0 && x == -rw - acc->fromIntX) 2943706f2543Smrg return; 2944706f2543Smrg if (acc->right.valid && boundedLe (yy, bounds->right)) { 2945706f2543Smrg rx = x; 2946706f2543Smrg lx = -x; 2947706f2543Smrg xalt = intersectLine (yy, acc->right); 2948706f2543Smrg if (xalt >= -rw - acc->fromIntX && xalt <= rx) 2949706f2543Smrg rx = xalt; 2950706f2543Smrg n = ICEIL(acc->fromIntX + lx); 2951706f2543Smrg if (lw > n) { 2952706f2543Smrg if (mask & 2) 2953706f2543Smrg newFinalSpan (acc->yorgu - y, 2954706f2543Smrg acc->xorg + n, acc->xorg + lw); 2955706f2543Smrg if (mask & 4) 2956706f2543Smrg newFinalSpan (acc->yorgl + y, 2957706f2543Smrg acc->xorg + n, acc->xorg + lw); 2958706f2543Smrg } 2959706f2543Smrg n = ICEIL(acc->fromIntX + rx); 2960706f2543Smrg if (n > -rw) { 2961706f2543Smrg if (mask & 1) 2962706f2543Smrg newFinalSpan (acc->yorgu - y, 2963706f2543Smrg acc->xorg - rw, acc->xorg + n); 2964706f2543Smrg if (mask & 8) 2965706f2543Smrg newFinalSpan (acc->yorgl + y, 2966706f2543Smrg acc->xorg - rw, acc->xorg + n); 2967706f2543Smrg } 2968706f2543Smrg } 2969706f2543Smrg arcSpan (y, 2970706f2543Smrg ICEIL(acc->fromIntX - x), 0, 2971706f2543Smrg ICEIL(acc->fromIntX + x), 0, 2972706f2543Smrg def, bounds, acc, mask); 2973706f2543Smrg } 2974706f2543Smrg} 2975706f2543Smrg 2976706f2543Smrg/* 2977706f2543Smrg * create whole arcs out of pieces. This code is 2978706f2543Smrg * very bad. 2979706f2543Smrg */ 2980706f2543Smrg 2981706f2543Smrgstatic struct finalSpan **finalSpans = NULL; 2982706f2543Smrgstatic int finalMiny = 0, finalMaxy = -1; 2983706f2543Smrgstatic int finalSize = 0; 2984706f2543Smrg 2985706f2543Smrgstatic int nspans = 0; /* total spans, not just y coords */ 2986706f2543Smrg 2987706f2543Smrgstruct finalSpan { 2988706f2543Smrg struct finalSpan *next; 2989706f2543Smrg int min, max; /* x values */ 2990706f2543Smrg}; 2991706f2543Smrg 2992706f2543Smrgstatic struct finalSpan *freeFinalSpans, *tmpFinalSpan; 2993706f2543Smrg 2994706f2543Smrg# define allocFinalSpan() (freeFinalSpans ?\ 2995706f2543Smrg ((tmpFinalSpan = freeFinalSpans), \ 2996706f2543Smrg (freeFinalSpans = freeFinalSpans->next), \ 2997706f2543Smrg (tmpFinalSpan->next = 0), \ 2998706f2543Smrg tmpFinalSpan) : \ 2999706f2543Smrg realAllocSpan ()) 3000706f2543Smrg 3001706f2543Smrg# define SPAN_CHUNK_SIZE 128 3002706f2543Smrg 3003706f2543Smrgstruct finalSpanChunk { 3004706f2543Smrg struct finalSpan data[SPAN_CHUNK_SIZE]; 3005706f2543Smrg struct finalSpanChunk *next; 3006706f2543Smrg}; 3007706f2543Smrg 3008706f2543Smrgstatic struct finalSpanChunk *chunks; 3009706f2543Smrg 3010706f2543Smrgstatic struct finalSpan * 3011706f2543SmrgrealAllocSpan (void) 3012706f2543Smrg{ 3013706f2543Smrg struct finalSpanChunk *newChunk; 3014706f2543Smrg struct finalSpan *span; 3015706f2543Smrg int i; 3016706f2543Smrg 3017706f2543Smrg newChunk = malloc(sizeof (struct finalSpanChunk)); 3018706f2543Smrg if (!newChunk) 3019706f2543Smrg return (struct finalSpan *) NULL; 3020706f2543Smrg newChunk->next = chunks; 3021706f2543Smrg chunks = newChunk; 3022706f2543Smrg freeFinalSpans = span = newChunk->data + 1; 3023706f2543Smrg for (i = 1; i < SPAN_CHUNK_SIZE-1; i++) { 3024706f2543Smrg span->next = span+1; 3025706f2543Smrg span++; 3026706f2543Smrg } 3027706f2543Smrg span->next = 0; 3028706f2543Smrg span = newChunk->data; 3029706f2543Smrg span->next = 0; 3030706f2543Smrg return span; 3031706f2543Smrg} 3032706f2543Smrg 3033706f2543Smrgstatic void 3034706f2543SmrgdisposeFinalSpans (void) 3035706f2543Smrg{ 3036706f2543Smrg struct finalSpanChunk *chunk, *next; 3037706f2543Smrg 3038706f2543Smrg for (chunk = chunks; chunk; chunk = next) { 3039706f2543Smrg next = chunk->next; 3040706f2543Smrg free(chunk); 3041706f2543Smrg } 3042706f2543Smrg chunks = 0; 3043706f2543Smrg freeFinalSpans = 0; 3044706f2543Smrg free(finalSpans); 3045706f2543Smrg finalSpans = 0; 3046706f2543Smrg} 3047706f2543Smrg 3048706f2543Smrgstatic void 3049706f2543SmrgfillSpans ( 3050706f2543Smrg DrawablePtr pDrawable, 3051706f2543Smrg GCPtr pGC) 3052706f2543Smrg{ 3053706f2543Smrg struct finalSpan *span; 3054706f2543Smrg DDXPointPtr xSpan; 3055706f2543Smrg int *xWidth; 3056706f2543Smrg int i; 3057706f2543Smrg struct finalSpan **f; 3058706f2543Smrg int spany; 3059706f2543Smrg DDXPointPtr xSpans; 3060706f2543Smrg int *xWidths; 3061706f2543Smrg 3062706f2543Smrg if (nspans == 0) 3063706f2543Smrg return; 3064706f2543Smrg xSpan = xSpans = malloc(nspans * sizeof (DDXPointRec)); 3065706f2543Smrg xWidth = xWidths = malloc(nspans * sizeof (int)); 3066706f2543Smrg if (xSpans && xWidths) 3067706f2543Smrg { 3068706f2543Smrg i = 0; 3069706f2543Smrg f = finalSpans; 3070706f2543Smrg for (spany = finalMiny; spany <= finalMaxy; spany++, f++) { 3071706f2543Smrg for (span = *f; span; span=span->next) { 3072706f2543Smrg if (span->max <= span->min) 3073706f2543Smrg continue; 3074706f2543Smrg xSpan->x = span->min; 3075706f2543Smrg xSpan->y = spany; 3076706f2543Smrg ++xSpan; 3077706f2543Smrg *xWidth++ = span->max - span->min; 3078706f2543Smrg ++i; 3079706f2543Smrg } 3080706f2543Smrg } 3081706f2543Smrg (*pGC->ops->FillSpans) (pDrawable, pGC, i, xSpans, xWidths, TRUE); 3082706f2543Smrg } 3083706f2543Smrg disposeFinalSpans (); 3084706f2543Smrg free(xSpans); 3085706f2543Smrg free(xWidths); 3086706f2543Smrg finalMiny = 0; 3087706f2543Smrg finalMaxy = -1; 3088706f2543Smrg finalSize = 0; 3089706f2543Smrg nspans = 0; 3090706f2543Smrg} 3091706f2543Smrg 3092706f2543Smrg# define SPAN_REALLOC 100 3093706f2543Smrg 3094706f2543Smrg# define findSpan(y) ((finalMiny <= (y) && (y) <= finalMaxy) ? \ 3095706f2543Smrg &finalSpans[(y) - finalMiny] : \ 3096706f2543Smrg realFindSpan (y)) 3097706f2543Smrg 3098706f2543Smrgstatic struct finalSpan ** 3099706f2543SmrgrealFindSpan (int y) 3100706f2543Smrg{ 3101706f2543Smrg struct finalSpan **newSpans; 3102706f2543Smrg int newSize, newMiny, newMaxy; 3103706f2543Smrg int change; 3104706f2543Smrg int i; 3105706f2543Smrg 3106706f2543Smrg if (y < finalMiny || y > finalMaxy) { 3107706f2543Smrg if (!finalSize) { 3108706f2543Smrg finalMiny = y; 3109706f2543Smrg finalMaxy = y - 1; 3110706f2543Smrg } 3111706f2543Smrg if (y < finalMiny) 3112706f2543Smrg change = finalMiny - y; 3113706f2543Smrg else 3114706f2543Smrg change = y - finalMaxy; 3115706f2543Smrg if (change >= SPAN_REALLOC) 3116706f2543Smrg change += SPAN_REALLOC; 3117706f2543Smrg else 3118706f2543Smrg change = SPAN_REALLOC; 3119706f2543Smrg newSize = finalSize + change; 3120706f2543Smrg newSpans = malloc(newSize * sizeof (struct finalSpan *)); 3121706f2543Smrg if (!newSpans) 3122706f2543Smrg return NULL; 3123706f2543Smrg newMiny = finalMiny; 3124706f2543Smrg newMaxy = finalMaxy; 3125706f2543Smrg if (y < finalMiny) 3126706f2543Smrg newMiny = finalMiny - change; 3127706f2543Smrg else 3128706f2543Smrg newMaxy = finalMaxy + change; 3129706f2543Smrg if (finalSpans) { 3130706f2543Smrg memmove(((char *) newSpans) + (finalMiny-newMiny) * sizeof (struct finalSpan *), 3131706f2543Smrg (char *) finalSpans, 3132706f2543Smrg finalSize * sizeof (struct finalSpan *)); 3133706f2543Smrg free(finalSpans); 3134706f2543Smrg } 3135706f2543Smrg if ((i = finalMiny - newMiny) > 0) 3136706f2543Smrg memset((char *)newSpans, 0, i * sizeof (struct finalSpan *)); 3137706f2543Smrg if ((i = newMaxy - finalMaxy) > 0) 3138706f2543Smrg memset((char *)(newSpans + newSize - i), 0, 3139706f2543Smrg i * sizeof (struct finalSpan *)); 3140706f2543Smrg finalSpans = newSpans; 3141706f2543Smrg finalMaxy = newMaxy; 3142706f2543Smrg finalMiny = newMiny; 3143706f2543Smrg finalSize = newSize; 3144706f2543Smrg } 3145706f2543Smrg return &finalSpans[y - finalMiny]; 3146706f2543Smrg} 3147706f2543Smrg 3148706f2543Smrgstatic void 3149706f2543SmrgnewFinalSpan ( 3150706f2543Smrg int y, 3151706f2543Smrg int xmin, 3152706f2543Smrg int xmax) 3153706f2543Smrg{ 3154706f2543Smrg struct finalSpan *x; 3155706f2543Smrg struct finalSpan **f; 3156706f2543Smrg struct finalSpan *oldx; 3157706f2543Smrg struct finalSpan *prev; 3158706f2543Smrg 3159706f2543Smrg f = findSpan (y); 3160706f2543Smrg if (!f) 3161706f2543Smrg return; 3162706f2543Smrg oldx = 0; 3163706f2543Smrg for (;;) { 3164706f2543Smrg prev = 0; 3165706f2543Smrg for (x = *f; x; x=x->next) { 3166706f2543Smrg if (x == oldx) { 3167706f2543Smrg prev = x; 3168706f2543Smrg continue; 3169706f2543Smrg } 3170706f2543Smrg if (x->min <= xmax && xmin <= x->max) { 3171706f2543Smrg if (oldx) { 3172706f2543Smrg oldx->min = min (x->min, xmin); 3173706f2543Smrg oldx->max = max (x->max, xmax); 3174706f2543Smrg if (prev) 3175706f2543Smrg prev->next = x->next; 3176706f2543Smrg else 3177706f2543Smrg *f = x->next; 3178706f2543Smrg --nspans; 3179706f2543Smrg } else { 3180706f2543Smrg x->min = min (x->min, xmin); 3181706f2543Smrg x->max = max (x->max, xmax); 3182706f2543Smrg oldx = x; 3183706f2543Smrg } 3184706f2543Smrg xmin = oldx->min; 3185706f2543Smrg xmax = oldx->max; 3186706f2543Smrg break; 3187706f2543Smrg } 3188706f2543Smrg prev = x; 3189706f2543Smrg } 3190706f2543Smrg if (!x) 3191706f2543Smrg break; 3192706f2543Smrg } 3193706f2543Smrg if (!oldx) { 3194706f2543Smrg x = allocFinalSpan (); 3195706f2543Smrg if (x) 3196706f2543Smrg { 3197706f2543Smrg x->min = xmin; 3198706f2543Smrg x->max = xmax; 3199706f2543Smrg x->next = *f; 3200706f2543Smrg *f = x; 3201706f2543Smrg ++nspans; 3202706f2543Smrg } 3203706f2543Smrg } 3204706f2543Smrg} 3205706f2543Smrg 3206706f2543Smrgstatic void 3207706f2543SmrgmirrorSppPoint ( 3208706f2543Smrg int quadrant, 3209706f2543Smrg SppPointPtr sppPoint) 3210706f2543Smrg{ 3211706f2543Smrg switch (quadrant) { 3212706f2543Smrg case 0: 3213706f2543Smrg break; 3214706f2543Smrg case 1: 3215706f2543Smrg sppPoint->x = -sppPoint->x; 3216706f2543Smrg break; 3217706f2543Smrg case 2: 3218706f2543Smrg sppPoint->x = -sppPoint->x; 3219706f2543Smrg sppPoint->y = -sppPoint->y; 3220706f2543Smrg break; 3221706f2543Smrg case 3: 3222706f2543Smrg sppPoint->y = -sppPoint->y; 3223706f2543Smrg break; 3224706f2543Smrg } 3225706f2543Smrg /* 3226706f2543Smrg * and translate to X coordinate system 3227706f2543Smrg */ 3228706f2543Smrg sppPoint->y = -sppPoint->y; 3229706f2543Smrg} 3230706f2543Smrg 3231706f2543Smrg/* 3232706f2543Smrg * split an arc into pieces which are scan-converted 3233706f2543Smrg * in the first-quadrant and mirrored into position. 3234706f2543Smrg * This is necessary as the scan-conversion code can 3235706f2543Smrg * only deal with arcs completely contained in the 3236706f2543Smrg * first quadrant. 3237706f2543Smrg */ 3238706f2543Smrg 3239706f2543Smrgstatic void 3240706f2543SmrgdrawArc ( 3241706f2543Smrg xArc *tarc, 3242706f2543Smrg int l, 3243706f2543Smrg int a0, 3244706f2543Smrg int a1, 3245706f2543Smrg miArcFacePtr right, 3246706f2543Smrg miArcFacePtr left) /* save end line points */ 3247706f2543Smrg{ 3248706f2543Smrg struct arc_def def; 3249706f2543Smrg struct accelerators acc; 3250706f2543Smrg int startq, endq, curq; 3251706f2543Smrg int rightq, leftq = 0, righta = 0, lefta = 0; 3252706f2543Smrg miArcFacePtr passRight, passLeft; 3253706f2543Smrg int q0 = 0, q1 = 0, mask; 3254706f2543Smrg struct band { 3255706f2543Smrg int a0, a1; 3256706f2543Smrg int mask; 3257706f2543Smrg } band[5], sweep[20]; 3258706f2543Smrg int bandno, sweepno; 3259706f2543Smrg int i, j; 3260706f2543Smrg int flipRight = 0, flipLeft = 0; 3261706f2543Smrg int copyEnd = 0; 3262706f2543Smrg miArcSpanData *spdata; 3263706f2543Smrg 3264706f2543Smrg spdata = miComputeWideEllipse(l, tarc); 3265706f2543Smrg if (!spdata) 3266706f2543Smrg return; 3267706f2543Smrg 3268706f2543Smrg if (a1 < a0) 3269706f2543Smrg a1 += 360 * 64; 3270706f2543Smrg startq = a0 / (90 * 64); 3271706f2543Smrg if (a0 == a1) 3272706f2543Smrg endq = startq; 3273706f2543Smrg else 3274706f2543Smrg endq = (a1-1) / (90 * 64); 3275706f2543Smrg bandno = 0; 3276706f2543Smrg curq = startq; 3277706f2543Smrg rightq = -1; 3278706f2543Smrg for (;;) { 3279706f2543Smrg switch (curq) { 3280706f2543Smrg case 0: 3281706f2543Smrg if (a0 > 90 * 64) 3282706f2543Smrg q0 = 0; 3283706f2543Smrg else 3284706f2543Smrg q0 = a0; 3285706f2543Smrg if (a1 < 360 * 64) 3286706f2543Smrg q1 = min (a1, 90 * 64); 3287706f2543Smrg else 3288706f2543Smrg q1 = 90 * 64; 3289706f2543Smrg if (curq == startq && a0 == q0 && rightq < 0) { 3290706f2543Smrg righta = q0; 3291706f2543Smrg rightq = curq; 3292706f2543Smrg } 3293706f2543Smrg if (curq == endq && a1 == q1) { 3294706f2543Smrg lefta = q1; 3295706f2543Smrg leftq = curq; 3296706f2543Smrg } 3297706f2543Smrg break; 3298706f2543Smrg case 1: 3299706f2543Smrg if (a1 < 90 * 64) 3300706f2543Smrg q0 = 0; 3301706f2543Smrg else 3302706f2543Smrg q0 = 180 * 64 - min (a1, 180 * 64); 3303706f2543Smrg if (a0 > 180 * 64) 3304706f2543Smrg q1 = 90 * 64; 3305706f2543Smrg else 3306706f2543Smrg q1 = 180 * 64 - max (a0, 90 * 64); 3307706f2543Smrg if (curq == startq && 180 * 64 - a0 == q1) { 3308706f2543Smrg righta = q1; 3309706f2543Smrg rightq = curq; 3310706f2543Smrg } 3311706f2543Smrg if (curq == endq && 180 * 64 - a1 == q0) { 3312706f2543Smrg lefta = q0; 3313706f2543Smrg leftq = curq; 3314706f2543Smrg } 3315706f2543Smrg break; 3316706f2543Smrg case 2: 3317706f2543Smrg if (a0 > 270 * 64) 3318706f2543Smrg q0 = 0; 3319706f2543Smrg else 3320706f2543Smrg q0 = max (a0, 180 * 64) - 180 * 64; 3321706f2543Smrg if (a1 < 180 * 64) 3322706f2543Smrg q1 = 90 * 64; 3323706f2543Smrg else 3324706f2543Smrg q1 = min (a1, 270 * 64) - 180 * 64; 3325706f2543Smrg if (curq == startq && a0 - 180*64 == q0) { 3326706f2543Smrg righta = q0; 3327706f2543Smrg rightq = curq; 3328706f2543Smrg } 3329706f2543Smrg if (curq == endq && a1 - 180 * 64 == q1) { 3330706f2543Smrg lefta = q1; 3331706f2543Smrg leftq = curq; 3332706f2543Smrg } 3333706f2543Smrg break; 3334706f2543Smrg case 3: 3335706f2543Smrg if (a1 < 270 * 64) 3336706f2543Smrg q0 = 0; 3337706f2543Smrg else 3338706f2543Smrg q0 = 360 * 64 - min (a1, 360 * 64); 3339706f2543Smrg q1 = 360 * 64 - max (a0, 270 * 64); 3340706f2543Smrg if (curq == startq && 360 * 64 - a0 == q1) { 3341706f2543Smrg righta = q1; 3342706f2543Smrg rightq = curq; 3343706f2543Smrg } 3344706f2543Smrg if (curq == endq && 360 * 64 - a1 == q0) { 3345706f2543Smrg lefta = q0; 3346706f2543Smrg leftq = curq; 3347706f2543Smrg } 3348706f2543Smrg break; 3349706f2543Smrg } 3350706f2543Smrg band[bandno].a0 = q0; 3351706f2543Smrg band[bandno].a1 = q1; 3352706f2543Smrg band[bandno].mask = 1 << curq; 3353706f2543Smrg bandno++; 3354706f2543Smrg if (curq == endq) 3355706f2543Smrg break; 3356706f2543Smrg curq++; 3357706f2543Smrg if (curq == 4) { 3358706f2543Smrg a0 = 0; 3359706f2543Smrg a1 -= 360 * 64; 3360706f2543Smrg curq = 0; 3361706f2543Smrg endq -= 4; 3362706f2543Smrg } 3363706f2543Smrg } 3364706f2543Smrg sweepno = 0; 3365706f2543Smrg for (;;) { 3366706f2543Smrg q0 = 90 * 64; 3367706f2543Smrg mask = 0; 3368706f2543Smrg /* 3369706f2543Smrg * find left-most point 3370706f2543Smrg */ 3371706f2543Smrg for (i = 0; i < bandno; i++) 3372706f2543Smrg if (band[i].a0 <= q0) { 3373706f2543Smrg q0 = band[i].a0; 3374706f2543Smrg q1 = band[i].a1; 3375706f2543Smrg mask = band[i].mask; 3376706f2543Smrg } 3377706f2543Smrg if (!mask) 3378706f2543Smrg break; 3379706f2543Smrg /* 3380706f2543Smrg * locate next point of change 3381706f2543Smrg */ 3382706f2543Smrg for (i = 0; i < bandno; i++) 3383706f2543Smrg if (!(mask & band[i].mask)) { 3384706f2543Smrg if (band[i].a0 == q0) { 3385706f2543Smrg if (band[i].a1 < q1) 3386706f2543Smrg q1 = band[i].a1; 3387706f2543Smrg mask |= band[i].mask; 3388706f2543Smrg } else if (band[i].a0 < q1) 3389706f2543Smrg q1 = band[i].a0; 3390706f2543Smrg } 3391706f2543Smrg /* 3392706f2543Smrg * create a new sweep 3393706f2543Smrg */ 3394706f2543Smrg sweep[sweepno].a0 = q0; 3395706f2543Smrg sweep[sweepno].a1 = q1; 3396706f2543Smrg sweep[sweepno].mask = mask; 3397706f2543Smrg sweepno++; 3398706f2543Smrg /* 3399706f2543Smrg * subtract the sweep from the affected bands 3400706f2543Smrg */ 3401706f2543Smrg for (i = 0; i < bandno; i++) 3402706f2543Smrg if (band[i].a0 == q0) { 3403706f2543Smrg band[i].a0 = q1; 3404706f2543Smrg /* 3405706f2543Smrg * check if this band is empty 3406706f2543Smrg */ 3407706f2543Smrg if (band[i].a0 == band[i].a1) 3408706f2543Smrg band[i].a1 = band[i].a0 = 90 * 64 + 1; 3409706f2543Smrg } 3410706f2543Smrg } 3411706f2543Smrg computeAcc (tarc, l, &def, &acc); 3412706f2543Smrg for (j = 0; j < sweepno; j++) { 3413706f2543Smrg mask = sweep[j].mask; 3414706f2543Smrg passRight = passLeft = 0; 3415706f2543Smrg if (mask & (1 << rightq)) { 3416706f2543Smrg if (sweep[j].a0 == righta) 3417706f2543Smrg passRight = right; 3418706f2543Smrg else if (sweep[j].a1 == righta) { 3419706f2543Smrg passLeft = right; 3420706f2543Smrg flipRight = 1; 3421706f2543Smrg } 3422706f2543Smrg } 3423706f2543Smrg if (mask & (1 << leftq)) { 3424706f2543Smrg if (sweep[j].a1 == lefta) 3425706f2543Smrg { 3426706f2543Smrg if (passLeft) 3427706f2543Smrg copyEnd = 1; 3428706f2543Smrg passLeft = left; 3429706f2543Smrg } 3430706f2543Smrg else if (sweep[j].a0 == lefta) { 3431706f2543Smrg if (passRight) 3432706f2543Smrg copyEnd = 1; 3433706f2543Smrg passRight = left; 3434706f2543Smrg flipLeft = 1; 3435706f2543Smrg } 3436706f2543Smrg } 3437706f2543Smrg drawQuadrant (&def, &acc, sweep[j].a0, sweep[j].a1, mask, 3438706f2543Smrg passRight, passLeft, spdata); 3439706f2543Smrg } 3440706f2543Smrg /* 3441706f2543Smrg * when copyEnd is set, both ends of the arc were computed 3442706f2543Smrg * at the same time; drawQuadrant only takes one end though, 3443706f2543Smrg * so the left end will be the only one holding the data. Copy 3444706f2543Smrg * it from there. 3445706f2543Smrg */ 3446706f2543Smrg if (copyEnd) 3447706f2543Smrg *right = *left; 3448706f2543Smrg /* 3449706f2543Smrg * mirror the coordinates generated for the 3450706f2543Smrg * faces of the arc 3451706f2543Smrg */ 3452706f2543Smrg if (right) { 3453706f2543Smrg mirrorSppPoint (rightq, &right->clock); 3454706f2543Smrg mirrorSppPoint (rightq, &right->center); 3455706f2543Smrg mirrorSppPoint (rightq, &right->counterClock); 3456706f2543Smrg if (flipRight) { 3457706f2543Smrg SppPointRec temp; 3458706f2543Smrg 3459706f2543Smrg temp = right->clock; 3460706f2543Smrg right->clock = right->counterClock; 3461706f2543Smrg right->counterClock = temp; 3462706f2543Smrg } 3463706f2543Smrg } 3464706f2543Smrg if (left) { 3465706f2543Smrg mirrorSppPoint (leftq, &left->counterClock); 3466706f2543Smrg mirrorSppPoint (leftq, &left->center); 3467706f2543Smrg mirrorSppPoint (leftq, &left->clock); 3468706f2543Smrg if (flipLeft) { 3469706f2543Smrg SppPointRec temp; 3470706f2543Smrg 3471706f2543Smrg temp = left->clock; 3472706f2543Smrg left->clock = left->counterClock; 3473706f2543Smrg left->counterClock = temp; 3474706f2543Smrg } 3475706f2543Smrg } 3476706f2543Smrg free(spdata); 3477706f2543Smrg} 3478706f2543Smrg 3479706f2543Smrgstatic void 3480706f2543SmrgdrawQuadrant ( 3481706f2543Smrg struct arc_def *def, 3482706f2543Smrg struct accelerators *acc, 3483706f2543Smrg int a0, 3484706f2543Smrg int a1, 3485706f2543Smrg int mask, 3486706f2543Smrg miArcFacePtr right, 3487706f2543Smrg miArcFacePtr left, 3488706f2543Smrg miArcSpanData *spdata) 3489706f2543Smrg{ 3490706f2543Smrg struct arc_bound bound; 3491706f2543Smrg double yy, x, xalt; 3492706f2543Smrg int y, miny, maxy; 3493706f2543Smrg int n; 3494706f2543Smrg miArcSpan *span; 3495706f2543Smrg 3496706f2543Smrg def->a0 = ((double) a0) / 64.0; 3497706f2543Smrg def->a1 = ((double) a1) / 64.0; 3498706f2543Smrg computeBound (def, &bound, acc, right, left); 3499706f2543Smrg yy = bound.inner.min; 3500706f2543Smrg if (bound.outer.min < yy) 3501706f2543Smrg yy = bound.outer.min; 3502706f2543Smrg miny = ICEIL(yy - acc->fromIntY); 3503706f2543Smrg yy = bound.inner.max; 3504706f2543Smrg if (bound.outer.max > yy) 3505706f2543Smrg yy = bound.outer.max; 3506706f2543Smrg maxy = floor(yy - acc->fromIntY); 3507706f2543Smrg y = spdata->k; 3508706f2543Smrg span = spdata->spans; 3509706f2543Smrg if (spdata->top) 3510706f2543Smrg { 3511706f2543Smrg if (a1 == 90 * 64 && (mask & 1)) 3512706f2543Smrg newFinalSpan (acc->yorgu - y - 1, acc->xorg, acc->xorg + 1); 3513706f2543Smrg span++; 3514706f2543Smrg } 3515706f2543Smrg for (n = spdata->count1; --n >= 0; ) 3516706f2543Smrg { 3517706f2543Smrg if (y < miny) 3518706f2543Smrg return; 3519706f2543Smrg if (y <= maxy) { 3520706f2543Smrg arcSpan (y, 3521706f2543Smrg span->lx, -span->lx, 0, span->lx + span->lw, 3522706f2543Smrg def, &bound, acc, mask); 3523706f2543Smrg if (span->rw + span->rx) 3524706f2543Smrg tailSpan (y, -span->rw, -span->rx, def, &bound, acc, mask); 3525706f2543Smrg } 3526706f2543Smrg y--; 3527706f2543Smrg span++; 3528706f2543Smrg } 3529706f2543Smrg if (y < miny) 3530706f2543Smrg return; 3531706f2543Smrg if (spdata->hole) 3532706f2543Smrg { 3533706f2543Smrg if (y <= maxy) 3534706f2543Smrg arcSpan (y, 0, 0, 0, 1, def, &bound, acc, mask & 0xc); 3535706f2543Smrg } 3536706f2543Smrg for (n = spdata->count2; --n >= 0; ) 3537706f2543Smrg { 3538706f2543Smrg if (y < miny) 3539706f2543Smrg return; 3540706f2543Smrg if (y <= maxy) 3541706f2543Smrg arcSpan (y, span->lx, span->lw, span->rx, span->rw, 3542706f2543Smrg def, &bound, acc, mask); 3543706f2543Smrg y--; 3544706f2543Smrg span++; 3545706f2543Smrg } 3546706f2543Smrg if (spdata->bot && miny <= y && y <= maxy) 3547706f2543Smrg { 3548706f2543Smrg n = mask; 3549706f2543Smrg if (y == miny) 3550706f2543Smrg n &= 0xc; 3551706f2543Smrg if (span->rw <= 0) { 3552706f2543Smrg arcSpan0 (span->lx, -span->lx, 0, span->lx + span->lw, 3553706f2543Smrg def, &bound, acc, n); 3554706f2543Smrg if (span->rw + span->rx) 3555706f2543Smrg tailSpan (y, -span->rw, -span->rx, def, &bound, acc, n); 3556706f2543Smrg } 3557706f2543Smrg else 3558706f2543Smrg arcSpan0 (span->lx, span->lw, span->rx, span->rw, 3559706f2543Smrg def, &bound, acc, n); 3560706f2543Smrg y--; 3561706f2543Smrg } 3562706f2543Smrg while (y >= miny) { 3563706f2543Smrg yy = y + acc->fromIntY; 3564706f2543Smrg if (def->w == def->h) { 3565706f2543Smrg xalt = def->w - def->l; 3566706f2543Smrg x = -sqrt(xalt * xalt - yy * yy); 3567706f2543Smrg } else { 3568706f2543Smrg x = tailX(yy, def, &bound, acc); 3569706f2543Smrg if (acc->left.valid && boundedLe (yy, bound.left)) { 3570706f2543Smrg xalt = intersectLine (yy, acc->left); 3571706f2543Smrg if (xalt < x) 3572706f2543Smrg x = xalt; 3573706f2543Smrg } 3574706f2543Smrg if (acc->right.valid && boundedLe (yy, bound.right)) { 3575706f2543Smrg xalt = intersectLine (yy, acc->right); 3576706f2543Smrg if (xalt < x) 3577706f2543Smrg x = xalt; 3578706f2543Smrg } 3579706f2543Smrg } 3580706f2543Smrg arcSpan (y, 3581706f2543Smrg ICEIL(acc->fromIntX - x), 0, 3582706f2543Smrg ICEIL(acc->fromIntX + x), 0, 3583706f2543Smrg def, &bound, acc, mask); 3584706f2543Smrg y--; 3585706f2543Smrg } 3586706f2543Smrg} 3587