tkCanvArc.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:64k
源码类别:

通讯编程

开发平台:

Visual C++

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