home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / generic / tkCanvArc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  50.9 KB  |  1,717 lines  |  [TEXT/CWIE]

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