4 * This file implements arc items for canvas widgets.
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.
17 static char rcsid
[] = "$Header: /user6/ouster/wish/RCS/tkCanvArc.c,v 1.5 92/08/16 15:42:20 ouster Exp $ SPRITE (Berkeley)";
26 * The structure below defines the record for each arc item.
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
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
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). */
64 * The definitions below define the sizes of the polygons used to
65 * display outline information for various styles of arcs:
68 #define CHORD_OUTLINE_PTS 7
69 #define PIE_OUTLINE1_PTS 6
70 #define PIE_OUTLINE2_PTS 7
73 * Information used for parsing configuration specs:
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
,
98 * Prototypes for procedures defined in this file:
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
,
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
));
133 * The structures below defines the arc item types by means of procedures
134 * that can be invoked by generic item code.
137 Tk_ItemType TkArcType
= {
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 */
160 #define PI 3.14159265358979323846
163 * The uid's below comprise the legal values for the "-style"
167 static Tk_Uid arcUid
= NULL
;
168 static Tk_Uid chordUid
= NULL
;
169 static Tk_Uid pieSliceUid
= NULL
;
172 *--------------------------------------------------------------
176 * This procedure is invoked to create a new arc item in
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
187 * A new arc item is created.
189 *--------------------------------------------------------------
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. */
201 register ArcItem
*arcPtr
= (ArcItem
*) itemPtr
;
204 Tcl_AppendResult(canvasPtr
->interp
, "wrong # args: should be \"",
205 Tk_PathName(canvasPtr
->tkwin
), "\" create ",
206 itemPtr
->typePtr
->name
, " x1 y1 x2 y2 ?options?",
212 * Carry out once-only initialization.
215 if (arcUid
== NULL
) {
216 arcUid
= Tk_GetUid("arc");
217 chordUid
= Tk_GetUid("chord");
218 pieSliceUid
= Tk_GetUid("pieslice");
222 * Carry out initialization that is needed in order to clean
223 * up after errors during the the remainder of this procedure.
228 arcPtr
->outlinePtr
= NULL
;
229 arcPtr
->numOutlinePoints
= 0;
231 arcPtr
->outlineColor
= NULL
;
232 arcPtr
->fillColor
= NULL
;
233 arcPtr
->fillStipple
= None
;
234 arcPtr
->style
= pieSliceUid
;
235 arcPtr
->outlineGC
= None
;
236 arcPtr
->fillGC
= None
;
239 * Process the arguments to fill in the item record.
242 if ((TkGetCanvasCoord(canvasPtr
, argv
[0], &arcPtr
->bbox
[0]) != TCL_OK
)
243 || (TkGetCanvasCoord(canvasPtr
, argv
[1],
244 &arcPtr
->bbox
[1]) != TCL_OK
)
245 || (TkGetCanvasCoord(canvasPtr
, argv
[2],
246 &arcPtr
->bbox
[2]) != TCL_OK
)
247 || (TkGetCanvasCoord(canvasPtr
, argv
[3],
248 &arcPtr
->bbox
[3]) != TCL_OK
)) {
252 if (ConfigureArc(canvasPtr
, itemPtr
, argc
-4, argv
+4, 0) != TCL_OK
) {
260 *--------------------------------------------------------------
264 * This procedure is invoked to process the "coords" widget
265 * command on arcs. See the user documentation for details
269 * Returns TCL_OK or TCL_ERROR, and sets canvasPtr->interp->result.
272 * The coordinates for the given item may be changed.
274 *--------------------------------------------------------------
279 register Tk_Canvas
*canvasPtr
, /* Canvas containing item. */
280 Tk_Item
*itemPtr
, /* Item whose coordinates are to be
281 * read or modified. */
282 int argc
, /* Number of coordinates supplied in
284 char **argv
/* Array of coordinates: x1, y1,
288 register ArcItem
*arcPtr
= (ArcItem
*) itemPtr
;
292 sprintf(buffer
, "%g %g %g %g", arcPtr
->bbox
[0],
293 arcPtr
->bbox
[1], arcPtr
->bbox
[2],
295 Tcl_SetResult(canvasPtr
->interp
, buffer
, TCL_VOLATILE
);
296 } else if (argc
== 4) {
297 if ((TkGetCanvasCoord(canvasPtr
, argv
[0],
298 &arcPtr
->bbox
[0]) != TCL_OK
)
299 || (TkGetCanvasCoord(canvasPtr
, argv
[1],
300 &arcPtr
->bbox
[1]) != TCL_OK
)
301 || (TkGetCanvasCoord(canvasPtr
, argv
[2],
302 &arcPtr
->bbox
[2]) != TCL_OK
)
303 || (TkGetCanvasCoord(canvasPtr
, argv
[3],
304 &arcPtr
->bbox
[3]) != TCL_OK
)) {
307 ComputeArcBbox(canvasPtr
, arcPtr
);
309 sprintf(canvasPtr
->interp
->result
,
310 "wrong # coordinates: expected 0 or 4, got %d",
318 *--------------------------------------------------------------
322 * This procedure is invoked to configure various aspects
323 * of a arc item, such as its outline and fill colors.
326 * A standard Tcl result code. If an error occurs, then
327 * an error message is left in canvasPtr->interp->result.
330 * Configuration information, such as colors and stipple
331 * patterns, may be set for itemPtr.
333 *--------------------------------------------------------------
338 Tk_Canvas
*canvasPtr
, /* Canvas containing itemPtr. */
339 Tk_Item
*itemPtr
, /* Arc item to reconfigure. */
340 int argc
, /* Number of elements in argv. */
341 char **argv
, /* Arguments describing things to configure. */
342 int flags
/* Flags to pass to Tk_ConfigureWidget. */
345 register ArcItem
*arcPtr
= (ArcItem
*) itemPtr
;
351 if (Tk_ConfigureWidget(canvasPtr
->interp
, canvasPtr
->tkwin
,
352 configSpecs
, argc
, argv
, (char *) arcPtr
, flags
) != TCL_OK
) {
357 * A few of the options require additional processing, such as
358 * style and graphics contexts.
361 i
= arcPtr
->start
/360.0;
362 arcPtr
->start
-= i
*360.0;
363 if (arcPtr
->start
< 0) {
364 arcPtr
->start
+= 360.0;
366 i
= arcPtr
->extent
/360.0;
367 arcPtr
->extent
-= i
*360.0;
369 if ((arcPtr
->style
!= arcUid
) && (arcPtr
->style
!= chordUid
)
370 && (arcPtr
->style
!= pieSliceUid
)) {
371 Tcl_AppendResult(canvasPtr
->interp
, "bad -style option \"",
372 arcPtr
->style
, "\": must be arc, chord, or pieslice",
374 arcPtr
->style
= pieSliceUid
;
378 if (arcPtr
->width
< 0) {
381 if (arcPtr
->style
== arcUid
) {
382 if (arcPtr
->fillColor
== NULL
) {
385 gcValues
.foreground
= arcPtr
->fillColor
->pixel
;
386 gcValues
.cap_style
= CapButt
;
387 gcValues
.line_width
= arcPtr
->width
;
388 mask
= GCForeground
|GCCapStyle
|GCLineWidth
;
389 if (arcPtr
->fillStipple
!= None
) {
390 gcValues
.stipple
= arcPtr
->fillStipple
;
391 gcValues
.fill_style
= FillStippled
;
392 mask
|= GCStipple
|GCFillStyle
;
394 newGC
= Tk_GetGC(canvasPtr
->tkwin
, mask
, &gcValues
);
396 } else if (arcPtr
->outlineColor
== NULL
) {
399 gcValues
.foreground
= arcPtr
->outlineColor
->pixel
;
400 gcValues
.cap_style
= CapButt
;
401 gcValues
.line_width
= arcPtr
->width
;
402 mask
= GCForeground
|GCCapStyle
|GCLineWidth
;
403 newGC
= Tk_GetGC(canvasPtr
->tkwin
, mask
, &gcValues
);
405 if (arcPtr
->outlineGC
!= None
) {
406 Tk_FreeGC(arcPtr
->outlineGC
);
408 arcPtr
->outlineGC
= newGC
;
410 if ((arcPtr
->fillColor
== NULL
) || (arcPtr
->style
== arcUid
)) {
413 gcValues
.foreground
= arcPtr
->fillColor
->pixel
;
414 if (arcPtr
->style
== chordUid
) {
415 gcValues
.arc_mode
= ArcChord
;
417 gcValues
.arc_mode
= ArcPieSlice
;
419 mask
= GCForeground
|GCArcMode
;
420 if (arcPtr
->fillStipple
!= None
) {
421 gcValues
.stipple
= arcPtr
->fillStipple
;
422 gcValues
.fill_style
= FillStippled
;
423 mask
|= GCStipple
|GCFillStyle
;
425 newGC
= Tk_GetGC(canvasPtr
->tkwin
, mask
, &gcValues
);
427 if (arcPtr
->fillGC
!= None
) {
428 Tk_FreeGC(arcPtr
->fillGC
);
430 arcPtr
->fillGC
= newGC
;
432 ComputeArcBbox(canvasPtr
, arcPtr
);
437 *--------------------------------------------------------------
441 * This procedure is called to clean up the data structure
442 * associated with a arc item.
448 * Resources associated with itemPtr are released.
450 *--------------------------------------------------------------
455 Tk_Item
*itemPtr
/* Item that is being deleted. */
458 register ArcItem
*arcPtr
= (ArcItem
*) itemPtr
;
460 if (arcPtr
->numOutlinePoints
!= 0) {
461 ckfree((char *) arcPtr
->outlinePtr
);
463 if (arcPtr
->outlineColor
!= NULL
) {
464 Tk_FreeColor(arcPtr
->outlineColor
);
466 if (arcPtr
->fillColor
!= NULL
) {
467 Tk_FreeColor(arcPtr
->fillColor
);
469 if (arcPtr
->fillStipple
!= None
) {
470 Tk_FreeBitmap(arcPtr
->fillStipple
);
472 if (arcPtr
->outlineGC
!= None
) {
473 Tk_FreeGC(arcPtr
->outlineGC
);
475 if (arcPtr
->fillGC
!= None
) {
476 Tk_FreeGC(arcPtr
->fillGC
);
481 *--------------------------------------------------------------
485 * This procedure is invoked to compute the bounding box of
486 * all the pixels that may be drawn as part of an arc.
492 * The fields x1, y1, x2, and y2 are updated in the header
495 *--------------------------------------------------------------
501 register Tk_Canvas
*canvasPtr
, /* Canvas that contains item. */
502 register ArcItem
*arcPtr
/* Item whose bbox is to be
506 double tmp
, center
[2], point
[2];
509 * Make sure that the first coordinates are the lowest ones.
512 if (arcPtr
->bbox
[1] > arcPtr
->bbox
[3]) {
514 tmp
= arcPtr
->bbox
[3];
515 arcPtr
->bbox
[3] = arcPtr
->bbox
[1];
516 arcPtr
->bbox
[1] = tmp
;
518 if (arcPtr
->bbox
[0] > arcPtr
->bbox
[2]) {
520 tmp
= arcPtr
->bbox
[2];
521 arcPtr
->bbox
[2] = arcPtr
->bbox
[0];
522 arcPtr
->bbox
[0] = tmp
;
525 ComputeArcOutline(arcPtr
);
528 * To compute the bounding box, start with the the bbox formed
529 * by the two endpoints of the arc. Then add in the center of
530 * the arc's oval (if relevant) and the 3-o'clock, 6-o'clock,
531 * 9-o'clock, and 12-o'clock positions, if they are relevant.
534 arcPtr
->header
.x1
= arcPtr
->header
.x2
= arcPtr
->center1
[0];
535 arcPtr
->header
.y1
= arcPtr
->header
.y2
= arcPtr
->center1
[1];
536 TkIncludePoint(canvasPtr
, (Tk_Item
*) arcPtr
, arcPtr
->center2
);
537 center
[0] = (arcPtr
->bbox
[0] + arcPtr
->bbox
[2])/2;
538 center
[1] = (arcPtr
->bbox
[1] + arcPtr
->bbox
[3])/2;
539 if (arcPtr
->style
!= arcUid
) {
540 TkIncludePoint(canvasPtr
, (Tk_Item
*) arcPtr
, center
);
543 tmp
= -arcPtr
->start
;
547 if ((tmp
< arcPtr
->extent
) || ((tmp
-360) > arcPtr
->extent
)) {
548 point
[0] = arcPtr
->bbox
[2];
549 point
[1] = center
[1];
550 TkIncludePoint(canvasPtr
, (Tk_Item
*) arcPtr
, point
);
552 tmp
= 90.0 - arcPtr
->start
;
556 if ((tmp
< arcPtr
->extent
) || ((tmp
-360) > arcPtr
->extent
)) {
557 point
[0] = center
[0];
558 point
[1] = arcPtr
->bbox
[1];
559 TkIncludePoint(canvasPtr
, (Tk_Item
*) arcPtr
, point
);
561 tmp
= 180.0 - arcPtr
->start
;
565 if ((tmp
< arcPtr
->extent
) || ((tmp
-360) > arcPtr
->extent
)) {
566 point
[0] = arcPtr
->bbox
[0];
567 point
[1] = center
[1];
568 TkIncludePoint(canvasPtr
, (Tk_Item
*) arcPtr
, point
);
570 tmp
= 270.0 - arcPtr
->start
;
574 if ((tmp
< arcPtr
->extent
) || ((tmp
-360) > arcPtr
->extent
)) {
575 point
[0] = center
[0];
576 point
[1] = arcPtr
->bbox
[3];
577 TkIncludePoint(canvasPtr
, (Tk_Item
*) arcPtr
, point
);
581 * Lastly, expand by the width of the arc (if the arc's outline is
582 * being drawn) and add one extra pixel just for safety.
585 if (arcPtr
->outlineColor
== NULL
) {
588 tmp
= (arcPtr
->width
+ 1)/2 + 1;
590 arcPtr
->header
.x1
-= tmp
;
591 arcPtr
->header
.y1
-= tmp
;
592 arcPtr
->header
.x2
+= tmp
;
593 arcPtr
->header
.y2
+= tmp
;
597 *--------------------------------------------------------------
601 * This procedure is invoked to draw an arc item in a given
608 * ItemPtr is drawn in drawable using the transformation
609 * information in canvasPtr.
611 *--------------------------------------------------------------
616 register Tk_Canvas
*canvasPtr
, /* Canvas that contains item. */
617 Tk_Item
*itemPtr
, /* Item to be displayed. */
618 Drawable drawable
/* Pixmap or window in which to draw
622 register ArcItem
*arcPtr
= (ArcItem
*) itemPtr
;
623 Display
*display
= Tk_Display(canvasPtr
->tkwin
);
624 int x1
, y1
, x2
, y2
, start
, extent
;
627 * Compute the screen coordinates of the bounding box for the item,
628 * plus integer values for the angles.
631 x1
= SCREEN_X(canvasPtr
, arcPtr
->bbox
[0]);
632 y1
= SCREEN_Y(canvasPtr
, arcPtr
->bbox
[1]);
633 x2
= SCREEN_X(canvasPtr
, arcPtr
->bbox
[2]);
634 y2
= SCREEN_Y(canvasPtr
, arcPtr
->bbox
[3]);
641 start
= (64*arcPtr
->start
) + 0.5;
642 extent
= (64*arcPtr
->extent
) + 0.5;
645 * Display filled arc first (if wanted), then outline.
648 if (arcPtr
->fillGC
!= None
) {
649 XFillArc(display
, drawable
, arcPtr
->fillGC
, x1
, y1
, (x2
-x1
),
650 (y2
-y1
), start
, extent
);
652 if (arcPtr
->outlineGC
!= None
) {
653 XDrawArc(display
, drawable
, arcPtr
->outlineGC
, x1
, y1
, (x2
-x1
),
654 (y2
-y1
), start
, extent
);
657 * If the outline width is very thin, don't use polygons to draw
658 * the linear parts of the outline (this often results in nothing
659 * being displayed); just draw lines instead.
662 if (arcPtr
->width
<= 2) {
663 x1
= SCREEN_X(canvasPtr
, arcPtr
->center1
[0]);
664 y1
= SCREEN_Y(canvasPtr
, arcPtr
->center1
[1]);
665 x2
= SCREEN_X(canvasPtr
, arcPtr
->center2
[0]);
666 y2
= SCREEN_Y(canvasPtr
, arcPtr
->center2
[1]);
668 if (arcPtr
->style
== chordUid
) {
669 XDrawLine(display
, drawable
, arcPtr
->outlineGC
,
671 } else if (arcPtr
->style
== pieSliceUid
) {
674 cx
= SCREEN_X(canvasPtr
, (arcPtr
->bbox
[0] + arcPtr
->bbox
[2])/2.0);
675 cy
= SCREEN_Y(canvasPtr
, (arcPtr
->bbox
[1] + arcPtr
->bbox
[3])/2.0);
676 XDrawLine(display
, drawable
, arcPtr
->outlineGC
,
678 XDrawLine(display
, drawable
, arcPtr
->outlineGC
,
682 if (arcPtr
->style
== chordUid
) {
683 TkFillPolygon(canvasPtr
, arcPtr
->outlinePtr
,
684 CHORD_OUTLINE_PTS
, drawable
, arcPtr
->outlineGC
);
685 } else if (arcPtr
->style
== pieSliceUid
) {
686 TkFillPolygon(canvasPtr
, arcPtr
->outlinePtr
,
687 PIE_OUTLINE1_PTS
, drawable
, arcPtr
->outlineGC
);
688 TkFillPolygon(canvasPtr
,
689 arcPtr
->outlinePtr
+ 2*PIE_OUTLINE1_PTS
,
690 PIE_OUTLINE2_PTS
, drawable
, arcPtr
->outlineGC
);
697 *--------------------------------------------------------------
701 * Computes the distance from a given point to a given
702 * arc, in canvas units.
705 * The return value is 0 if the point whose x and y coordinates
706 * are coordPtr[0] and coordPtr[1] is inside the arc. If the
707 * point isn't inside the arc then the return value is the
708 * distance from the point to the arc. If itemPtr is filled,
709 * then anywhere in the interior is considered "inside"; if
710 * itemPtr isn't filled, then "inside" means only the area
711 * occupied by the outline.
716 *--------------------------------------------------------------
722 Tk_Canvas
*canvasPtr
, /* Canvas containing item. */
723 Tk_Item
*itemPtr
, /* Item to check against point. */
724 double *pointPtr
/* Pointer to x and y coordinates. */
727 register ArcItem
*arcPtr
= (ArcItem
*) itemPtr
;
728 double vertex
[2], pointAngle
, diff
, dist
, newDist
;
729 double poly
[8], polyDist
, width
;
730 int filled
, angleInRange
;
732 if ((arcPtr
->fillGC
!= None
) || (arcPtr
->outlineGC
== None
)) {
739 * See if the point is within the angular range of the arc.
740 * Remember, X angles are backwards from the way we'd normally
741 * think of them. Also, compensate for any eccentricity of
745 vertex
[0] = (arcPtr
->bbox
[0] + arcPtr
->bbox
[2])/2.0;
746 vertex
[1] = (arcPtr
->bbox
[1] + arcPtr
->bbox
[3])/2.0;
747 pointAngle
= -atan2((pointPtr
[1] - vertex
[1])
748 /(arcPtr
->bbox
[3] - arcPtr
->bbox
[1]),
749 (pointPtr
[0] - vertex
[0])/(arcPtr
->bbox
[2] - arcPtr
->bbox
[0]));
750 pointAngle
*= 180/PI
;
751 diff
= pointAngle
- arcPtr
->start
;
752 diff
-= ((int) (diff
/360.0) * 360.0);
756 angleInRange
= (diff
<= arcPtr
->extent
) ||
757 ((arcPtr
->extent
< 0) && ((diff
- 360.0) >= arcPtr
->extent
));
760 * Now perform different tests depending on what kind of arc
761 * we're dealing with.
764 if (arcPtr
->style
== arcUid
) {
766 return TkOvalToPoint(arcPtr
->bbox
, (double) arcPtr
->width
,
769 dist
= hypot(pointPtr
[0] - arcPtr
->center1
[0],
770 pointPtr
[1] - arcPtr
->center1
[1]);
771 newDist
= hypot(pointPtr
[0] - arcPtr
->center2
[0],
772 pointPtr
[1] - arcPtr
->center2
[1]);
773 if (newDist
< dist
) {
779 if ((arcPtr
->fillGC
!= None
) || (arcPtr
->outlineGC
== None
)) {
784 if (arcPtr
->outlineGC
== None
) {
787 width
= arcPtr
->width
;
790 if (arcPtr
->style
== pieSliceUid
) {
792 dist
= TkPolygonToPoint(arcPtr
->outlinePtr
, PIE_OUTLINE1_PTS
,
794 newDist
= TkPolygonToPoint(arcPtr
->outlinePtr
+ 2*PIE_OUTLINE1_PTS
,
795 PIE_OUTLINE2_PTS
, pointPtr
);
797 dist
= TkLineToPoint(vertex
, arcPtr
->center1
, pointPtr
);
798 newDist
= TkLineToPoint(vertex
, arcPtr
->center2
, pointPtr
);
800 if (newDist
< dist
) {
804 newDist
= TkOvalToPoint(arcPtr
->bbox
, width
, filled
, pointPtr
);
805 if (newDist
< dist
) {
813 * This is a chord-style arc. We have to deal specially with the
814 * triangular piece that represents the difference between a
815 * chord-style arc and a pie-slice arc (for small angles this piece
816 * is excluded here where it would be included for pie slices;
817 * for large angles the piece is included here but would be
818 * excluded for pie slices).
822 dist
= TkPolygonToPoint(arcPtr
->outlinePtr
, CHORD_OUTLINE_PTS
,
825 dist
= TkLineToPoint(arcPtr
->center1
, arcPtr
->center2
, pointPtr
);
827 poly
[0] = poly
[6] = vertex
[0];
828 poly
[1] = poly
[7] = vertex
[1];
829 poly
[2] = arcPtr
->center1
[0];
830 poly
[3] = arcPtr
->center1
[1];
831 poly
[4] = arcPtr
->center2
[0];
832 poly
[5] = arcPtr
->center2
[1];
833 polyDist
= TkPolygonToPoint(poly
, 4, pointPtr
);
835 if ((arcPtr
->extent
< -180.0) || (arcPtr
->extent
> 180.0)
836 || (polyDist
> 0.0)) {
837 newDist
= TkOvalToPoint(arcPtr
->bbox
, width
, filled
, pointPtr
);
838 if (newDist
< dist
) {
843 if ((arcPtr
->extent
< -180.0) || (arcPtr
->extent
> 180.0)) {
844 if (filled
&& (polyDist
< dist
)) {
853 *--------------------------------------------------------------
857 * This procedure is called to determine whether an item
858 * lies entirely inside, entirely outside, or overlapping
862 * -1 is returned if the item is entirely outside the area
863 * given by rectPtr, 0 if it overlaps, and 1 if it is entirely
864 * inside the given area.
869 *--------------------------------------------------------------
875 Tk_Canvas
*canvasPtr
, /* Canvas containing item. */
876 Tk_Item
*itemPtr
, /* Item to check against arc. */
877 double *rectPtr
/* Pointer to array of four coordinates
878 * (x1, y1, x2, y2) describing rectangular
882 register ArcItem
*arcPtr
= (ArcItem
*) itemPtr
;
883 double rx
, ry
; /* Radii for transformed oval: these define
884 * an oval centered at the origin. */
885 double tRect
[4]; /* Transformed version of x1, y1, x2, y2,
886 * for coord. system where arc is centered
888 double center
[2], width
, angle
, tmp
;
889 double points
[20], *pointPtr
;
890 int numPoints
, filled
;
891 int inside
; /* Non-zero means every test so far suggests
892 * that arc is inside rectangle. 0 means
893 * every test so far shows arc to be outside
897 if ((arcPtr
->fillGC
!= None
) || (arcPtr
->outlineGC
== None
)) {
902 if (arcPtr
->outlineGC
== None
) {
905 width
= arcPtr
->width
;
909 * Transform both the arc and the rectangle so that the arc's oval
910 * is centered on the origin.
913 center
[0] = (arcPtr
->bbox
[0] + arcPtr
->bbox
[2])/2.0;
914 center
[1] = (arcPtr
->bbox
[1] + arcPtr
->bbox
[3])/2.0;
915 tRect
[0] = rectPtr
[0] - center
[0];
916 tRect
[1] = rectPtr
[1] - center
[1];
917 tRect
[2] = rectPtr
[2] - center
[0];
918 tRect
[3] = rectPtr
[3] - center
[1];
919 rx
= arcPtr
->bbox
[2] - center
[0] + width
/2.0;
920 ry
= arcPtr
->bbox
[3] - center
[1] + width
/2.0;
923 * Find the extreme points of the arc and see whether these are all
924 * inside the rectangle (in which case we're done), partly in and
925 * partly out (in which case we're done), or all outside (in which
926 * case we have more work to do). The extreme points include the
927 * following, which are checked in order:
929 * 1. The outside points of the arc, corresponding to start and
931 * 2. The center of the arc (but only in pie-slice mode).
932 * 3. The 12, 3, 6, and 9-o'clock positions (but only if the arc
933 * includes those angles).
938 angle
= -arcPtr
->start
*(PI
/180.0);
939 pointPtr
[0] = rx
*cos(angle
);
940 pointPtr
[1] = ry
*sin(angle
);
941 angle
+= -arcPtr
->extent
*(PI
/180.0);
942 pointPtr
[2] = rx
*cos(angle
);
943 pointPtr
[3] = ry
*sin(angle
);
947 if ((arcPtr
->style
== pieSliceUid
) && (arcPtr
->extent
< 180.0)) {
954 tmp
= -arcPtr
->start
;
958 if ((tmp
< arcPtr
->extent
) || ((tmp
-360) > arcPtr
->extent
)) {
964 tmp
= 90.0 - arcPtr
->start
;
968 if ((tmp
< arcPtr
->extent
) || ((tmp
-360) > arcPtr
->extent
)) {
974 tmp
= 180.0 - arcPtr
->start
;
978 if ((tmp
< arcPtr
->extent
) || ((tmp
-360) > arcPtr
->extent
)) {
984 tmp
= 270.0 - arcPtr
->start
;
988 if ((tmp
< arcPtr
->extent
) || ((tmp
-360) > arcPtr
->extent
)) {
996 * Now that we've located the extreme points, loop through them all
997 * to see which are inside the rectangle.
1000 inside
= (points
[0] > tRect
[0]) && (points
[0] < tRect
[2])
1001 && (points
[1] > tRect
[1]) && (points
[1] < tRect
[3]);
1002 for (pointPtr
= points
+2; numPoints
> 1; pointPtr
+= 2, numPoints
--) {
1003 newInside
= (pointPtr
[0] > tRect
[0]) && (pointPtr
[0] < tRect
[2])
1004 && (pointPtr
[1] > tRect
[1]) && (pointPtr
[1] < tRect
[3]);
1005 if (newInside
!= inside
) {
1015 * So far, oval appears to be outside rectangle, but can't yet tell
1016 * for sure. Next, test each of the four sides of the rectangle
1017 * against the bounding region for the arc. If any intersections
1018 * are found, then return "overlapping". First, test against the
1019 * polygon(s) forming the sides of a chord or pie-slice.
1022 if (arcPtr
->style
== pieSliceUid
) {
1024 if (TkPolygonToArea(arcPtr
->outlinePtr
, PIE_OUTLINE1_PTS
,
1028 if (TkPolygonToArea(arcPtr
->outlinePtr
+ 2*PIE_OUTLINE1_PTS
,
1029 PIE_OUTLINE2_PTS
, rectPtr
) != -1) {
1033 if ((TkLineToArea(center
, arcPtr
->center1
, rectPtr
) != -1) ||
1034 (TkLineToArea(center
, arcPtr
->center2
, rectPtr
) != -1)) {
1038 } else if (arcPtr
->style
== chordUid
) {
1040 if (TkPolygonToArea(arcPtr
->outlinePtr
, CHORD_OUTLINE_PTS
,
1045 if (TkLineToArea(arcPtr
->center1
, arcPtr
->center2
,
1053 * Next check for overlap between each of the four sides and the
1054 * outer perimiter of the arc. If the arc isn't filled, then also
1055 * check the inner perimeter of the arc.
1058 if (HorizLineToArc(tRect
[0], tRect
[2], tRect
[1], rx
, ry
, arcPtr
->start
,
1060 || HorizLineToArc(tRect
[0], tRect
[2], tRect
[3], rx
, ry
,
1061 arcPtr
->start
, arcPtr
->extent
)
1062 || VertLineToArc(tRect
[0], tRect
[1], tRect
[3], rx
, ry
,
1063 arcPtr
->start
, arcPtr
->extent
)
1064 || VertLineToArc(tRect
[2], tRect
[1], tRect
[3], rx
, ry
,
1065 arcPtr
->start
, arcPtr
->extent
)) {
1068 if ((width
> 1.0) && !filled
) {
1071 if (HorizLineToArc(tRect
[0], tRect
[2], tRect
[1], rx
, ry
, arcPtr
->start
,
1073 || HorizLineToArc(tRect
[0], tRect
[2], tRect
[3], rx
, ry
,
1074 arcPtr
->start
, arcPtr
->extent
)
1075 || VertLineToArc(tRect
[0], tRect
[1], tRect
[3], rx
, ry
,
1076 arcPtr
->start
, arcPtr
->extent
)
1077 || VertLineToArc(tRect
[2], tRect
[1], tRect
[3], rx
, ry
,
1078 arcPtr
->start
, arcPtr
->extent
)) {
1084 * The arc still appears to be totally disjoint from the rectangle,
1085 * but it's also possible that the rectangle is totally inside the arc.
1086 * Do one last check, which is to check one point of the rectangle
1087 * to see if it's inside the arc. If it is, we've got overlap. If
1088 * it isn't, the arc's really outside the rectangle.
1091 if (ArcToPoint(canvasPtr
, itemPtr
, rectPtr
) == 0.0) {
1098 *--------------------------------------------------------------
1102 * This procedure is invoked to rescale an arc item.
1108 * The arc referred to by itemPtr is rescaled so that the
1109 * following transformation is applied to all point
1111 * x' = originX + scaleX*(x-originX)
1112 * y' = originY + scaleY*(y-originY)
1114 *--------------------------------------------------------------
1119 Tk_Canvas
*canvasPtr
, /* Canvas containing arc. */
1120 Tk_Item
*itemPtr
, /* Arc to be scaled. */
1122 double originY
, /* Origin about which to scale rect. */
1123 double scaleX
, /* Amount to scale in X direction. */
1124 double scaleY
/* Amount to scale in Y direction. */
1127 register ArcItem
*arcPtr
= (ArcItem
*) itemPtr
;
1129 arcPtr
->bbox
[0] = originX
+ scaleX
*(arcPtr
->bbox
[0] - originX
);
1130 arcPtr
->bbox
[1] = originY
+ scaleY
*(arcPtr
->bbox
[1] - originY
);
1131 arcPtr
->bbox
[2] = originX
+ scaleX
*(arcPtr
->bbox
[2] - originX
);
1132 arcPtr
->bbox
[3] = originY
+ scaleY
*(arcPtr
->bbox
[3] - originY
);
1133 ComputeArcBbox(canvasPtr
, arcPtr
);
1137 *--------------------------------------------------------------
1141 * This procedure is called to move an arc by a given amount.
1147 * The position of the arc is offset by (xDelta, yDelta), and
1148 * the bounding box is updated in the generic part of the item
1151 *--------------------------------------------------------------
1156 Tk_Canvas
*canvasPtr
, /* Canvas containing item. */
1157 Tk_Item
*itemPtr
, /* Item that is being moved. */
1159 double deltaY
/* Amount by which item is to be
1163 register ArcItem
*arcPtr
= (ArcItem
*) itemPtr
;
1165 arcPtr
->bbox
[0] += deltaX
;
1166 arcPtr
->bbox
[1] += deltaY
;
1167 arcPtr
->bbox
[2] += deltaX
;
1168 arcPtr
->bbox
[3] += deltaY
;
1169 ComputeArcBbox(canvasPtr
, arcPtr
);
1173 *--------------------------------------------------------------
1175 * ComputeArcOutline --
1177 * This procedure creates a polygon describing everything in
1178 * the outline for an arc except what's in the curved part.
1179 * For a "pie slice" arc this is a V-shaped chunk, and for
1180 * a "chord" arc this is a linear chunk (with cutaway corners).
1181 * For "arc" arcs, this stuff isn't relevant.
1187 * The information at arcPtr->outlinePtr gets modified, and
1188 * storage for arcPtr->outlinePtr may be allocated or freed.
1190 *--------------------------------------------------------------
1194 ComputeArcOutline (register ArcItem
*arcPtr
)
1196 double sin1
, cos1
, sin2
, cos2
, angle
, halfWidth
;
1197 double boxWidth
, boxHeight
;
1198 double vertex
[2], corner1
[2], corner2
[2];
1202 * Make sure that the outlinePtr array is large enough to hold
1203 * either a chord or pie-slice outline.
1206 if (arcPtr
->numOutlinePoints
== 0) {
1207 arcPtr
->outlinePtr
= (double *) ckalloc((unsigned)
1208 (26 * sizeof(double)));
1209 arcPtr
->numOutlinePoints
= 22;
1211 outlinePtr
= arcPtr
->outlinePtr
;
1214 * First compute the two points that lie at the centers of
1215 * the ends of the curved arc segment, which are marked with
1216 * X's in the figure below:
1226 * The code is tricky because the arc can be ovular in shape.
1227 * It computes the position for a unit circle, and then
1228 * scales to fit the shape of the arc's bounding box.
1230 * Also, watch out because angles go counter-clockwise like you
1231 * might expect, but the y-coordinate system is inverted. To
1232 * handle this, just negate the angles in all the computations.
1235 boxWidth
= arcPtr
->bbox
[2] - arcPtr
->bbox
[0];
1236 boxHeight
= arcPtr
->bbox
[3] - arcPtr
->bbox
[1];
1237 angle
= -arcPtr
->start
*PI
/180.0;
1240 angle
-= arcPtr
->extent
*PI
/180.0;
1243 vertex
[0] = (arcPtr
->bbox
[0] + arcPtr
->bbox
[2])/2.0;
1244 vertex
[1] = (arcPtr
->bbox
[1] + arcPtr
->bbox
[3])/2.0;
1245 arcPtr
->center1
[0] = vertex
[0] + cos1
*boxWidth
/2.0;
1246 arcPtr
->center1
[1] = vertex
[1] + sin1
*boxHeight
/2.0;
1247 arcPtr
->center2
[0] = vertex
[0] + cos2
*boxWidth
/2.0;
1248 arcPtr
->center2
[1] = vertex
[1] + sin2
*boxHeight
/2.0;
1251 * Next compute the "outermost corners" of the arc, which are
1252 * marked with X's in the figure below:
1261 * The code below is tricky because it has to handle eccentricity
1262 * in the shape of the oval. The key in the code below is to
1263 * realize that the slope of the line from arcPtr->center1 to corner1
1264 * is (boxWidth*sin1)/(boxHeight*cos1), and similarly for arcPtr->center2
1265 * and corner2. These formulas can be computed from the formula for
1269 halfWidth
= arcPtr
->width
/2.0;
1270 angle
= atan2(boxWidth
*sin1
, boxHeight
*cos1
);
1271 corner1
[0] = arcPtr
->center1
[0] + cos(angle
)*halfWidth
;
1272 corner1
[1] = arcPtr
->center1
[1] + sin(angle
)*halfWidth
;
1273 angle
= atan2(boxWidth
*sin2
, boxHeight
*cos2
);
1274 corner2
[0] = arcPtr
->center2
[0] + cos(angle
)*halfWidth
;
1275 corner2
[1] = arcPtr
->center2
[1] + sin(angle
)*halfWidth
;
1278 * For a chord outline, generate a six-sided polygon with three
1279 * points for each end of the chord. The first and third points
1280 * for each end are butt points generated on either side of the
1281 * center point. The second point is the corner point.
1284 if (arcPtr
->style
== chordUid
) {
1285 outlinePtr
[0] = outlinePtr
[12] = corner1
[0];
1286 outlinePtr
[1] = outlinePtr
[13] = corner1
[1];
1287 TkGetButtPoints(arcPtr
->center2
, arcPtr
->center1
,
1288 (double) arcPtr
->width
, 0, outlinePtr
+10, outlinePtr
+2);
1289 outlinePtr
[4] = arcPtr
->center2
[0] + outlinePtr
[2]
1290 - arcPtr
->center1
[0];
1291 outlinePtr
[5] = arcPtr
->center2
[1] + outlinePtr
[3]
1292 - arcPtr
->center1
[1];
1293 outlinePtr
[6] = corner2
[0];
1294 outlinePtr
[7] = corner2
[1];
1295 outlinePtr
[8] = arcPtr
->center2
[0] + outlinePtr
[10]
1296 - arcPtr
->center1
[0];
1297 outlinePtr
[9] = arcPtr
->center2
[1] + outlinePtr
[11]
1298 - arcPtr
->center1
[1];
1299 } else if (arcPtr
->style
== pieSliceUid
) {
1301 * For pie slices, generate two polygons, one for each side
1302 * of the pie slice. The first arm has a shape like this,
1303 * where the center of the oval is X, arcPtr->center1 is at Y, and
1306 * _____________________
1311 * |_____________________/
1315 TkGetButtPoints(arcPtr
->center1
, vertex
, (double) arcPtr
->width
, 0,
1316 outlinePtr
, outlinePtr
+2);
1317 outlinePtr
[4] = arcPtr
->center1
[0] + outlinePtr
[2] - vertex
[0];
1318 outlinePtr
[5] = arcPtr
->center1
[1] + outlinePtr
[3] - vertex
[1];
1319 outlinePtr
[6] = corner1
[0];
1320 outlinePtr
[7] = corner1
[1];
1321 outlinePtr
[8] = arcPtr
->center1
[0] + outlinePtr
[0] - vertex
[0];
1322 outlinePtr
[9] = arcPtr
->center1
[1] + outlinePtr
[1] - vertex
[1];
1323 outlinePtr
[10] = outlinePtr
[0];
1324 outlinePtr
[11] = outlinePtr
[1];
1327 * The second arm has a shape like this:
1330 * ______________________
1335 * \______________________/
1337 * Similar to above X is the center of the oval/circle, Y is
1338 * arcPtr->center2, and Z is corner2. The extra jog out to the left
1339 * of X is needed in or to produce a butted joint with the
1340 * first arm; the corner to the right of X is one of the
1341 * first two points of the first arm, depending on extent.
1344 TkGetButtPoints(arcPtr
->center2
, vertex
, (double) arcPtr
->width
, 0,
1345 outlinePtr
+12, outlinePtr
+16);
1346 if ((arcPtr
->extent
> 180) ||
1347 ((arcPtr
->extent
< 0) && (arcPtr
->extent
> -180))) {
1348 outlinePtr
[14] = outlinePtr
[0];
1349 outlinePtr
[15] = outlinePtr
[1];
1351 outlinePtr
[14] = outlinePtr
[2];
1352 outlinePtr
[15] = outlinePtr
[3];
1354 outlinePtr
[18] = arcPtr
->center2
[0] + outlinePtr
[16] - vertex
[0];
1355 outlinePtr
[19] = arcPtr
->center2
[1] + outlinePtr
[17] - vertex
[1];
1356 outlinePtr
[20] = corner2
[0];
1357 outlinePtr
[21] = corner2
[1];
1358 outlinePtr
[22] = arcPtr
->center2
[0] + outlinePtr
[12] - vertex
[0];
1359 outlinePtr
[23] = arcPtr
->center2
[1] + outlinePtr
[13] - vertex
[1];
1360 outlinePtr
[24] = outlinePtr
[12];
1361 outlinePtr
[25] = outlinePtr
[13];
1366 *--------------------------------------------------------------
1370 * Determines whether a horizontal line segment intersects
1374 * The return value is 1 if the given line intersects the
1375 * infinitely-thin arc section defined by rx, ry, start,
1376 * and extent, and 0 otherwise. Only the perimeter of the
1377 * arc is checked: interior areas (e.g. pie-slice or chord)
1383 *--------------------------------------------------------------
1389 double x2
, /* X-coords of endpoints of line segment.
1390 * X1 must be <= x2. */
1391 double y
, /* Y-coordinate of line segment. */
1393 double ry
, /* These x- and y-radii define an oval
1394 * centered at the origin. */
1396 double extent
/* Angles that define extent of arc, in
1397 * the standard fashion for this module. */
1401 double tx
, ty
; /* Coordinates of intersection point in
1402 * transformed coordinate system. */
1406 * Compute the x-coordinate of one possible intersection point
1407 * between the arc and the line. Use a transformed coordinate
1408 * system where the oval is a unit circle centered at the origin.
1409 * Then scale back to get actual x-coordinate.
1421 * Test both intersection points.
1424 if ((x
>= x1
) && (x
<= x2
) && AngleInRange(tx
, ty
, start
, extent
)) {
1427 if ((-x
>= x1
) && (-x
<= x2
) && AngleInRange(-tx
, ty
, start
, extent
)) {
1434 *--------------------------------------------------------------
1438 * Determines whether a vertical line segment intersects
1442 * The return value is 1 if the given line intersects the
1443 * infinitely-thin arc section defined by rx, ry, start,
1444 * and extent, and 0 otherwise. Only the perimeter of the
1445 * arc is checked: interior areas (e.g. pie-slice or chord)
1451 *--------------------------------------------------------------
1456 double x
, /* X-coordinate of line segment. */
1458 double y2
, /* Y-coords of endpoints of line segment.
1459 * Y1 must be <= y2. */
1461 double ry
, /* These x- and y-radii define an oval
1462 * centered at the origin. */
1464 double extent
/* Angles that define extent of arc, in
1465 * the standard fashion for this module. */
1469 double tx
, ty
; /* Coordinates of intersection point in
1470 * transformed coordinate system. */
1474 * Compute the y-coordinate of one possible intersection point
1475 * between the arc and the line. Use a transformed coordinate
1476 * system where the oval is a unit circle centered at the origin.
1477 * Then scale back to get actual y-coordinate.
1489 * Test both intersection points.
1492 if ((y
> y1
) && (y
< y2
) && AngleInRange(tx
, ty
, start
, extent
)) {
1495 if ((-y
> y1
) && (-y
< y2
) && AngleInRange(tx
, -ty
, start
, extent
)) {
1502 *--------------------------------------------------------------
1506 * Determine whether the angle from the origin to a given
1507 * point is within a given range.
1510 * The return value is 1 if the angle from (0,0) to (x,y)
1511 * is in the range given by start and extent, where angles
1512 * are interpreted in the standard way for ovals (meaning
1513 * backwards from normal interpretation). Otherwise the
1514 * return value is 0.
1519 *--------------------------------------------------------------
1525 double y
, /* Coordinate of point; angle measured
1526 * from origin to here, relative to x-axis. */
1527 double start
, /* First angle, degrees, >=0, <=360. */
1528 double extent
/* Size of arc in degrees >=-360, <=360. */
1533 diff
= -atan2(y
, x
);
1534 diff
= diff
*(180.0/PI
) - start
;
1535 while (diff
> 360.0) {
1538 while (diff
< 0.0) {
1542 return diff
<= extent
;
1544 return (diff
-360.0) >= extent
;