/[dtapublic]/projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkcanvarc.c
ViewVC logotype

Annotation of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkcanvarc.c

Parent Directory Parent Directory | Revision Log Revision Log


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

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25