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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 69 - (show annotations) (download)
Sat Nov 5 10:54:17 2016 UTC (7 years, 4 months ago) by dashley
File MIME type: text/plain
File size: 68170 byte(s)
License and property (keyword) changes.
1 /* $Header$ */
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 /* End of tkcanvarc.c */

Properties

Name Value
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25