Annotation of researchv9/X11/src/X.V11R1/server/ddx/mi/miarc.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.