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