|
|
1.1 ! root 1: /*********************************************************** ! 2: Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, ! 3: and the Massachusetts Institute of Technology, Cambridge, Massachusetts. ! 4: ! 5: All Rights Reserved ! 6: ! 7: Permission to use, copy, modify, and distribute this software and its ! 8: documentation for any purpose and without fee is hereby granted, ! 9: provided that the above copyright notice appear in all copies and that ! 10: both that copyright notice and this permission notice appear in ! 11: supporting documentation, and that the names of Digital or MIT not be ! 12: used in advertising or publicity pertaining to distribution of the ! 13: software without specific, written prior permission. ! 14: ! 15: DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ! 16: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ! 17: DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ! 18: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, ! 19: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ! 20: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ! 21: SOFTWARE. ! 22: ! 23: ******************************************************************/ ! 24: /* $Header: miarc.c,v 1.46 87/08/31 16:39:34 toddb Exp $ */ ! 25: /* Author: Todd Newman */ ! 26: #include "X.h" ! 27: #include "Xprotostr.h" ! 28: #include "misc.h" ! 29: #include "gcstruct.h" ! 30: #include "scrnintstr.h" ! 31: #include "pixmapstr.h" ! 32: #include "windowstr.h" ! 33: #include "mifpoly.h" ! 34: ! 35: extern double sqrt(), cos(), sin(), atan(); ! 36: /* these are from our <math.h>, but I'm told some systems don't have ! 37: * math.h and that they're not in all versions of math.h. Psi! */ ! 38: #define M_PI 3.14159265358979323846 ! 39: #define M_PI_2 1.57079632679489661923 ! 40: ! 41: ! 42: #define SAMESIGN(a, b) ((((a) >= 0) && ((b) >= 0)) ||\ ! 43: (((a) <= 0) && ((b) <= 0))) ! 44: ! 45: /* This contains the information needed to draw one arc of a polyarc. ! 46: * An array of them can be allocated if the polyarc has more than 1 part */ ! 47: typedef struct ! 48: { ! 49: int cpt; ! 50: DDXPointPtr pPts; ! 51: } POLYARCINFO; ! 52: ! 53: #define GCValsFunction 0 ! 54: #define GCValsForeground 1 ! 55: #define GCValsBackground 2 ! 56: #define GCValsLineWidth 3 ! 57: #define GCValsCapStyle 4 ! 58: #define GCValsJoinStyle 5 ! 59: #define GCValsArcMode 6 ! 60: static int gcvals[]= {GXcopy, 1, 0, 0, 0, 0, 0}; ! 61: ! 62: /* MIPOLYARC -- Public entry for the polyarc call. ! 63: * Strategy: Similar in many ways to that for wide lines. ! 64: * In general, we will each arc segment as a polyline. (We can make the arc ! 65: * arbitrarily smooth by increasing the number of segments and shortening ! 66: * the length of each segment.) ! 67: * If there's only 1 arc, or if the arc is draw with zero width lines, we ! 68: * don't have to worry about the rasterop or join styles. ! 69: * Otherwise, we set up pDrawTo and pGCTo according to the rasterop, then ! 70: * draw using pGCTo and pDrawTo. If the raster-op was "tricky," that is, ! 71: * if it involves the destination, then we use PushPixels to move the bits ! 72: * from the scratch drawable to pDraw. (See the wide line code for a ! 73: * fuller explanation of this.) ! 74: */ ! 75: void ! 76: miPolyArc(pDraw, pGC, narcs, parcs) ! 77: DrawablePtr pDraw; ! 78: GCPtr pGC; ! 79: int narcs; ! 80: xArc *parcs; ! 81: { ! 82: register int i, j; ! 83: register DDXPointPtr ppt; /* Points for the current arc */ ! 84: register DDXPointPtr pAllPts; /* Points for all arcs so far */ ! 85: register int cpt, /* count of points in current arc */ ! 86: cptAll; /* count of points in all arcs */ ! 87: DDXPointPtr pPts; /* Points for the current arc */ ! 88: int xMin, xMax, yMin, yMax, yOrg, xOrg, dx, dy, ! 89: ifirst, ilast, count, gcmode, arcmode, width; ! 90: Bool fAllOne, fTricky; ! 91: PixmapPtr pDrawTo; ! 92: GCPtr pGCTo; ! 93: POLYARCINFO *polyarcs; ! 94: DDXPointRec LastPt; ! 95: ! 96: ! 97: width = pGC->lineWidth; ! 98: if(width == 0 || narcs == 1) ! 99: { ! 100: /* don't have to worry about overlap or joinstyles */ ! 101: for(i = 0; i < narcs; i++) ! 102: { ! 103: pPts = (DDXPointPtr)NULL; ! 104: if( cpt = miGetArcPts(&parcs[i], 0, &pPts)) ! 105: { ! 106: (*pGC->Polylines)(pDraw, pGC, CoordModeOrigin, cpt, pPts); ! 107: Xfree(pPts); ! 108: } ! 109: } ! 110: } ! 111: else ! 112: { ! 113: count = 0; ! 114: ifirst = 0; ! 115: fAllOne = FALSE; ! 116: pPts = (DDXPointPtr) NULL; ! 117: pAllPts = (DDXPointPtr) NULL; ! 118: polyarcs = (POLYARCINFO *)ALLOCATE_LOCAL(narcs * sizeof(POLYARCINFO)); ! 119: if(!polyarcs) ! 120: return; ! 121: ! 122: xMin = yMin = MAXSHORT; ! 123: xMax = yMax = MINSHORT; ! 124: ! 125: /* Get all points for all the arcs. */ ! 126: for(i = 0; i < narcs; i++) ! 127: { ! 128: pPts = (DDXPointPtr) NULL; ! 129: if((cpt = miGetArcPts(&parcs[i], 0, &pPts)) == 0) ! 130: { ! 131: /* One of the arcs was empty. Give up */ ! 132: while(--i >= 0) ! 133: { ! 134: Xfree(polyarcs[i].pPts); ! 135: } ! 136: DEALLOCATE_LOCAL(polyarcs); ! 137: return; ! 138: } ! 139: polyarcs[i].cpt = cpt; ! 140: polyarcs[i].pPts = pPts; ! 141: ppt = pPts; ! 142: for(j = 0; j < cpt; j++) ! 143: { ! 144: xMin = min(xMin, ppt->x); ! 145: yMin = min(yMin, ppt->y); ! 146: xMax = max(xMax, ppt->x); ! 147: yMax = max(yMax, ppt->y); ! 148: ppt++; ! 149: } ! 150: } ! 151: /* Set up pDrawTo and pGCTo based on the rasterop */ ! 152: switch(pGC->alu) ! 153: { ! 154: case GXclear: /* 0 */ ! 155: case GXcopy: /* src */ ! 156: case GXcopyInverted: /* NOT src */ ! 157: case GXset: /* 1 */ ! 158: fTricky = FALSE; ! 159: pDrawTo = (PixmapPtr) pDraw; ! 160: pGCTo = pGC; ! 161: if(pGCTo->arcMode != ArcChord) ! 162: { ! 163: arcmode = pGCTo->arcMode; ! 164: DoChangeGC(pGCTo, GCArcMode, &gcvals[GCValsArcMode], 0); ! 165: ValidateGC(pDrawTo, pGCTo); ! 166: } ! 167: else ! 168: arcmode = ArcChord; ! 169: ! 170: break; ! 171: case GXand: /* src AND dst */ ! 172: case GXandReverse: /* src AND NOT dst */ ! 173: case GXandInverted: /* NOT src AND dst */ ! 174: case GXnoop: /* dst */ ! 175: case GXxor: /* src XOR dst */ ! 176: case GXor: /* src OR dst */ ! 177: case GXnor: /* NOT src AND NOT dst */ ! 178: case GXequiv: /* NOT src XOR dst */ ! 179: case GXinvert: /* NOT dst */ ! 180: case GXorReverse: /* src OR NOT dst */ ! 181: case GXorInverted: /* NOT src OR dst */ ! 182: case GXnand: /* NOT src OR NOT dst */ ! 183: fTricky = TRUE; ! 184: ! 185: pGCTo = GetScratchGC(1, pDraw->pScreen); ! 186: gcvals[GCValsLineWidth] = pGC->lineWidth; ! 187: gcvals[GCValsCapStyle] = pGC->capStyle; ! 188: gcvals[GCValsJoinStyle] = pGC->joinStyle; ! 189: ! 190: /* Also what about arcmode?? */ ! 191: gcmode = GCFunction | GCForeground | GCBackground | GCLineWidth | ! 192: GCCapStyle | GCJoinStyle; ! 193: DoChangeGC(pGCTo, gcmode, gcvals, 0); ! 194: ! 195: xOrg = xMin - (width + 1)/2; ! 196: yOrg = yMin - (width + 1)/2; ! 197: dx = xMax - xMin + width + 1; ! 198: dy = yMax - yMin + width + 1; ! 199: for(i = 0; i < narcs; i++) ! 200: { ! 201: cpt = polyarcs[i].cpt; ! 202: ppt = polyarcs[i].pPts; ! 203: for(j = 0; j < cpt; j++) ! 204: { ! 205: ppt->x -= xOrg; ! 206: ppt->y -= yOrg; ! 207: ppt++; ! 208: } ! 209: } ! 210: ! 211: /* allocate a 1 bit deep pixmap of the appropriate size, and ! 212: * validate it */ ! 213: pDrawTo = (PixmapPtr)(*pDraw->pScreen->CreatePixmap) ! 214: (pDraw->pScreen, dx, dy, 1, XYBitmap); ! 215: ValidateGC(pDrawTo, pGCTo); ! 216: miClearDrawable(pDrawTo, pGCTo); ! 217: } ! 218: ! 219: ilast = narcs - 1; ! 220: ! 221: /* If the last arc joins with the first, find all the final arcs ! 222: * that join together and join them with the initial ones. ! 223: */ ! 224: if(PtEqual(polyarcs[0].pPts[0], ! 225: polyarcs[ilast].pPts[polyarcs[ilast].cpt - 1]) ) ! 226: { ! 227: count = 1; ! 228: while(PtEqual (polyarcs[ilast].pPts[0], ! 229: polyarcs[ilast - 1].pPts[polyarcs[ilast - 1].cpt - 1]) ) ! 230: { ! 231: if(ilast <= 1) ! 232: { ! 233: fAllOne = TRUE; ! 234: break; ! 235: } ! 236: else ! 237: { ! 238: ilast--; ! 239: count++; ! 240: } ! 241: } ! 242: if(!fAllOne) ! 243: { ! 244: while(PtEqual(polyarcs[ifirst].pPts[polyarcs[ifirst].cpt -1], ! 245: polyarcs[ifirst + 1].pPts[0])) ! 246: ifirst++; ! 247: cptAll = polyarcs[ilast].cpt; ! 248: pAllPts = polyarcs[ilast].pPts; ! 249: polyarcs[ilast++].pPts = (DDXPointPtr) NULL; ! 250: for(; ilast < narcs; ilast++) ! 251: { ! 252: cpt = polyarcs[ilast].cpt; ! 253: pAllPts = (DDXPointPtr) Xrealloc(pAllPts, ! 254: (cptAll+cpt-1) * sizeof(DDXPointRec)); ! 255: bcopy((char *) &polyarcs[ilast].pPts[1], ! 256: (char *) &pAllPts[cptAll], ! 257: (cpt - 1) * sizeof(DDXPointRec)); ! 258: cptAll += cpt - 1; ! 259: } ! 260: for( i = 0; i <= ifirst; i++) ! 261: { ! 262: cpt = polyarcs[i].cpt; ! 263: pAllPts = (DDXPointPtr) Xrealloc(pAllPts, ! 264: (cptAll+cpt-1) * sizeof(DDXPointRec)); ! 265: bcopy((char *) &polyarcs[i].pPts[1], ! 266: (char *) &pAllPts[cptAll], ! 267: (cpt - 1) * sizeof(DDXPointRec)); ! 268: cptAll += cpt - 1; ! 269: } ! 270: (*pGCTo->Polylines)(pDrawTo, pGCTo, CoordModeOrigin, ! 271: cptAll, pAllPts); ! 272: /* Don't need to free pAllPts, because we're sure to ! 273: * Xrealloc it again */ ! 274: if(fTricky) ! 275: { ! 276: (*pGC->PushPixels)(pGC, pDrawTo, pDraw, dx, dy, ! 277: xOrg, yOrg); ! 278: miClearDrawable(pDrawTo, pGCTo); ! 279: } ! 280: } ! 281: ifirst++; ! 282: } ! 283: narcs -= count; ! 284: ! 285: /* Now draw all the (remaining) arcs */ ! 286: cptAll = 0; ! 287: for(i = ifirst; i < narcs; i++) ! 288: { ! 289: cpt = polyarcs[i].cpt; ! 290: pPts = polyarcs[i].pPts; ! 291: ! 292: if((i > ifirst) && PtEqual(pPts[0], LastPt)) ! 293: { ! 294: pAllPts = (DDXPointPtr) ! 295: Xrealloc(pAllPts, ! 296: (cptAll-1 + cpt) * sizeof(DDXPointRec)); ! 297: bcopy((char *)&pPts[1], ! 298: (char *)&pAllPts[cptAll], ! 299: (cpt - 1) * sizeof(DDXPointRec)); ! 300: cptAll += cpt - 1; ! 301: } ! 302: else ! 303: { ! 304: /* Flush what we have so far and start collecting again */ ! 305: if(cptAll > 0) ! 306: { ! 307: (*pGC->Polylines)(pDrawTo, pGCTo, CoordModeOrigin, ! 308: cptAll, pAllPts); ! 309: Xfree(pAllPts); ! 310: if(fTricky) ! 311: { ! 312: (*pGC->PushPixels)(pGC, pDrawTo, pDraw, dx, dy, ! 313: xOrg, yOrg); ! 314: miClearDrawable(pDrawTo, pGCTo); ! 315: } ! 316: } ! 317: cptAll = cpt; ! 318: pAllPts = pPts; ! 319: } ! 320: LastPt = pPts[cpt-1]; ! 321: } /* end for each remaining arc */ ! 322: ! 323: ! 324: if(cptAll > 0) ! 325: { ! 326: (*pGC->Polylines)(pDrawTo,pGCTo, CoordModeOrigin, cptAll, pAllPts); ! 327: Xfree(pAllPts); ! 328: } ! 329: if(fTricky) ! 330: (*pGC->PushPixels)(pGC, pDrawTo, pDraw, dx, dy, xOrg, yOrg); ! 331: for(i = 0; i < narcs; i++) ! 332: { ! 333: Xfree(polyarcs[i].pPts); ! 334: } ! 335: DEALLOCATE_LOCAL(polyarcs); ! 336: if(fTricky) ! 337: { ! 338: (*pGCTo->pScreen->DestroyPixmap)(pDrawTo); ! 339: FreeScratchGC(pGCTo); ! 340: } ! 341: else ! 342: if(arcmode != ArcChord) ! 343: { ! 344: DoChangeGC(pGCTo, GCArcMode, &arcmode, 0); ! 345: ValidateGC(pDrawTo, pGCTo); ! 346: } ! 347: } ! 348: } ! 349: ! 350: /* 360 degrees * 64 sub-degree positions */ ! 351: #define FULLCIRCLE 64 * 360 ! 352: ! 353: /* MIPOLYFILLARC -- The public entry for the PolyFillArc request. ! 354: * Since we don't have to worry about overlapping segments, we can just ! 355: * fill each arc as it comes. As above, we convert the arc into a set of ! 356: * line segments and then fill the resulting polygon. ! 357: */ ! 358: void ! 359: miPolyFillArc(pDraw, pGC, narcs, parcs) ! 360: DrawablePtr pDraw; ! 361: GCPtr pGC; ! 362: int narcs; ! 363: xArc *parcs; ! 364: { ! 365: int i, cpt; ! 366: DDXPointPtr pPts; ! 367: ! 368: for(i = 0; i < narcs; i++) ! 369: { ! 370: /* We do this test every time because a full circle PieSlice isn't ! 371: * really a slice, but a full pie, and the Chord code (below) should ! 372: * handle it better */ ! 373: if(pGC->arcMode == ArcPieSlice && parcs[i].angle2 < FULLCIRCLE) ! 374: { ! 375: cpt = 1; ! 376: pPts = (DDXPointPtr)Xalloc(sizeof(DDXPointRec)); ! 377: if(cpt = miGetArcPts(&parcs[i], cpt, &pPts)) ! 378: { ! 379: pPts[0].x = parcs[i].x + parcs[i].width/2; ! 380: pPts[0].y = parcs[i].y + parcs[i].height/2; ! 381: (*pGC->FillPolygon)(pDraw, pGC, Convex, ! 382: CoordModeOrigin, cpt + 1, pPts); ! 383: Xfree((char *) pPts); ! 384: } ! 385: } ! 386: else /* Chord */ ! 387: { ! 388: pPts = (DDXPointPtr)NULL; ! 389: if(cpt = miGetArcPts(&parcs[i], 0, &pPts)) ! 390: { ! 391: (*pGC->FillPolygon)(pDraw, pGC, Convex, ! 392: CoordModeOrigin, cpt, pPts); ! 393: Xfree((char *) pPts); ! 394: } ! 395: } ! 396: } ! 397: } ! 398: ! 399: /* MIGETARCPTS -- Converts an arc into a set of line segments -- a helper ! 400: * routine for arc and line (round cap) code. ! 401: * Returns the number of points in the arc. Note that it takes a pointer ! 402: * to a pointer to where it should put the points and an index (cpt). ! 403: * This procedure allocates the space necessary to fit the arc points. ! 404: * Sometimes it's convenient for those points to be at the end of an existing ! 405: * array. (For example, if we want to leave a spare point to make sectors ! 406: * instead of segments.) So we pass in the Xalloc()ed chunk that contains the ! 407: * array and an index saying where we should start stashing the points. ! 408: * If there isn't an array already, we just pass in a null pointer and ! 409: * count on Xrealloc() to handle the null pointer correctly. ! 410: */ ! 411: int ! 412: miGetArcPts(parc, cpt, ppPts) ! 413: xArc *parc; /* points to an arc */ ! 414: int cpt; /* number of points already in arc list */ ! 415: DDXPointPtr *ppPts; /* pointer to pointer to arc-list -- modified */ ! 416: { ! 417: double st, /* Start Theta, start angle */ ! 418: et, /* End Theta, offset from start theta */ ! 419: dt, /* Delta Theta, angle to sweep ellipse */ ! 420: cdt, /* Cos Delta Theta, actually 2 cos(dt) */ ! 421: x0, y0, /* the recurrence formula needs two points to start */ ! 422: x1, y1, ! 423: x2, y2, /* this will be the new point generated */ ! 424: xc, yc; /* the center point */ ! 425: int count, i; ! 426: DDXPointPtr poly; ! 427: ! 428: /* The spec says that positive angles indicate counterclockwise motion. ! 429: * Given our coordinate system (with 0,0 in the upper left corner), ! 430: * the screen appears flipped in Y. The easiest fix is to negate the ! 431: * angles given */ ! 432: ! 433: /* Throw out multiples of 360 degrees. */ ! 434: i = -parc->angle1; ! 435: if(i < 0) ! 436: { ! 437: while (i < -FULLCIRCLE) ! 438: i += FULLCIRCLE; ! 439: } ! 440: else ! 441: { ! 442: while(i > FULLCIRCLE) ! 443: i -= FULLCIRCLE; ! 444: } ! 445: st = (double ) i; ! 446: st *= ((double)M_PI) / (64 * 180); /* convert to degrees, then to rads */ ! 447: ! 448: i = -parc->angle2; ! 449: /* If it's more than one full rotation, make it exactly 1 rotation */ ! 450: if(i > FULLCIRCLE || i < -FULLCIRCLE) ! 451: { ! 452: i = FULLCIRCLE; ! 453: } ! 454: et = (double) i; ! 455: et *= ((double)M_PI) / (64 * 180); /* convert to degrees, then to rads */ ! 456: ! 457: /* Try to get a delta theta that is within 1/2 pixel. Then adjust it ! 458: * so that it divides evenly into the total. ! 459: * I'm just using cdt 'cause I'm lazy. ! 460: */ ! 461: cdt = max(parc->width, parc->height)/2; ! 462: if(cdt <= 0) ! 463: return 0; ! 464: dt = ( (double)2.0 / sqrt(cdt)); ! 465: count = et/dt; ! 466: count = abs(count) + 1; ! 467: dt = et/count; ! 468: count++; ! 469: ! 470: cdt = 2 * cos(dt); ! 471: ! 472: poly = (DDXPointPtr) Xrealloc(*ppPts, (count + cpt) * sizeof(DDXPointRec)); ! 473: *ppPts = poly; ! 474: ! 475: xc = parc->width/2.0; /* store half width and half height */ ! 476: yc = parc->height/2.0; ! 477: ! 478: ! 479: x0 = xc * cos(st); ! 480: y0 = yc * sin(st); ! 481: x1 = xc * cos(st + dt); ! 482: y1 = yc * sin(st + dt); ! 483: xc += parc->x; /* by adding initial point, these become */ ! 484: yc += parc->y; /* the center point */ ! 485: poly[cpt].x = ROUNDTOINT(xc + x0); ! 486: poly[cpt].y = ROUNDTOINT(yc + y0); ! 487: poly[cpt + 1].x = ROUNDTOINT(xc + x1); ! 488: poly[cpt + 1].y = ROUNDTOINT(yc + y1); ! 489: ! 490: for(i = 2; i < count; i++) ! 491: { ! 492: x2 = cdt * x1 - x0; ! 493: y2 = cdt * y1 - y0; ! 494: poly[cpt + i].x = ROUNDTOINT(xc + x2); ! 495: poly[cpt + i].y = ROUNDTOINT(yc + y2); ! 496: ! 497: x0 = x1; y0 = y1; ! 498: x1 = x2; y1 = y2; ! 499: } ! 500: /* adjust the last point */ ! 501: poly[cpt +i -1].x = ROUNDTOINT(cos(st + et) * parc->width/2.0 + xc); ! 502: poly[cpt +i -1].y = ROUNDTOINT(sin(st + et) * parc->height/2.0 + yc); ! 503: ! 504: return(count); ! 505: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.