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