home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / tcl / tk3.3b1 / tkCanvArc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-02  |  51.2 KB  |  1,707 lines

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