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 *--------------------------------------------------------------
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. */
200 register ArcItem
*arcPtr
= (ArcItem
*) itemPtr
;
203 Tcl_AppendResult(canvasPtr
->interp
, "wrong # args: should be \"",
204 Tk_PathName(canvasPtr
->tkwin
), "\" create ",
205 itemPtr
->typePtr
->name
, " x1 y1 x2 y2 ?options?",
211 * Carry out once-only initialization.
214 if (arcUid
== NULL
) {
215 arcUid
= Tk_GetUid("arc");
216 chordUid
= Tk_GetUid("chord");
217 pieSliceUid
= Tk_GetUid("pieslice");
221 * Carry out initialization that is needed in order to clean
222 * up after errors during the the remainder of this procedure.
227 arcPtr
->outlinePtr
= NULL
;
228 arcPtr
->numOutlinePoints
= 0;
230 arcPtr
->outlineColor
= NULL
;
231 arcPtr
->fillColor
= NULL
;
232 arcPtr
->fillStipple
= None
;
233 arcPtr
->style
= pieSliceUid
;
234 arcPtr
->outlineGC
= None
;
235 arcPtr
->fillGC
= None
;
238 * Process the arguments to fill in the item record.
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
)) {
251 if (ConfigureArc(canvasPtr
, itemPtr
, argc
-4, argv
+4, 0) != TCL_OK
) {
259 *--------------------------------------------------------------
263 * This procedure is invoked to process the "coords" widget
264 * command on arcs. See the user documentation for details
268 * Returns TCL_OK or TCL_ERROR, and sets canvasPtr->interp->result.
271 * The coordinates for the given item may be changed.
273 *--------------------------------------------------------------
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
283 char **argv
; /* Array of coordinates: x1, y1,
286 register ArcItem
*arcPtr
= (ArcItem
*) itemPtr
;
290 sprintf(buffer
, "%g %g %g %g", arcPtr
->bbox
[0],
291 arcPtr
->bbox
[1], arcPtr
->bbox
[2],
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
)) {
305 ComputeArcBbox(canvasPtr
, arcPtr
);
307 sprintf(canvasPtr
->interp
->result
,
308 "wrong # coordinates: expected 0 or 4, got %d",
316 *--------------------------------------------------------------
320 * This procedure is invoked to configure various aspects
321 * of a arc item, such as its outline and fill colors.
324 * A standard Tcl result code. If an error occurs, then
325 * an error message is left in canvasPtr->interp->result.
328 * Configuration information, such as colors and stipple
329 * patterns, may be set for itemPtr.
331 *--------------------------------------------------------------
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. */
342 register ArcItem
*arcPtr
= (ArcItem
*) itemPtr
;
348 if (Tk_ConfigureWidget(canvasPtr
->interp
, canvasPtr
->tkwin
,
349 configSpecs
, argc
, argv
, (char *) arcPtr
, flags
) != TCL_OK
) {
354 * A few of the options require additional processing, such as
355 * style and graphics contexts.
358 i
= arcPtr
->start
/360.0;
359 arcPtr
->start
-= i
*360.0;
360 if (arcPtr
->start
< 0) {
361 arcPtr
->start
+= 360.0;
363 i
= arcPtr
->extent
/360.0;
364 arcPtr
->extent
-= i
*360.0;
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",
371 arcPtr
->style
= pieSliceUid
;
375 if (arcPtr
->width
< 0) {
378 if (arcPtr
->style
== arcUid
) {
379 if (arcPtr
->fillColor
== NULL
) {
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
;
391 newGC
= Tk_GetGC(canvasPtr
->tkwin
, mask
, &gcValues
);
393 } else if (arcPtr
->outlineColor
== NULL
) {
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
);
402 if (arcPtr
->outlineGC
!= None
) {
403 Tk_FreeGC(arcPtr
->outlineGC
);
405 arcPtr
->outlineGC
= newGC
;
407 if ((arcPtr
->fillColor
== NULL
) || (arcPtr
->style
== arcUid
)) {
410 gcValues
.foreground
= arcPtr
->fillColor
->pixel
;
411 if (arcPtr
->style
== chordUid
) {
412 gcValues
.arc_mode
= ArcChord
;
414 gcValues
.arc_mode
= ArcPieSlice
;
416 mask
= GCForeground
|GCArcMode
;
417 if (arcPtr
->fillStipple
!= None
) {
418 gcValues
.stipple
= arcPtr
->fillStipple
;
419 gcValues
.fill_style
= FillStippled
;
420 mask
|= GCStipple
|GCFillStyle
;
422 newGC
= Tk_GetGC(canvasPtr
->tkwin
, mask
, &gcValues
);
424 if (arcPtr
->fillGC
!= None
) {
425 Tk_FreeGC(arcPtr
->fillGC
);
427 arcPtr
->fillGC
= newGC
;
429 ComputeArcBbox(canvasPtr
, arcPtr
);
434 *--------------------------------------------------------------
438 * This procedure is called to clean up the data structure
439 * associated with a arc item.
445 * Resources associated with itemPtr are released.
447 *--------------------------------------------------------------
452 Tk_Item
*itemPtr
; /* Item that is being deleted. */
454 register ArcItem
*arcPtr
= (ArcItem
*) itemPtr
;
456 if (arcPtr
->numOutlinePoints
!= 0) {
457 ckfree((char *) arcPtr
->outlinePtr
);
459 if (arcPtr
->outlineColor
!= NULL
) {
460 Tk_FreeColor(arcPtr
->outlineColor
);
462 if (arcPtr
->fillColor
!= NULL
) {
463 Tk_FreeColor(arcPtr
->fillColor
);
465 if (arcPtr
->fillStipple
!= None
) {
466 Tk_FreeBitmap(arcPtr
->fillStipple
);
468 if (arcPtr
->outlineGC
!= None
) {
469 Tk_FreeGC(arcPtr
->outlineGC
);
471 if (arcPtr
->fillGC
!= None
) {
472 Tk_FreeGC(arcPtr
->fillGC
);
477 *--------------------------------------------------------------
481 * This procedure is invoked to compute the bounding box of
482 * all the pixels that may be drawn as part of an arc.
488 * The fields x1, y1, x2, and y2 are updated in the header
491 *--------------------------------------------------------------
496 ComputeArcBbox(canvasPtr
, arcPtr
)
497 register Tk_Canvas
*canvasPtr
; /* Canvas that contains item. */
498 register ArcItem
*arcPtr
; /* Item whose bbox is to be
501 double tmp
, center
[2], point
[2];
504 * Make sure that the first coordinates are the lowest ones.
507 if (arcPtr
->bbox
[1] > arcPtr
->bbox
[3]) {
509 tmp
= arcPtr
->bbox
[3];
510 arcPtr
->bbox
[3] = arcPtr
->bbox
[1];
511 arcPtr
->bbox
[1] = tmp
;
513 if (arcPtr
->bbox
[0] > arcPtr
->bbox
[2]) {
515 tmp
= arcPtr
->bbox
[2];
516 arcPtr
->bbox
[2] = arcPtr
->bbox
[0];
517 arcPtr
->bbox
[0] = tmp
;
520 ComputeArcOutline(arcPtr
);
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.
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
);
538 tmp
= -arcPtr
->start
;
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
);
547 tmp
= 90.0 - arcPtr
->start
;
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
);
556 tmp
= 180.0 - arcPtr
->start
;
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
);
565 tmp
= 270.0 - arcPtr
->start
;
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
);
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.
580 if (arcPtr
->outlineColor
== NULL
) {
583 tmp
= (arcPtr
->width
+ 1)/2 + 1;
585 arcPtr
->header
.x1
-= tmp
;
586 arcPtr
->header
.y1
-= tmp
;
587 arcPtr
->header
.x2
+= tmp
;
588 arcPtr
->header
.y2
+= tmp
;
592 *--------------------------------------------------------------
596 * This procedure is invoked to draw an arc item in a given
603 * ItemPtr is drawn in drawable using the transformation
604 * information in canvasPtr.
606 *--------------------------------------------------------------
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
616 register ArcItem
*arcPtr
= (ArcItem
*) itemPtr
;
617 Display
*display
= Tk_Display(canvasPtr
->tkwin
);
618 int x1
, y1
, x2
, y2
, start
, extent
;
621 * Compute the screen coordinates of the bounding box for the item,
622 * plus integer values for the angles.
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]);
635 start
= (64*arcPtr
->start
) + 0.5;
636 extent
= (64*arcPtr
->extent
) + 0.5;
639 * Display filled arc first (if wanted), then outline.
642 if (arcPtr
->fillGC
!= None
) {
643 XFillArc(display
, drawable
, arcPtr
->fillGC
, x1
, y1
, (x2
-x1
),
644 (y2
-y1
), start
, extent
);
646 if (arcPtr
->outlineGC
!= None
) {
647 XDrawArc(display
, drawable
, arcPtr
->outlineGC
, x1
, y1
, (x2
-x1
),
648 (y2
-y1
), start
, extent
);
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.
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]);
662 if (arcPtr
->style
== chordUid
) {
663 XDrawLine(display
, drawable
, arcPtr
->outlineGC
,
665 } else if (arcPtr
->style
== pieSliceUid
) {
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
,
672 XDrawLine(display
, drawable
, arcPtr
->outlineGC
,
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
);
691 *--------------------------------------------------------------
695 * Computes the distance from a given point to a given
696 * arc, in canvas units.
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.
710 *--------------------------------------------------------------
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. */
720 register ArcItem
*arcPtr
= (ArcItem
*) itemPtr
;
721 double vertex
[2], pointAngle
, diff
, dist
, newDist
;
722 double poly
[8], polyDist
, width
;
723 int filled
, angleInRange
;
725 if ((arcPtr
->fillGC
!= None
) || (arcPtr
->outlineGC
== None
)) {
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
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);
749 angleInRange
= (diff
<= arcPtr
->extent
) ||
750 ((arcPtr
->extent
< 0) && ((diff
- 360.0) >= arcPtr
->extent
));
753 * Now perform different tests depending on what kind of arc
754 * we're dealing with.
757 if (arcPtr
->style
== arcUid
) {
759 return TkOvalToPoint(arcPtr
->bbox
, (double) arcPtr
->width
,
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
) {
772 if ((arcPtr
->fillGC
!= None
) || (arcPtr
->outlineGC
== None
)) {
777 if (arcPtr
->outlineGC
== None
) {
780 width
= arcPtr
->width
;
783 if (arcPtr
->style
== pieSliceUid
) {
785 dist
= TkPolygonToPoint(arcPtr
->outlinePtr
, PIE_OUTLINE1_PTS
,
787 newDist
= TkPolygonToPoint(arcPtr
->outlinePtr
+ 2*PIE_OUTLINE1_PTS
,
788 PIE_OUTLINE2_PTS
, pointPtr
);
790 dist
= TkLineToPoint(vertex
, arcPtr
->center1
, pointPtr
);
791 newDist
= TkLineToPoint(vertex
, arcPtr
->center2
, pointPtr
);
793 if (newDist
< dist
) {
797 newDist
= TkOvalToPoint(arcPtr
->bbox
, width
, filled
, pointPtr
);
798 if (newDist
< dist
) {
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).
815 dist
= TkPolygonToPoint(arcPtr
->outlinePtr
, CHORD_OUTLINE_PTS
,
818 dist
= TkLineToPoint(arcPtr
->center1
, arcPtr
->center2
, pointPtr
);
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
);
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
) {
836 if ((arcPtr
->extent
< -180.0) || (arcPtr
->extent
> 180.0)) {
837 if (filled
&& (polyDist
< dist
)) {
846 *--------------------------------------------------------------
850 * This procedure is called to determine whether an item
851 * lies entirely inside, entirely outside, or overlapping
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.
862 *--------------------------------------------------------------
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
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
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
889 if ((arcPtr
->fillGC
!= None
) || (arcPtr
->outlineGC
== None
)) {
894 if (arcPtr
->outlineGC
== None
) {
897 width
= arcPtr
->width
;
901 * Transform both the arc and the rectangle so that the arc's oval
902 * is centered on the origin.
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;
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:
921 * 1. The outside points of the arc, corresponding to start and
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).
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
);
939 if ((arcPtr
->style
== pieSliceUid
) && (arcPtr
->extent
< 180.0)) {
946 tmp
= -arcPtr
->start
;
950 if ((tmp
< arcPtr
->extent
) || ((tmp
-360) > arcPtr
->extent
)) {
956 tmp
= 90.0 - arcPtr
->start
;
960 if ((tmp
< arcPtr
->extent
) || ((tmp
-360) > arcPtr
->extent
)) {
966 tmp
= 180.0 - arcPtr
->start
;
970 if ((tmp
< arcPtr
->extent
) || ((tmp
-360) > arcPtr
->extent
)) {
976 tmp
= 270.0 - arcPtr
->start
;
980 if ((tmp
< arcPtr
->extent
) || ((tmp
-360) > arcPtr
->extent
)) {
988 * Now that we've located the extreme points, loop through them all
989 * to see which are inside the rectangle.
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
) {
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.
1014 if (arcPtr
->style
== pieSliceUid
) {
1016 if (TkPolygonToArea(arcPtr
->outlinePtr
, PIE_OUTLINE1_PTS
,
1020 if (TkPolygonToArea(arcPtr
->outlinePtr
+ 2*PIE_OUTLINE1_PTS
,
1021 PIE_OUTLINE2_PTS
, rectPtr
) != -1) {
1025 if ((TkLineToArea(center
, arcPtr
->center1
, rectPtr
) != -1) ||
1026 (TkLineToArea(center
, arcPtr
->center2
, rectPtr
) != -1)) {
1030 } else if (arcPtr
->style
== chordUid
) {
1032 if (TkPolygonToArea(arcPtr
->outlinePtr
, CHORD_OUTLINE_PTS
,
1037 if (TkLineToArea(arcPtr
->center1
, arcPtr
->center2
,
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.
1050 if (HorizLineToArc(tRect
[0], tRect
[2], tRect
[1], rx
, ry
, arcPtr
->start
,
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
)) {
1060 if ((width
> 1.0) && !filled
) {
1063 if (HorizLineToArc(tRect
[0], tRect
[2], tRect
[1], rx
, ry
, arcPtr
->start
,
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
)) {
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.
1083 if (ArcToPoint(canvasPtr
, itemPtr
, rectPtr
) == 0.0) {
1090 *--------------------------------------------------------------
1094 * This procedure is invoked to rescale an arc item.
1100 * The arc referred to by itemPtr is rescaled so that the
1101 * following transformation is applied to all point
1103 * x' = originX + scaleX*(x-originX)
1104 * y' = originY + scaleY*(y-originY)
1106 *--------------------------------------------------------------
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. */
1117 register ArcItem
*arcPtr
= (ArcItem
*) itemPtr
;
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
);
1127 *--------------------------------------------------------------
1131 * This procedure is called to move an arc by a given amount.
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
1141 *--------------------------------------------------------------
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
1151 register ArcItem
*arcPtr
= (ArcItem
*) itemPtr
;
1153 arcPtr
->bbox
[0] += deltaX
;
1154 arcPtr
->bbox
[1] += deltaY
;
1155 arcPtr
->bbox
[2] += deltaX
;
1156 arcPtr
->bbox
[3] += deltaY
;
1157 ComputeArcBbox(canvasPtr
, arcPtr
);
1161 *--------------------------------------------------------------
1163 * ComputeArcOutline --
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.
1175 * The information at arcPtr->outlinePtr gets modified, and
1176 * storage for arcPtr->outlinePtr may be allocated or freed.
1178 *--------------------------------------------------------------
1182 ComputeArcOutline(arcPtr
)
1183 register ArcItem
*arcPtr
;
1185 double sin1
, cos1
, sin2
, cos2
, angle
, halfWidth
;
1186 double boxWidth
, boxHeight
;
1187 double vertex
[2], corner1
[2], corner2
[2];
1191 * Make sure that the outlinePtr array is large enough to hold
1192 * either a chord or pie-slice outline.
1195 if (arcPtr
->numOutlinePoints
== 0) {
1196 arcPtr
->outlinePtr
= (double *) ckalloc((unsigned)
1197 (26 * sizeof(double)));
1198 arcPtr
->numOutlinePoints
= 22;
1200 outlinePtr
= arcPtr
->outlinePtr
;
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:
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.
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.
1224 boxWidth
= arcPtr
->bbox
[2] - arcPtr
->bbox
[0];
1225 boxHeight
= arcPtr
->bbox
[3] - arcPtr
->bbox
[1];
1226 angle
= -arcPtr
->start
*PI
/180.0;
1229 angle
-= arcPtr
->extent
*PI
/180.0;
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;
1240 * Next compute the "outermost corners" of the arc, which are
1241 * marked with X's in the figure below:
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
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
;
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.
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
) {
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
1295 * _____________________
1300 * |_____________________/
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];
1316 * The second arm has a shape like this:
1319 * ______________________
1324 * \______________________/
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.
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];
1340 outlinePtr
[14] = outlinePtr
[2];
1341 outlinePtr
[15] = outlinePtr
[3];
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];
1355 *--------------------------------------------------------------
1359 * Determines whether a horizontal line segment intersects
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)
1372 *--------------------------------------------------------------
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. */
1386 double tx
, ty
; /* Coordinates of intersection point in
1387 * transformed coordinate system. */
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.
1406 * Test both intersection points.
1409 if ((x
>= x1
) && (x
<= x2
) && AngleInRange(tx
, ty
, start
, extent
)) {
1412 if ((-x
>= x1
) && (-x
<= x2
) && AngleInRange(-tx
, ty
, start
, extent
)) {
1419 *--------------------------------------------------------------
1423 * Determines whether a vertical line segment intersects
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)
1436 *--------------------------------------------------------------
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. */
1450 double tx
, ty
; /* Coordinates of intersection point in
1451 * transformed coordinate system. */
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.
1470 * Test both intersection points.
1473 if ((y
> y1
) && (y
< y2
) && AngleInRange(tx
, ty
, start
, extent
)) {
1476 if ((-y
> y1
) && (-y
< y2
) && AngleInRange(tx
, -ty
, start
, extent
)) {
1483 *--------------------------------------------------------------
1487 * Determine whether the angle from the origin to a given
1488 * point is within a given range.
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.
1500 *--------------------------------------------------------------
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. */
1512 diff
= -atan2(y
, x
);
1513 diff
= diff
*(180.0/PI
) - start
;
1514 while (diff
> 360.0) {
1517 while (diff
< 0.0) {
1521 return diff
<= extent
;
1523 return (diff
-360.0) >= extent
;