]> git.zerfleddert.de Git - micropolis/blob - src/tk/tkcvarc.c
Fixes for compilation with gcc 15
[micropolis] / src / tk / tkcvarc.c
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 \f
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 (
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 {
201 register ArcItem *arcPtr = (ArcItem *) itemPtr;
202
203 if (argc < 4) {
204 Tcl_AppendResult(canvasPtr->interp, "wrong # args: should be \"",
205 Tk_PathName(canvasPtr->tkwin), "\" create ",
206 itemPtr->typePtr->name, " x1 y1 x2 y2 ?options?",
207 (char *) NULL);
208 return TCL_ERROR;
209 }
210
211 /*
212 * Carry out once-only initialization.
213 */
214
215 if (arcUid == NULL) {
216 arcUid = Tk_GetUid("arc");
217 chordUid = Tk_GetUid("chord");
218 pieSliceUid = Tk_GetUid("pieslice");
219 }
220
221 /*
222 * Carry out initialization that is needed in order to clean
223 * up after errors during the the remainder of this procedure.
224 */
225
226 arcPtr->start = 0;
227 arcPtr->extent = 90;
228 arcPtr->outlinePtr = NULL;
229 arcPtr->numOutlinePoints = 0;
230 arcPtr->width = 1;
231 arcPtr->outlineColor = NULL;
232 arcPtr->fillColor = NULL;
233 arcPtr->fillStipple = None;
234 arcPtr->style = pieSliceUid;
235 arcPtr->outlineGC = None;
236 arcPtr->fillGC = None;
237
238 /*
239 * Process the arguments to fill in the item record.
240 */
241
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)) {
249 return TCL_ERROR;
250 }
251
252 if (ConfigureArc(canvasPtr, itemPtr, argc-4, argv+4, 0) != TCL_OK) {
253 DeleteArc(itemPtr);
254 return TCL_ERROR;
255 }
256 return TCL_OK;
257 }
258 \f
259 /*
260 *--------------------------------------------------------------
261 *
262 * ArcCoords --
263 *
264 * This procedure is invoked to process the "coords" widget
265 * command on arcs. See the user documentation for details
266 * on what it does.
267 *
268 * Results:
269 * Returns TCL_OK or TCL_ERROR, and sets canvasPtr->interp->result.
270 *
271 * Side effects:
272 * The coordinates for the given item may be changed.
273 *
274 *--------------------------------------------------------------
275 */
276
277 static int
278 ArcCoords (
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
283 * argv. */
284 char **argv /* Array of coordinates: x1, y1,
285 * x2, y2, ... */
286 )
287 {
288 register ArcItem *arcPtr = (ArcItem *) itemPtr;
289 char buffer[500];
290
291 if (argc == 0) {
292 sprintf(buffer, "%g %g %g %g", arcPtr->bbox[0],
293 arcPtr->bbox[1], arcPtr->bbox[2],
294 arcPtr->bbox[3]);
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)) {
305 return TCL_ERROR;
306 }
307 ComputeArcBbox(canvasPtr, arcPtr);
308 } else {
309 sprintf(canvasPtr->interp->result,
310 "wrong # coordinates: expected 0 or 4, got %d",
311 argc);
312 return TCL_ERROR;
313 }
314 return TCL_OK;
315 }
316 \f
317 /*
318 *--------------------------------------------------------------
319 *
320 * ConfigureArc --
321 *
322 * This procedure is invoked to configure various aspects
323 * of a arc item, such as its outline and fill colors.
324 *
325 * Results:
326 * A standard Tcl result code. If an error occurs, then
327 * an error message is left in canvasPtr->interp->result.
328 *
329 * Side effects:
330 * Configuration information, such as colors and stipple
331 * patterns, may be set for itemPtr.
332 *
333 *--------------------------------------------------------------
334 */
335
336 static int
337 ConfigureArc (
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. */
343 )
344 {
345 register ArcItem *arcPtr = (ArcItem *) itemPtr;
346 XGCValues gcValues;
347 GC newGC;
348 unsigned long mask;
349 int i;
350
351 if (Tk_ConfigureWidget(canvasPtr->interp, canvasPtr->tkwin,
352 configSpecs, argc, argv, (char *) arcPtr, flags) != TCL_OK) {
353 return TCL_ERROR;
354 }
355
356 /*
357 * A few of the options require additional processing, such as
358 * style and graphics contexts.
359 */
360
361 i = arcPtr->start/360.0;
362 arcPtr->start -= i*360.0;
363 if (arcPtr->start < 0) {
364 arcPtr->start += 360.0;
365 }
366 i = arcPtr->extent/360.0;
367 arcPtr->extent -= i*360.0;
368
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",
373 (char *) NULL);
374 arcPtr->style = pieSliceUid;
375 return TCL_ERROR;
376 }
377
378 if (arcPtr->width < 0) {
379 arcPtr->width = 1;
380 }
381 if (arcPtr->style == arcUid) {
382 if (arcPtr->fillColor == NULL) {
383 newGC = None;
384 } else {
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;
393 }
394 newGC = Tk_GetGC(canvasPtr->tkwin, mask, &gcValues);
395 }
396 } else if (arcPtr->outlineColor == NULL) {
397 newGC = None;
398 } else {
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);
404 }
405 if (arcPtr->outlineGC != None) {
406 Tk_FreeGC(arcPtr->outlineGC);
407 }
408 arcPtr->outlineGC = newGC;
409
410 if ((arcPtr->fillColor == NULL) || (arcPtr->style == arcUid)) {
411 newGC = None;
412 } else {
413 gcValues.foreground = arcPtr->fillColor->pixel;
414 if (arcPtr->style == chordUid) {
415 gcValues.arc_mode = ArcChord;
416 } else {
417 gcValues.arc_mode = ArcPieSlice;
418 }
419 mask = GCForeground|GCArcMode;
420 if (arcPtr->fillStipple != None) {
421 gcValues.stipple = arcPtr->fillStipple;
422 gcValues.fill_style = FillStippled;
423 mask |= GCStipple|GCFillStyle;
424 }
425 newGC = Tk_GetGC(canvasPtr->tkwin, mask, &gcValues);
426 }
427 if (arcPtr->fillGC != None) {
428 Tk_FreeGC(arcPtr->fillGC);
429 }
430 arcPtr->fillGC = newGC;
431
432 ComputeArcBbox(canvasPtr, arcPtr);
433 return TCL_OK;
434 }
435 \f
436 /*
437 *--------------------------------------------------------------
438 *
439 * DeleteArc --
440 *
441 * This procedure is called to clean up the data structure
442 * associated with a arc item.
443 *
444 * Results:
445 * None.
446 *
447 * Side effects:
448 * Resources associated with itemPtr are released.
449 *
450 *--------------------------------------------------------------
451 */
452
453 static void
454 DeleteArc (
455 Tk_Item *itemPtr /* Item that is being deleted. */
456 )
457 {
458 register ArcItem *arcPtr = (ArcItem *) itemPtr;
459
460 if (arcPtr->numOutlinePoints != 0) {
461 ckfree((char *) arcPtr->outlinePtr);
462 }
463 if (arcPtr->outlineColor != NULL) {
464 Tk_FreeColor(arcPtr->outlineColor);
465 }
466 if (arcPtr->fillColor != NULL) {
467 Tk_FreeColor(arcPtr->fillColor);
468 }
469 if (arcPtr->fillStipple != None) {
470 Tk_FreeBitmap(arcPtr->fillStipple);
471 }
472 if (arcPtr->outlineGC != None) {
473 Tk_FreeGC(arcPtr->outlineGC);
474 }
475 if (arcPtr->fillGC != None) {
476 Tk_FreeGC(arcPtr->fillGC);
477 }
478 }
479 \f
480 /*
481 *--------------------------------------------------------------
482 *
483 * ComputeArcBbox --
484 *
485 * This procedure is invoked to compute the bounding box of
486 * all the pixels that may be drawn as part of an arc.
487 *
488 * Results:
489 * None.
490 *
491 * Side effects:
492 * The fields x1, y1, x2, and y2 are updated in the header
493 * for itemPtr.
494 *
495 *--------------------------------------------------------------
496 */
497
498 /* ARGSUSED */
499 static void
500 ComputeArcBbox (
501 register Tk_Canvas *canvasPtr, /* Canvas that contains item. */
502 register ArcItem *arcPtr /* Item whose bbox is to be
503 * recomputed. */
504 )
505 {
506 double tmp, center[2], point[2];
507
508 /*
509 * Make sure that the first coordinates are the lowest ones.
510 */
511
512 if (arcPtr->bbox[1] > arcPtr->bbox[3]) {
513 double tmp;
514 tmp = arcPtr->bbox[3];
515 arcPtr->bbox[3] = arcPtr->bbox[1];
516 arcPtr->bbox[1] = tmp;
517 }
518 if (arcPtr->bbox[0] > arcPtr->bbox[2]) {
519 double tmp;
520 tmp = arcPtr->bbox[2];
521 arcPtr->bbox[2] = arcPtr->bbox[0];
522 arcPtr->bbox[0] = tmp;
523 }
524
525 ComputeArcOutline(arcPtr);
526
527 /*
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.
532 */
533
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);
541 }
542
543 tmp = -arcPtr->start;
544 if (tmp < 0) {
545 tmp += 360.0;
546 }
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);
551 }
552 tmp = 90.0 - arcPtr->start;
553 if (tmp < 0) {
554 tmp += 360.0;
555 }
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);
560 }
561 tmp = 180.0 - arcPtr->start;
562 if (tmp < 0) {
563 tmp += 360.0;
564 }
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);
569 }
570 tmp = 270.0 - arcPtr->start;
571 if (tmp < 0) {
572 tmp += 360.0;
573 }
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);
578 }
579
580 /*
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.
583 */
584
585 if (arcPtr->outlineColor == NULL) {
586 tmp = 1;
587 } else {
588 tmp = (arcPtr->width + 1)/2 + 1;
589 }
590 arcPtr->header.x1 -= tmp;
591 arcPtr->header.y1 -= tmp;
592 arcPtr->header.x2 += tmp;
593 arcPtr->header.y2 += tmp;
594 }
595 \f
596 /*
597 *--------------------------------------------------------------
598 *
599 * DisplayArc --
600 *
601 * This procedure is invoked to draw an arc item in a given
602 * drawable.
603 *
604 * Results:
605 * None.
606 *
607 * Side effects:
608 * ItemPtr is drawn in drawable using the transformation
609 * information in canvasPtr.
610 *
611 *--------------------------------------------------------------
612 */
613
614 static void
615 DisplayArc (
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
619 * item. */
620 )
621 {
622 register ArcItem *arcPtr = (ArcItem *) itemPtr;
623 Display *display = Tk_Display(canvasPtr->tkwin);
624 int x1, y1, x2, y2, start, extent;
625
626 /*
627 * Compute the screen coordinates of the bounding box for the item,
628 * plus integer values for the angles.
629 */
630
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]);
635 if (x2 <= x1) {
636 x2 = x1+1;
637 }
638 if (y2 <= y1) {
639 y2 = y1+1;
640 }
641 start = (64*arcPtr->start) + 0.5;
642 extent = (64*arcPtr->extent) + 0.5;
643
644 /*
645 * Display filled arc first (if wanted), then outline.
646 */
647
648 if (arcPtr->fillGC != None) {
649 XFillArc(display, drawable, arcPtr->fillGC, x1, y1, (x2-x1),
650 (y2-y1), start, extent);
651 }
652 if (arcPtr->outlineGC != None) {
653 XDrawArc(display, drawable, arcPtr->outlineGC, x1, y1, (x2-x1),
654 (y2-y1), start, extent);
655
656 /*
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.
660 */
661
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]);
667
668 if (arcPtr->style == chordUid) {
669 XDrawLine(display, drawable, arcPtr->outlineGC,
670 x1, y1, x2, y2);
671 } else if (arcPtr->style == pieSliceUid) {
672 int cx, cy;
673
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,
677 cx, cy, x1, y1);
678 XDrawLine(display, drawable, arcPtr->outlineGC,
679 cx, cy, x2, y2);
680 }
681 } else {
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);
691 }
692 }
693 }
694 }
695 \f
696 /*
697 *--------------------------------------------------------------
698 *
699 * ArcToPoint --
700 *
701 * Computes the distance from a given point to a given
702 * arc, in canvas units.
703 *
704 * Results:
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.
712 *
713 * Side effects:
714 * None.
715 *
716 *--------------------------------------------------------------
717 */
718
719 /* ARGSUSED */
720 static double
721 ArcToPoint (
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. */
725 )
726 {
727 register ArcItem *arcPtr = (ArcItem *) itemPtr;
728 double vertex[2], pointAngle, diff, dist, newDist;
729 double poly[8], polyDist, width;
730 int filled, angleInRange;
731
732 if ((arcPtr->fillGC != None) || (arcPtr->outlineGC == None)) {
733 filled = 1;
734 } else {
735 filled = 0;
736 }
737
738 /*
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
742 * the oval.
743 */
744
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);
753 if (diff < 0) {
754 diff += 360.0;
755 }
756 angleInRange = (diff <= arcPtr->extent) ||
757 ((arcPtr->extent < 0) && ((diff - 360.0) >= arcPtr->extent));
758
759 /*
760 * Now perform different tests depending on what kind of arc
761 * we're dealing with.
762 */
763
764 if (arcPtr->style == arcUid) {
765 if (angleInRange) {
766 return TkOvalToPoint(arcPtr->bbox, (double) arcPtr->width,
767 0, pointPtr);
768 }
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) {
774 return newDist;
775 }
776 return dist;
777 }
778
779 if ((arcPtr->fillGC != None) || (arcPtr->outlineGC == None)) {
780 filled = 1;
781 } else {
782 filled = 0;
783 }
784 if (arcPtr->outlineGC == None) {
785 width = 0.0;
786 } else {
787 width = arcPtr->width;
788 }
789
790 if (arcPtr->style == pieSliceUid) {
791 if (width > 1.0) {
792 dist = TkPolygonToPoint(arcPtr->outlinePtr, PIE_OUTLINE1_PTS,
793 pointPtr);
794 newDist = TkPolygonToPoint(arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS,
795 PIE_OUTLINE2_PTS, pointPtr);
796 } else {
797 dist = TkLineToPoint(vertex, arcPtr->center1, pointPtr);
798 newDist = TkLineToPoint(vertex, arcPtr->center2, pointPtr);
799 }
800 if (newDist < dist) {
801 dist = newDist;
802 }
803 if (angleInRange) {
804 newDist = TkOvalToPoint(arcPtr->bbox, width, filled, pointPtr);
805 if (newDist < dist) {
806 dist = newDist;
807 }
808 }
809 return dist;
810 }
811
812 /*
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).
819 */
820
821 if (width > 1.0) {
822 dist = TkPolygonToPoint(arcPtr->outlinePtr, CHORD_OUTLINE_PTS,
823 pointPtr);
824 } else {
825 dist = TkLineToPoint(arcPtr->center1, arcPtr->center2, pointPtr);
826 }
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);
834 if (angleInRange) {
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) {
839 dist = newDist;
840 }
841 }
842 } else {
843 if ((arcPtr->extent < -180.0) || (arcPtr->extent > 180.0)) {
844 if (filled && (polyDist < dist)) {
845 dist = polyDist;
846 }
847 }
848 }
849 return dist;
850 }
851 \f
852 /*
853 *--------------------------------------------------------------
854 *
855 * ArcToArea --
856 *
857 * This procedure is called to determine whether an item
858 * lies entirely inside, entirely outside, or overlapping
859 * a given area.
860 *
861 * Results:
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.
865 *
866 * Side effects:
867 * None.
868 *
869 *--------------------------------------------------------------
870 */
871
872 /* ARGSUSED */
873 static int
874 ArcToArea (
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
879 * area. */
880 )
881 {
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
887 * on the origin. */
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
894 * of rectangle. */
895 int newInside;
896
897 if ((arcPtr->fillGC != None) || (arcPtr->outlineGC == None)) {
898 filled = 1;
899 } else {
900 filled = 0;
901 }
902 if (arcPtr->outlineGC == None) {
903 width = 0.0;
904 } else {
905 width = arcPtr->width;
906 }
907
908 /*
909 * Transform both the arc and the rectangle so that the arc's oval
910 * is centered on the origin.
911 */
912
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;
921
922 /*
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:
928 *
929 * 1. The outside points of the arc, corresponding to start and
930 * extent.
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).
934 */
935
936 pointPtr = points;
937 numPoints = 0;
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);
944 numPoints = 2;
945 pointPtr += 4;
946
947 if ((arcPtr->style == pieSliceUid) && (arcPtr->extent < 180.0)) {
948 pointPtr[0] = 0.0;
949 pointPtr[1] = 0.0;
950 numPoints++;
951 pointPtr += 2;
952 }
953
954 tmp = -arcPtr->start;
955 if (tmp < 0) {
956 tmp += 360.0;
957 }
958 if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
959 pointPtr[0] = rx;
960 pointPtr[1] = 0.0;
961 numPoints++;
962 pointPtr += 2;
963 }
964 tmp = 90.0 - arcPtr->start;
965 if (tmp < 0) {
966 tmp += 360.0;
967 }
968 if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
969 pointPtr[0] = 0.0;
970 pointPtr[1] = -ry;
971 numPoints++;
972 pointPtr += 2;
973 }
974 tmp = 180.0 - arcPtr->start;
975 if (tmp < 0) {
976 tmp += 360.0;
977 }
978 if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
979 pointPtr[0] = -rx;
980 pointPtr[1] = 0.0;
981 numPoints++;
982 pointPtr += 2;
983 }
984 tmp = 270.0 - arcPtr->start;
985 if (tmp < 0) {
986 tmp += 360.0;
987 }
988 if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
989 pointPtr[0] = 0.0;
990 pointPtr[1] = ry;
991 numPoints++;
992 pointPtr += 2;
993 }
994
995 /*
996 * Now that we've located the extreme points, loop through them all
997 * to see which are inside the rectangle.
998 */
999
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) {
1006 return 0;
1007 }
1008 }
1009
1010 if (inside) {
1011 return 1;
1012 }
1013
1014 /*
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.
1020 */
1021
1022 if (arcPtr->style == pieSliceUid) {
1023 if (width >= 1.0) {
1024 if (TkPolygonToArea(arcPtr->outlinePtr, PIE_OUTLINE1_PTS,
1025 rectPtr) != -1) {
1026 return 0;
1027 }
1028 if (TkPolygonToArea(arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS,
1029 PIE_OUTLINE2_PTS, rectPtr) != -1) {
1030 return 0;
1031 }
1032 } else {
1033 if ((TkLineToArea(center, arcPtr->center1, rectPtr) != -1) ||
1034 (TkLineToArea(center, arcPtr->center2, rectPtr) != -1)) {
1035 return 0;
1036 }
1037 }
1038 } else if (arcPtr->style == chordUid) {
1039 if (width >= 1.0) {
1040 if (TkPolygonToArea(arcPtr->outlinePtr, CHORD_OUTLINE_PTS,
1041 rectPtr) != -1) {
1042 return 0;
1043 }
1044 } else {
1045 if (TkLineToArea(arcPtr->center1, arcPtr->center2,
1046 rectPtr) != -1) {
1047 return 0;
1048 }
1049 }
1050 }
1051
1052 /*
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.
1056 */
1057
1058 if (HorizLineToArc(tRect[0], tRect[2], tRect[1], rx, ry, arcPtr->start,
1059 arcPtr->extent)
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)) {
1066 return 0;
1067 }
1068 if ((width > 1.0) && !filled) {
1069 rx -= width;
1070 ry -= width;
1071 if (HorizLineToArc(tRect[0], tRect[2], tRect[1], rx, ry, arcPtr->start,
1072 arcPtr->extent)
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)) {
1079 return 0;
1080 }
1081 }
1082
1083 /*
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.
1089 */
1090
1091 if (ArcToPoint(canvasPtr, itemPtr, rectPtr) == 0.0) {
1092 return 0;
1093 }
1094 return -1;
1095 }
1096 \f
1097 /*
1098 *--------------------------------------------------------------
1099 *
1100 * ScaleArc --
1101 *
1102 * This procedure is invoked to rescale an arc item.
1103 *
1104 * Results:
1105 * None.
1106 *
1107 * Side effects:
1108 * The arc referred to by itemPtr is rescaled so that the
1109 * following transformation is applied to all point
1110 * coordinates:
1111 * x' = originX + scaleX*(x-originX)
1112 * y' = originY + scaleY*(y-originY)
1113 *
1114 *--------------------------------------------------------------
1115 */
1116
1117 static void
1118 ScaleArc (
1119 Tk_Canvas *canvasPtr, /* Canvas containing arc. */
1120 Tk_Item *itemPtr, /* Arc to be scaled. */
1121 double originX,
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. */
1125 )
1126 {
1127 register ArcItem *arcPtr = (ArcItem *) itemPtr;
1128
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);
1134 }
1135 \f
1136 /*
1137 *--------------------------------------------------------------
1138 *
1139 * TranslateArc --
1140 *
1141 * This procedure is called to move an arc by a given amount.
1142 *
1143 * Results:
1144 * None.
1145 *
1146 * Side effects:
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
1149 * structure.
1150 *
1151 *--------------------------------------------------------------
1152 */
1153
1154 static void
1155 TranslateArc (
1156 Tk_Canvas *canvasPtr, /* Canvas containing item. */
1157 Tk_Item *itemPtr, /* Item that is being moved. */
1158 double deltaX,
1159 double deltaY /* Amount by which item is to be
1160 * moved. */
1161 )
1162 {
1163 register ArcItem *arcPtr = (ArcItem *) itemPtr;
1164
1165 arcPtr->bbox[0] += deltaX;
1166 arcPtr->bbox[1] += deltaY;
1167 arcPtr->bbox[2] += deltaX;
1168 arcPtr->bbox[3] += deltaY;
1169 ComputeArcBbox(canvasPtr, arcPtr);
1170 }
1171 \f
1172 /*
1173 *--------------------------------------------------------------
1174 *
1175 * ComputeArcOutline --
1176 *
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.
1182 *
1183 * Results:
1184 * None.
1185 *
1186 * Side effects:
1187 * The information at arcPtr->outlinePtr gets modified, and
1188 * storage for arcPtr->outlinePtr may be allocated or freed.
1189 *
1190 *--------------------------------------------------------------
1191 */
1192
1193 static void
1194 ComputeArcOutline (register ArcItem *arcPtr)
1195 {
1196 double sin1, cos1, sin2, cos2, angle, halfWidth;
1197 double boxWidth, boxHeight;
1198 double vertex[2], corner1[2], corner2[2];
1199 double *outlinePtr;
1200
1201 /*
1202 * Make sure that the outlinePtr array is large enough to hold
1203 * either a chord or pie-slice outline.
1204 */
1205
1206 if (arcPtr->numOutlinePoints == 0) {
1207 arcPtr->outlinePtr = (double *) ckalloc((unsigned)
1208 (26 * sizeof(double)));
1209 arcPtr->numOutlinePoints = 22;
1210 }
1211 outlinePtr = arcPtr->outlinePtr;
1212
1213 /*
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:
1217 *
1218 *
1219 * * * *
1220 * * *
1221 * * * * *
1222 * * * * *
1223 * * * * *
1224 * X * * X
1225 *
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.
1229 *
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.
1233 */
1234
1235 boxWidth = arcPtr->bbox[2] - arcPtr->bbox[0];
1236 boxHeight = arcPtr->bbox[3] - arcPtr->bbox[1];
1237 angle = -arcPtr->start*PI/180.0;
1238 sin1 = sin(angle);
1239 cos1 = cos(angle);
1240 angle -= arcPtr->extent*PI/180.0;
1241 sin2 = sin(angle);
1242 cos2 = cos(angle);
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;
1249
1250 /*
1251 * Next compute the "outermost corners" of the arc, which are
1252 * marked with X's in the figure below:
1253 *
1254 * * * *
1255 * * *
1256 * * * * *
1257 * * * * *
1258 * X * * X
1259 * * *
1260 *
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
1266 * the oval.
1267 */
1268
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;
1276
1277 /*
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.
1282 */
1283
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) {
1300 /*
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
1304 * corner1 is at Z:
1305 *
1306 * _____________________
1307 * | \
1308 * | \
1309 * X Y Z
1310 * | /
1311 * |_____________________/
1312 *
1313 */
1314
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];
1325
1326 /*
1327 * The second arm has a shape like this:
1328 *
1329 *
1330 * ______________________
1331 * / \
1332 * / \
1333 * Z Y X /
1334 * \ /
1335 * \______________________/
1336 *
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.
1342 */
1343
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];
1350 } else {
1351 outlinePtr[14] = outlinePtr[2];
1352 outlinePtr[15] = outlinePtr[3];
1353 }
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];
1362 }
1363 }
1364 \f
1365 /*
1366 *--------------------------------------------------------------
1367 *
1368 * HorizLineToArc --
1369 *
1370 * Determines whether a horizontal line segment intersects
1371 * a given arc.
1372 *
1373 * Results:
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)
1378 * are not checked.
1379 *
1380 * Side effects:
1381 * None.
1382 *
1383 *--------------------------------------------------------------
1384 */
1385
1386 static int
1387 HorizLineToArc (
1388 double x1,
1389 double x2, /* X-coords of endpoints of line segment.
1390 * X1 must be <= x2. */
1391 double y, /* Y-coordinate of line segment. */
1392 double rx,
1393 double ry, /* These x- and y-radii define an oval
1394 * centered at the origin. */
1395 double start,
1396 double extent /* Angles that define extent of arc, in
1397 * the standard fashion for this module. */
1398 )
1399 {
1400 double tmp;
1401 double tx, ty; /* Coordinates of intersection point in
1402 * transformed coordinate system. */
1403 double x;
1404
1405 /*
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.
1410 */
1411
1412 ty = y/ry;
1413 tmp = 1 - ty*ty;
1414 if (tmp < 0) {
1415 return 0;
1416 }
1417 tx = sqrt(tmp);
1418 x = tx*rx;
1419
1420 /*
1421 * Test both intersection points.
1422 */
1423
1424 if ((x >= x1) && (x <= x2) && AngleInRange(tx, ty, start, extent)) {
1425 return 1;
1426 }
1427 if ((-x >= x1) && (-x <= x2) && AngleInRange(-tx, ty, start, extent)) {
1428 return 1;
1429 }
1430 return 0;
1431 }
1432 \f
1433 /*
1434 *--------------------------------------------------------------
1435 *
1436 * VertLineToArc --
1437 *
1438 * Determines whether a vertical line segment intersects
1439 * a given arc.
1440 *
1441 * Results:
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)
1446 * are not checked.
1447 *
1448 * Side effects:
1449 * None.
1450 *
1451 *--------------------------------------------------------------
1452 */
1453
1454 static int
1455 VertLineToArc (
1456 double x, /* X-coordinate of line segment. */
1457 double y1,
1458 double y2, /* Y-coords of endpoints of line segment.
1459 * Y1 must be <= y2. */
1460 double rx,
1461 double ry, /* These x- and y-radii define an oval
1462 * centered at the origin. */
1463 double start,
1464 double extent /* Angles that define extent of arc, in
1465 * the standard fashion for this module. */
1466 )
1467 {
1468 double tmp;
1469 double tx, ty; /* Coordinates of intersection point in
1470 * transformed coordinate system. */
1471 double y;
1472
1473 /*
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.
1478 */
1479
1480 tx = x/rx;
1481 tmp = 1 - tx*tx;
1482 if (tmp < 0) {
1483 return 0;
1484 }
1485 ty = sqrt(tmp);
1486 y = ty*ry;
1487
1488 /*
1489 * Test both intersection points.
1490 */
1491
1492 if ((y > y1) && (y < y2) && AngleInRange(tx, ty, start, extent)) {
1493 return 1;
1494 }
1495 if ((-y > y1) && (-y < y2) && AngleInRange(tx, -ty, start, extent)) {
1496 return 1;
1497 }
1498 return 0;
1499 }
1500 \f
1501 /*
1502 *--------------------------------------------------------------
1503 *
1504 * AngleInRange --
1505 *
1506 * Determine whether the angle from the origin to a given
1507 * point is within a given range.
1508 *
1509 * Results:
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.
1515 *
1516 * Side effects:
1517 * None.
1518 *
1519 *--------------------------------------------------------------
1520 */
1521
1522 static int
1523 AngleInRange (
1524 double x,
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. */
1529 )
1530 {
1531 double diff;
1532
1533 diff = -atan2(y, x);
1534 diff = diff*(180.0/PI) - start;
1535 while (diff > 360.0) {
1536 diff -= 360.0;
1537 }
1538 while (diff < 0.0) {
1539 diff += 360.0;
1540 }
1541 if (extent >= 0) {
1542 return diff <= extent;
1543 }
1544 return (diff-360.0) >= extent;
1545 }
Impressum, Datenschutz