Annotation of micropolis/src/tk/tkcvline.c, revision 1.1

1.1     ! root        1: /* 
        !             2:  * tkCanvLine.c --
        !             3:  *
        !             4:  *     This file implements line items for canvas widgets.
        !             5:  *
        !             6:  * Copyright 1991-1992 Regents of the University of California.
        !             7:  * Permission to use, copy, modify, and distribute this
        !             8:  * software and its documentation for any purpose and without
        !             9:  * fee is hereby granted, provided that the above copyright
        !            10:  * notice appear in all copies.  The University of California
        !            11:  * makes no representations about the suitability of this
        !            12:  * software for any purpose.  It is provided "as is" without
        !            13:  * express or implied warranty.
        !            14:  */
        !            15: 
        !            16: #ifndef lint
        !            17: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkCanvLine.c,v 1.7 92/07/28 15:40:08 ouster Exp $ SPRITE (Berkeley)";
        !            18: #endif
        !            19: 
        !            20: #include <stdio.h>
        !            21: #include <math.h>
        !            22: #include "tkint.h"
        !            23: #include "tkcanvas.h"
        !            24: #include "tkconfig.h"
        !            25: 
        !            26: /*
        !            27:  * The structure below defines the record for each line item.
        !            28:  */
        !            29: 
        !            30: typedef struct LineItem  {
        !            31:     Tk_Item header;            /* Generic stuff that's the same for all
        !            32:                                 * types.  MUST BE FIRST IN STRUCTURE. */
        !            33:     Tk_Canvas *canvasPtr;      /* Canvas containing item.  Needed for
        !            34:                                 * parsing arrow shapes. */
        !            35:     int numPoints;             /* Number of points in line (always >= 2). */
        !            36:     double *coordPtr;          /* Pointer to malloc-ed array containing
        !            37:                                 * x- and y-coords of all points in line.
        !            38:                                 * X-coords are even-valued indices, y-coords
        !            39:                                 * are corresponding odd-valued indices. */
        !            40:     int width;                 /* Width of line. */
        !            41:     XColor *fg;                        /* Foreground color for line. */
        !            42:     Pixmap fillStipple;                /* Stipple bitmap for filling line. */
        !            43:     int capStyle;              /* Cap style for line. */
        !            44:     int joinStyle;             /* Join style for line. */
        !            45:     GC gc;                     /* Graphics context for filling line. */
        !            46:     Tk_Uid arrow;              /* Indicates whether or not to draw arrowheads:
        !            47:                                 * "none", "first", "last", or "both". */
        !            48:     float arrowShapeA;         /* Distance from tip of arrowhead to center. */
        !            49:     float arrowShapeB;         /* Distance from tip of arrowhead to trailing
        !            50:                                 * point, measured along shaft. */
        !            51:     float arrowShapeC;         /* Distance of trailing points from outside
        !            52:                                 * edge of shaft. */
        !            53:     double *firstArrowPtr;     /* Points to array of 5 points describing
        !            54:                                 * polygon for arrowhead at first point in
        !            55:                                 * line.  First point of arrowhead is tip.
        !            56:                                 * Malloc'ed.  NULL means no arrowhead at
        !            57:                                 * first point. */
        !            58:     double *lastArrowPtr;      /* Points to polygon for arrowhead at last
        !            59:                                 * point in line (5 points, first of which
        !            60:                                 * is tip).  Malloc'ed.  NULL means no
        !            61:                                 * arrowhead at last point. */
        !            62:     int smooth;                        /* Non-zero means draw line smoothed (i.e.
        !            63:                                 * with Bezier splines). */
        !            64:     int splineSteps;           /* Number of steps in each spline segment. */
        !            65: } LineItem;
        !            66: 
        !            67: /*
        !            68:  * Number of points in an arrowHead:
        !            69:  */
        !            70: 
        !            71: #define PTS_IN_ARROW 6
        !            72: 
        !            73: /*
        !            74:  * Prototypes for procedures defined in this file:
        !            75:  */
        !            76: 
        !            77: static void            ComputeLineBbox _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !            78:                            LineItem *linePtr));
        !            79: static int             ConfigureLine _ANSI_ARGS_((
        !            80:                            Tk_Canvas *canvasPtr, Tk_Item *itemPtr, int argc,
        !            81:                            char **argv, int flags));
        !            82: static int             ConfigureArrows _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !            83:                            LineItem *linePtr));
        !            84: static int             CreateLine _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !            85:                            struct Tk_Item *itemPtr, int argc, char **argv));
        !            86: static void            DeleteLine _ANSI_ARGS_((Tk_Item *itemPtr));
        !            87: static void            DisplayLine _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !            88:                            Tk_Item *itemPtr, Drawable dst));
        !            89: static int             LineCoords _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !            90:                            Tk_Item *itemPtr, int argc, char **argv));
        !            91: static int             LineToArea _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !            92:                            Tk_Item *itemPtr, double *rectPtr));
        !            93: static double          LineToPoint _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !            94:                            Tk_Item *itemPtr, double *coordPtr));
        !            95: static int             ParseArrowShape _ANSI_ARGS_((ClientData clientData,
        !            96:                            Tcl_Interp *interp, Tk_Window tkwin, char *value,
        !            97:                            char *recordPtr, int offset));
        !            98: static char *          PrintArrowShape _ANSI_ARGS_((ClientData clientData,
        !            99:                            Tk_Window tkwin, char *recordPtr, int offset,
        !           100:                            Tcl_FreeProc **freeProcPtr));
        !           101: static void            ScaleLine _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !           102:                            Tk_Item *itemPtr, double originX, double originY,
        !           103:                            double scaleX, double scaleY));
        !           104: static void            TranslateLine _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !           105:                            Tk_Item *itemPtr, double deltaX, double deltaY));
        !           106: 
        !           107: /*
        !           108:  * Information used for parsing configuration specs.  If you change any
        !           109:  * of the default strings, be sure to change the corresponding default
        !           110:  * values in CreateLine.
        !           111:  */
        !           112: 
        !           113: static Tk_CustomOption arrowShapeOption = {ParseArrowShape,
        !           114:        PrintArrowShape, (ClientData) NULL};
        !           115: 
        !           116: static Tk_ConfigSpec configSpecs[] = {
        !           117:     {TK_CONFIG_UID, "-arrow", (char *) NULL, (char *) NULL,
        !           118:        "none", Tk_Offset(LineItem, arrow), TK_CONFIG_DONT_SET_DEFAULT},
        !           119:     {TK_CONFIG_CUSTOM, "-arrowshape", (char *) NULL, (char *) NULL,
        !           120:        "8 10 3", Tk_Offset(LineItem, arrowShapeA),
        !           121:        TK_CONFIG_DONT_SET_DEFAULT, &arrowShapeOption},
        !           122:     {TK_CONFIG_CAP_STYLE, "-capstyle", (char *) NULL, (char *) NULL,
        !           123:        "butt", Tk_Offset(LineItem, capStyle), TK_CONFIG_DONT_SET_DEFAULT},
        !           124:     {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL,
        !           125:        "black", Tk_Offset(LineItem, fg), 0},
        !           126:     {TK_CONFIG_JOIN_STYLE, "-joinstyle", (char *) NULL, (char *) NULL,
        !           127:        "round", Tk_Offset(LineItem, joinStyle), TK_CONFIG_DONT_SET_DEFAULT},
        !           128:     {TK_CONFIG_BOOLEAN, "-smooth", (char *) NULL, (char *) NULL,
        !           129:        "no", Tk_Offset(LineItem, smooth), TK_CONFIG_DONT_SET_DEFAULT},
        !           130:     {TK_CONFIG_INT, "-splinesteps", (char *) NULL, (char *) NULL,
        !           131:        "12", Tk_Offset(LineItem, splineSteps), TK_CONFIG_DONT_SET_DEFAULT},
        !           132:     {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL,
        !           133:        (char *) NULL, Tk_Offset(LineItem, fillStipple), TK_CONFIG_NULL_OK},
        !           134:     {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL,
        !           135:        (char *) NULL, 0, TK_CONFIG_NULL_OK, &tkCanvasTagsOption},
        !           136:     {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL,
        !           137:        "1", Tk_Offset(LineItem, width), TK_CONFIG_DONT_SET_DEFAULT},
        !           138:     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
        !           139:        (char *) NULL, 0, 0}
        !           140: };
        !           141: 
        !           142: /*
        !           143:  * The structures below defines the line item type by means
        !           144:  * of procedures that can be invoked by generic item code.
        !           145:  */
        !           146: 
        !           147: Tk_ItemType TkLineType = {
        !           148:     "line",                            /* name */
        !           149:     sizeof(LineItem),                  /* itemSize */
        !           150:     CreateLine,                                /* createProc */
        !           151:     configSpecs,                       /* configSpecs */
        !           152:     ConfigureLine,                     /* configureProc */
        !           153:     LineCoords,                                /* coordProc */
        !           154:     DeleteLine,                                /* deleteProc */
        !           155:     DisplayLine,                       /* displayProc */
        !           156:     0,                                 /* alwaysRedraw */
        !           157:     LineToPoint,                       /* pointProc */
        !           158:     LineToArea,                                /* areaProc */
        !           159:     (Tk_ItemPostscriptProc *) NULL,    /* postscriptProc */
        !           160:     ScaleLine,                         /* scaleProc */
        !           161:     TranslateLine,                     /* translateProc */
        !           162:     (Tk_ItemIndexProc *) NULL,         /* indexProc */
        !           163:     (Tk_ItemCursorProc *) NULL,                /* cursorProc */
        !           164:     (Tk_ItemSelectionProc *) NULL,     /* selectionProc */
        !           165:     (Tk_ItemInsertProc *) NULL,                /* insertProc */
        !           166:     (Tk_ItemDCharsProc *) NULL,                /* dTextProc */
        !           167:     (Tk_ItemType *) NULL               /* nextPtr */
        !           168: };
        !           169: 
        !           170: /*
        !           171:  * The Tk_Uid's below refer to uids for the various arrow types:
        !           172:  */
        !           173: 
        !           174: static Tk_Uid noneUid = NULL;
        !           175: static Tk_Uid firstUid = NULL;
        !           176: static Tk_Uid lastUid = NULL;
        !           177: static Tk_Uid bothUid = NULL;
        !           178: 
        !           179: /*
        !           180:  * The definition below determines how large are static arrays
        !           181:  * used to hold spline points (splines larger than this have to
        !           182:  * have their arrays malloc-ed).
        !           183:  */
        !           184: 
        !           185: #define MAX_STATIC_POINTS 200
        !           186: 
        !           187: /*
        !           188:  *--------------------------------------------------------------
        !           189:  *
        !           190:  * CreateLine --
        !           191:  *
        !           192:  *     This procedure is invoked to create a new line item in
        !           193:  *     a canvas.
        !           194:  *
        !           195:  * Results:
        !           196:  *     A standard Tcl return value.  If an error occurred in
        !           197:  *     creating the item, then an error message is left in
        !           198:  *     canvasPtr->interp->result;  in this case itemPtr is
        !           199:  *     left uninitialized, so it can be safely freed by the
        !           200:  *     caller.
        !           201:  *
        !           202:  * Side effects:
        !           203:  *     A new line item is created.
        !           204:  *
        !           205:  *--------------------------------------------------------------
        !           206:  */
        !           207: 
        !           208: static int
        !           209: CreateLine(canvasPtr, itemPtr, argc, argv)
        !           210:     register Tk_Canvas *canvasPtr;     /* Canvas to hold new item. */
        !           211:     Tk_Item *itemPtr;                  /* Record to hold new item;  header
        !           212:                                         * has been initialized by caller. */
        !           213:     int argc;                          /* Number of arguments in argv. */
        !           214:     char **argv;                       /* Arguments describing line. */
        !           215: {
        !           216:     register LineItem *linePtr = (LineItem *) itemPtr;
        !           217:     int i;
        !           218: 
        !           219:     if (argc < 4) {
        !           220:        Tcl_AppendResult(canvasPtr->interp, "wrong # args:  should be \"",
        !           221:                Tk_PathName(canvasPtr->tkwin),
        !           222:                "\" create x1 y1 x2 y2 ?x3 y3 ...? ?options?",
        !           223:                (char *) NULL);
        !           224:        return TCL_ERROR;
        !           225:     }
        !           226: 
        !           227:     /*
        !           228:      * Carry out initialization that is needed to set defaults and to
        !           229:      * allow proper cleanup after errors during the the remainder of
        !           230:      * this procedure.
        !           231:      */
        !           232: 
        !           233:     linePtr->canvasPtr = canvasPtr;
        !           234:     linePtr->numPoints = 0;
        !           235:     linePtr->coordPtr = NULL;
        !           236:     linePtr->width = 1;
        !           237:     linePtr->fg = None;
        !           238:     linePtr->fillStipple = None;
        !           239:     linePtr->capStyle = CapButt;
        !           240:     linePtr->joinStyle = JoinRound;
        !           241:     linePtr->gc = None;
        !           242:     if (noneUid == NULL) {
        !           243:        noneUid = Tk_GetUid("none");
        !           244:        firstUid = Tk_GetUid("first");
        !           245:        lastUid = Tk_GetUid("last");
        !           246:        bothUid = Tk_GetUid("both");
        !           247:     }
        !           248:     linePtr->arrow = noneUid;
        !           249:     linePtr->arrowShapeA = 8.0;
        !           250:     linePtr->arrowShapeB = 10.0;
        !           251:     linePtr->arrowShapeC = 3.0;
        !           252:     linePtr->firstArrowPtr = NULL;
        !           253:     linePtr->lastArrowPtr = NULL;
        !           254:     linePtr->smooth = 0;
        !           255:     linePtr->splineSteps = 12;
        !           256: 
        !           257:     /*
        !           258:      * Count the number of points and then parse them into a point
        !           259:      * array.  Leading arguments are assumed to be points if they
        !           260:      * start with a digit or a minus sign followed by a digit.
        !           261:      */
        !           262: 
        !           263:     for (i = 4; i < (argc-1); i+=2) {
        !           264:        if ((!isdigit(argv[i][0])) &&
        !           265:                ((argv[i][0] != '-') || (!isdigit(argv[i][1])))) {
        !           266:            break;
        !           267:        }
        !           268:     }
        !           269:     if (LineCoords(canvasPtr, itemPtr, i, argv) != TCL_OK) {
        !           270:        goto error;
        !           271:     }
        !           272:     if (ConfigureLine(canvasPtr, itemPtr, argc-i, argv+i, 0) == TCL_OK) {
        !           273:        return TCL_OK;
        !           274:     }
        !           275: 
        !           276:     error:
        !           277:     DeleteLine(itemPtr);
        !           278:     return TCL_ERROR;
        !           279: }
        !           280: 
        !           281: /*
        !           282:  *--------------------------------------------------------------
        !           283:  *
        !           284:  * LineCoords --
        !           285:  *
        !           286:  *     This procedure is invoked to process the "coords" widget
        !           287:  *     command on lines.  See the user documentation for details
        !           288:  *     on what it does.
        !           289:  *
        !           290:  * Results:
        !           291:  *     Returns TCL_OK or TCL_ERROR, and sets canvasPtr->interp->result.
        !           292:  *
        !           293:  * Side effects:
        !           294:  *     The coordinates for the given item may be changed.
        !           295:  *
        !           296:  *--------------------------------------------------------------
        !           297:  */
        !           298: 
        !           299: static int
        !           300: LineCoords(canvasPtr, itemPtr, argc, argv)
        !           301:     register Tk_Canvas *canvasPtr;     /* Canvas containing item. */
        !           302:     Tk_Item *itemPtr;                  /* Item whose coordinates are to be
        !           303:                                         * read or modified. */
        !           304:     int argc;                          /* Number of coordinates supplied in
        !           305:                                         * argv. */
        !           306:     char **argv;                       /* Array of coordinates: x1, y1,
        !           307:                                         * x2, y2, ... */
        !           308: {
        !           309:     register LineItem *linePtr = (LineItem *) itemPtr;
        !           310:     char buffer[300];
        !           311:     int i, numPoints;
        !           312: 
        !           313:     if (argc == 0) {
        !           314:        for (i = 0; i < 2*linePtr->numPoints; i++) {
        !           315:            sprintf(buffer, "%g", linePtr->coordPtr[i]);
        !           316:            Tcl_AppendElement(canvasPtr->interp, buffer, 0);
        !           317:        }
        !           318:     } else if (argc < 4) {
        !           319:        Tcl_AppendResult(canvasPtr->interp,
        !           320:                "too few coordinates for line:  must have at least 4",
        !           321:                (char *) NULL);
        !           322:        return TCL_ERROR;
        !           323:     } else if (argc & 1) {
        !           324:        Tcl_AppendResult(canvasPtr->interp,
        !           325:                "odd number of coordinates specified for line",
        !           326:                (char *) NULL);
        !           327:        return TCL_ERROR;
        !           328:     } else {
        !           329:        numPoints = argc/2;
        !           330:        if (linePtr->numPoints != numPoints) {
        !           331:            if (linePtr->coordPtr != NULL) {
        !           332:                ckfree((char *) linePtr->coordPtr);
        !           333:            }
        !           334:            linePtr->coordPtr = (double *) ckalloc((unsigned)
        !           335:                    (sizeof(double) * argc));
        !           336:            linePtr->numPoints = numPoints;
        !           337:        }
        !           338:        for (i = argc-1; i >= 0; i--) {
        !           339:            if (TkGetCanvasCoord(canvasPtr, argv[i], &linePtr->coordPtr[i])
        !           340:                    != TCL_OK) {
        !           341:                return TCL_ERROR;
        !           342:            }
        !           343:        }
        !           344:        ComputeLineBbox(canvasPtr, linePtr);
        !           345:     }
        !           346:     return TCL_OK;
        !           347: }
        !           348: 
        !           349: /*
        !           350:  *--------------------------------------------------------------
        !           351:  *
        !           352:  * ConfigureLine --
        !           353:  *
        !           354:  *     This procedure is invoked to configure various aspects
        !           355:  *     of a line item such as its background color.
        !           356:  *
        !           357:  * Results:
        !           358:  *     A standard Tcl result code.  If an error occurs, then
        !           359:  *     an error message is left in canvasPtr->interp->result.
        !           360:  *
        !           361:  * Side effects:
        !           362:  *     Configuration information, such as colors and stipple
        !           363:  *     patterns, may be set for itemPtr.
        !           364:  *
        !           365:  *--------------------------------------------------------------
        !           366:  */
        !           367: 
        !           368: static int
        !           369: ConfigureLine(canvasPtr, itemPtr, argc, argv, flags)
        !           370:     Tk_Canvas *canvasPtr;      /* Canvas containing itemPtr. */
        !           371:     Tk_Item *itemPtr;          /* Line item to reconfigure. */
        !           372:     int argc;                  /* Number of elements in argv.  */
        !           373:     char **argv;               /* Arguments describing things to configure. */
        !           374:     int flags;                 /* Flags to pass to Tk_ConfigureWidget. */
        !           375: {
        !           376:     register LineItem *linePtr = (LineItem *) itemPtr;
        !           377:     XGCValues gcValues;
        !           378:     GC newGC;
        !           379:     unsigned long mask;
        !           380: 
        !           381:     if (Tk_ConfigureWidget(canvasPtr->interp, canvasPtr->tkwin,
        !           382:            configSpecs, argc, argv, (char *) linePtr, flags) != TCL_OK) {
        !           383:        return TCL_ERROR;
        !           384:     }
        !           385: 
        !           386:     /*
        !           387:      * A few of the options require additional processing, such as
        !           388:      * graphics contexts.
        !           389:      */
        !           390: 
        !           391:     if (linePtr->fg == NULL) {
        !           392:        newGC = None;
        !           393:     } else {
        !           394:        gcValues.foreground = linePtr->fg->pixel;
        !           395:        gcValues.join_style = linePtr->joinStyle;
        !           396:        if (linePtr->width < 0) {
        !           397:            linePtr->width = 1;
        !           398:        }
        !           399:        gcValues.line_width = linePtr->width;
        !           400:        mask = GCForeground|GCJoinStyle|GCLineWidth;
        !           401:        if (linePtr->fillStipple != None) {
        !           402:            gcValues.stipple = linePtr->fillStipple;
        !           403:            gcValues.fill_style = FillStippled;
        !           404:            mask |= GCStipple|GCFillStyle;
        !           405:        }
        !           406:        if (linePtr->arrow == noneUid) {
        !           407:            gcValues.cap_style = linePtr->capStyle;
        !           408:            mask |= GCCapStyle;
        !           409:        }
        !           410:        newGC = Tk_GetGC(canvasPtr->tkwin, mask, &gcValues);
        !           411:     }
        !           412:     if (linePtr->gc != None) {
        !           413:        Tk_FreeGC(linePtr->gc);
        !           414:     }
        !           415:     linePtr->gc = newGC;
        !           416: 
        !           417:     /*
        !           418:      * Keep spline parameters within reasonable limits.
        !           419:      */
        !           420: 
        !           421:     if (linePtr->splineSteps < 1) {
        !           422:        linePtr->splineSteps = 1;
        !           423:     } else if (linePtr->splineSteps > 100) {
        !           424:        linePtr->splineSteps = 100;
        !           425:     }
        !           426: 
        !           427:     /*
        !           428:      * Setup arrowheads, if needed.  If arrowheads are turned off,
        !           429:      * restore the line's endpoints (they were shortened when the
        !           430:      * arrowheads were added).
        !           431:      */
        !           432: 
        !           433:     if ((linePtr->firstArrowPtr != NULL) && (linePtr->arrow != firstUid)
        !           434:            && (linePtr->arrow != bothUid)) {
        !           435:        linePtr->coordPtr[0] = linePtr->firstArrowPtr[0];
        !           436:        linePtr->coordPtr[1] = linePtr->firstArrowPtr[1];
        !           437:        ckfree((char *) linePtr->firstArrowPtr);
        !           438:        linePtr->firstArrowPtr = NULL;
        !           439:     }
        !           440:     if ((linePtr->lastArrowPtr != NULL) && (linePtr->arrow != lastUid)
        !           441:            && (linePtr->arrow != bothUid)) {
        !           442:        int index;
        !           443: 
        !           444:        index = 2*(linePtr->numPoints-1);
        !           445:        linePtr->coordPtr[index] = linePtr->lastArrowPtr[0];
        !           446:        linePtr->coordPtr[index+1] = linePtr->lastArrowPtr[1];
        !           447:        ckfree((char *) linePtr->lastArrowPtr);
        !           448:        linePtr->lastArrowPtr = NULL;
        !           449:     }
        !           450:     if (linePtr->arrow != noneUid) {
        !           451:        if ((linePtr->arrow != firstUid) && (linePtr->arrow != lastUid)
        !           452:                && (linePtr->arrow != bothUid)) {
        !           453:            Tcl_AppendResult(canvasPtr->interp, "bad arrow spec \"",
        !           454:                    linePtr->arrow, "\": must be none, first, last, or both",
        !           455:                    (char *) NULL);
        !           456:            linePtr->arrow = noneUid;
        !           457:            return TCL_ERROR;
        !           458:        }
        !           459:        ConfigureArrows(canvasPtr, linePtr);
        !           460:     }
        !           461: 
        !           462:     /*
        !           463:      * Recompute bounding box for line.
        !           464:      */
        !           465: 
        !           466:     ComputeLineBbox(canvasPtr, linePtr);
        !           467: 
        !           468:     return TCL_OK;
        !           469: }
        !           470: 
        !           471: /*
        !           472:  *--------------------------------------------------------------
        !           473:  *
        !           474:  * DeleteLine --
        !           475:  *
        !           476:  *     This procedure is called to clean up the data structure
        !           477:  *     associated with a line item.
        !           478:  *
        !           479:  * Results:
        !           480:  *     None.
        !           481:  *
        !           482:  * Side effects:
        !           483:  *     Resources associated with itemPtr are released.
        !           484:  *
        !           485:  *--------------------------------------------------------------
        !           486:  */
        !           487: 
        !           488: static void
        !           489: DeleteLine(itemPtr)
        !           490:     Tk_Item *itemPtr;                  /* Item that is being deleted. */
        !           491: {
        !           492:     register LineItem *linePtr = (LineItem *) itemPtr;
        !           493: 
        !           494:     if (linePtr->coordPtr != NULL) {
        !           495:        ckfree((char *) linePtr->coordPtr);
        !           496:     }
        !           497:     if (linePtr->fg != NULL) {
        !           498:        Tk_FreeColor(linePtr->fg);
        !           499:     }
        !           500:     if (linePtr->fillStipple != None) {
        !           501:        Tk_FreeBitmap(linePtr->fillStipple);
        !           502:     }
        !           503:     if (linePtr->gc != None) {
        !           504:        Tk_FreeGC(linePtr->gc);
        !           505:     }
        !           506:     if (linePtr->firstArrowPtr != NULL) {
        !           507:        ckfree((char *) linePtr->firstArrowPtr);
        !           508:     }
        !           509:     if (linePtr->lastArrowPtr != NULL) {
        !           510:        ckfree((char *) linePtr->lastArrowPtr);
        !           511:     }
        !           512: }
        !           513: 
        !           514: /*
        !           515:  *--------------------------------------------------------------
        !           516:  *
        !           517:  * ComputeLineBbox --
        !           518:  *
        !           519:  *     This procedure is invoked to compute the bounding box of
        !           520:  *     all the pixels that may be drawn as part of a line.
        !           521:  *
        !           522:  * Results:
        !           523:  *     None.
        !           524:  *
        !           525:  * Side effects:
        !           526:  *     The fields x1, y1, x2, and y2 are updated in the header
        !           527:  *     for itemPtr.
        !           528:  *
        !           529:  *--------------------------------------------------------------
        !           530:  */
        !           531: 
        !           532: static void
        !           533: ComputeLineBbox(canvasPtr, linePtr)
        !           534:     register Tk_Canvas *canvasPtr;     /* Canvas that contains item. */
        !           535:     LineItem *linePtr;                 /* Item whose bbos is to be
        !           536:                                         * recomputed. */
        !           537: {
        !           538:     register double *coordPtr;
        !           539:     int i;
        !           540: 
        !           541:     coordPtr = linePtr->coordPtr;
        !           542:     linePtr->header.x1 = linePtr->header.x2 = *coordPtr;
        !           543:     linePtr->header.y1 = linePtr->header.y2 = coordPtr[1];
        !           544: 
        !           545:     /*
        !           546:      * Compute the bounding box of all the points in the line,
        !           547:      * then expand in all directions by the line's width to take
        !           548:      * care of butting or rounded corners and projecting or
        !           549:      * rounded caps.  This expansion is an overestimate (worst-case
        !           550:      * is square root of two over two) but it's simple.  Don't do
        !           551:      * anything special for curves.  This causes an additional
        !           552:      * overestimate in the bounding box, but is faster.
        !           553:      */
        !           554: 
        !           555:     for (i = 1, coordPtr = linePtr->coordPtr+2; i < linePtr->numPoints;
        !           556:            i++, coordPtr += 2) {
        !           557:        TkIncludePoint(canvasPtr, (Tk_Item *) linePtr, coordPtr);
        !           558:     }
        !           559:     linePtr->header.x1 -= linePtr->width;
        !           560:     linePtr->header.x2 += linePtr->width;
        !           561:     linePtr->header.y1 -= linePtr->width;
        !           562:     linePtr->header.y2 += linePtr->width;
        !           563: 
        !           564:     /*
        !           565:      * For mitered lines, make a second pass through all the points.
        !           566:      * Compute the locations of the two miter vertex points and add
        !           567:      * those into the bounding box.
        !           568:      */
        !           569: 
        !           570:     if (linePtr->joinStyle == JoinMiter) {
        !           571:        for (i = linePtr->numPoints, coordPtr = linePtr->coordPtr; i >= 3;
        !           572:                i--, coordPtr += 2) {
        !           573:            double miter[4];
        !           574:            int j;
        !           575:     
        !           576:            if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4,
        !           577:                    (double) linePtr->width, miter, miter+2)) {
        !           578:                for (j = 0; j < 4; j += 2) {
        !           579:                    TkIncludePoint(canvasPtr, (Tk_Item *) linePtr, miter+j);
        !           580:                }
        !           581:            }
        !           582:        }
        !           583:     }
        !           584: 
        !           585:     /*
        !           586:      * Add in the sizes of arrowheads, if any.
        !           587:      */
        !           588: 
        !           589:     if (linePtr->arrow != noneUid) {
        !           590:        if (linePtr->arrow != lastUid) {
        !           591:            for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW;
        !           592:                    i++, coordPtr += 2) {
        !           593:                TkIncludePoint(canvasPtr, (Tk_Item *) linePtr, coordPtr);
        !           594:            }
        !           595:        }
        !           596:        if (linePtr->arrow != firstUid) {
        !           597:            for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW;
        !           598:                    i++, coordPtr += 2) {
        !           599:                TkIncludePoint(canvasPtr, (Tk_Item *) linePtr, coordPtr);
        !           600:            }
        !           601:        }
        !           602:     }
        !           603: 
        !           604:     /*
        !           605:      * Add one more pixel of fudge factor just to be safe (e.g.
        !           606:      * X may round differently than we do).
        !           607:      */
        !           608: 
        !           609:     linePtr->header.x1 -= 1;
        !           610:     linePtr->header.x2 += 1;
        !           611:     linePtr->header.y1 -= 1;
        !           612:     linePtr->header.y2 += 1;
        !           613: }
        !           614: 
        !           615: /*
        !           616:  *--------------------------------------------------------------
        !           617:  *
        !           618:  * DisplayLine --
        !           619:  *
        !           620:  *     This procedure is invoked to draw a line item in a given
        !           621:  *     drawable.
        !           622:  *
        !           623:  * Results:
        !           624:  *     None.
        !           625:  *
        !           626:  * Side effects:
        !           627:  *     ItemPtr is drawn in drawable using the transformation
        !           628:  *     information in canvasPtr.
        !           629:  *
        !           630:  *--------------------------------------------------------------
        !           631:  */
        !           632: 
        !           633: static void
        !           634: DisplayLine(canvasPtr, itemPtr, drawable)
        !           635:     register Tk_Canvas *canvasPtr;     /* Canvas that contains item. */
        !           636:     Tk_Item *itemPtr;                  /* Item to be displayed. */
        !           637:     Drawable drawable;                 /* Pixmap or window in which to draw
        !           638:                                         * item. */
        !           639: {
        !           640:     register LineItem *linePtr = (LineItem *) itemPtr;
        !           641:     XPoint staticPoints[MAX_STATIC_POINTS];
        !           642:     XPoint *pointPtr;
        !           643:     register XPoint *pPtr;
        !           644:     register double *coordPtr;
        !           645:     int i, numPoints;
        !           646: 
        !           647:     if (linePtr->gc == None) {
        !           648:        return;
        !           649:     }
        !           650: 
        !           651:     /*
        !           652:      * Build up an array of points in screen coordinates.  Use a
        !           653:      * static array unless the line has an enormous number of points;
        !           654:      * in this case, dynamically allocate an array.  For smoothed lines,
        !           655:      * generate the curve points on each redisplay.
        !           656:      */
        !           657: 
        !           658:     if ((linePtr->smooth) && (linePtr->numPoints > 2)) {
        !           659:        numPoints = 1 + linePtr->numPoints*linePtr->splineSteps;
        !           660:     } else {
        !           661:        numPoints = linePtr->numPoints;
        !           662:     }
        !           663: 
        !           664:     if (numPoints <= MAX_STATIC_POINTS) {
        !           665:        pointPtr = staticPoints;
        !           666:     } else {
        !           667:        pointPtr = (XPoint *) ckalloc((unsigned) (numPoints * sizeof(XPoint)));
        !           668:     }
        !           669: 
        !           670:     if (linePtr->smooth) {
        !           671:        numPoints = TkMakeBezierCurve(canvasPtr, linePtr->coordPtr,
        !           672:                linePtr->numPoints, linePtr->splineSteps, pointPtr,
        !           673:                (double *) NULL);
        !           674:     } else {
        !           675:        for (i = 0, coordPtr = linePtr->coordPtr, pPtr = pointPtr;
        !           676:                i < linePtr->numPoints;  i += 1, coordPtr += 2, pPtr++) {
        !           677:            pPtr->x = SCREEN_X(canvasPtr, *coordPtr);
        !           678:            pPtr->y = SCREEN_Y(canvasPtr, coordPtr[1]);
        !           679:        }
        !           680:     }
        !           681: 
        !           682:     /*
        !           683:      * Display line, the free up line storage if it was dynamically
        !           684:      * allocated.
        !           685:      */
        !           686: 
        !           687:     XDrawLines(Tk_Display(canvasPtr->tkwin), drawable, linePtr->gc,
        !           688:            pointPtr, numPoints, CoordModeOrigin);
        !           689:     if (pointPtr != staticPoints) {
        !           690:        ckfree((char *) pointPtr);
        !           691:     }
        !           692: 
        !           693:     /*
        !           694:      * Display arrowheads, if they are wanted.
        !           695:      */
        !           696: 
        !           697:     if (linePtr->arrow != noneUid) {
        !           698:        if (linePtr->arrow != lastUid) {
        !           699:            TkFillPolygon(canvasPtr, linePtr->firstArrowPtr, PTS_IN_ARROW,
        !           700:                    drawable, linePtr->gc);
        !           701:        }
        !           702:        if (linePtr->arrow != firstUid) {
        !           703:            TkFillPolygon(canvasPtr, linePtr->lastArrowPtr, PTS_IN_ARROW,
        !           704:                    drawable, linePtr->gc);
        !           705:        }
        !           706:     }
        !           707: }
        !           708: 
        !           709: /*
        !           710:  *--------------------------------------------------------------
        !           711:  *
        !           712:  * LineToPoint --
        !           713:  *
        !           714:  *     Computes the distance from a given point to a given
        !           715:  *     line, in canvas units.
        !           716:  *
        !           717:  * Results:
        !           718:  *     The return value is 0 if the point whose x and y coordinates
        !           719:  *     are pointPtr[0] and pointPtr[1] is inside the line.  If the
        !           720:  *     point isn't inside the line then the return value is the
        !           721:  *     distance from the point to the line.
        !           722:  *
        !           723:  * Side effects:
        !           724:  *     None.
        !           725:  *
        !           726:  *--------------------------------------------------------------
        !           727:  */
        !           728: 
        !           729:        /* ARGSUSED */
        !           730: static double
        !           731: LineToPoint(canvasPtr, itemPtr, pointPtr)
        !           732:     Tk_Canvas *canvasPtr;      /* Canvas containing item. */
        !           733:     Tk_Item *itemPtr;          /* Item to check against point. */
        !           734:     double *pointPtr;          /* Pointer to x and y coordinates. */
        !           735: {
        !           736:     register LineItem *linePtr = (LineItem *) itemPtr;
        !           737:     register double *coordPtr, *linePoints;
        !           738:     double staticSpace[2*MAX_STATIC_POINTS];
        !           739:     double poly[10];
        !           740:     double bestDist, dist;
        !           741:     int numPoints, count;
        !           742:     int changedMiterToBevel;   /* Non-zero means that a mitered corner
        !           743:                                 * had to be treated as beveled after all
        !           744:                                 * because the angle was < 11 degrees. */
        !           745: 
        !           746:     bestDist = 1.0e40;
        !           747: 
        !           748:     /*
        !           749:      * Handle smoothed lines by generating an expanded set of points
        !           750:      * against which to do the check.
        !           751:      */
        !           752: 
        !           753:     if ((linePtr->smooth) && (linePtr->numPoints > 2)) {
        !           754:        numPoints = 1 + linePtr->numPoints*linePtr->splineSteps;
        !           755:        if (numPoints <= MAX_STATIC_POINTS) {
        !           756:            linePoints = staticSpace;
        !           757:        } else {
        !           758:            linePoints = (double *) ckalloc((unsigned)
        !           759:                    (2*numPoints*sizeof(double)));
        !           760:        }
        !           761:        numPoints = TkMakeBezierCurve(canvasPtr, linePtr->coordPtr,
        !           762:                linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL,
        !           763:                linePoints);
        !           764:     } else {
        !           765:        numPoints = linePtr->numPoints;
        !           766:        linePoints = linePtr->coordPtr;
        !           767:     }
        !           768: 
        !           769:     /*
        !           770:      * The overall idea is to iterate through all of the edges of
        !           771:      * the line, computing a polygon for each edge and testing the
        !           772:      * point against that polygon.  In addition, there are additional
        !           773:      * tests to deal with rounded joints and caps.
        !           774:      */
        !           775: 
        !           776:     changedMiterToBevel = 0;
        !           777:     for (count = numPoints, coordPtr = linePoints; count >= 2;
        !           778:            count--, coordPtr += 2) {
        !           779: 
        !           780:        /*
        !           781:         * If rounding is done around the first point then compute
        !           782:         * the distance between the point and the point.
        !           783:         */
        !           784: 
        !           785:        if (((linePtr->capStyle == CapRound) && (count == numPoints))
        !           786:                || ((linePtr->joinStyle == JoinRound)
        !           787:                        && (count != numPoints))) {
        !           788:            dist = hypot(coordPtr[0] - pointPtr[0], coordPtr[1] - pointPtr[1])
        !           789:                    - linePtr->width/2.0;
        !           790:            if (dist <= 0.0) {
        !           791:                bestDist = 0.0;
        !           792:                goto done;
        !           793:            } else if (dist < bestDist) {
        !           794:                bestDist = dist;
        !           795:            }
        !           796:        }
        !           797: 
        !           798:        /*
        !           799:         * Compute the polygonal shape corresponding to this edge,
        !           800:         * consisting of two points for the first point of the edge
        !           801:         * and two points for the last point of the edge.
        !           802:         */
        !           803: 
        !           804:        if (count == numPoints) {
        !           805:            TkGetButtPoints(coordPtr+2, coordPtr, (double) linePtr->width,
        !           806:                    linePtr->capStyle == CapProjecting, poly, poly+2);
        !           807:        } else if ((linePtr->joinStyle == JoinMiter) && !changedMiterToBevel) {
        !           808:            poly[0] = poly[6];
        !           809:            poly[1] = poly[7];
        !           810:            poly[2] = poly[4];
        !           811:            poly[3] = poly[5];
        !           812:        } else {
        !           813:            TkGetButtPoints(coordPtr+2, coordPtr, (double) linePtr->width, 0,
        !           814:                    poly, poly+2);
        !           815: 
        !           816:            /*
        !           817:             * If this line uses beveled joints, then check the distance
        !           818:             * to a polygon comprising the last two points of the previous
        !           819:             * polygon and the first two from this polygon;  this checks
        !           820:             * the wedges that fill the mitered joint.
        !           821:             */
        !           822: 
        !           823:            if ((linePtr->joinStyle == JoinBevel) || changedMiterToBevel) {
        !           824:                poly[8] = poly[0];
        !           825:                poly[9] = poly[1];
        !           826:                dist = TkPolygonToPoint(poly, 5, pointPtr);
        !           827:                if (dist <= 0.0) {
        !           828:                    bestDist = 0.0;
        !           829:                    goto done;
        !           830:                } else if (dist < bestDist) {
        !           831:                    bestDist = dist;
        !           832:                }
        !           833:                changedMiterToBevel = 0;
        !           834:            }
        !           835:        }
        !           836:        if (count == 2) {
        !           837:            TkGetButtPoints(coordPtr, coordPtr+2, (double) linePtr->width,
        !           838:                    linePtr->capStyle == CapProjecting, poly+4, poly+6);
        !           839:        } else if (linePtr->joinStyle == JoinMiter) {
        !           840:            if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4,
        !           841:                    (double) linePtr->width, poly+4, poly+6) == 0) {
        !           842:                changedMiterToBevel = 1;
        !           843:                TkGetButtPoints(coordPtr, coordPtr+2, (double) linePtr->width,
        !           844:                        0, poly+4, poly+6);
        !           845:            }
        !           846:        } else {
        !           847:            TkGetButtPoints(coordPtr, coordPtr+2, (double) linePtr->width, 0,
        !           848:                    poly+4, poly+6);
        !           849:        }
        !           850:        poly[8] = poly[0];
        !           851:        poly[9] = poly[1];
        !           852:        dist = TkPolygonToPoint(poly, 5, pointPtr);
        !           853:        if (dist <= 0.0) {
        !           854:            bestDist = 0.0;
        !           855:            goto done;
        !           856:        } else if (dist < bestDist) {
        !           857:            bestDist = dist;
        !           858:        }
        !           859:     }
        !           860: 
        !           861:     /*
        !           862:      * If caps are rounded, check the distance to the cap around the
        !           863:      * final end point of the line.
        !           864:      */
        !           865: 
        !           866:     if (linePtr->capStyle == CapRound) {
        !           867:        dist = hypot(coordPtr[0] - pointPtr[0], coordPtr[1] - pointPtr[1])
        !           868:                - linePtr->width/2.0;
        !           869:        if (dist <= 0.0) {
        !           870:            bestDist = 0.0;
        !           871:            goto done;
        !           872:        } else if (dist < bestDist) {
        !           873:            bestDist = dist;
        !           874:        }
        !           875:     }
        !           876: 
        !           877:     /*
        !           878:      * If there are arrowheads, check the distance to the arrowheads.
        !           879:      */
        !           880: 
        !           881:     if (linePtr->arrow != noneUid) {
        !           882:        if (linePtr->arrow != lastUid) {
        !           883:            dist = TkPolygonToPoint(linePtr->firstArrowPtr, PTS_IN_ARROW,
        !           884:                    pointPtr);
        !           885:            if (dist <= 0.0) {
        !           886:                bestDist = 0.0;
        !           887:                goto done;
        !           888:            } else if (dist < bestDist) {
        !           889:                bestDist = dist;
        !           890:            }
        !           891:        }
        !           892:        if (linePtr->arrow != firstUid) {
        !           893:            dist = TkPolygonToPoint(linePtr->lastArrowPtr, PTS_IN_ARROW,
        !           894:                    pointPtr);
        !           895:            if (dist <= 0.0) {
        !           896:                bestDist = 0.0;
        !           897:                goto done;
        !           898:            } else if (dist < bestDist) {
        !           899:                bestDist = dist;
        !           900:            }
        !           901:        }
        !           902:     }
        !           903: 
        !           904:     done:
        !           905:     if ((linePoints != staticSpace) && (linePoints != linePtr->coordPtr)) {
        !           906:        ckfree((char *) linePoints);
        !           907:     }
        !           908:     return bestDist;
        !           909: }
        !           910: 
        !           911: /*
        !           912:  *--------------------------------------------------------------
        !           913:  *
        !           914:  * LineToArea --
        !           915:  *
        !           916:  *     This procedure is called to determine whether an item
        !           917:  *     lies entirely inside, entirely outside, or overlapping
        !           918:  *     a given rectangular area.
        !           919:  *
        !           920:  * Results:
        !           921:  *     -1 is returned if the item is entirely outside the
        !           922:  *     area, 0 if it overlaps, and 1 if it is entirely
        !           923:  *     inside the given area.
        !           924:  *
        !           925:  * Side effects:
        !           926:  *     None.
        !           927:  *
        !           928:  *--------------------------------------------------------------
        !           929:  */
        !           930: 
        !           931:        /* ARGSUSED */
        !           932: static int
        !           933: LineToArea(canvasPtr, itemPtr, rectPtr)
        !           934:     Tk_Canvas *canvasPtr;      /* Canvas containing item. */
        !           935:     Tk_Item *itemPtr;          /* Item to check against line. */
        !           936:     double *rectPtr;
        !           937: {
        !           938:     register LineItem *linePtr = (LineItem *) itemPtr;
        !           939:     register double *coordPtr;
        !           940:     double staticSpace[2*MAX_STATIC_POINTS];
        !           941:     double *linePoints, poly[10];
        !           942:     double radius;
        !           943:     int numPoints, count;
        !           944:     int changedMiterToBevel;   /* Non-zero means that a mitered corner
        !           945:                                 * had to be treated as beveled after all
        !           946:                                 * because the angle was < 11 degrees. */
        !           947:     int inside;                        /* Tentative guess about what to return,
        !           948:                                 * based on all points seen so far:  one
        !           949:                                 * means everything seen so far was
        !           950:                                 * inside the area;  -1 means everything
        !           951:                                 * was outside the area.  0 means overlap
        !           952:                                 * has been found. */ 
        !           953: 
        !           954:     radius = linePtr->width/2.0;
        !           955:     inside = -1;
        !           956: 
        !           957:     /*
        !           958:      * Handle smoothed lines by generating an expanded set of points
        !           959:      * against which to do the check.
        !           960:      */
        !           961: 
        !           962:     if ((linePtr->smooth) && (linePtr->numPoints > 2)) {
        !           963:        numPoints = 1 + linePtr->numPoints*linePtr->splineSteps;
        !           964:        if (numPoints <= MAX_STATIC_POINTS) {
        !           965:            linePoints = staticSpace;
        !           966:        } else {
        !           967:            linePoints = (double *) ckalloc((unsigned)
        !           968:                    (2*numPoints*sizeof(double)));
        !           969:        }
        !           970:        numPoints = TkMakeBezierCurve(canvasPtr, linePtr->coordPtr,
        !           971:                linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL,
        !           972:                linePoints);
        !           973:     } else {
        !           974:        numPoints = linePtr->numPoints;
        !           975:        linePoints = linePtr->coordPtr;
        !           976:     }
        !           977: 
        !           978:     coordPtr = linePoints;
        !           979:     if ((coordPtr[0] >= rectPtr[0]) && (coordPtr[0] <= rectPtr[2])
        !           980:            && (coordPtr[1] >= rectPtr[1]) && (coordPtr[1] <= rectPtr[3])) {
        !           981:        inside = 1;
        !           982:     }
        !           983: 
        !           984:     /*
        !           985:      * Iterate through all of the edges of the line, computing a polygon
        !           986:      * for each edge and testing the area against that polygon.  In
        !           987:      * addition, there are additional tests to deal with rounded joints
        !           988:      * and caps.
        !           989:      */
        !           990: 
        !           991:     changedMiterToBevel = 0;
        !           992:     for (count = numPoints; count >= 2; count--, coordPtr += 2) {
        !           993: 
        !           994:        /*
        !           995:         * If rounding is done around the first point of the edge
        !           996:         * then test a circular region around the point with the
        !           997:         * area.
        !           998:         */
        !           999: 
        !          1000:        if (((linePtr->capStyle == CapRound) && (count == numPoints))
        !          1001:                || ((linePtr->joinStyle == JoinRound)
        !          1002:                && (count != numPoints))) {
        !          1003:            poly[0] = coordPtr[0] - radius;
        !          1004:            poly[1] = coordPtr[1] - radius;
        !          1005:            poly[2] = coordPtr[0] + radius;
        !          1006:            poly[3] = coordPtr[1] + radius;
        !          1007:            if (TkOvalToArea(poly, rectPtr) != inside) {
        !          1008:                inside = 0;
        !          1009:                goto done;
        !          1010:            }
        !          1011:        }
        !          1012: 
        !          1013:        /*
        !          1014:         * Compute the polygonal shape corresponding to this edge,
        !          1015:         * consisting of two points for the first point of the edge
        !          1016:         * and two points for the last point of the edge.
        !          1017:         */
        !          1018: 
        !          1019:        if (count == numPoints) {
        !          1020:            TkGetButtPoints(coordPtr+2, coordPtr, (double) linePtr->width,
        !          1021:                    linePtr->capStyle == CapProjecting, poly, poly+2);
        !          1022:        } else if ((linePtr->joinStyle == JoinMiter) && !changedMiterToBevel) {
        !          1023:            poly[0] = poly[6];
        !          1024:            poly[1] = poly[7];
        !          1025:            poly[2] = poly[4];
        !          1026:            poly[3] = poly[5];
        !          1027:        } else {
        !          1028:            TkGetButtPoints(coordPtr+2, coordPtr, (double) linePtr->width, 0,
        !          1029:                    poly, poly+2);
        !          1030: 
        !          1031:            /*
        !          1032:             * If the last joint was beveled, then also check a
        !          1033:             * polygon comprising the last two points of the previous
        !          1034:             * polygon and the first two from this polygon;  this checks
        !          1035:             * the wedges that fill the beveled joint.
        !          1036:             */
        !          1037: 
        !          1038:            if ((linePtr->joinStyle == JoinBevel) || changedMiterToBevel) {
        !          1039:                poly[8] = poly[0];
        !          1040:                poly[9] = poly[1];
        !          1041:                if (TkPolygonToArea(poly, 5, rectPtr) != inside) {
        !          1042:                    inside = 0;
        !          1043:                    goto done;
        !          1044:                }
        !          1045:                changedMiterToBevel = 0;
        !          1046:            }
        !          1047:        }
        !          1048:        if (count == 2) {
        !          1049:            TkGetButtPoints(coordPtr, coordPtr+2, (double) linePtr->width,
        !          1050:                    linePtr->capStyle == CapProjecting, poly+4, poly+6);
        !          1051:        } else if (linePtr->joinStyle == JoinMiter) {
        !          1052:            if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4,
        !          1053:                    (double) linePtr->width, poly+4, poly+6) == 0) {
        !          1054:                changedMiterToBevel = 1;
        !          1055:                TkGetButtPoints(coordPtr, coordPtr+2, (double) linePtr->width,
        !          1056:                        0, poly+4, poly+6);
        !          1057:            }
        !          1058:        } else {
        !          1059:            TkGetButtPoints(coordPtr, coordPtr+2, (double) linePtr->width, 0,
        !          1060:                    poly+4, poly+6);
        !          1061:        }
        !          1062:        poly[8] = poly[0];
        !          1063:        poly[9] = poly[1];
        !          1064:        if (TkPolygonToArea(poly, 5, rectPtr) != inside) {
        !          1065:            inside = 0;
        !          1066:            goto done;
        !          1067:        }
        !          1068:     }
        !          1069: 
        !          1070:     /*
        !          1071:      * If caps are rounded, check the cap around the final point
        !          1072:      * of the line.
        !          1073:      */
        !          1074: 
        !          1075:     if (linePtr->capStyle == CapRound) {
        !          1076:        poly[0] = coordPtr[0] - radius;
        !          1077:        poly[1] = coordPtr[1] - radius;
        !          1078:        poly[2] = coordPtr[0] + radius;
        !          1079:        poly[3] = coordPtr[1] + radius;
        !          1080:        if (TkOvalToArea(poly, rectPtr) != inside) {
        !          1081:            inside = 0;
        !          1082:            goto done;
        !          1083:        }
        !          1084:     }
        !          1085: 
        !          1086:     /*
        !          1087:      * Check arrowheads, if any.
        !          1088:      */
        !          1089: 
        !          1090:     if (linePtr->arrow != noneUid) {
        !          1091:        if (linePtr->arrow != lastUid) {
        !          1092:            if (TkPolygonToArea(linePtr->firstArrowPtr, PTS_IN_ARROW,
        !          1093:                    rectPtr) != inside) {
        !          1094:                inside = 0;
        !          1095:                goto done;
        !          1096:            }
        !          1097:        }
        !          1098:        if (linePtr->arrow != firstUid) {
        !          1099:            if (TkPolygonToArea(linePtr->lastArrowPtr, PTS_IN_ARROW,
        !          1100:                    rectPtr) != inside) {
        !          1101:                inside = 0;
        !          1102:                goto done;
        !          1103:            }
        !          1104:        }
        !          1105:     }
        !          1106: 
        !          1107:     done:
        !          1108:     if ((linePoints != staticSpace) && (linePoints != linePtr->coordPtr)) {
        !          1109:        ckfree((char *) linePoints);
        !          1110:     }
        !          1111:     return inside;
        !          1112: }
        !          1113: 
        !          1114: /*
        !          1115:  *--------------------------------------------------------------
        !          1116:  *
        !          1117:  * ScaleLine --
        !          1118:  *
        !          1119:  *     This procedure is invoked to rescale a line item.
        !          1120:  *
        !          1121:  * Results:
        !          1122:  *     None.
        !          1123:  *
        !          1124:  * Side effects:
        !          1125:  *     The line referred to by itemPtr is rescaled so that the
        !          1126:  *     following transformation is applied to all point
        !          1127:  *     coordinates:
        !          1128:  *             x' = originX + scaleX*(x-originX)
        !          1129:  *             y' = originY + scaleY*(y-originY)
        !          1130:  *
        !          1131:  *--------------------------------------------------------------
        !          1132:  */
        !          1133: 
        !          1134: static void
        !          1135: ScaleLine(canvasPtr, itemPtr, originX, originY, scaleX, scaleY)
        !          1136:     Tk_Canvas *canvasPtr;              /* Canvas containing line. */
        !          1137:     Tk_Item *itemPtr;                  /* Line to be scaled. */
        !          1138:     double originX, originY;           /* Origin about which to scale rect. */
        !          1139:     double scaleX;                     /* Amount to scale in X direction. */
        !          1140:     double scaleY;                     /* Amount to scale in Y direction. */
        !          1141: {
        !          1142:     LineItem *linePtr = (LineItem *) itemPtr;
        !          1143:     register double *coordPtr;
        !          1144:     int i;
        !          1145: 
        !          1146:     for (i = 0, coordPtr = linePtr->coordPtr; i < linePtr->numPoints;
        !          1147:            i++, coordPtr += 2) {
        !          1148:        coordPtr[0] = originX + scaleX*(*coordPtr - originX);
        !          1149:        coordPtr[1] = originY + scaleY*(coordPtr[1] - originY);
        !          1150:     }
        !          1151:     if (linePtr->firstArrowPtr != NULL) {
        !          1152:        for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW;
        !          1153:                i++, coordPtr += 2) {
        !          1154:            coordPtr[0] = originX + scaleX*(coordPtr[0] - originX);
        !          1155:            coordPtr[1] = originY + scaleY*(coordPtr[1] - originY);
        !          1156:        }
        !          1157:     }
        !          1158:     if (linePtr->lastArrowPtr != NULL) {
        !          1159:        for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW;
        !          1160:                i++, coordPtr += 2) {
        !          1161:            coordPtr[0] = originX + scaleX*(coordPtr[0] - originX);
        !          1162:            coordPtr[1] = originY + scaleY*(coordPtr[1] - originY);
        !          1163:        }
        !          1164:     }
        !          1165:     ComputeLineBbox(canvasPtr, linePtr);
        !          1166: }
        !          1167: 
        !          1168: /*
        !          1169:  *--------------------------------------------------------------
        !          1170:  *
        !          1171:  * TranslateLine --
        !          1172:  *
        !          1173:  *     This procedure is called to move a line by a given amount.
        !          1174:  *
        !          1175:  * Results:
        !          1176:  *     None.
        !          1177:  *
        !          1178:  * Side effects:
        !          1179:  *     The position of the line is offset by (xDelta, yDelta), and
        !          1180:  *     the bounding box is updated in the generic part of the item
        !          1181:  *     structure.
        !          1182:  *
        !          1183:  *--------------------------------------------------------------
        !          1184:  */
        !          1185: 
        !          1186: static void
        !          1187: TranslateLine(canvasPtr, itemPtr, deltaX, deltaY)
        !          1188:     Tk_Canvas *canvasPtr;              /* Canvas containing item. */
        !          1189:     Tk_Item *itemPtr;                  /* Item that is being moved. */
        !          1190:     double deltaX, deltaY;             /* Amount by which item is to be
        !          1191:                                         * moved. */
        !          1192: {
        !          1193:     LineItem *linePtr = (LineItem *) itemPtr;
        !          1194:     register double *coordPtr;
        !          1195:     int i;
        !          1196: 
        !          1197:     for (i = 0, coordPtr = linePtr->coordPtr; i < linePtr->numPoints;
        !          1198:            i++, coordPtr += 2) {
        !          1199:        coordPtr[0] += deltaX;
        !          1200:        coordPtr[1] += deltaY;
        !          1201:     }
        !          1202:     if (linePtr->firstArrowPtr != NULL) {
        !          1203:        for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW;
        !          1204:                i++, coordPtr += 2) {
        !          1205:            coordPtr[0] += deltaX;
        !          1206:            coordPtr[1] += deltaY;
        !          1207:        }
        !          1208:     }
        !          1209:     if (linePtr->lastArrowPtr != NULL) {
        !          1210:        for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW;
        !          1211:                i++, coordPtr += 2) {
        !          1212:            coordPtr[0] += deltaX;
        !          1213:            coordPtr[1] += deltaY;
        !          1214:        }
        !          1215:     }
        !          1216:     ComputeLineBbox(canvasPtr, linePtr);
        !          1217: }
        !          1218: 
        !          1219: /*
        !          1220:  *--------------------------------------------------------------
        !          1221:  *
        !          1222:  * ParseArrowShape --
        !          1223:  *
        !          1224:  *     This procedure is called back during option parsing to
        !          1225:  *     parse arrow shape information.
        !          1226:  *
        !          1227:  * Results:
        !          1228:  *     The return value is a standard Tcl result:  TCL_OK means
        !          1229:  *     that the arrow shape information was parsed ok, and
        !          1230:  *     TCL_ERROR means it couldn't be parsed.
        !          1231:  *
        !          1232:  * Side effects:
        !          1233:  *     Arrow information in recordPtr is updated.
        !          1234:  *
        !          1235:  *--------------------------------------------------------------
        !          1236:  */
        !          1237: 
        !          1238:        /* ARGSUSED */
        !          1239: static int
        !          1240: ParseArrowShape(clientData, interp, tkwin, value, recordPtr, offset)
        !          1241:     ClientData clientData;     /* Not used. */
        !          1242:     Tcl_Interp *interp;                /* Used for error reporting. */
        !          1243:     Tk_Window tkwin;           /* Not used. */
        !          1244:     char *value;               /* Textual specification of arrow shape. */
        !          1245:     char *recordPtr;           /* Pointer to item record in which to
        !          1246:                                 * store arrow information. */
        !          1247:     int offset;                        /* Offset of shape information in widget
        !          1248:                                 * record. */
        !          1249: {
        !          1250:     LineItem *linePtr = (LineItem *) recordPtr;
        !          1251:     double a, b, c;
        !          1252:     int argc;
        !          1253:     char **argv = NULL;
        !          1254: 
        !          1255:     if (offset != Tk_Offset(LineItem, arrowShapeA)) {
        !          1256:        panic("ParseArrowShape received bogus offset");
        !          1257:     }
        !          1258: 
        !          1259:     if (Tcl_SplitList(interp, value, &argc, &argv) != TCL_OK) {
        !          1260:        syntaxError:
        !          1261:        Tcl_ResetResult(interp);
        !          1262:        Tcl_AppendResult(interp, "bad arrow shape \"", value,
        !          1263:                "\": must be list with three numbers", (char *) NULL);
        !          1264:        if (argv != NULL) {
        !          1265:            ckfree((char *) argv);
        !          1266:        }
        !          1267:        return TCL_ERROR;
        !          1268:     }
        !          1269:     if (argc != 3) {
        !          1270:        goto syntaxError;
        !          1271:     }
        !          1272:     if ((TkGetCanvasCoord(linePtr->canvasPtr, argv[0], &a) != TCL_OK)
        !          1273:            || (TkGetCanvasCoord(linePtr->canvasPtr, argv[1], &b) != TCL_OK)
        !          1274:            || (TkGetCanvasCoord(linePtr->canvasPtr, argv[2], &c) != TCL_OK)) {
        !          1275:        goto syntaxError;
        !          1276:     }
        !          1277:     linePtr->arrowShapeA = a;
        !          1278:     linePtr->arrowShapeB = b;
        !          1279:     linePtr->arrowShapeC = c;
        !          1280:     ckfree((char *) argv);
        !          1281:     return TCL_OK;
        !          1282: }
        !          1283: 
        !          1284: /*
        !          1285:  *--------------------------------------------------------------
        !          1286:  *
        !          1287:  * PrintArrowShape --
        !          1288:  *
        !          1289:  *     This procedure is a callback invoked by the configuration
        !          1290:  *     code to return a printable value describing an arrow shape.
        !          1291:  *
        !          1292:  * Results:
        !          1293:  *     None.
        !          1294:  *
        !          1295:  * Side effects:
        !          1296:  *     None.
        !          1297:  *
        !          1298:  *--------------------------------------------------------------
        !          1299:  */
        !          1300: 
        !          1301:     /* ARGSUSED */
        !          1302: static char *
        !          1303: PrintArrowShape(clientData, tkwin, recordPtr, offset, freeProcPtr)
        !          1304:     ClientData clientData;     /* Not used. */
        !          1305:     Tk_Window tkwin;           /* Window associated with linePtr's widget. */
        !          1306:     char *recordPtr;           /* Pointer to item record containing current
        !          1307:                                 * shape information. */
        !          1308:     int offset;                        /* Offset of arrow information in record. */
        !          1309:     Tcl_FreeProc **freeProcPtr;        /* Store address of procedure to call to
        !          1310:                                 * free string here. */
        !          1311: {
        !          1312:     LineItem *linePtr = (LineItem *) recordPtr;
        !          1313:     char *buffer;
        !          1314: 
        !          1315:     buffer = ckalloc(120);
        !          1316:     sprintf(buffer, "%.5g %.5g %.5g", linePtr->arrowShapeA,
        !          1317:            linePtr->arrowShapeB, linePtr->arrowShapeC);
        !          1318:     *freeProcPtr = (Tcl_FreeProc *) free;
        !          1319:     return buffer;
        !          1320: }
        !          1321: 
        !          1322: /*
        !          1323:  *--------------------------------------------------------------
        !          1324:  *
        !          1325:  * ConfigureArrows --
        !          1326:  *
        !          1327:  *     If arrowheads have been requested for a line, this
        !          1328:  *     procedure makes arrangements for the arrowheads.
        !          1329:  *
        !          1330:  * Results:
        !          1331:  *     A standard Tcl return value.  If an error occurs, then
        !          1332:  *     an error message is left in canvasPtr->interp->result.
        !          1333:  *
        !          1334:  * Side effects:
        !          1335:  *     Information in linePtr is set up for one or two arrowheads.
        !          1336:  *     the firstArrowPtr and lastArrowPtr polygons are allocated
        !          1337:  *     and initialized, if need be, and the end points of the line
        !          1338:  *     are adjusted so that a thick line doesn't stick out past
        !          1339:  *     the arrowheads.
        !          1340:  *
        !          1341:  *--------------------------------------------------------------
        !          1342:  */
        !          1343: 
        !          1344:        /* ARGSUSED */
        !          1345: static int
        !          1346: ConfigureArrows(canvasPtr, linePtr)
        !          1347:     Tk_Canvas *canvasPtr;              /* Canvas in which arrows will be
        !          1348:                                         * displayed (interp and tkwin
        !          1349:                                         * fields are needed). */
        !          1350:     register LineItem *linePtr;                /* Item to configure for arrows. */
        !          1351: {
        !          1352:     double *poly, *coordPtr;
        !          1353:     double dx, dy, length, sinTheta, cosTheta, temp, shapeC;
        !          1354:     double fracHeight;                 /* Line width as fraction of
        !          1355:                                         * arrowhead width. */
        !          1356:     double backup;                     /* Distance to backup end points
        !          1357:                                         * so the line ends in the middle
        !          1358:                                         * of the arrowhead. */
        !          1359:     double vertX, vertY;               /* Position of arrowhead vertex. */
        !          1360: 
        !          1361:     /*
        !          1362:      * If there's an arrowhead on the first point of the line, compute
        !          1363:      * its polygon and adjust the first point of the line so that the
        !          1364:      * line doesn't stick out past the leading edge of the arrowhead.
        !          1365:      */
        !          1366: 
        !          1367:     shapeC = linePtr->arrowShapeC + linePtr->width/2.0;
        !          1368:     fracHeight = (linePtr->width/2.0)/shapeC;
        !          1369:     backup = fracHeight*linePtr->arrowShapeB
        !          1370:            + linePtr->arrowShapeA*(1.0 - fracHeight)/2.0;
        !          1371:     if (linePtr->arrow != lastUid) {
        !          1372:        poly = linePtr->firstArrowPtr;
        !          1373:        if (poly == NULL) {
        !          1374:            poly = (double *) ckalloc((unsigned)
        !          1375:                    (2*PTS_IN_ARROW*sizeof(double)));
        !          1376:            poly[0] = poly[10] = linePtr->coordPtr[0];
        !          1377:            poly[1] = poly[11] = linePtr->coordPtr[1];
        !          1378:            linePtr->firstArrowPtr = poly;
        !          1379:        }
        !          1380:        dx = poly[0] - linePtr->coordPtr[2];
        !          1381:        dy = poly[1] - linePtr->coordPtr[3];
        !          1382:        length = hypot(dx, dy);
        !          1383:        if (length == 0) {
        !          1384:            sinTheta = cosTheta = 0.0;
        !          1385:        } else {
        !          1386:            sinTheta = dy/length;
        !          1387:            cosTheta = dx/length;
        !          1388:        }
        !          1389:        vertX = poly[0] - linePtr->arrowShapeA*cosTheta;
        !          1390:        vertY = poly[1] - linePtr->arrowShapeA*sinTheta;
        !          1391:        temp = shapeC*sinTheta;
        !          1392:        poly[2] = poly[0] - linePtr->arrowShapeB*cosTheta + temp;
        !          1393:        poly[8] = poly[2] - 2*temp;
        !          1394:        temp = shapeC*cosTheta;
        !          1395:        poly[3] = poly[1] - linePtr->arrowShapeB*sinTheta - temp;
        !          1396:        poly[9] = poly[3] + 2*temp;
        !          1397:        poly[4] = poly[2]*fracHeight + vertX*(1.0-fracHeight);
        !          1398:        poly[5] = poly[3]*fracHeight + vertY*(1.0-fracHeight);
        !          1399:        poly[6] = poly[8]*fracHeight + vertX*(1.0-fracHeight);
        !          1400:        poly[7] = poly[9]*fracHeight + vertY*(1.0-fracHeight);
        !          1401: 
        !          1402:        /*
        !          1403:         * Polygon done.  Now move the first point towards the second so
        !          1404:         * that the corners at the end of the line are inside the
        !          1405:         * arrowhead.
        !          1406:         */
        !          1407: 
        !          1408:        linePtr->coordPtr[0] = poly[0] - backup*cosTheta;
        !          1409:        linePtr->coordPtr[1] = poly[1] - backup*sinTheta;
        !          1410:     }
        !          1411: 
        !          1412:     /*
        !          1413:      * Similar arrowhead calculation for the last point of the line.
        !          1414:      */
        !          1415: 
        !          1416:     if (linePtr->arrow != firstUid) {
        !          1417:        coordPtr = linePtr->coordPtr + 2*(linePtr->numPoints-2);
        !          1418:        poly = linePtr->lastArrowPtr;
        !          1419:        if (poly == NULL) {
        !          1420:            poly = (double *) ckalloc((unsigned)
        !          1421:                    (2*PTS_IN_ARROW*sizeof(double)));
        !          1422:            poly[0] = poly[10] = coordPtr[2];
        !          1423:            poly[1] = poly[11] = coordPtr[3];
        !          1424:            linePtr->lastArrowPtr = poly;
        !          1425:        }
        !          1426:        dx = poly[0] - coordPtr[0];
        !          1427:        dy = poly[1] - coordPtr[1];
        !          1428:        length = hypot(dx, dy);
        !          1429:        if (length == 0) {
        !          1430:            sinTheta = cosTheta = 0.0;
        !          1431:        } else {
        !          1432:            sinTheta = dy/length;
        !          1433:            cosTheta = dx/length;
        !          1434:        }
        !          1435:        vertX = poly[0] - linePtr->arrowShapeA*cosTheta;
        !          1436:        vertY = poly[1] - linePtr->arrowShapeA*sinTheta;
        !          1437:        temp = shapeC*sinTheta;
        !          1438:        poly[2] = poly[0] - linePtr->arrowShapeB*cosTheta + temp;
        !          1439:        poly[8] = poly[2] - 2*temp;
        !          1440:        temp = shapeC*cosTheta;
        !          1441:        poly[3] = poly[1] - linePtr->arrowShapeB*sinTheta - temp;
        !          1442:        poly[9] = poly[3] + 2*temp;
        !          1443:        poly[4] = poly[2]*fracHeight + vertX*(1.0-fracHeight);
        !          1444:        poly[5] = poly[3]*fracHeight + vertY*(1.0-fracHeight);
        !          1445:        poly[6] = poly[8]*fracHeight + vertX*(1.0-fracHeight);
        !          1446:        poly[7] = poly[9]*fracHeight + vertY*(1.0-fracHeight);
        !          1447:        coordPtr[2] = poly[0] - backup*cosTheta;
        !          1448:        coordPtr[3] = poly[1] - backup*sinTheta;
        !          1449:     }
        !          1450: 
        !          1451:     return TCL_OK;
        !          1452: }

unix.superglobalmegacorp.com

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