Annotation of micropolis/src/tk/tkcvarc.c, revision 1.1.1.1

1.1       root        1: /* 
                      2:  * tkCanvArc.c --
                      3:  *
                      4:  *     This file implements arc items for canvas widgets.
                      5:  *
                      6:  * Copyright 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/tkCanvArc.c,v 1.5 92/08/16 15:42:20 ouster Exp $ SPRITE (Berkeley)";
                     18: #endif
                     19: 
                     20: #include <stdio.h>
                     21: #include <math.h>
                     22: #include "tkint.h"
                     23: #include "tkcanvas.h"
                     24: 
                     25: /*
                     26:  * The structure below defines the record for each arc item.
                     27:  */
                     28: 
                     29: typedef struct ArcItem  {
                     30:     Tk_Item header;            /* Generic stuff that's the same for all
                     31:                                 * types.  MUST BE FIRST IN STRUCTURE. */
                     32:     double bbox[4];            /* Coordinates (x1, y1, x2, y2) of bounding
                     33:                                 * box for oval of which arc is a piece. */
                     34:     double start;              /* Angle at which arc begins, in degrees
                     35:                                 * between 0 and 360. */
                     36:     double extent;             /* Extent of arc (angular distance from
                     37:                                 * start to end of arc) in degrees between
                     38:                                 * -360 and 360. */
                     39:     double *outlinePtr;                /* Points to (x,y) coordinates for points
                     40:                                 * that define one or two closed polygons
                     41:                                 * representing the portion of the outline
                     42:                                 * that isn't part of the arc (the V-shape
                     43:                                 * for a pie slice or a line-like segment
                     44:                                 * for a chord).  Malloc'ed. */
                     45:     int numOutlinePoints;      /* Number of points at outlinePtr.  Zero
                     46:                                 * means no space allocated. */
                     47:     int width;                 /* Width of outline (in pixels). */
                     48:     XColor *outlineColor;      /* Color for outline.  NULL means don't
                     49:                                 * draw outline. */
                     50:     XColor *fillColor;         /* Color for filling arc (used for drawing
                     51:                                 * outline too when style is "arc").  NULL
                     52:                                 * means don't fill arc. */
                     53:     Pixmap fillStipple;                /* Stipple bitmap for filling item. */
                     54:     Tk_Uid style;              /* How to draw arc: arc, chord, or pieslice. */
                     55:     GC outlineGC;              /* Graphics context for outline. */
                     56:     GC fillGC;                 /* Graphics context for filling item. */
                     57:     double center1[2];         /* Coordinates of center of arc outline at
                     58:                                 * start (see ComputeArcOutline). */
                     59:     double center2[2];         /* Coordinates of center of arc outline at
                     60:                                 * start+extent (see ComputeArcOutline). */
                     61: } ArcItem;
                     62: 
                     63: /*
                     64:  * The definitions below define the sizes of the polygons used to
                     65:  * display outline information for various styles of arcs:
                     66:  */
                     67: 
                     68: #define CHORD_OUTLINE_PTS      7
                     69: #define PIE_OUTLINE1_PTS       6
                     70: #define PIE_OUTLINE2_PTS       7
                     71: 
                     72: /*
                     73:  * Information used for parsing configuration specs:
                     74:  */
                     75: 
                     76: static Tk_ConfigSpec configSpecs[] = {
                     77:     {TK_CONFIG_DOUBLE, "-extent", (char *) NULL, (char *) NULL,
                     78:        "90", Tk_Offset(ArcItem, extent), TK_CONFIG_DONT_SET_DEFAULT},
                     79:     {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL,
                     80:        (char *) NULL, Tk_Offset(ArcItem, fillColor), TK_CONFIG_NULL_OK},
                     81:     {TK_CONFIG_COLOR, "-outline", (char *) NULL, (char *) NULL,
                     82:        "black", Tk_Offset(ArcItem, outlineColor), TK_CONFIG_NULL_OK},
                     83:     {TK_CONFIG_DOUBLE, "-start", (char *) NULL, (char *) NULL,
                     84:        "0", Tk_Offset(ArcItem, start), TK_CONFIG_DONT_SET_DEFAULT},
                     85:     {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL,
                     86:        (char *) NULL, Tk_Offset(ArcItem, fillStipple), TK_CONFIG_NULL_OK},
                     87:     {TK_CONFIG_UID, "-style", (char *) NULL, (char *) NULL,
                     88:        "pieslice", Tk_Offset(ArcItem, style), TK_CONFIG_DONT_SET_DEFAULT},
                     89:     {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL,
                     90:        (char *) NULL, 0, TK_CONFIG_NULL_OK, &tkCanvasTagsOption},
                     91:     {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL,
                     92:        "1", Tk_Offset(ArcItem, width), TK_CONFIG_DONT_SET_DEFAULT},
                     93:     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
                     94:        (char *) NULL, 0, 0}
                     95: };
                     96: 
                     97: /*
                     98:  * Prototypes for procedures defined in this file:
                     99:  */
                    100: 
                    101: static int             ArcCoords _ANSI_ARGS_((Tk_Canvas *canvasPtr,
                    102:                            Tk_Item *itemPtr, int argc, char **argv));
                    103: static int             AngleInRange _ANSI_ARGS_((double x, double y,
                    104:                            double start, double extent));
                    105: static int             ArcToArea _ANSI_ARGS_((Tk_Canvas *canvasPtr,
                    106:                            Tk_Item *itemPtr, double *rectPtr));
                    107: static double          ArcToPoint _ANSI_ARGS_((Tk_Canvas *canvasPtr,
                    108:                            Tk_Item *itemPtr, double *coordPtr));
                    109: static void            ComputeArcBbox _ANSI_ARGS_((Tk_Canvas *canvasPtr,
                    110:                            ArcItem *arcPtr));
                    111: static void            ComputeArcOutline _ANSI_ARGS_((ArcItem *arcPtr));
                    112: static int             ConfigureArc _ANSI_ARGS_((
                    113:                            Tk_Canvas *canvasPtr, Tk_Item *itemPtr, int argc,
                    114:                            char **argv, int flags));
                    115: static int             CreateArc _ANSI_ARGS_((Tk_Canvas *canvasPtr,
                    116:                            struct Tk_Item *itemPtr, int argc, char **argv));
                    117: static void            DeleteArc _ANSI_ARGS_((Tk_Item *itemPtr));
                    118: static void            DisplayArc _ANSI_ARGS_((Tk_Canvas *canvasPtr,
                    119:                            Tk_Item *itemPtr, Drawable dst));
                    120: static int             HorizLineToArc _ANSI_ARGS_((double x1, double x2,
                    121:                            double y, double rx, double ry,
                    122:                            double start, double extent));
                    123: static void            ScaleArc _ANSI_ARGS_((Tk_Canvas *canvasPtr,
                    124:                            Tk_Item *itemPtr, double originX, double originY,
                    125:                            double scaleX, double scaleY));
                    126: static void            TranslateArc _ANSI_ARGS_((Tk_Canvas *canvasPtr,
                    127:                            Tk_Item *itemPtr, double deltaX, double deltaY));
                    128: static int             VertLineToArc _ANSI_ARGS_((double x, double y1,
                    129:                            double y2, double rx, double ry,
                    130:                            double start, double extent));
                    131: 
                    132: /*
                    133:  * The structures below defines the arc item types by means of procedures
                    134:  * that can be invoked by generic item code.
                    135:  */
                    136: 
                    137: Tk_ItemType TkArcType = {
                    138:     "arc",                             /* name */
                    139:     sizeof(ArcItem),                   /* itemSize */
                    140:     CreateArc,                         /* createProc */
                    141:     configSpecs,                       /* configSpecs */
                    142:     ConfigureArc,                      /* configureProc */
                    143:     ArcCoords,                         /* coordProc */
                    144:     DeleteArc,                         /* deleteProc */
                    145:     DisplayArc,                                /* displayProc */
                    146:     0,                                 /* alwaysRedraw */
                    147:     ArcToPoint,                                /* pointProc */
                    148:     ArcToArea,                         /* areaProc */
                    149:     (Tk_ItemPostscriptProc *) NULL,    /* postscriptProc */
                    150:     ScaleArc,                          /* scaleProc */
                    151:     TranslateArc,                      /* translateProc */
                    152:     (Tk_ItemIndexProc *) NULL,         /* indexProc */
                    153:     (Tk_ItemCursorProc *) NULL,                /* cursorProc */
                    154:     (Tk_ItemSelectionProc *) NULL,     /* selectionProc */
                    155:     (Tk_ItemInsertProc *) NULL,                /* insertProc */
                    156:     (Tk_ItemDCharsProc *) NULL,                /* dTextProc */
                    157:     (Tk_ItemType *) NULL               /* nextPtr */
                    158: };
                    159: 
                    160: #define PI 3.14159265358979323846
                    161: 
                    162: /*
                    163:  * The uid's below comprise the legal values for the "-style"
                    164:  * option for arcs.
                    165:  */
                    166: 
                    167: static Tk_Uid arcUid =  NULL;
                    168: static Tk_Uid chordUid =  NULL;
                    169: static Tk_Uid pieSliceUid = NULL;
                    170: 
                    171: /*
                    172:  *--------------------------------------------------------------
                    173:  *
                    174:  * CreateArc --
                    175:  *
                    176:  *     This procedure is invoked to create a new arc item in
                    177:  *     a canvas.
                    178:  *
                    179:  * Results:
                    180:  *     A standard Tcl return value.  If an error occurred in
                    181:  *     creating the item, then an error message is left in
                    182:  *     canvasPtr->interp->result;  in this case itemPtr is
                    183:  *     left uninitialized, so it can be safely freed by the
                    184:  *     caller.
                    185:  *
                    186:  * Side effects:
                    187:  *     A new arc item is created.
                    188:  *
                    189:  *--------------------------------------------------------------
                    190:  */
                    191: 
                    192: static int
                    193: CreateArc(canvasPtr, itemPtr, argc, argv)
                    194:     register Tk_Canvas *canvasPtr;     /* Canvas to hold new item. */
                    195:     Tk_Item *itemPtr;                  /* Record to hold new item;  header
                    196:                                         * has been initialized by caller. */
                    197:     int argc;                          /* Number of arguments in argv. */
                    198:     char **argv;                       /* Arguments describing arc. */
                    199: {
                    200:     register ArcItem *arcPtr = (ArcItem *) itemPtr;
                    201: 
                    202:     if (argc < 4) {
                    203:        Tcl_AppendResult(canvasPtr->interp, "wrong # args:  should be \"",
                    204:                Tk_PathName(canvasPtr->tkwin), "\" create ",
                    205:                itemPtr->typePtr->name, " x1 y1 x2 y2 ?options?",
                    206:                (char *) NULL);
                    207:        return TCL_ERROR;
                    208:     }
                    209: 
                    210:     /*
                    211:      * Carry out once-only initialization.
                    212:      */
                    213: 
                    214:     if (arcUid == NULL) {
                    215:        arcUid = Tk_GetUid("arc");
                    216:        chordUid = Tk_GetUid("chord");
                    217:        pieSliceUid = Tk_GetUid("pieslice");
                    218:     }
                    219: 
                    220:     /*
                    221:      * Carry out initialization that is needed in order to clean
                    222:      * up after errors during the the remainder of this procedure.
                    223:      */
                    224: 
                    225:     arcPtr->start = 0;
                    226:     arcPtr->extent = 90;
                    227:     arcPtr->outlinePtr = NULL;
                    228:     arcPtr->numOutlinePoints = 0;
                    229:     arcPtr->width = 1;
                    230:     arcPtr->outlineColor = NULL;
                    231:     arcPtr->fillColor = NULL;
                    232:     arcPtr->fillStipple = None;
                    233:     arcPtr->style = pieSliceUid;
                    234:     arcPtr->outlineGC = None;
                    235:     arcPtr->fillGC = None;
                    236: 
                    237:     /*
                    238:      * Process the arguments to fill in the item record.
                    239:      */
                    240: 
                    241:     if ((TkGetCanvasCoord(canvasPtr, argv[0], &arcPtr->bbox[0]) != TCL_OK)
                    242:            || (TkGetCanvasCoord(canvasPtr, argv[1],
                    243:                &arcPtr->bbox[1]) != TCL_OK)
                    244:            || (TkGetCanvasCoord(canvasPtr, argv[2],
                    245:                    &arcPtr->bbox[2]) != TCL_OK)
                    246:            || (TkGetCanvasCoord(canvasPtr, argv[3],
                    247:                    &arcPtr->bbox[3]) != TCL_OK)) {
                    248:        return TCL_ERROR;
                    249:     }
                    250: 
                    251:     if (ConfigureArc(canvasPtr, itemPtr, argc-4, argv+4, 0) != TCL_OK) {
                    252:        DeleteArc(itemPtr);
                    253:        return TCL_ERROR;
                    254:     }
                    255:     return TCL_OK;
                    256: }
                    257: 
                    258: /*
                    259:  *--------------------------------------------------------------
                    260:  *
                    261:  * ArcCoords --
                    262:  *
                    263:  *     This procedure is invoked to process the "coords" widget
                    264:  *     command on arcs.  See the user documentation for details
                    265:  *     on what it does.
                    266:  *
                    267:  * Results:
                    268:  *     Returns TCL_OK or TCL_ERROR, and sets canvasPtr->interp->result.
                    269:  *
                    270:  * Side effects:
                    271:  *     The coordinates for the given item may be changed.
                    272:  *
                    273:  *--------------------------------------------------------------
                    274:  */
                    275: 
                    276: static int
                    277: ArcCoords(canvasPtr, itemPtr, argc, argv)
                    278:     register Tk_Canvas *canvasPtr;     /* Canvas containing item. */
                    279:     Tk_Item *itemPtr;                  /* Item whose coordinates are to be
                    280:                                         * read or modified. */
                    281:     int argc;                          /* Number of coordinates supplied in
                    282:                                         * argv. */
                    283:     char **argv;                       /* Array of coordinates: x1, y1,
                    284:                                         * x2, y2, ... */
                    285: {
                    286:     register ArcItem *arcPtr = (ArcItem *) itemPtr;
                    287:     char buffer[500];
                    288: 
                    289:     if (argc == 0) {
                    290:        sprintf(buffer, "%g %g %g %g", arcPtr->bbox[0],
                    291:                arcPtr->bbox[1], arcPtr->bbox[2],
                    292:                arcPtr->bbox[3]);
                    293:        Tcl_SetResult(canvasPtr->interp, buffer, TCL_VOLATILE);
                    294:     } else if (argc == 4) {
                    295:        if ((TkGetCanvasCoord(canvasPtr, argv[0],
                    296:                    &arcPtr->bbox[0]) != TCL_OK)
                    297:                || (TkGetCanvasCoord(canvasPtr, argv[1],
                    298:                    &arcPtr->bbox[1]) != TCL_OK)
                    299:                || (TkGetCanvasCoord(canvasPtr, argv[2],
                    300:                        &arcPtr->bbox[2]) != TCL_OK)
                    301:                || (TkGetCanvasCoord(canvasPtr, argv[3],
                    302:                        &arcPtr->bbox[3]) != TCL_OK)) {
                    303:            return TCL_ERROR;
                    304:        }
                    305:        ComputeArcBbox(canvasPtr, arcPtr);
                    306:     } else {
                    307:        sprintf(canvasPtr->interp->result,
                    308:                "wrong # coordinates:  expected 0 or 4, got %d",
                    309:                argc);
                    310:        return TCL_ERROR;
                    311:     }
                    312:     return TCL_OK;
                    313: }
                    314: 
                    315: /*
                    316:  *--------------------------------------------------------------
                    317:  *
                    318:  * ConfigureArc --
                    319:  *
                    320:  *     This procedure is invoked to configure various aspects
                    321:  *     of a arc item, such as its outline and fill colors.
                    322:  *
                    323:  * Results:
                    324:  *     A standard Tcl result code.  If an error occurs, then
                    325:  *     an error message is left in canvasPtr->interp->result.
                    326:  *
                    327:  * Side effects:
                    328:  *     Configuration information, such as colors and stipple
                    329:  *     patterns, may be set for itemPtr.
                    330:  *
                    331:  *--------------------------------------------------------------
                    332:  */
                    333: 
                    334: static int
                    335: ConfigureArc(canvasPtr, itemPtr, argc, argv, flags)
                    336:     Tk_Canvas *canvasPtr;      /* Canvas containing itemPtr. */
                    337:     Tk_Item *itemPtr;          /* Arc item to reconfigure. */
                    338:     int argc;                  /* Number of elements in argv.  */
                    339:     char **argv;               /* Arguments describing things to configure. */
                    340:     int flags;                 /* Flags to pass to Tk_ConfigureWidget. */
                    341: {
                    342:     register ArcItem *arcPtr = (ArcItem *) itemPtr;
                    343:     XGCValues gcValues;
                    344:     GC newGC;
                    345:     unsigned long mask;
                    346:     int i;
                    347: 
                    348:     if (Tk_ConfigureWidget(canvasPtr->interp, canvasPtr->tkwin,
                    349:            configSpecs, argc, argv, (char *) arcPtr, flags) != TCL_OK) {
                    350:        return TCL_ERROR;
                    351:     }
                    352: 
                    353:     /*
                    354:      * A few of the options require additional processing, such as
                    355:      * style and graphics contexts.
                    356:      */
                    357: 
                    358:     i = arcPtr->start/360.0;
                    359:     arcPtr->start -= i*360.0;
                    360:     if (arcPtr->start < 0) {
                    361:        arcPtr->start += 360.0;
                    362:     }
                    363:     i = arcPtr->extent/360.0;
                    364:     arcPtr->extent -= i*360.0;
                    365: 
                    366:     if ((arcPtr->style != arcUid) && (arcPtr->style != chordUid)
                    367:            && (arcPtr->style != pieSliceUid)) {
                    368:        Tcl_AppendResult(canvasPtr->interp, "bad -style option \"",
                    369:                arcPtr->style, "\": must be arc, chord, or pieslice",
                    370:                (char *) NULL);
                    371:        arcPtr->style = pieSliceUid;
                    372:        return TCL_ERROR;
                    373:     }
                    374: 
                    375:     if (arcPtr->width < 0) {
                    376:        arcPtr->width = 1;
                    377:     }
                    378:     if (arcPtr->style == arcUid) {
                    379:        if (arcPtr->fillColor == NULL) {
                    380:            newGC = None;
                    381:        } else {
                    382:            gcValues.foreground = arcPtr->fillColor->pixel;
                    383:            gcValues.cap_style = CapButt;
                    384:            gcValues.line_width = arcPtr->width;
                    385:            mask = GCForeground|GCCapStyle|GCLineWidth;
                    386:            if (arcPtr->fillStipple != None) {
                    387:                gcValues.stipple = arcPtr->fillStipple;
                    388:                gcValues.fill_style = FillStippled;
                    389:                mask |= GCStipple|GCFillStyle;
                    390:            }
                    391:            newGC = Tk_GetGC(canvasPtr->tkwin, mask, &gcValues);
                    392:        }
                    393:     } else if (arcPtr->outlineColor == NULL) {
                    394:        newGC = None;
                    395:     } else {
                    396:        gcValues.foreground = arcPtr->outlineColor->pixel;
                    397:        gcValues.cap_style = CapButt;
                    398:        gcValues.line_width = arcPtr->width;
                    399:        mask = GCForeground|GCCapStyle|GCLineWidth;
                    400:        newGC = Tk_GetGC(canvasPtr->tkwin, mask, &gcValues);
                    401:     }
                    402:     if (arcPtr->outlineGC != None) {
                    403:        Tk_FreeGC(arcPtr->outlineGC);
                    404:     }
                    405:     arcPtr->outlineGC = newGC;
                    406: 
                    407:     if ((arcPtr->fillColor == NULL) || (arcPtr->style == arcUid)) {
                    408:        newGC = None;
                    409:     } else {
                    410:        gcValues.foreground = arcPtr->fillColor->pixel;
                    411:        if (arcPtr->style == chordUid) {
                    412:            gcValues.arc_mode = ArcChord;
                    413:        } else {
                    414:            gcValues.arc_mode = ArcPieSlice;
                    415:        }
                    416:        mask = GCForeground|GCArcMode;
                    417:        if (arcPtr->fillStipple != None) {
                    418:            gcValues.stipple = arcPtr->fillStipple;
                    419:            gcValues.fill_style = FillStippled;
                    420:            mask |= GCStipple|GCFillStyle;
                    421:        }
                    422:        newGC = Tk_GetGC(canvasPtr->tkwin, mask, &gcValues);
                    423:     }
                    424:     if (arcPtr->fillGC != None) {
                    425:        Tk_FreeGC(arcPtr->fillGC);
                    426:     }
                    427:     arcPtr->fillGC = newGC;
                    428: 
                    429:     ComputeArcBbox(canvasPtr, arcPtr);
                    430:     return TCL_OK;
                    431: }
                    432: 
                    433: /*
                    434:  *--------------------------------------------------------------
                    435:  *
                    436:  * DeleteArc --
                    437:  *
                    438:  *     This procedure is called to clean up the data structure
                    439:  *     associated with a arc item.
                    440:  *
                    441:  * Results:
                    442:  *     None.
                    443:  *
                    444:  * Side effects:
                    445:  *     Resources associated with itemPtr are released.
                    446:  *
                    447:  *--------------------------------------------------------------
                    448:  */
                    449: 
                    450: static void
                    451: DeleteArc(itemPtr)
                    452:     Tk_Item *itemPtr;                  /* Item that is being deleted. */
                    453: {
                    454:     register ArcItem *arcPtr = (ArcItem *) itemPtr;
                    455: 
                    456:     if (arcPtr->numOutlinePoints != 0) {
                    457:        ckfree((char *) arcPtr->outlinePtr);
                    458:     }
                    459:     if (arcPtr->outlineColor != NULL) {
                    460:        Tk_FreeColor(arcPtr->outlineColor);
                    461:     }
                    462:     if (arcPtr->fillColor != NULL) {
                    463:        Tk_FreeColor(arcPtr->fillColor);
                    464:     }
                    465:     if (arcPtr->fillStipple != None) {
                    466:        Tk_FreeBitmap(arcPtr->fillStipple);
                    467:     }
                    468:     if (arcPtr->outlineGC != None) {
                    469:        Tk_FreeGC(arcPtr->outlineGC);
                    470:     }
                    471:     if (arcPtr->fillGC != None) {
                    472:        Tk_FreeGC(arcPtr->fillGC);
                    473:     }
                    474: }
                    475: 
                    476: /*
                    477:  *--------------------------------------------------------------
                    478:  *
                    479:  * ComputeArcBbox --
                    480:  *
                    481:  *     This procedure is invoked to compute the bounding box of
                    482:  *     all the pixels that may be drawn as part of an arc.
                    483:  *
                    484:  * Results:
                    485:  *     None.
                    486:  *
                    487:  * Side effects:
                    488:  *     The fields x1, y1, x2, and y2 are updated in the header
                    489:  *     for itemPtr.
                    490:  *
                    491:  *--------------------------------------------------------------
                    492:  */
                    493: 
                    494:        /* ARGSUSED */
                    495: static void
                    496: ComputeArcBbox(canvasPtr, arcPtr)
                    497:     register Tk_Canvas *canvasPtr;     /* Canvas that contains item. */
                    498:     register ArcItem *arcPtr;          /* Item whose bbox is to be
                    499:                                         * recomputed. */
                    500: {
                    501:     double tmp, center[2], point[2];
                    502: 
                    503:     /*
                    504:      * Make sure that the first coordinates are the lowest ones.
                    505:      */
                    506: 
                    507:     if (arcPtr->bbox[1] > arcPtr->bbox[3]) {
                    508:        double tmp;
                    509:        tmp = arcPtr->bbox[3];
                    510:        arcPtr->bbox[3] = arcPtr->bbox[1];
                    511:        arcPtr->bbox[1] = tmp;
                    512:     }
                    513:     if (arcPtr->bbox[0] > arcPtr->bbox[2]) {
                    514:        double tmp;
                    515:        tmp = arcPtr->bbox[2];
                    516:        arcPtr->bbox[2] = arcPtr->bbox[0];
                    517:        arcPtr->bbox[0] = tmp;
                    518:     }
                    519: 
                    520:     ComputeArcOutline(arcPtr);
                    521: 
                    522:     /*
                    523:      * To compute the bounding box, start with the the bbox formed
                    524:      * by the two endpoints of the arc.  Then add in the center of
                    525:      * the arc's oval (if relevant) and the 3-o'clock, 6-o'clock,
                    526:      * 9-o'clock, and 12-o'clock positions, if they are relevant.
                    527:      */
                    528: 
                    529:     arcPtr->header.x1 = arcPtr->header.x2 = arcPtr->center1[0];
                    530:     arcPtr->header.y1 = arcPtr->header.y2 = arcPtr->center1[1];
                    531:     TkIncludePoint(canvasPtr, (Tk_Item *) arcPtr, arcPtr->center2);
                    532:     center[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2;
                    533:     center[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2;
                    534:     if (arcPtr->style != arcUid) {
                    535:        TkIncludePoint(canvasPtr, (Tk_Item *) arcPtr, center);
                    536:     }
                    537: 
                    538:     tmp = -arcPtr->start;
                    539:     if (tmp < 0) {
                    540:        tmp += 360.0;
                    541:     }
                    542:     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
                    543:        point[0] = arcPtr->bbox[2];
                    544:        point[1] = center[1];
                    545:        TkIncludePoint(canvasPtr, (Tk_Item *) arcPtr, point);
                    546:     }
                    547:     tmp = 90.0 - arcPtr->start;
                    548:     if (tmp < 0) {
                    549:        tmp += 360.0;
                    550:     }
                    551:     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
                    552:        point[0] = center[0];
                    553:        point[1] = arcPtr->bbox[1];
                    554:        TkIncludePoint(canvasPtr, (Tk_Item *) arcPtr, point);
                    555:     }
                    556:     tmp = 180.0 - arcPtr->start;
                    557:     if (tmp < 0) {
                    558:        tmp += 360.0;
                    559:     }
                    560:     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
                    561:        point[0] = arcPtr->bbox[0];
                    562:        point[1] = center[1];
                    563:        TkIncludePoint(canvasPtr, (Tk_Item *) arcPtr, point);
                    564:     }
                    565:     tmp = 270.0 - arcPtr->start;
                    566:     if (tmp < 0) {
                    567:        tmp += 360.0;
                    568:     }
                    569:     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
                    570:        point[0] = center[0];
                    571:        point[1] = arcPtr->bbox[3];
                    572:        TkIncludePoint(canvasPtr, (Tk_Item *) arcPtr, point);
                    573:     }
                    574: 
                    575:     /*
                    576:      * Lastly, expand by the width of the arc (if the arc's outline is
                    577:      * being drawn) and add one extra pixel just for safety.
                    578:      */
                    579: 
                    580:     if (arcPtr->outlineColor == NULL) {
                    581:        tmp = 1;
                    582:     } else {
                    583:        tmp = (arcPtr->width + 1)/2 + 1;
                    584:     }
                    585:     arcPtr->header.x1 -= tmp;
                    586:     arcPtr->header.y1 -= tmp;
                    587:     arcPtr->header.x2 += tmp;
                    588:     arcPtr->header.y2 += tmp;
                    589: }
                    590: 
                    591: /*
                    592:  *--------------------------------------------------------------
                    593:  *
                    594:  * DisplayArc --
                    595:  *
                    596:  *     This procedure is invoked to draw an arc item in a given
                    597:  *     drawable.
                    598:  *
                    599:  * Results:
                    600:  *     None.
                    601:  *
                    602:  * Side effects:
                    603:  *     ItemPtr is drawn in drawable using the transformation
                    604:  *     information in canvasPtr.
                    605:  *
                    606:  *--------------------------------------------------------------
                    607:  */
                    608: 
                    609: static void
                    610: DisplayArc(canvasPtr, itemPtr, drawable)
                    611:     register Tk_Canvas *canvasPtr;     /* Canvas that contains item. */
                    612:     Tk_Item *itemPtr;                  /* Item to be displayed. */
                    613:     Drawable drawable;                 /* Pixmap or window in which to draw
                    614:                                         * item. */
                    615: {
                    616:     register ArcItem *arcPtr = (ArcItem *) itemPtr;
                    617:     Display *display = Tk_Display(canvasPtr->tkwin);
                    618:     int x1, y1, x2, y2, start, extent;
                    619: 
                    620:     /*
                    621:      * Compute the screen coordinates of the bounding box for the item,
                    622:      * plus integer values for the angles.
                    623:      */
                    624: 
                    625:     x1 = SCREEN_X(canvasPtr, arcPtr->bbox[0]);
                    626:     y1 = SCREEN_Y(canvasPtr, arcPtr->bbox[1]);
                    627:     x2 = SCREEN_X(canvasPtr, arcPtr->bbox[2]);
                    628:     y2 = SCREEN_Y(canvasPtr, arcPtr->bbox[3]);
                    629:     if (x2 <= x1) {
                    630:        x2 = x1+1;
                    631:     }
                    632:     if (y2 <= y1) {
                    633:        y2 = y1+1;
                    634:     }
                    635:     start = (64*arcPtr->start) + 0.5;
                    636:     extent = (64*arcPtr->extent) + 0.5;
                    637: 
                    638:     /*
                    639:      * Display filled arc first (if wanted), then outline.
                    640:      */
                    641: 
                    642:     if (arcPtr->fillGC != None) {
                    643:        XFillArc(display, drawable, arcPtr->fillGC, x1, y1, (x2-x1),
                    644:                (y2-y1), start, extent);
                    645:     }
                    646:     if (arcPtr->outlineGC != None) {
                    647:        XDrawArc(display, drawable, arcPtr->outlineGC, x1, y1, (x2-x1),
                    648:                (y2-y1), start, extent);
                    649: 
                    650:        /*
                    651:         * If the outline width is very thin, don't use polygons to draw
                    652:         * the linear parts of the outline (this often results in nothing
                    653:         * being displayed); just draw lines instead.
                    654:         */
                    655: 
                    656:        if (arcPtr->width <= 2) {
                    657:            x1 = SCREEN_X(canvasPtr, arcPtr->center1[0]);
                    658:            y1 = SCREEN_Y(canvasPtr, arcPtr->center1[1]);
                    659:            x2 = SCREEN_X(canvasPtr, arcPtr->center2[0]);
                    660:            y2 = SCREEN_Y(canvasPtr, arcPtr->center2[1]);
                    661: 
                    662:            if (arcPtr->style == chordUid) {
                    663:                XDrawLine(display, drawable, arcPtr->outlineGC,
                    664:                        x1, y1, x2, y2);
                    665:            } else if (arcPtr->style == pieSliceUid) {
                    666:                int cx, cy;
                    667:     
                    668:                cx = SCREEN_X(canvasPtr, (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0);
                    669:                cy = SCREEN_Y(canvasPtr, (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0);
                    670:                XDrawLine(display, drawable, arcPtr->outlineGC,
                    671:                        cx, cy, x1, y1);
                    672:                XDrawLine(display, drawable, arcPtr->outlineGC,
                    673:                        cx, cy, x2, y2);
                    674:            }
                    675:        } else {
                    676:            if (arcPtr->style == chordUid) {
                    677:                TkFillPolygon(canvasPtr, arcPtr->outlinePtr,
                    678:                        CHORD_OUTLINE_PTS, drawable, arcPtr->outlineGC);
                    679:            } else if (arcPtr->style == pieSliceUid) {
                    680:                TkFillPolygon(canvasPtr, arcPtr->outlinePtr,
                    681:                        PIE_OUTLINE1_PTS, drawable, arcPtr->outlineGC);
                    682:                TkFillPolygon(canvasPtr,
                    683:                        arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS,
                    684:                        PIE_OUTLINE2_PTS, drawable, arcPtr->outlineGC);
                    685:            }
                    686:        }
                    687:     }
                    688: }
                    689: 
                    690: /*
                    691:  *--------------------------------------------------------------
                    692:  *
                    693:  * ArcToPoint --
                    694:  *
                    695:  *     Computes the distance from a given point to a given
                    696:  *     arc, in canvas units.
                    697:  *
                    698:  * Results:
                    699:  *     The return value is 0 if the point whose x and y coordinates
                    700:  *     are coordPtr[0] and coordPtr[1] is inside the arc.  If the
                    701:  *     point isn't inside the arc then the return value is the
                    702:  *     distance from the point to the arc.  If itemPtr is filled,
                    703:  *     then anywhere in the interior is considered "inside"; if
                    704:  *     itemPtr isn't filled, then "inside" means only the area
                    705:  *     occupied by the outline.
                    706:  *
                    707:  * Side effects:
                    708:  *     None.
                    709:  *
                    710:  *--------------------------------------------------------------
                    711:  */
                    712: 
                    713:        /* ARGSUSED */
                    714: static double
                    715: ArcToPoint(canvasPtr, itemPtr, pointPtr)
                    716:     Tk_Canvas *canvasPtr;      /* Canvas containing item. */
                    717:     Tk_Item *itemPtr;          /* Item to check against point. */
                    718:     double *pointPtr;          /* Pointer to x and y coordinates. */
                    719: {
                    720:     register ArcItem *arcPtr = (ArcItem *) itemPtr;
                    721:     double vertex[2], pointAngle, diff, dist, newDist;
                    722:     double poly[8], polyDist, width;
                    723:     int filled, angleInRange;
                    724: 
                    725:     if ((arcPtr->fillGC != None) || (arcPtr->outlineGC == None)) {
                    726:        filled = 1;
                    727:     } else {
                    728:        filled = 0;
                    729:     }
                    730: 
                    731:     /*
                    732:      * See if the point is within the angular range of the arc.
                    733:      * Remember, X angles are backwards from the way we'd normally
                    734:      * think of them.  Also, compensate for any eccentricity of
                    735:      * the oval.
                    736:      */
                    737: 
                    738:     vertex[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0;
                    739:     vertex[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0;
                    740:     pointAngle = -atan2((pointPtr[1] - vertex[1])
                    741:            /(arcPtr->bbox[3] - arcPtr->bbox[1]),
                    742:            (pointPtr[0] - vertex[0])/(arcPtr->bbox[2] - arcPtr->bbox[0]));
                    743:     pointAngle *= 180/PI;
                    744:     diff = pointAngle - arcPtr->start;
                    745:     diff -= ((int) (diff/360.0) * 360.0);
                    746:     if (diff < 0) {
                    747:        diff += 360.0;
                    748:     }
                    749:     angleInRange = (diff <= arcPtr->extent) ||
                    750:            ((arcPtr->extent < 0) && ((diff - 360.0) >= arcPtr->extent));
                    751: 
                    752:     /*
                    753:      * Now perform different tests depending on what kind of arc
                    754:      * we're dealing with.
                    755:      */
                    756: 
                    757:     if (arcPtr->style == arcUid) {
                    758:        if (angleInRange) {
                    759:            return TkOvalToPoint(arcPtr->bbox, (double) arcPtr->width,
                    760:                    0, pointPtr);
                    761:        }
                    762:        dist = hypot(pointPtr[0] - arcPtr->center1[0],
                    763:                pointPtr[1] - arcPtr->center1[1]);
                    764:        newDist = hypot(pointPtr[0] - arcPtr->center2[0],
                    765:                pointPtr[1] - arcPtr->center2[1]);
                    766:        if (newDist < dist) {
                    767:            return newDist;
                    768:        }
                    769:        return dist;
                    770:     }
                    771: 
                    772:     if ((arcPtr->fillGC != None) || (arcPtr->outlineGC == None)) {
                    773:        filled = 1;
                    774:     } else {
                    775:        filled = 0;
                    776:     }
                    777:     if (arcPtr->outlineGC == None) {
                    778:        width = 0.0;
                    779:     } else {
                    780:        width = arcPtr->width;
                    781:     }
                    782: 
                    783:     if (arcPtr->style == pieSliceUid) {
                    784:        if (width > 1.0) {
                    785:            dist = TkPolygonToPoint(arcPtr->outlinePtr, PIE_OUTLINE1_PTS,
                    786:                    pointPtr);
                    787:            newDist = TkPolygonToPoint(arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS,
                    788:                        PIE_OUTLINE2_PTS, pointPtr);
                    789:        } else {
                    790:            dist = TkLineToPoint(vertex, arcPtr->center1, pointPtr);
                    791:            newDist = TkLineToPoint(vertex, arcPtr->center2, pointPtr);
                    792:        }
                    793:        if (newDist < dist) {
                    794:            dist = newDist;
                    795:        }
                    796:        if (angleInRange) {
                    797:            newDist = TkOvalToPoint(arcPtr->bbox, width, filled, pointPtr);
                    798:            if (newDist < dist) {
                    799:                dist = newDist;
                    800:            }
                    801:        }
                    802:        return dist;
                    803:     }
                    804: 
                    805:     /*
                    806:      * This is a chord-style arc.  We have to deal specially with the
                    807:      * triangular piece that represents the difference between a
                    808:      * chord-style arc and a pie-slice arc (for small angles this piece
                    809:      * is excluded here where it would be included for pie slices;
                    810:      * for large angles the piece is included here but would be
                    811:      * excluded for pie slices).
                    812:      */
                    813: 
                    814:     if (width > 1.0) {
                    815:        dist = TkPolygonToPoint(arcPtr->outlinePtr, CHORD_OUTLINE_PTS,
                    816:                    pointPtr);
                    817:     } else {
                    818:        dist = TkLineToPoint(arcPtr->center1, arcPtr->center2, pointPtr);
                    819:     }
                    820:     poly[0] = poly[6] = vertex[0];
                    821:     poly[1] = poly[7] = vertex[1];
                    822:     poly[2] = arcPtr->center1[0];
                    823:     poly[3] = arcPtr->center1[1];
                    824:     poly[4] = arcPtr->center2[0];
                    825:     poly[5] = arcPtr->center2[1];
                    826:     polyDist = TkPolygonToPoint(poly, 4, pointPtr);
                    827:     if (angleInRange) {
                    828:        if ((arcPtr->extent < -180.0) || (arcPtr->extent > 180.0)
                    829:                || (polyDist > 0.0)) {
                    830:            newDist = TkOvalToPoint(arcPtr->bbox, width, filled, pointPtr);
                    831:            if (newDist < dist) {
                    832:                dist = newDist;
                    833:            }
                    834:        }
                    835:     } else {
                    836:        if ((arcPtr->extent < -180.0) || (arcPtr->extent > 180.0)) {
                    837:            if (filled && (polyDist < dist)) {
                    838:                dist = polyDist;
                    839:            }
                    840:        }
                    841:     }
                    842:     return dist;
                    843: }
                    844: 
                    845: /*
                    846:  *--------------------------------------------------------------
                    847:  *
                    848:  * ArcToArea --
                    849:  *
                    850:  *     This procedure is called to determine whether an item
                    851:  *     lies entirely inside, entirely outside, or overlapping
                    852:  *     a given area.
                    853:  *
                    854:  * Results:
                    855:  *     -1 is returned if the item is entirely outside the area
                    856:  *     given by rectPtr, 0 if it overlaps, and 1 if it is entirely
                    857:  *     inside the given area.
                    858:  *
                    859:  * Side effects:
                    860:  *     None.
                    861:  *
                    862:  *--------------------------------------------------------------
                    863:  */
                    864: 
                    865:        /* ARGSUSED */
                    866: static int
                    867: ArcToArea(canvasPtr, itemPtr, rectPtr)
                    868:     Tk_Canvas *canvasPtr;      /* Canvas containing item. */
                    869:     Tk_Item *itemPtr;          /* Item to check against arc. */
                    870:     double *rectPtr;           /* Pointer to array of four coordinates
                    871:                                 * (x1, y1, x2, y2) describing rectangular
                    872:                                 * area.  */
                    873: {
                    874:     register ArcItem *arcPtr = (ArcItem *) itemPtr;
                    875:     double rx, ry;             /* Radii for transformed oval:  these define
                    876:                                 * an oval centered at the origin. */
                    877:     double tRect[4];           /* Transformed version of x1, y1, x2, y2,
                    878:                                 * for coord. system where arc is centered
                    879:                                 * on the origin. */
                    880:     double center[2], width, angle, tmp;
                    881:     double points[20], *pointPtr;
                    882:     int numPoints, filled;
                    883:     int inside;                        /* Non-zero means every test so far suggests
                    884:                                 * that arc is inside rectangle.  0 means
                    885:                                 * every test so far shows arc to be outside
                    886:                                 * of rectangle. */
                    887:     int newInside;
                    888: 
                    889:     if ((arcPtr->fillGC != None) || (arcPtr->outlineGC == None)) {
                    890:        filled = 1;
                    891:     } else {
                    892:        filled = 0;
                    893:     }
                    894:     if (arcPtr->outlineGC == None) {
                    895:        width = 0.0;
                    896:     } else {
                    897:        width = arcPtr->width;
                    898:     }
                    899: 
                    900:     /*
                    901:      * Transform both the arc and the rectangle so that the arc's oval
                    902:      * is centered on the origin.
                    903:      */
                    904: 
                    905:     center[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0;
                    906:     center[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0;
                    907:     tRect[0] = rectPtr[0] - center[0];
                    908:     tRect[1] = rectPtr[1] - center[1];
                    909:     tRect[2] = rectPtr[2] - center[0];
                    910:     tRect[3] = rectPtr[3] - center[1];
                    911:     rx = arcPtr->bbox[2] - center[0] + width/2.0;
                    912:     ry = arcPtr->bbox[3] - center[1] + width/2.0;
                    913: 
                    914:     /*
                    915:      * Find the extreme points of the arc and see whether these are all
                    916:      * inside the rectangle (in which case we're done), partly in and
                    917:      * partly out (in which case we're done), or all outside (in which
                    918:      * case we have more work to do).  The extreme points include the
                    919:      * following, which are checked in order:
                    920:      *
                    921:      * 1. The outside points of the arc, corresponding to start and
                    922:      *   extent.
                    923:      * 2. The center of the arc (but only in pie-slice mode).
                    924:      * 3. The 12, 3, 6, and 9-o'clock positions (but only if the arc
                    925:      *    includes those angles).
                    926:      */
                    927: 
                    928:     pointPtr = points;
                    929:     numPoints = 0;
                    930:     angle = -arcPtr->start*(PI/180.0);
                    931:     pointPtr[0] = rx*cos(angle);
                    932:     pointPtr[1] = ry*sin(angle);
                    933:     angle += -arcPtr->extent*(PI/180.0);
                    934:     pointPtr[2] = rx*cos(angle);
                    935:     pointPtr[3] = ry*sin(angle);
                    936:     numPoints = 2;
                    937:     pointPtr += 4;
                    938: 
                    939:     if ((arcPtr->style == pieSliceUid) && (arcPtr->extent < 180.0)) {
                    940:        pointPtr[0] = 0.0;
                    941:        pointPtr[1] = 0.0;
                    942:        numPoints++;
                    943:        pointPtr += 2;
                    944:     }
                    945: 
                    946:     tmp = -arcPtr->start;
                    947:     if (tmp < 0) {
                    948:        tmp += 360.0;
                    949:     }
                    950:     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
                    951:        pointPtr[0] = rx;
                    952:        pointPtr[1] = 0.0;
                    953:        numPoints++;
                    954:        pointPtr += 2;
                    955:     }
                    956:     tmp = 90.0 - arcPtr->start;
                    957:     if (tmp < 0) {
                    958:        tmp += 360.0;
                    959:     }
                    960:     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
                    961:        pointPtr[0] = 0.0;
                    962:        pointPtr[1] = -ry;
                    963:        numPoints++;
                    964:        pointPtr += 2;
                    965:     }
                    966:     tmp = 180.0 - arcPtr->start;
                    967:     if (tmp < 0) {
                    968:        tmp += 360.0;
                    969:     }
                    970:     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
                    971:        pointPtr[0] = -rx;
                    972:        pointPtr[1] = 0.0;
                    973:        numPoints++;
                    974:        pointPtr += 2;
                    975:     }
                    976:     tmp = 270.0 - arcPtr->start;
                    977:     if (tmp < 0) {
                    978:        tmp += 360.0;
                    979:     }
                    980:     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
                    981:        pointPtr[0] = 0.0;
                    982:        pointPtr[1] = ry;
                    983:        numPoints++;
                    984:        pointPtr += 2;
                    985:     }
                    986: 
                    987:     /*
                    988:      * Now that we've located the extreme points, loop through them all
                    989:      * to see which are inside the rectangle.
                    990:      */
                    991: 
                    992:     inside = (points[0] > tRect[0]) && (points[0] < tRect[2])
                    993:            && (points[1] > tRect[1]) && (points[1] < tRect[3]);
                    994:     for (pointPtr = points+2; numPoints > 1; pointPtr += 2, numPoints--) {
                    995:        newInside = (pointPtr[0] > tRect[0]) && (pointPtr[0] < tRect[2])
                    996:                && (pointPtr[1] > tRect[1]) && (pointPtr[1] < tRect[3]);
                    997:        if (newInside != inside) {
                    998:            return 0;
                    999:        }
                   1000:     }
                   1001: 
                   1002:     if (inside) {
                   1003:        return 1;
                   1004:     }
                   1005: 
                   1006:     /*
                   1007:      * So far, oval appears to be outside rectangle, but can't yet tell
                   1008:      * for sure.  Next, test each of the four sides of the rectangle
                   1009:      * against the bounding region for the arc.  If any intersections
                   1010:      * are found, then return "overlapping".  First, test against the
                   1011:      * polygon(s) forming the sides of a chord or pie-slice.
                   1012:      */
                   1013: 
                   1014:     if (arcPtr->style == pieSliceUid) {
                   1015:        if (width >= 1.0) {
                   1016:            if (TkPolygonToArea(arcPtr->outlinePtr, PIE_OUTLINE1_PTS,
                   1017:                    rectPtr) != -1)  {
                   1018:                return 0;
                   1019:            }
                   1020:            if (TkPolygonToArea(arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS,
                   1021:                    PIE_OUTLINE2_PTS, rectPtr) != -1) {
                   1022:                return 0;
                   1023:            }
                   1024:        } else {
                   1025:            if ((TkLineToArea(center, arcPtr->center1, rectPtr) != -1) ||
                   1026:                    (TkLineToArea(center, arcPtr->center2, rectPtr) != -1)) {
                   1027:                return 0;
                   1028:            }
                   1029:        }
                   1030:     } else if (arcPtr->style == chordUid) {
                   1031:        if (width >= 1.0) {
                   1032:            if (TkPolygonToArea(arcPtr->outlinePtr, CHORD_OUTLINE_PTS,
                   1033:                    rectPtr) != -1) {
                   1034:                return 0;
                   1035:            }
                   1036:        } else {
                   1037:            if (TkLineToArea(arcPtr->center1, arcPtr->center2,
                   1038:                    rectPtr) != -1) {
                   1039:                return 0;
                   1040:            }
                   1041:        }
                   1042:     }
                   1043: 
                   1044:     /*
                   1045:      * Next check for overlap between each of the four sides and the
                   1046:      * outer perimiter of the arc.  If the arc isn't filled, then also
                   1047:      * check the inner perimeter of the arc.
                   1048:      */
                   1049: 
                   1050:     if (HorizLineToArc(tRect[0], tRect[2], tRect[1], rx, ry, arcPtr->start,
                   1051:                arcPtr->extent)
                   1052:            || HorizLineToArc(tRect[0], tRect[2], tRect[3], rx, ry,
                   1053:                arcPtr->start, arcPtr->extent)
                   1054:            || VertLineToArc(tRect[0], tRect[1], tRect[3], rx, ry,
                   1055:                arcPtr->start, arcPtr->extent)
                   1056:            || VertLineToArc(tRect[2], tRect[1], tRect[3], rx, ry,
                   1057:                arcPtr->start, arcPtr->extent)) {
                   1058:        return 0;
                   1059:     }
                   1060:     if ((width > 1.0) && !filled) {
                   1061:        rx -= width;
                   1062:        ry -= width;
                   1063:        if (HorizLineToArc(tRect[0], tRect[2], tRect[1], rx, ry, arcPtr->start,
                   1064:                    arcPtr->extent)
                   1065:                || HorizLineToArc(tRect[0], tRect[2], tRect[3], rx, ry,
                   1066:                    arcPtr->start, arcPtr->extent)
                   1067:                || VertLineToArc(tRect[0], tRect[1], tRect[3], rx, ry,
                   1068:                    arcPtr->start, arcPtr->extent)
                   1069:                || VertLineToArc(tRect[2], tRect[1], tRect[3], rx, ry,
                   1070:                    arcPtr->start, arcPtr->extent)) {
                   1071:            return 0;
                   1072:        }
                   1073:     }
                   1074: 
                   1075:     /*
                   1076:      * The arc still appears to be totally disjoint from the rectangle,
                   1077:      * but it's also possible that the rectangle is totally inside the arc.
                   1078:      * Do one last check, which is to check one point of the rectangle
                   1079:      * to see if it's inside the arc.  If it is, we've got overlap.  If
                   1080:      * it isn't, the arc's really outside the rectangle.
                   1081:      */
                   1082: 
                   1083:     if (ArcToPoint(canvasPtr, itemPtr, rectPtr) == 0.0) {
                   1084:        return 0;
                   1085:     }
                   1086:     return -1;
                   1087: }
                   1088: 
                   1089: /*
                   1090:  *--------------------------------------------------------------
                   1091:  *
                   1092:  * ScaleArc --
                   1093:  *
                   1094:  *     This procedure is invoked to rescale an arc item.
                   1095:  *
                   1096:  * Results:
                   1097:  *     None.
                   1098:  *
                   1099:  * Side effects:
                   1100:  *     The arc referred to by itemPtr is rescaled so that the
                   1101:  *     following transformation is applied to all point
                   1102:  *     coordinates:
                   1103:  *             x' = originX + scaleX*(x-originX)
                   1104:  *             y' = originY + scaleY*(y-originY)
                   1105:  *
                   1106:  *--------------------------------------------------------------
                   1107:  */
                   1108: 
                   1109: static void
                   1110: ScaleArc(canvasPtr, itemPtr, originX, originY, scaleX, scaleY)
                   1111:     Tk_Canvas *canvasPtr;              /* Canvas containing arc. */
                   1112:     Tk_Item *itemPtr;                  /* Arc to be scaled. */
                   1113:     double originX, originY;           /* Origin about which to scale rect. */
                   1114:     double scaleX;                     /* Amount to scale in X direction. */
                   1115:     double scaleY;                     /* Amount to scale in Y direction. */
                   1116: {
                   1117:     register ArcItem *arcPtr = (ArcItem *) itemPtr;
                   1118: 
                   1119:     arcPtr->bbox[0] = originX + scaleX*(arcPtr->bbox[0] - originX);
                   1120:     arcPtr->bbox[1] = originY + scaleY*(arcPtr->bbox[1] - originY);
                   1121:     arcPtr->bbox[2] = originX + scaleX*(arcPtr->bbox[2] - originX);
                   1122:     arcPtr->bbox[3] = originY + scaleY*(arcPtr->bbox[3] - originY);
                   1123:     ComputeArcBbox(canvasPtr, arcPtr);
                   1124: }
                   1125: 
                   1126: /*
                   1127:  *--------------------------------------------------------------
                   1128:  *
                   1129:  * TranslateArc --
                   1130:  *
                   1131:  *     This procedure is called to move an arc by a given amount.
                   1132:  *
                   1133:  * Results:
                   1134:  *     None.
                   1135:  *
                   1136:  * Side effects:
                   1137:  *     The position of the arc is offset by (xDelta, yDelta), and
                   1138:  *     the bounding box is updated in the generic part of the item
                   1139:  *     structure.
                   1140:  *
                   1141:  *--------------------------------------------------------------
                   1142:  */
                   1143: 
                   1144: static void
                   1145: TranslateArc(canvasPtr, itemPtr, deltaX, deltaY)
                   1146:     Tk_Canvas *canvasPtr;              /* Canvas containing item. */
                   1147:     Tk_Item *itemPtr;                  /* Item that is being moved. */
                   1148:     double deltaX, deltaY;             /* Amount by which item is to be
                   1149:                                         * moved. */
                   1150: {
                   1151:     register ArcItem *arcPtr = (ArcItem *) itemPtr;
                   1152: 
                   1153:     arcPtr->bbox[0] += deltaX;
                   1154:     arcPtr->bbox[1] += deltaY;
                   1155:     arcPtr->bbox[2] += deltaX;
                   1156:     arcPtr->bbox[3] += deltaY;
                   1157:     ComputeArcBbox(canvasPtr, arcPtr);
                   1158: }
                   1159: 
                   1160: /*
                   1161:  *--------------------------------------------------------------
                   1162:  *
                   1163:  * ComputeArcOutline --
                   1164:  *
                   1165:  *     This procedure creates a polygon describing everything in
                   1166:  *     the outline for an arc except what's in the curved part.
                   1167:  *     For a "pie slice" arc this is a V-shaped chunk, and for
                   1168:  *     a "chord" arc this is a linear chunk (with cutaway corners).
                   1169:  *     For "arc" arcs, this stuff isn't relevant.
                   1170:  *
                   1171:  * Results:
                   1172:  *     None.
                   1173:  *
                   1174:  * Side effects:
                   1175:  *     The information at arcPtr->outlinePtr gets modified, and
                   1176:  *     storage for arcPtr->outlinePtr may be allocated or freed.
                   1177:  *
                   1178:  *--------------------------------------------------------------
                   1179:  */
                   1180: 
                   1181: static void
                   1182: ComputeArcOutline(arcPtr)
                   1183:     register ArcItem *arcPtr;
                   1184: {
                   1185:     double sin1, cos1, sin2, cos2, angle, halfWidth;
                   1186:     double boxWidth, boxHeight;
                   1187:     double vertex[2], corner1[2], corner2[2];
                   1188:     double *outlinePtr;
                   1189: 
                   1190:     /*
                   1191:      * Make sure that the outlinePtr array is large enough to hold
                   1192:      * either a chord or pie-slice outline.
                   1193:      */
                   1194: 
                   1195:     if (arcPtr->numOutlinePoints == 0) {
                   1196:        arcPtr->outlinePtr = (double *) ckalloc((unsigned)
                   1197:                (26 * sizeof(double)));
                   1198:        arcPtr->numOutlinePoints = 22;
                   1199:     }
                   1200:     outlinePtr = arcPtr->outlinePtr;
                   1201: 
                   1202:     /*
                   1203:      * First compute the two points that lie at the centers of
                   1204:      * the ends of the curved arc segment, which are marked with
                   1205:      * X's in the figure below:
                   1206:      *
                   1207:      *
                   1208:      *                           * * *
                   1209:      *                       *          *
                   1210:      *                    *      * *      *
                   1211:      *                  *    *         *    *
                   1212:      *                 *   *             *   *
                   1213:      *                  X *               * X
                   1214:      *
                   1215:      * The code is tricky because the arc can be ovular in shape.
                   1216:      * It computes the position for a unit circle, and then
                   1217:      * scales to fit the shape of the arc's bounding box.
                   1218:      *
                   1219:      * Also, watch out because angles go counter-clockwise like you
                   1220:      * might expect, but the y-coordinate system is inverted.  To
                   1221:      * handle this, just negate the angles in all the computations.
                   1222:      */
                   1223: 
                   1224:     boxWidth = arcPtr->bbox[2] - arcPtr->bbox[0];
                   1225:     boxHeight = arcPtr->bbox[3] - arcPtr->bbox[1];
                   1226:     angle = -arcPtr->start*PI/180.0;
                   1227:     sin1 = sin(angle);
                   1228:     cos1 = cos(angle);
                   1229:     angle -= arcPtr->extent*PI/180.0;
                   1230:     sin2 = sin(angle);
                   1231:     cos2 = cos(angle);
                   1232:     vertex[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0;
                   1233:     vertex[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0;
                   1234:     arcPtr->center1[0] = vertex[0] + cos1*boxWidth/2.0;
                   1235:     arcPtr->center1[1] = vertex[1] + sin1*boxHeight/2.0;
                   1236:     arcPtr->center2[0] = vertex[0] + cos2*boxWidth/2.0;
                   1237:     arcPtr->center2[1] = vertex[1] + sin2*boxHeight/2.0;
                   1238: 
                   1239:     /*
                   1240:      * Next compute the "outermost corners" of the arc, which are
                   1241:      * marked with X's in the figure below:
                   1242:      *
                   1243:      *                           * * *
                   1244:      *                       *          *
                   1245:      *                    *      * *      *
                   1246:      *                  *    *         *    *
                   1247:      *                 X   *             *   X
                   1248:      *                    *               *
                   1249:      *
                   1250:      * The code below is tricky because it has to handle eccentricity
                   1251:      * in the shape of the oval.  The key in the code below is to
                   1252:      * realize that the slope of the line from arcPtr->center1 to corner1
                   1253:      * is (boxWidth*sin1)/(boxHeight*cos1), and similarly for arcPtr->center2
                   1254:      * and corner2.  These formulas can be computed from the formula for
                   1255:      * the oval.
                   1256:      */
                   1257: 
                   1258:     halfWidth = arcPtr->width/2.0;
                   1259:     angle = atan2(boxWidth*sin1, boxHeight*cos1);
                   1260:     corner1[0] = arcPtr->center1[0] + cos(angle)*halfWidth;
                   1261:     corner1[1] = arcPtr->center1[1] + sin(angle)*halfWidth;
                   1262:     angle = atan2(boxWidth*sin2, boxHeight*cos2);
                   1263:     corner2[0] = arcPtr->center2[0] + cos(angle)*halfWidth;
                   1264:     corner2[1] = arcPtr->center2[1] + sin(angle)*halfWidth;
                   1265: 
                   1266:     /*
                   1267:      * For a chord outline, generate a six-sided polygon with three
                   1268:      * points for each end of the chord.  The first and third points
                   1269:      * for each end are butt points generated on either side of the
                   1270:      * center point.  The second point is the corner point.
                   1271:      */
                   1272: 
                   1273:     if (arcPtr->style == chordUid) {
                   1274:        outlinePtr[0] = outlinePtr[12] = corner1[0];
                   1275:        outlinePtr[1] = outlinePtr[13] = corner1[1];
                   1276:        TkGetButtPoints(arcPtr->center2, arcPtr->center1,
                   1277:                (double) arcPtr->width, 0, outlinePtr+10, outlinePtr+2);
                   1278:        outlinePtr[4] = arcPtr->center2[0] + outlinePtr[2]
                   1279:                - arcPtr->center1[0];
                   1280:        outlinePtr[5] = arcPtr->center2[1] + outlinePtr[3]
                   1281:                - arcPtr->center1[1];
                   1282:        outlinePtr[6] = corner2[0];
                   1283:        outlinePtr[7] = corner2[1];
                   1284:        outlinePtr[8] = arcPtr->center2[0] + outlinePtr[10]
                   1285:                - arcPtr->center1[0];
                   1286:        outlinePtr[9] = arcPtr->center2[1] + outlinePtr[11]
                   1287:                - arcPtr->center1[1];
                   1288:     } else if (arcPtr->style == pieSliceUid) {
                   1289:        /*
                   1290:         * For pie slices, generate two polygons, one for each side
                   1291:         * of the pie slice.  The first arm has a shape like this,
                   1292:         * where the center of the oval is X, arcPtr->center1 is at Y, and
                   1293:         * corner1 is at Z:
                   1294:         *
                   1295:         *       _____________________
                   1296:         *      |                     \
                   1297:         *      |                      \
                   1298:         *      X                    Y  Z
                   1299:         *      |                      /
                   1300:         *      |_____________________/
                   1301:         *
                   1302:         */
                   1303: 
                   1304:        TkGetButtPoints(arcPtr->center1, vertex, (double) arcPtr->width, 0,
                   1305:                outlinePtr, outlinePtr+2);
                   1306:        outlinePtr[4] = arcPtr->center1[0] + outlinePtr[2] - vertex[0];
                   1307:        outlinePtr[5] = arcPtr->center1[1] + outlinePtr[3] - vertex[1];
                   1308:        outlinePtr[6] = corner1[0];
                   1309:        outlinePtr[7] = corner1[1];
                   1310:        outlinePtr[8] = arcPtr->center1[0] + outlinePtr[0] - vertex[0];
                   1311:        outlinePtr[9] = arcPtr->center1[1] + outlinePtr[1] - vertex[1];
                   1312:        outlinePtr[10] = outlinePtr[0];
                   1313:        outlinePtr[11] = outlinePtr[1];
                   1314: 
                   1315:        /*
                   1316:         * The second arm has a shape like this:
                   1317:         *
                   1318:         *
                   1319:         *         ______________________
                   1320:         *        /                       \
                   1321:         *       /                         \
                   1322:         *      Z  Y                    X  /
                   1323:         *       \                        /
                   1324:         *        \______________________/
                   1325:         *
                   1326:         * Similar to above X is the center of the oval/circle, Y is
                   1327:         * arcPtr->center2, and Z is corner2.  The extra jog out to the left
                   1328:         * of X is needed in or to produce a butted joint with the
                   1329:         * first arm;  the corner to the right of X is one of the
                   1330:         * first two points of the first arm, depending on extent.
                   1331:         */
                   1332: 
                   1333:        TkGetButtPoints(arcPtr->center2, vertex, (double) arcPtr->width, 0,
                   1334:                outlinePtr+12, outlinePtr+16);
                   1335:        if ((arcPtr->extent > 180) ||
                   1336:                ((arcPtr->extent < 0) && (arcPtr->extent > -180))) {
                   1337:            outlinePtr[14] = outlinePtr[0];
                   1338:            outlinePtr[15] = outlinePtr[1];
                   1339:        } else {
                   1340:            outlinePtr[14] = outlinePtr[2];
                   1341:            outlinePtr[15] = outlinePtr[3];
                   1342:        }
                   1343:        outlinePtr[18] = arcPtr->center2[0] + outlinePtr[16] - vertex[0];
                   1344:        outlinePtr[19] = arcPtr->center2[1] + outlinePtr[17] - vertex[1];
                   1345:        outlinePtr[20] = corner2[0];
                   1346:        outlinePtr[21] = corner2[1];
                   1347:        outlinePtr[22] = arcPtr->center2[0] + outlinePtr[12] - vertex[0];
                   1348:        outlinePtr[23] = arcPtr->center2[1] + outlinePtr[13] - vertex[1];
                   1349:        outlinePtr[24] = outlinePtr[12];
                   1350:        outlinePtr[25] = outlinePtr[13];
                   1351:     }
                   1352: }
                   1353: 
                   1354: /*
                   1355:  *--------------------------------------------------------------
                   1356:  *
                   1357:  * HorizLineToArc --
                   1358:  *
                   1359:  *     Determines whether a horizontal line segment intersects
                   1360:  *     a given arc.
                   1361:  *
                   1362:  * Results:
                   1363:  *     The return value is 1 if the given line intersects the
                   1364:  *     infinitely-thin arc section defined by rx, ry, start,
                   1365:  *     and extent, and 0 otherwise.  Only the perimeter of the
                   1366:  *     arc is checked: interior areas (e.g. pie-slice or chord)
                   1367:  *     are not checked.
                   1368:  *
                   1369:  * Side effects:
                   1370:  *     None.
                   1371:  *
                   1372:  *--------------------------------------------------------------
                   1373:  */
                   1374: 
                   1375: static int
                   1376: HorizLineToArc(x1, x2, y, rx, ry, start, extent)
                   1377:     double x1, x2;             /* X-coords of endpoints of line segment. 
                   1378:                                 * X1 must be <= x2. */
                   1379:     double y;                  /* Y-coordinate of line segment. */
                   1380:     double rx, ry;             /* These x- and y-radii define an oval
                   1381:                                 * centered at the origin. */
                   1382:     double start, extent;      /* Angles that define extent of arc, in
                   1383:                                 * the standard fashion for this module. */
                   1384: {
                   1385:     double tmp;
                   1386:     double tx, ty;             /* Coordinates of intersection point in
                   1387:                                 * transformed coordinate system. */
                   1388:     double x;
                   1389: 
                   1390:     /*
                   1391:      * Compute the x-coordinate of one possible intersection point
                   1392:      * between the arc and the line.  Use a transformed coordinate
                   1393:      * system where the oval is a unit circle centered at the origin.
                   1394:      * Then scale back to get actual x-coordinate.
                   1395:      */
                   1396: 
                   1397:     ty = y/ry;
                   1398:     tmp = 1 - ty*ty;
                   1399:     if (tmp < 0) {
                   1400:        return 0;
                   1401:     }
                   1402:     tx = sqrt(tmp);
                   1403:     x = tx*rx;
                   1404: 
                   1405:     /*
                   1406:      * Test both intersection points.
                   1407:      */
                   1408: 
                   1409:     if ((x >= x1) && (x <= x2) && AngleInRange(tx, ty, start, extent)) {
                   1410:        return 1;
                   1411:     }
                   1412:     if ((-x >= x1) && (-x <= x2) && AngleInRange(-tx, ty, start, extent)) {
                   1413:        return 1;
                   1414:     }
                   1415:     return 0;
                   1416: }
                   1417: 
                   1418: /*
                   1419:  *--------------------------------------------------------------
                   1420:  *
                   1421:  * VertLineToArc --
                   1422:  *
                   1423:  *     Determines whether a vertical line segment intersects
                   1424:  *     a given arc.
                   1425:  *
                   1426:  * Results:
                   1427:  *     The return value is 1 if the given line intersects the
                   1428:  *     infinitely-thin arc section defined by rx, ry, start,
                   1429:  *     and extent, and 0 otherwise.  Only the perimeter of the
                   1430:  *     arc is checked: interior areas (e.g. pie-slice or chord)
                   1431:  *     are not checked.
                   1432:  *
                   1433:  * Side effects:
                   1434:  *     None.
                   1435:  *
                   1436:  *--------------------------------------------------------------
                   1437:  */
                   1438: 
                   1439: static int
                   1440: VertLineToArc(x, y1, y2, rx, ry, start, extent)
                   1441:     double x;                  /* X-coordinate of line segment. */
                   1442:     double y1, y2;             /* Y-coords of endpoints of line segment. 
                   1443:                                 * Y1 must be <= y2. */
                   1444:     double rx, ry;             /* These x- and y-radii define an oval
                   1445:                                 * centered at the origin. */
                   1446:     double start, extent;      /* Angles that define extent of arc, in
                   1447:                                 * the standard fashion for this module. */
                   1448: {
                   1449:     double tmp;
                   1450:     double tx, ty;             /* Coordinates of intersection point in
                   1451:                                 * transformed coordinate system. */
                   1452:     double y;
                   1453: 
                   1454:     /*
                   1455:      * Compute the y-coordinate of one possible intersection point
                   1456:      * between the arc and the line.  Use a transformed coordinate
                   1457:      * system where the oval is a unit circle centered at the origin.
                   1458:      * Then scale back to get actual y-coordinate.
                   1459:      */
                   1460: 
                   1461:     tx = x/rx;
                   1462:     tmp = 1 - tx*tx;
                   1463:     if (tmp < 0) {
                   1464:        return 0;
                   1465:     }
                   1466:     ty = sqrt(tmp);
                   1467:     y = ty*ry;
                   1468: 
                   1469:     /*
                   1470:      * Test both intersection points.
                   1471:      */
                   1472: 
                   1473:     if ((y > y1) && (y < y2) && AngleInRange(tx, ty, start, extent)) {
                   1474:        return 1;
                   1475:     }
                   1476:     if ((-y > y1) && (-y < y2) && AngleInRange(tx, -ty, start, extent)) {
                   1477:        return 1;
                   1478:     }
                   1479:     return 0;
                   1480: }
                   1481: 
                   1482: /*
                   1483:  *--------------------------------------------------------------
                   1484:  *
                   1485:  * AngleInRange --
                   1486:  *
                   1487:  *     Determine whether the angle from the origin to a given
                   1488:  *     point is within a given range.
                   1489:  *
                   1490:  * Results:
                   1491:  *     The return value is 1 if the angle from (0,0) to (x,y)
                   1492:  *     is in the range given by start and extent, where angles
                   1493:  *     are interpreted in the standard way for ovals (meaning
                   1494:  *     backwards from normal interpretation).  Otherwise the
                   1495:  *     return value is 0.
                   1496:  *
                   1497:  * Side effects:
                   1498:  *     None.
                   1499:  *
                   1500:  *--------------------------------------------------------------
                   1501:  */
                   1502: 
                   1503: static int
                   1504: AngleInRange(x, y, start, extent)
                   1505:     double x, y;               /* Coordinate of point;  angle measured
                   1506:                                 * from origin to here, relative to x-axis. */
                   1507:     double start;              /* First angle, degrees, >=0, <=360. */
                   1508:     double extent;             /* Size of arc in degrees >=-360, <=360. */
                   1509: {
                   1510:     double diff;
                   1511: 
                   1512:     diff = -atan2(y, x);
                   1513:     diff = diff*(180.0/PI) - start;
                   1514:     while (diff > 360.0) {
                   1515:        diff -= 360.0;
                   1516:     }
                   1517:     while (diff < 0.0) {
                   1518:        diff += 360.0;
                   1519:     }
                   1520:     if (extent >= 0) {
                   1521:        return diff <= extent;
                   1522:     }
                   1523:     return (diff-360.0) >= extent;
                   1524: }

unix.superglobalmegacorp.com

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