Annotation of researchv9/X11/src/X.V11R1/server/ddx/mi/milines.c, revision 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: milines.c,v 1.45 87/09/11 07:20:09 toddb Exp $ */
        !            25: 
        !            26: /*
        !            27:  *
        !            28:  *  Written by Todd Newman 
        !            29:  *  loosely based on long ago code and recent advice
        !            30:  *  from Brian Kelleher, John Danskin
        !            31:  *
        !            32:  *  Draw fat lines using a convex polygon routine.
        !            33:  */
        !            34: 
        !            35: #include <stdio.h>
        !            36: extern double hypot();
        !            37: #include "X.h"
        !            38: #include "windowstr.h"
        !            39: #include "Xprotostr.h"
        !            40: #include "gcstruct.h"
        !            41: #include "scrnintstr.h"
        !            42: #include "miscstruct.h"
        !            43: #include "pixmapstr.h"
        !            44: #include "mifpoly.h"
        !            45: #include "mi.h"
        !            46: 
        !            47: #define GCVALSALU      0
        !            48: #define GCVALSFORE     1
        !            49: #define GCVALSBACK     2
        !            50: #define GCVALSWIDTH    3
        !            51: #define GCVALSCAPSTYLE 4
        !            52: #define GCVALSJOINSTYLE        5
        !            53: #define GCVALSARCMODE  6
        !            54: static int gcvals[] = {GXcopy, 1, 0, 0, 0, 0, ArcChord};
        !            55: 
        !            56: #define SAMESIGN(a, b)  ((((a) >= 0) && ((b) >= 0)) ||\
        !            57:                     (((a) <= 0) && ((b) <= 0)))
        !            58: 
        !            59: SppPointRec IntersectLines();
        !            60: 
        !            61: /* MIWIDELINE - Public entry for PolyLine call
        !            62:  * handles 1 segment wide lines specially.  Then it sets up the GC/Drawable
        !            63:  * based on the raster op.  If the raster op is one that doesn't look at
        !            64:  * the destination, then we can draw directly onto the drawable.  If the
        !            65:  * raster op does look at the destination (e.g., Xor), then we will draw
        !            66:  * with GXcopy onto a side bitmap and then squeegee the appropriate pattern
        !            67:  * (foreground, or tile, or stipple) onto the real drawable.
        !            68:  * We call one of two helpers (miMiter or miNonMiter) to actually draw
        !            69:  * the line segments. Which helper we call is determined by the device
        !            70:  * specific GC validator (e.g., mfbValidateGC).
        !            71:  */
        !            72: void
        !            73: miWideLine(pDrawable, pGC, mode, npt, pPts)
        !            74:     DrawablePtr pDrawable;
        !            75:     GCPtr      pGC;
        !            76:     int                mode;
        !            77:     int                npt;
        !            78:     DDXPointPtr pPts;
        !            79: {
        !            80:     int                width = pGC->lineWidth;
        !            81:     SppPointPtr pSppPts, pSppT;
        !            82:     int                gcflags, i, xOrg, yOrg, fTricky, arcmode;
        !            83:     int                xMin, xMax, yMin, yMax, dx, dy;
        !            84:     DrawablePtr        pDrawTo;
        !            85:     GCPtr      pGCTo;
        !            86: 
        !            87: 
        !            88:     /* make everything absolute */
        !            89:     if (mode == CoordModePrevious)
        !            90:     {
        !            91:        DDXPointPtr pptTmp;
        !            92:        int nptTmp;
        !            93: 
        !            94:        pptTmp = pPts + 1;
        !            95:        nptTmp = npt - 1;
        !            96:        while (nptTmp--)
        !            97:        {
        !            98:            pptTmp->x += (pptTmp-1)->x;
        !            99:            pptTmp->y += (pptTmp-1)->y;
        !           100:            pptTmp++;
        !           101:        }
        !           102:     }
        !           103:     switch(pGC->alu)
        !           104:     {
        !           105:       case GXclear:            /* 0 */
        !           106:       case GXcopy:             /* src */
        !           107:       case GXcopyInverted:     /* NOT src */
        !           108:       case GXset:              /* 1 */
        !           109:        fTricky = FALSE;
        !           110:         xOrg = yOrg = 0;
        !           111:        pDrawTo = pDrawable;
        !           112:        pGCTo = pGC;
        !           113:        arcmode = pGCTo->arcMode;
        !           114:        if(arcmode != ArcChord)
        !           115:        {
        !           116:            DoChangeGC(pGCTo, GCArcMode, &gcvals[GCVALSARCMODE], 0);
        !           117:            ValidateGC(pDrawTo, pGCTo);
        !           118:        }
        !           119: 
        !           120:        break;
        !           121:       case GXand:              /* src AND dst */
        !           122:       case GXandReverse:       /* src AND NOT dst */
        !           123:       case GXandInverted:      /* NOT src AND dst */
        !           124:       case GXnoop:             /* dst */
        !           125:       case GXxor:              /* src XOR dst */
        !           126:       case GXor        :               /* src OR dst */
        !           127:       case GXnor:              /* NOT src AND NOT dst */
        !           128:       case GXequiv:            /* NOT src XOR dst */
        !           129:       case GXinvert:           /* NOT dst */
        !           130:       case GXorReverse:                /* src OR NOT dst */
        !           131:       case GXorInverted:       /* NOT src OR dst */
        !           132:       case GXnand:             /* NOT src OR NOT dst */
        !           133:        fTricky = TRUE;
        !           134:        yMin = yMax = pPts[0].y;
        !           135:        xMin = xMax = pPts[0].x;
        !           136: 
        !           137:        for (i = 1; i < npt; i++)
        !           138:        {
        !           139:            xMin = min(xMin, pPts[i].x);
        !           140:            xMax = max(xMax, pPts[i].x);
        !           141:            yMin = min(yMin, pPts[i].y);
        !           142:            yMax = max(yMax, pPts[i].y);
        !           143:        }
        !           144:        xOrg = xMin - (width + 1)/2;
        !           145:        yOrg = yMin - (width + 1)/2;
        !           146:        dx = xMax - xMin + width + 1;
        !           147:        dy = yMax - yMin + width + 1;
        !           148:        pDrawTo = (DrawablePtr) (*pDrawable->pScreen->CreatePixmap)
        !           149:          (pDrawable->pScreen, dx, dy, 1, XYBitmap);
        !           150:        pGCTo = GetScratchGC(1, pDrawable->pScreen);
        !           151:        gcvals[GCVALSWIDTH] = width;
        !           152:        gcvals[GCVALSCAPSTYLE] = pGC->capStyle;
        !           153:        gcvals[GCVALSJOINSTYLE] = pGC->joinStyle;
        !           154:        gcflags = GCFunction|GCForeground|GCBackground|GCLineWidth |
        !           155:                  GCCapStyle | GCJoinStyle;
        !           156:        if(pGCTo->arcMode != ArcChord)
        !           157:            gcflags |= GCArcMode;
        !           158:        arcmode = ArcChord;
        !           159:        DoChangeGC(pGCTo, gcflags, gcvals, 0);
        !           160:        ValidateGC(pDrawTo, pGCTo);
        !           161:        miClearDrawable(pDrawTo, pGCTo);
        !           162: 
        !           163:     }
        !           164:     pSppPts = (SppPointPtr) Xalloc((npt + 1)  * sizeof(SppPointRec));
        !           165:     pSppT = pSppPts;
        !           166:     /* convert points to DblPts */
        !           167:     for(i = 0; i < npt; i++)
        !           168:     {
        !           169:        pSppT->x = (double) pPts->x;
        !           170:        pSppT++->y = (double) pPts++->y;
        !           171:        
        !           172:     }
        !           173: 
        !           174:     /* Draw the lines with the appropriate join style.
        !           175:      * We always wants caps drawn. */
        !           176:     (*pGCTo->LineHelper) (pDrawTo, pGCTo, TRUE, npt, pSppPts, xOrg, yOrg);
        !           177: 
        !           178:     if(arcmode != ArcChord)
        !           179:     {
        !           180:        DoChangeGC(pGCTo, GCArcMode, &arcmode, 0);
        !           181:        ValidateGC(pDrawTo, pGCTo);
        !           182:     }
        !           183:     if(fTricky)
        !           184:     {
        !           185:        if (pGC->miTranslate && (pDrawable->type == DRAWABLE_WINDOW) )
        !           186:        {
        !           187:            xOrg += ((WindowPtr)pDrawable)->absCorner.x;
        !           188:            yOrg += ((WindowPtr)pDrawable)->absCorner.y;
        !           189:        }
        !           190: 
        !           191:        (*pGC->PushPixels)(pGC, pDrawTo, pDrawable, dx, dy, xOrg, yOrg);
        !           192:        (*pDrawable->pScreen->DestroyPixmap)(pDrawTo);
        !           193:        FreeScratchGC(pGCTo);
        !           194:     }
        !           195: }
        !           196: 
        !           197: /* MIONESEGWIDE -- private helper for wide line code
        !           198:  * Draw wide line which only has 1 segment.  This is so easy that it's worth
        !           199:  * special casing. Regardless of the raster op, this can't self-intersect.
        !           200:  * Also handles fluke cases where we're called with only 1 point 
        !           201:  */
        !           202: static
        !           203: void
        !           204: miOneSegWide(pDrawable, pGC, npt, pPts, caps, xOrg, yOrg)
        !           205:     DrawablePtr pDrawable;
        !           206:     GCPtr      pGC;
        !           207:     int                npt;
        !           208:     SppPointPtr pPts;
        !           209:     int                caps, xOrg, yOrg;
        !           210: {
        !           211:     SppPointRec        PolyPoints[4];
        !           212:     int                width = pGC->lineWidth;
        !           213: 
        !           214:     if(npt == 1)
        !           215:     {
        !           216:        Xrealloc(pPts, 2 * sizeof(SppPointRec));
        !           217:         pPts[1] = pPts[0];
        !           218:     }
        !           219:     if(caps && pGC->capStyle == CapProjecting)
        !           220:     {
        !           221:        if(PtEqual(pPts[0], pPts[1]))
        !           222:        {
        !           223:            pPts[0].y -= width/2.0;
        !           224:            pPts[1].y += width/2.0;
        !           225:        }
        !           226:        else
        !           227:        {
        !           228:            pPts[0] = miExtendSegment(pPts[0], pPts[1], width/2);
        !           229:            pPts[1] = miExtendSegment(pPts[1], pPts[0], width/2);
        !           230:        }
        !           231:     }
        !           232:     miGetPts(pPts[0], pPts[1], &PolyPoints[0], 
        !           233:           &PolyPoints[1], &PolyPoints[2], &PolyPoints[3], width);
        !           234:     miFillSppPoly(pDrawable, pGC, 4, PolyPoints, -xOrg, -yOrg);
        !           235:     if(caps && pGC->capStyle == CapRound)
        !           236:     {
        !           237:        miRoundCap(pDrawable, pGC, pPts[0], pPts[1], PolyPoints[0],
        !           238:          PolyPoints[3], FirstEnd, xOrg, yOrg);
        !           239:        miRoundCap(pDrawable, pGC, pPts[1], pPts[0], PolyPoints[2],
        !           240:          PolyPoints[1], SecondEnd, xOrg, yOrg);
        !           241:     }
        !           242: }
        !           243: 
        !           244: /* MIMITER -- helper for wide line code, stuffed into GC.lineHelper by
        !           245:  * validation routine
        !           246:  * draw wide polylines by finding the polygon that outlines
        !           247:  * each wide line segment, and drawing that. Uses GC's fill polygon routine.
        !           248:  *
        !           249:  * internal vertexes are joined with a mitre as in PostScript. 
        !           250:  * vertices at the beginning and end of the polyline
        !           251:  * are given the appropriate end unless they meet at the same point in which
        !           252:  * case they are mitred together.  */
        !           253: 
        !           254: void
        !           255: miMiter (pDraw, pGC, caps, npt, pPts, xOrg, yOrg)
        !           256:     DrawablePtr pDraw;
        !           257:     GCPtr      pGC;
        !           258:     int                caps;
        !           259:     int                npt;
        !           260:     SppPointPtr pPts;
        !           261:     int                xOrg, yOrg;
        !           262: {
        !           263:     int                width = pGC->lineWidth;
        !           264:     SppPointRec        PolyPoints[4], FirstEdge[2];
        !           265:     SppPointRec        p1, p2, p3, p4, p5, p6, p7, p8;
        !           266:     int                edges_match, i,
        !           267:                capStyle = pGC->capStyle;
        !           268: 
        !           269:     /*
        !           270:      * special case length 1 polyline
        !           271:      */
        !           272:     if(npt <= 2)
        !           273:     {
        !           274:         miOneSegWide(pDraw, pGC, npt, pPts, caps, xOrg, yOrg);
        !           275:        return;
        !           276:     }
        !           277:     miGetPts(pPts[0], pPts[1], &p1, &p2, &p3, &p4, width);
        !           278: 
        !           279:     /*
        !           280:      * start on first edge of first point
        !           281:      */
        !           282:     if (PtEqual(pPts[0], pPts[npt-1]))
        !           283:     {
        !           284:        /*
        !           285:         * edges match so mitre them
        !           286:         */
        !           287:        edges_match = 1;
        !           288:        miGetPts(pPts[npt-2], pPts[npt-1], &p5, &p6, &p7, &p8, width);
        !           289: 
        !           290:        PolyPoints[3] = IntersectLines(p1, p2, p5, p6);
        !           291:        PolyPoints[2] = IntersectLines(p3, p4, p7, p8);
        !           292: 
        !           293:        FirstEdge[0] = PolyPoints[3];
        !           294:        FirstEdge[1] = PolyPoints[2];
        !           295:     }
        !           296:     else
        !           297:     {
        !           298:        edges_match = 0;
        !           299:        PolyPoints[3] = p1;
        !           300:        PolyPoints[2] = p4;
        !           301:        if (caps && capStyle == CapProjecting)
        !           302:        {
        !           303:            pPts[0] = miExtendSegment(pPts[0], pPts[1], width/2);
        !           304:            miGetPts(pPts[0], pPts[1], &p1, &p2, &p3, &p4, width);
        !           305:            pPts[npt-1] = miExtendSegment(pPts[npt-1], pPts[npt-2], width/2);
        !           306:        }
        !           307:        else if (caps && capStyle == CapRound)
        !           308:        {
        !           309:            miRoundCap(pDraw, pGC, pPts[0], pPts[1], p1, p4, FirstEnd,
        !           310:                     xOrg, yOrg);
        !           311:            miGetPts(pPts[npt-1], pPts[npt-2], &p5, &p6, &p7, &p8, width);
        !           312:            miRoundCap(pDraw, pGC, pPts[npt-1], pPts[npt-2], p5, p8, FirstEnd,
        !           313:                     xOrg, yOrg);
        !           314:        }
        !           315:     }
        !           316: 
        !           317:     for (i = 1; i < (npt - 1); i++)
        !           318:     {
        !           319:        /*
        !           320:         * find the next edge
        !           321:         * build a polygon out of the next edge and the last one
        !           322:         * send the polygon
        !           323:         * bump to next
        !           324:         */
        !           325:        miGetPts(pPts[i], pPts[i+1], &p5, &p6, &p7, &p8, width);
        !           326: 
        !           327:        PolyPoints[0] = PolyPoints[3];
        !           328:        PolyPoints[1] = PolyPoints[2];
        !           329:        PolyPoints[2] = IntersectLines(p4, p3, p7, p8);
        !           330:        PolyPoints[3] = IntersectLines(p1, p2, p5, p6);
        !           331: 
        !           332:        miFillSppPoly(pDraw, pGC, 4, PolyPoints, -xOrg, -yOrg);
        !           333: 
        !           334:        p1 = p5;  p2 = p6;  p3 = p7;  p4 = p8;
        !           335: 
        !           336:     }
        !           337: 
        !           338:     PolyPoints[0] = PolyPoints[3];
        !           339:     PolyPoints[1] = PolyPoints[2];
        !           340: 
        !           341:     if (edges_match)
        !           342:     {
        !           343:        PolyPoints[2] = FirstEdge[1];
        !           344:        PolyPoints[3] = FirstEdge[0];
        !           345:     }
        !           346:     else
        !           347:     {
        !           348:        miGetPts(pPts[npt-2], pPts[npt-1], &p5, &p6, &p7, &p8, width);
        !           349:        PolyPoints[2] = p7;
        !           350:        PolyPoints[3] = p6;
        !           351:     }
        !           352:        
        !           353:     miFillSppPoly(pDraw, pGC, 4, PolyPoints, -xOrg, -yOrg);
        !           354: }
        !           355: 
        !           356: /* MINOTMITER -- helper for wide line code, stuffed into GC.lineHelper by
        !           357:  * validation routine
        !           358:  *
        !           359:  * internal vertexes are joined with a bevel or rounded joint as in PostScript. 
        !           360:  * vertices at the beginning and end of the polyline
        !           361:  * are given the appropriate end unless they meet at the same point in which
        !           362:  * case they are drawn with the appropriate join.  */
        !           363: 
        !           364: typedef struct {
        !           365:     int                c;
        !           366:     SppPointRec        v0, v1, v2, v3, v4;
        !           367:     SppPointRec        p1, p2, p3, p4;
        !           368: } POLYLINEINFO;
        !           369: 
        !           370: void
        !           371: miNotMiter (pDraw, pGC, caps, npt, pPts, xOrg, yOrg)
        !           372:     DrawablePtr pDraw;
        !           373:     GCPtr      pGC;
        !           374:     int                caps;
        !           375:     int                npt;
        !           376:     SppPointPtr pPts;
        !           377:     int                xOrg, yOrg;
        !           378: {
        !           379:     int                i, c,
        !           380:                width = pGC->lineWidth,
        !           381:                capStyle = pGC->capStyle,
        !           382:                joinStyle = pGC->joinStyle;
        !           383:     Bool       edges_match;
        !           384:     SppPointRec        FirstEdge[4],   /* 2 extra for special npt == 2 */
        !           385:                wedge[3],
        !           386:                p, p1, p2, p3, p4, p5, p6, p7, p8, center;
        !           387:     POLYLINEINFO *plinfo;
        !           388: 
        !           389:     /* special case length 1 polyline */
        !           390:     if(npt <= 2)
        !           391:     {
        !           392:         miOneSegWide(pDraw, pGC, npt, pPts, caps, xOrg, yOrg);
        !           393:        return;
        !           394:     }
        !           395:     if(!(plinfo = (POLYLINEINFO *) ALLOCATE_LOCAL(npt * sizeof(POLYLINEINFO))))
        !           396:        return;
        !           397:     miGetPts(pPts[0], pPts[1], &p1, &p2, &p3, &p4, width);
        !           398:     /* save the points, in case this is hard */
        !           399:     plinfo[0].p1 = p1;
        !           400:     plinfo[0].p2 = p2;
        !           401:     plinfo[0].p3 = p3;
        !           402:     plinfo[0].p4 = p4;
        !           403: 
        !           404:     /*
        !           405:      * If ends meet, calculate angle of final intersection and points
        !           406:      * of intersection for it.
        !           407:      */
        !           408:     if(PtEqual(pPts[0], pPts[npt-1]))
        !           409:     {
        !           410:        edges_match = TRUE;
        !           411:        miGetPts(pPts[npt-2], pPts[npt-1], &p5, &p6, &p7, &p8, width);
        !           412: 
        !           413:        c = (pPts[0].x - pPts[npt-2].x)*(pPts[1].y - pPts[0].y) -
        !           414:            (pPts[1].x - pPts[0].x)*(pPts[0].y - pPts[npt-2].y);
        !           415:        plinfo[0].c = c;
        !           416: 
        !           417:        if(c > 0)       /* it's a clockwise turn */
        !           418:        {
        !           419:            p = IntersectLines(p1, p2, p5, p6);
        !           420:            plinfo[0].v0 = p4;
        !           421:            plinfo[0].v1 = p7;
        !           422:            plinfo[0].v2 = p;
        !           423:            FirstEdge[0] = p;
        !           424:            FirstEdge[1] = p7;
        !           425:            if(joinStyle == JoinRound)
        !           426:            {
        !           427:                center.x = (p4.x + p7.x)/2;
        !           428:                center.y = (p4.y + p7.y)/2;
        !           429:                miRoundCap(pDraw, pGC, center, p, p4, p7, NotEnd, xOrg, yOrg);
        !           430:            }
        !           431:        }
        !           432:        else if (c < 0) /* counterclockwise */
        !           433:        {
        !           434:            p = IntersectLines(p3, p4, p7, p8);
        !           435:            plinfo[0].v0 = p;
        !           436:            plinfo[0].v1 = p6;
        !           437:            plinfo[0].v2 = p1;
        !           438:            FirstEdge[0] = p6;
        !           439:            FirstEdge[1] = p;
        !           440:            if(joinStyle == JoinRound)
        !           441:            {
        !           442:                center.x = (p6.x + p1.x)/2;
        !           443:                center.y = (p6.y + p1.y)/2;
        !           444:                miRoundCap(pDraw, pGC, center, p, p1, p6, NotEnd, xOrg, yOrg);
        !           445:            }
        !           446:        }
        !           447:        else /* straight line intersection */
        !           448:        {
        !           449:            plinfo[0].v1 = p4;
        !           450:            plinfo[0].v2 = p1;
        !           451:            FirstEdge[0] = p6;
        !           452:            FirstEdge[1] = p7;
        !           453: 
        !           454:        }
        !           455:     }
        !           456:     else       /* Ends don't meet */
        !           457:     {
        !           458:        if(caps)
        !           459:        {
        !           460:            if(capStyle == CapProjecting)
        !           461:            {
        !           462:                pPts[0] = miExtendSegment(pPts[0], pPts[1], width/2);
        !           463:                miGetPts(pPts[0], pPts[1], &p1, &p2, &p3, &p4, width);
        !           464:                plinfo[0].p1 = p1;
        !           465:                plinfo[0].p2 = p2;
        !           466:                plinfo[0].p3 = p3;
        !           467:                plinfo[0].p4 = p4;
        !           468:                pPts[npt-1] =
        !           469:                    miExtendSegment(pPts[npt-1], pPts[npt-2], width/2);
        !           470:            } else if (capStyle == CapRound)
        !           471:            {
        !           472:                miRoundCap(pDraw, pGC, pPts[0], pPts[1], p1, p4, FirstEnd,
        !           473:                         xOrg, yOrg);
        !           474:                miGetPts(pPts[npt-1], pPts[npt-2], &p5, &p6, &p7, &p8, width);
        !           475:                miRoundCap(pDraw, pGC, pPts[npt-1], pPts[npt-2], p5, p8,
        !           476:                         FirstEnd, xOrg, yOrg);
        !           477:            }
        !           478:        }
        !           479:        edges_match = FALSE;
        !           480:        plinfo[0].c = 0;        /* treat no connection as straight connection */
        !           481:        plinfo[0].v1 = p4;
        !           482:        plinfo[0].v2 = p1;
        !           483: 
        !           484:     }
        !           485: 
        !           486:     for (i = 1; i < (npt - 1); i++)
        !           487:     {
        !           488:        /* Find the point of intersection with the previous segment.
        !           489:         * Make sure it's on this segment */
        !           490:        if(plinfo[i-1].c > 0)
        !           491:        {
        !           492:            p = plinfo[i-1].v2;
        !           493:        }
        !           494:        else if (plinfo[i-1].c < 0)
        !           495:        {
        !           496:            p = plinfo[i-1].v0;
        !           497:        }
        !           498:        miGetPts(pPts[i], pPts[i+1], &p5, &p6, &p7, &p8, width);
        !           499:        
        !           500:        plinfo[i].p1 = p5;
        !           501:        plinfo[i].p2 = p6;
        !           502:        plinfo[i].p3 = p7;
        !           503:        plinfo[i].p4 = p8;
        !           504: 
        !           505:        /* Figure out whether this angle turns clockwise or not by taking
        !           506:         * the total cross product of the three vectors formed by drawing
        !           507:         * vectors between the start of the previous segment and the start
        !           508:         * and end of this one */
        !           509:        if(i == npt - 1)
        !           510:            c = 0;
        !           511:        else
        !           512:            c = (pPts[i].x - pPts[i-1].x)*(pPts[i + 1].y - pPts[i].y) -
        !           513:                 (pPts[i + 1].x - pPts[i].x)*(pPts[i].y - pPts[i-1].y);
        !           514:        plinfo[i].c = c;
        !           515: 
        !           516: 
        !           517:        if(c > 0)       /* counter-clockwise */         
        !           518:        {
        !           519:            p = IntersectLines(p1, p2, p5, p6);
        !           520:            plinfo[i].v0 = p8;
        !           521:            plinfo[i].v1 = p3;
        !           522:            plinfo[i].v2 = p;
        !           523: 
        !           524:            plinfo[i-1].v3 = p;
        !           525:            plinfo[i-1].v4 = p3;
        !           526:            if(joinStyle == JoinRound)
        !           527:            {
        !           528:                center.x = (p8.x + p3.x)/2;
        !           529:                center.y = (p8.y + p3.y)/2;
        !           530:                miRoundCap(pDraw, pGC, center, p, p8, p3, NotEnd, xOrg, yOrg);
        !           531:            }
        !           532:        }
        !           533:        else if (c < 0) 
        !           534:        {
        !           535:            p = IntersectLines(p3, p4, p7, p8);
        !           536:            plinfo[i].v0 = p;
        !           537:            plinfo[i].v1 = p2;
        !           538:            plinfo[i].v2 = p5;
        !           539: 
        !           540:            plinfo[i-1].v3 = p2;
        !           541:            plinfo[i-1].v4 = p;
        !           542:            if(joinStyle == JoinRound)
        !           543:            {
        !           544:                center.x = (p2.x + p5.x)/2;
        !           545:                center.y = (p2.y + p5.y)/2;
        !           546:                miRoundCap(pDraw, pGC, center, p, p2, p5, NotEnd, xOrg, yOrg);
        !           547:            }
        !           548:        }
        !           549:        else                    /* straight line intersection */
        !           550:        {
        !           551:            plinfo[i].v1 = p2;
        !           552:            plinfo[i].v2 = p3;
        !           553:            plinfo[i-1].v3 = p2;
        !           554:            plinfo[i-1].v4 = p3;
        !           555: 
        !           556:        }
        !           557: 
        !           558:        p1 = p5;  p2 = p6;  p3 = p7;  p4 = p8;
        !           559:     }
        !           560: 
        !           561:     /* Special case for final segment --
        !           562:     */
        !           563:     if(plinfo[i-1].c > 0)
        !           564:     {
        !           565:        p = plinfo[i-1].v2;
        !           566:     }
        !           567:     else if (plinfo[i-1].c < 0)
        !           568:     {
        !           569:        p = plinfo[i-1].v0;
        !           570:     }
        !           571: 
        !           572:     if (edges_match)
        !           573:     {
        !           574:        plinfo[i-1].v3 = FirstEdge[0];
        !           575:        plinfo[i-1].v4 = FirstEdge[1];
        !           576:        if(plinfo[i-1].c > 0)
        !           577:        {
        !           578:            p = plinfo[i-1].v2;
        !           579:        }
        !           580:        else if (plinfo[i-1].c < 0)
        !           581:        {
        !           582:            p = plinfo[i-1].v0;
        !           583:        }
        !           584:     }
        !           585:     else
        !           586:     {
        !           587:        miGetPts(pPts[npt-2], pPts[npt-1], &p5, &p6, &p7, &p8, width);
        !           588:        plinfo[i-1].v3 = p6;
        !           589:        plinfo[i-1].v4 = p7;
        !           590:     }
        !           591:     /*
        !           592:      * plinfo[i].c is 0 if there is no notch, either because the lines meet
        !           593:      * at 180 degrees, or the lines don't meet.  
        !           594:      * Since we've set the alu to GCCopy, we don't worry about drawing
        !           595:      * points twice.
        !           596:      */
        !           597:     for(i = 0; i < (npt - 1); i++)
        !           598:     {
        !           599:        if(plinfo[i].c < 0)
        !           600:        {
        !           601:            wedge[1] = plinfo[i].p1;
        !           602:            wedge[2] = i ? plinfo[i - 1].p2 : plinfo[npt-2].p2;
        !           603:        }
        !           604:        else if (plinfo[i].c > 0)
        !           605:        {
        !           606:            wedge[1] = plinfo[i].p4;
        !           607:            wedge[2] = i ? plinfo[i-1].p3 : plinfo[npt-2].p3;
        !           608:        }
        !           609: 
        !           610:        if(plinfo[i].c)
        !           611:        {
        !           612:            wedge[0] = pPts[i];
        !           613:            /* Check that points aren't colinear */
        !           614:            if(!(wedge[0].x == wedge[1].x && wedge[1].x == wedge[2].x) &&
        !           615:               !(wedge[0].y == wedge[1].y && wedge[1].y == wedge[2].y))
        !           616:            {
        !           617:                miFillSppPoly(pDraw, pGC, 3, wedge, -xOrg, -yOrg);
        !           618:            }
        !           619:        }
        !           620:        miFillSppPoly(pDraw, pGC, 4, &plinfo[i].p1, -xOrg, -yOrg);
        !           621:     }
        !           622:     DEALLOCATE_LOCAL(plinfo);  
        !           623: }
        !           624: 
        !           625: /* MIGETPTS -- helper function
        !           626:  *  Get the corners of the polygon formed for a line with the endpoints
        !           627:  *  p1In, p2In and the given width stuff the corners into *p1Out, *p2Out ...
        !           628:  *  p1Out and p4Out are always on the same end as p1In.
        !           629:  */
        !           630: void
        !           631: miGetPts(p1In, p2In, p1Out, p2Out, p3Out, p4Out, width)
        !           632:     SppPointRec p1In, p2In;
        !           633:     SppPointPtr p1Out, p2Out, p3Out, p4Out;
        !           634:     int width;
        !           635: {
        !           636:     double hyp;         /* true distance of line (hypotenuse) */
        !           637:     double dx, dy;
        !           638:     double tmpdx, tmpdy;
        !           639: 
        !           640:     tmpdx = (double)(p1In.x - p2In.x);
        !           641:     tmpdy = (double)(p1In.y - p2In.y);
        !           642: 
        !           643:     hyp = hypot(tmpdx, tmpdy);
        !           644:     if (!ISZERO(hyp))
        !           645:     {
        !           646:     /* NOTE: the division by 2 must be done in floating point */
        !           647:        dy = (tmpdx * width/2.0) / hyp;
        !           648:        dx = (tmpdy * width/2.0) / hyp;
        !           649: 
        !           650:        p1Out->x = (p1In.x + dx);
        !           651:        p1Out->y = (p1In.y - dy);
        !           652: 
        !           653:        p2Out->x = (p2In.x + dx);
        !           654:        p2Out->y = (p2In.y - dy);
        !           655: 
        !           656:        p3Out->x = (p2In.x - dx);
        !           657:        p3Out->y = (p2In.y + dy);
        !           658: 
        !           659:        p4Out->x = (p1In.x - dx);
        !           660:        p4Out->y = (p1In.y + dy);
        !           661:     }
        !           662:     else
        !           663:     {    
        !           664:        /* Bizarre answer, but it's what the spec calls for */
        !           665:        p1Out->x = p2Out->x = p1In.x - width/2.0;
        !           666:        p3Out->x = p4Out->x = p1In.x + width/2.0;
        !           667:        p1Out->y = p2Out->y = p3Out->y = p4Out->y = p1In.y;
        !           668:     }
        !           669: }
        !           670: 
        !           671: /* INTERSECTLINES -- private helper for line code 
        !           672:  *  Return the intersection of the line from p1 to p2 with
        !           673:  *  the line from p3 to p4.
        !           674:  *
        !           675:  *  First, reduce the lines to:   y = m1x + b,  and y = m2x + c.
        !           676:  *  Then do the standard math.
        !           677:  */
        !           678: static
        !           679: SppPointRec
        !           680: IntersectLines(p1, p2, p3, p4)
        !           681:     SppPointRec p1, p2, p3, p4;
        !           682: {
        !           683:     SppPointRec i;
        !           684:     double m1, m2;
        !           685:     double b1, b2;
        !           686:     double dx1, dx2;
        !           687:     double tx;
        !           688: 
        !           689:     dx1 = p2.x - p1.x;
        !           690:     dx2 = p4.x - p3.x;
        !           691: 
        !           692:     if (ISZERO(dx1))
        !           693:     {
        !           694:        if (! ISZERO(dx2))
        !           695:        {
        !           696:            i.y = p3.y + ((p4.y - p3.y) * (p1.x - p3.x)) / (p4.x - p3.x);
        !           697:            i.x = p1.x;
        !           698:        }
        !           699:        else
        !           700:            i = p2;
        !           701:     }
        !           702:     else if (ISZERO(dx2))
        !           703:     {
        !           704:        i.y = p1.y + ((p2.y - p1.y) * (p3.x - p1.x)) / (p2.x - p1.x);
        !           705:        i.x = p3.x;
        !           706:     }
        !           707:     else
        !           708:     {
        !           709:        m1 = (p2.y - p1.y) / dx1;
        !           710:        m2 = (p4.y - p3.y) / dx2;
        !           711: 
        !           712:        b1 = p2.y - (m1 * p2.x);
        !           713:        b2 = p4.y - (m2 * p4.x);
        !           714: 
        !           715:        if (! ISEQUAL(m1, m2))
        !           716:            i.x = (tx = ((b2-b1) / (m1-m2)));
        !           717:        else
        !           718:            i.x = (tx = p2.x);
        !           719: 
        !           720:        i.y = m1 * tx + b1;
        !           721:     }
        !           722:     return(i);
        !           723: }
        !           724: 
        !           725: 
        !           726: /* MIEXTENDSEGMENT -- a private helper function 
        !           727:  * Calcuate point p3 made by extending the segment backward (away from p2)
        !           728:  * by a length d */
        !           729: 
        !           730: SppPointRec
        !           731: miExtendSegment(p1, p2, d)
        !           732:     SppPointRec        p1, p2;
        !           733:     int                d;
        !           734: {
        !           735:     SppPointRec        p3;
        !           736:     double     l, dx, dy, hypot();
        !           737: 
        !           738:     dx = p2.x - p1.x;
        !           739:     dy = p2.y - p1.y;
        !           740:     l = hypot(dx, dy);
        !           741:     if(!ISZERO(l))
        !           742:     {
        !           743:        p3.x = (p2.x - (l + d)/l * dx);
        !           744:        p3.y = (p2.y - (l + d)/l * dy);
        !           745:     }
        !           746:     else
        !           747:     {
        !           748:        ErrorF("ExtendSegment called with coincident points.\n");
        !           749:        p3 = p2;
        !           750:     }
        !           751:     return(p3);
        !           752: }
        !           753: 
        !           754: /* MIROUNDCAP -- a private helper function
        !           755:  * Put Rounded cap on end. pCenter is the center of this end of the line
        !           756:  * pEnd is the center of the other end of the line. pCorner is one of the
        !           757:  * two corners at this end of the line.  It doesn't matter which of the two
        !           758:  * corners you give it. pOtherCorner is the other one.
        !           759:  */
        !           760: void
        !           761: miRoundCap(pDraw, pGC, pCenter, pEnd, pCorner, pOtherCorner, fLineEnd,
        !           762:      xOrg, yOrg)
        !           763:     DrawablePtr        pDraw;
        !           764:     GCPtr      pGC;
        !           765:     SppPointRec        pCenter, pEnd;
        !           766:     SppPointRec        pCorner, pOtherCorner;
        !           767:     int                fLineEnd, xOrg, yOrg;
        !           768: {
        !           769:     int                c, i, signc, cpt;
        !           770:     double     width;
        !           771:     double     dx, dy, hypot();
        !           772:     xArc       arc;
        !           773:     DDXPointPtr        pArcPts;
        !           774:     SppPointPtr        pPts;
        !           775:     int                arcmode = pGC->arcMode;
        !           776: 
        !           777:     if(arcmode != ArcChord)
        !           778:     {
        !           779:        DoChangeGC(pGC, GCArcMode, &gcvals[GCVALSARCMODE], 0);
        !           780:        ValidateGC(pDraw, pGC);
        !           781:     }
        !           782:     if (fLineEnd == NotEnd)
        !           783:     {
        !           784:        dx = pCenter.x - pCorner.x;
        !           785:        dy = pCenter.y - pCorner.y;
        !           786:        width = hypot(dx, dy);
        !           787:     }
        !           788:     else
        !           789:        width = pGC->lineWidth;
        !           790:     if(PtEqual(pCenter, pEnd))
        !           791:     {
        !           792:        signc = 1;
        !           793:     }
        !           794:     else
        !           795:     {
        !           796:        c = (pCenter.x - pEnd.x) * (pCorner.y - pCenter.y) -
        !           797:             (pCorner.x - pCenter.x) * (pCenter.y - pEnd.y);
        !           798:        signc = -sign(c);
        !           799:     }
        !           800: 
        !           801:     /* These come back scaled by 64 and all ready to use */
        !           802:     arc.x = ROUNDTOINT(pCenter.x - width/2);
        !           803:     arc.y = ROUNDTOINT(pCenter.y - width/2);
        !           804:     arc.width = ROUNDTOINT(width);
        !           805:     arc.height = arc.width;
        !           806:     arc.angle1 = -PtToAngle(pCenter, pCorner);
        !           807:     arc.angle2 = -signc * 180 * 64;
        !           808:     pArcPts = (DDXPointPtr)NULL;
        !           809:     if( cpt = miGetArcPts(&arc, 0, &pArcPts))
        !           810:     {
        !           811:        /* by drawing with miFillSppPoly and setting the endpoints of the arc
        !           812:         * to be the corners, we assure that the cap will meet up with the
        !           813:         * rest of the line */
        !           814:        pPts = (SppPointPtr) Xalloc(cpt * sizeof(SppPointRec));
        !           815:        for(i = 1; i < cpt -1; i++)
        !           816:        {
        !           817:            pPts[i].x = (double) pArcPts[i].x;
        !           818:            pPts[i].y = (double) pArcPts[i].y;
        !           819:        }
        !           820:        pPts[0] = pCorner;
        !           821:        pPts[cpt - 1] = pOtherCorner;
        !           822:        miFillSppPoly(pDraw, pGC, cpt, pPts, -xOrg, -yOrg);
        !           823:        Xfree((char *)pArcPts);
        !           824:        Xfree((char *)pPts);
        !           825:        if(arcmode != ArcChord)
        !           826:        {
        !           827:            DoChangeGC(pGC, GCArcMode, &arcmode, 0);
        !           828:            ValidateGC(pDraw, pGC);
        !           829:        }
        !           830:     }
        !           831: }
        !           832: 
        !           833: /* these are from <math.h>, but I'm told some systems don't have math.h Psi! */
        !           834: extern double sqrt(), cos(), sin(), atan();
        !           835: #define M_PI   3.14159265358979323846
        !           836: #define M_PI_2 1.57079632679489661923
        !           837: 
        !           838: /* PTTOANGLE -- a private helper function
        !           839:  * Given two points, compute the slope of the line segment
        !           840:  * Result is in radians * 64
        !           841:  */
        !           842: static
        !           843: int
        !           844: PtToAngle(c, p)
        !           845:     SppPointRec        c, p;
        !           846: {
        !           847:     double     dx, dy, theta;
        !           848: 
        !           849:     dx = p.x - c.x;
        !           850:     dy  = p.y - c.y;
        !           851:     if(dx == 0)
        !           852:     {
        !           853:        theta = (dy > 0) ? M_PI_2 : -M_PI_2;
        !           854:     }
        !           855:     else
        !           856:         theta =(atan(dy/dx));
        !           857:     if(dx < 0)
        !           858:        theta += M_PI;
        !           859:     theta = (theta * 64 * 180/M_PI);
        !           860:     return(ROUNDTOINT(theta));
        !           861: }
        !           862: 

unix.superglobalmegacorp.com

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