1/* 2 * tkCanvArc.c -- 3 * 4 * This file implements arc items for canvas widgets. 5 * 6 * Copyright (c) 1992-1994 The Regents of the University of California. 7 * Copyright (c) 1994-1997 Sun Microsystems, Inc. 8 * 9 * See the file "license.terms" for information on usage and redistribution of 10 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 11 * 12 * RCS: @(#) $Id$ 13 */ 14 15#include <stdio.h> 16#include "tkInt.h" 17#include "tkCanvas.h" 18 19/* 20 * The structure below defines the record for each arc item. 21 */ 22 23typedef enum { 24 PIESLICE_STYLE, CHORD_STYLE, ARC_STYLE 25} Style; 26 27typedef struct ArcItem { 28 Tk_Item header; /* Generic stuff that's the same for all 29 * types. MUST BE FIRST IN STRUCTURE. */ 30 Tk_Outline outline; /* Outline structure */ 31 double bbox[4]; /* Coordinates (x1, y1, x2, y2) of bounding 32 * box for oval of which arc is a piece. */ 33 double start; /* Angle at which arc begins, in degrees 34 * between 0 and 360. */ 35 double extent; /* Extent of arc (angular distance from start 36 * to end of arc) in degrees between -360 and 37 * 360. */ 38 double *outlinePtr; /* Points to (x,y) coordinates for points that 39 * define one or two closed polygons 40 * representing the portion of the outline 41 * that isn't part of the arc (the V-shape for 42 * a pie slice or a line-like segment for a 43 * chord). Malloc'ed. */ 44 int numOutlinePoints; /* Number of points at outlinePtr. Zero means 45 * no space allocated. */ 46 Tk_TSOffset tsoffset; 47 XColor *fillColor; /* Color for filling arc (used for drawing 48 * outline too when style is "arc"). NULL 49 * means don't fill arc. */ 50 XColor *activeFillColor; /* Color for filling arc (used for drawing 51 * outline too when style is "arc" and state 52 * is "active"). NULL means use fillColor. */ 53 XColor *disabledFillColor; /* Color for filling arc (used for drawing 54 * outline too when style is "arc" and state 55 * is "disabled". NULL means use fillColor */ 56 Pixmap fillStipple; /* Stipple bitmap for filling item. */ 57 Pixmap activeFillStipple; /* Stipple bitmap for filling item if state is 58 * active. */ 59 Pixmap disabledFillStipple; /* Stipple bitmap for filling item if state is 60 * disabled. */ 61 Style style; /* How to draw arc: arc, chord, or 62 * pieslice. */ 63 GC fillGC; /* Graphics context for filling item. */ 64 double center1[2]; /* Coordinates of center of arc outline at 65 * start (see ComputeArcOutline). */ 66 double center2[2]; /* Coordinates of center of arc outline at 67 * start+extent (see ComputeArcOutline). */ 68} ArcItem; 69 70/* 71 * The definitions below define the sizes of the polygons used to display 72 * outline information for various styles of arcs: 73 */ 74 75#define CHORD_OUTLINE_PTS 7 76#define PIE_OUTLINE1_PTS 6 77#define PIE_OUTLINE2_PTS 7 78 79/* 80 * Information used for parsing configuration specs: 81 */ 82 83static int StyleParseProc(ClientData clientData, Tcl_Interp *interp, 84 Tk_Window tkwin, CONST char *value, 85 char *widgRec, int offset); 86static char * StylePrintProc(ClientData clientData, Tk_Window tkwin, 87 char *widgRec, int offset, Tcl_FreeProc **freeProcPtr); 88 89static Tk_CustomOption stateOption = { 90 (Tk_OptionParseProc *) TkStateParseProc, 91 TkStatePrintProc, (ClientData) 2 92}; 93static Tk_CustomOption styleOption = { 94 (Tk_OptionParseProc *) StyleParseProc, 95 StylePrintProc, (ClientData) NULL 96}; 97static Tk_CustomOption tagsOption = { 98 (Tk_OptionParseProc *) Tk_CanvasTagsParseProc, 99 Tk_CanvasTagsPrintProc, (ClientData) NULL 100}; 101static Tk_CustomOption dashOption = { 102 (Tk_OptionParseProc *) TkCanvasDashParseProc, 103 TkCanvasDashPrintProc, (ClientData) NULL 104}; 105static Tk_CustomOption offsetOption = { 106 (Tk_OptionParseProc *) TkOffsetParseProc, 107 TkOffsetPrintProc, (ClientData) (TK_OFFSET_RELATIVE) 108}; 109static Tk_CustomOption pixelOption = { 110 (Tk_OptionParseProc *) TkPixelParseProc, 111 TkPixelPrintProc, (ClientData) NULL 112}; 113 114static Tk_ConfigSpec configSpecs[] = { 115 {TK_CONFIG_CUSTOM, "-activedash", NULL, NULL, 116 NULL, Tk_Offset(ArcItem, outline.activeDash), 117 TK_CONFIG_NULL_OK, &dashOption}, 118 {TK_CONFIG_COLOR, "-activefill", NULL, NULL, 119 NULL, Tk_Offset(ArcItem, activeFillColor), TK_CONFIG_NULL_OK}, 120 {TK_CONFIG_COLOR, "-activeoutline", NULL, NULL, 121 NULL, Tk_Offset(ArcItem, outline.activeColor), TK_CONFIG_NULL_OK}, 122 {TK_CONFIG_BITMAP, "-activeoutlinestipple", NULL, NULL, 123 NULL, Tk_Offset(ArcItem, outline.activeStipple), TK_CONFIG_NULL_OK}, 124 {TK_CONFIG_BITMAP, "-activestipple", NULL, NULL, 125 NULL, Tk_Offset(ArcItem, activeFillStipple), TK_CONFIG_NULL_OK}, 126 {TK_CONFIG_CUSTOM, "-activewidth", NULL, NULL, 127 "0.0", Tk_Offset(ArcItem, outline.activeWidth), 128 TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, 129 {TK_CONFIG_CUSTOM, "-dash", NULL, NULL, 130 NULL, Tk_Offset(ArcItem, outline.dash), 131 TK_CONFIG_NULL_OK, &dashOption}, 132 {TK_CONFIG_PIXELS, "-dashoffset", NULL, NULL, 133 "0", Tk_Offset(ArcItem, outline.offset), TK_CONFIG_DONT_SET_DEFAULT}, 134 {TK_CONFIG_CUSTOM, "-disableddash", NULL, NULL, 135 NULL, Tk_Offset(ArcItem, outline.disabledDash), 136 TK_CONFIG_NULL_OK, &dashOption}, 137 {TK_CONFIG_COLOR, "-disabledfill", NULL, NULL, 138 NULL, Tk_Offset(ArcItem, disabledFillColor), TK_CONFIG_NULL_OK}, 139 {TK_CONFIG_COLOR, "-disabledoutline", NULL, NULL, 140 NULL, Tk_Offset(ArcItem, outline.disabledColor), TK_CONFIG_NULL_OK}, 141 {TK_CONFIG_BITMAP, "-disabledoutlinestipple", NULL, NULL, 142 NULL, Tk_Offset(ArcItem, outline.disabledStipple), TK_CONFIG_NULL_OK}, 143 {TK_CONFIG_BITMAP, "-disabledstipple", NULL, NULL, 144 NULL, Tk_Offset(ArcItem, disabledFillStipple), TK_CONFIG_NULL_OK}, 145 {TK_CONFIG_CUSTOM, "-disabledwidth", NULL, NULL, 146 "0.0", Tk_Offset(ArcItem, outline.disabledWidth), 147 TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, 148 {TK_CONFIG_DOUBLE, "-extent", NULL, NULL, 149 "90", Tk_Offset(ArcItem, extent), TK_CONFIG_DONT_SET_DEFAULT}, 150 {TK_CONFIG_COLOR, "-fill", NULL, NULL, 151 NULL, Tk_Offset(ArcItem, fillColor), TK_CONFIG_NULL_OK}, 152 {TK_CONFIG_CUSTOM, "-offset", NULL, NULL, 153 "0,0", Tk_Offset(ArcItem, tsoffset), 154 TK_CONFIG_DONT_SET_DEFAULT, &offsetOption}, 155 {TK_CONFIG_COLOR, "-outline", NULL, NULL, 156 "black", Tk_Offset(ArcItem, outline.color), TK_CONFIG_NULL_OK}, 157 {TK_CONFIG_CUSTOM, "-outlineoffset", NULL, NULL, 158 "0,0", Tk_Offset(ArcItem, outline.tsoffset), 159 TK_CONFIG_DONT_SET_DEFAULT, &offsetOption}, 160 {TK_CONFIG_BITMAP, "-outlinestipple", NULL, NULL, 161 NULL, Tk_Offset(ArcItem, outline.stipple), TK_CONFIG_NULL_OK}, 162 {TK_CONFIG_DOUBLE, "-start", NULL, NULL, 163 "0", Tk_Offset(ArcItem, start), TK_CONFIG_DONT_SET_DEFAULT}, 164 {TK_CONFIG_CUSTOM, "-state", NULL, NULL, 165 NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK, &stateOption}, 166 {TK_CONFIG_BITMAP, "-stipple", NULL, NULL, 167 NULL, Tk_Offset(ArcItem, fillStipple), TK_CONFIG_NULL_OK}, 168 {TK_CONFIG_CUSTOM, "-style", NULL, NULL, 169 NULL, Tk_Offset(ArcItem, style), TK_CONFIG_DONT_SET_DEFAULT, 170 &styleOption}, 171 {TK_CONFIG_CUSTOM, "-tags", NULL, NULL, 172 NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, 173 {TK_CONFIG_CUSTOM, "-width", NULL, NULL, 174 "1.0", Tk_Offset(ArcItem, outline.width), TK_CONFIG_DONT_SET_DEFAULT, 175 &pixelOption}, 176 {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} 177}; 178 179/* 180 * Prototypes for functions defined in this file: 181 */ 182 183static void ComputeArcBbox(Tk_Canvas canvas, ArcItem *arcPtr); 184static int ConfigureArc(Tcl_Interp *interp, 185 Tk_Canvas canvas, Tk_Item *itemPtr, int objc, 186 Tcl_Obj *CONST objv[], int flags); 187static int CreateArc(Tcl_Interp *interp, 188 Tk_Canvas canvas, struct Tk_Item *itemPtr, 189 int objc, Tcl_Obj *CONST objv[]); 190static void DeleteArc(Tk_Canvas canvas, 191 Tk_Item *itemPtr, Display *display); 192static void DisplayArc(Tk_Canvas canvas, 193 Tk_Item *itemPtr, Display *display, Drawable dst, 194 int x, int y, int width, int height); 195static int ArcCoords(Tcl_Interp *interp, Tk_Canvas canvas, 196 Tk_Item *itemPtr, int objc, Tcl_Obj *CONST objv[]); 197static int ArcToArea(Tk_Canvas canvas, 198 Tk_Item *itemPtr, double *rectPtr); 199static double ArcToPoint(Tk_Canvas canvas, 200 Tk_Item *itemPtr, double *coordPtr); 201static int ArcToPostscript(Tcl_Interp *interp, 202 Tk_Canvas canvas, Tk_Item *itemPtr, int prepass); 203static void ScaleArc(Tk_Canvas canvas, 204 Tk_Item *itemPtr, double originX, double originY, 205 double scaleX, double scaleY); 206static void TranslateArc(Tk_Canvas canvas, 207 Tk_Item *itemPtr, double deltaX, double deltaY); 208static int AngleInRange(double x, double y, 209 double start, double extent); 210static void ComputeArcOutline(Tk_Canvas canvas, ArcItem *arcPtr); 211static int HorizLineToArc(double x1, double x2, 212 double y, double rx, double ry, 213 double start, double extent); 214static int VertLineToArc(double x, double y1, 215 double y2, double rx, double ry, 216 double start, double extent); 217 218/* 219 * The structures below defines the arc item types by means of functions that 220 * can be invoked by generic item code. 221 */ 222 223Tk_ItemType tkArcType = { 224 "arc", /* name */ 225 sizeof(ArcItem), /* itemSize */ 226 CreateArc, /* createProc */ 227 configSpecs, /* configSpecs */ 228 ConfigureArc, /* configureProc */ 229 ArcCoords, /* coordProc */ 230 DeleteArc, /* deleteProc */ 231 DisplayArc, /* displayProc */ 232 TK_CONFIG_OBJS, /* flags */ 233 ArcToPoint, /* pointProc */ 234 ArcToArea, /* areaProc */ 235 ArcToPostscript, /* postscriptProc */ 236 ScaleArc, /* scaleProc */ 237 TranslateArc, /* translateProc */ 238 NULL, /* indexProc */ 239 NULL, /* icursorProc */ 240 NULL, /* selectionProc */ 241 NULL, /* insertProc */ 242 NULL, /* dTextProc */ 243 NULL, /* nextPtr */ 244}; 245 246#ifndef PI 247#define PI 3.14159265358979323846 248#endif 249 250/* 251 *-------------------------------------------------------------- 252 * 253 * CreateArc -- 254 * 255 * This function is invoked to create a new arc item in a canvas. 256 * 257 * Results: 258 * A standard Tcl return value. If an error occurred in creating the 259 * item, then an error message is left in the interp's result; in this 260 * case itemPtr is left uninitialized, so it can be safely freed by the 261 * caller. 262 * 263 * Side effects: 264 * A new arc item is created. 265 * 266 *-------------------------------------------------------------- 267 */ 268 269static int 270CreateArc( 271 Tcl_Interp *interp, /* Interpreter for error reporting. */ 272 Tk_Canvas canvas, /* Canvas to hold new item. */ 273 Tk_Item *itemPtr, /* Record to hold new item; header has been 274 * initialized by caller. */ 275 int objc, /* Number of arguments in objv. */ 276 Tcl_Obj *CONST objv[]) /* Arguments describing arc. */ 277{ 278 ArcItem *arcPtr = (ArcItem *) itemPtr; 279 int i; 280 281 if (objc == 0) { 282 Tcl_Panic("canvas did not pass any coords\n"); 283 } 284 285 /* 286 * Carry out initialization that is needed in order to clean up after 287 * errors during the the remainder of this function. 288 */ 289 290 Tk_CreateOutline(&(arcPtr->outline)); 291 arcPtr->start = 0; 292 arcPtr->extent = 90; 293 arcPtr->outlinePtr = NULL; 294 arcPtr->numOutlinePoints = 0; 295 arcPtr->tsoffset.flags = 0; 296 arcPtr->tsoffset.xoffset = 0; 297 arcPtr->tsoffset.yoffset = 0; 298 arcPtr->fillColor = NULL; 299 arcPtr->activeFillColor = NULL; 300 arcPtr->disabledFillColor = NULL; 301 arcPtr->fillStipple = None; 302 arcPtr->activeFillStipple = None; 303 arcPtr->disabledFillStipple = None; 304 arcPtr->style = PIESLICE_STYLE; 305 arcPtr->fillGC = None; 306 307 /* 308 * Process the arguments to fill in the item record. 309 */ 310 311 for (i = 1; i < objc; i++) { 312 char *arg = Tcl_GetString(objv[i]); 313 314 if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) { 315 break; 316 } 317 } 318 if (ArcCoords(interp, canvas, itemPtr, i, objv) != TCL_OK) { 319 goto error; 320 } 321 if (ConfigureArc(interp, canvas, itemPtr, objc-i, objv+i, 0) == TCL_OK) { 322 return TCL_OK; 323 } 324 325 error: 326 DeleteArc(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); 327 return TCL_ERROR; 328} 329 330/* 331 *-------------------------------------------------------------- 332 * 333 * ArcCoords -- 334 * 335 * This function is invoked to process the "coords" widget command on 336 * arcs. See the user documentation for details on what it does. 337 * 338 * Results: 339 * Returns TCL_OK or TCL_ERROR, and sets the interp's result. 340 * 341 * Side effects: 342 * The coordinates for the given item may be changed. 343 * 344 *-------------------------------------------------------------- 345 */ 346 347static int 348ArcCoords( 349 Tcl_Interp *interp, /* Used for error reporting. */ 350 Tk_Canvas canvas, /* Canvas containing item. */ 351 Tk_Item *itemPtr, /* Item whose coordinates are to be read or 352 * modified. */ 353 int objc, /* Number of coordinates supplied in objv. */ 354 Tcl_Obj *CONST objv[]) /* Array of coordinates: x1, y1, x2, y2, ... */ 355{ 356 ArcItem *arcPtr = (ArcItem *) itemPtr; 357 358 if (objc == 0) { 359 Tcl_Obj *obj = Tcl_NewObj(); 360 Tcl_Obj *subobj = Tcl_NewDoubleObj(arcPtr->bbox[0]); 361 362 Tcl_ListObjAppendElement(interp, obj, subobj); 363 subobj = Tcl_NewDoubleObj(arcPtr->bbox[1]); 364 Tcl_ListObjAppendElement(interp, obj, subobj); 365 subobj = Tcl_NewDoubleObj(arcPtr->bbox[2]); 366 Tcl_ListObjAppendElement(interp, obj, subobj); 367 subobj = Tcl_NewDoubleObj(arcPtr->bbox[3]); 368 Tcl_ListObjAppendElement(interp, obj, subobj); 369 Tcl_SetObjResult(interp, obj); 370 } else if ((objc == 1)||(objc == 4)) { 371 if (objc==1) { 372 if (Tcl_ListObjGetElements(interp, objv[0], &objc, 373 (Tcl_Obj ***) &objv) != TCL_OK) { 374 return TCL_ERROR; 375 } else if (objc != 4) { 376 char buf[64 + TCL_INTEGER_SPACE]; 377 378 sprintf(buf, "wrong # coordinates: expected 4, got %d", objc); 379 Tcl_SetResult(interp, buf, TCL_VOLATILE); 380 return TCL_ERROR; 381 } 382 } 383 if ((Tk_CanvasGetCoordFromObj(interp, canvas, objv[0], 384 &arcPtr->bbox[0]) != TCL_OK) 385 || (Tk_CanvasGetCoordFromObj(interp, canvas, objv[1], 386 &arcPtr->bbox[1]) != TCL_OK) 387 || (Tk_CanvasGetCoordFromObj(interp, canvas, objv[2], 388 &arcPtr->bbox[2]) != TCL_OK) 389 || (Tk_CanvasGetCoordFromObj(interp, canvas, objv[3], 390 &arcPtr->bbox[3]) != TCL_OK)) { 391 return TCL_ERROR; 392 } 393 ComputeArcBbox(canvas, arcPtr); 394 } else { 395 char buf[64 + TCL_INTEGER_SPACE]; 396 397 sprintf(buf, "wrong # coordinates: expected 0 or 4, got %d", objc); 398 Tcl_SetResult(interp, buf, TCL_VOLATILE); 399 return TCL_ERROR; 400 } 401 return TCL_OK; 402} 403 404/* 405 *-------------------------------------------------------------- 406 * 407 * ConfigureArc -- 408 * 409 * This function is invoked to configure various aspects of a arc item, 410 * such as its outline and fill colors. 411 * 412 * Results: 413 * A standard Tcl result code. If an error occurs, then an error message 414 * is left in the interp's result. 415 * 416 * Side effects: 417 * Configuration information, such as colors and stipple patterns, may be 418 * set for itemPtr. 419 * 420 *-------------------------------------------------------------- 421 */ 422 423static int 424ConfigureArc( 425 Tcl_Interp *interp, /* Used for error reporting. */ 426 Tk_Canvas canvas, /* Canvas containing itemPtr. */ 427 Tk_Item *itemPtr, /* Arc item to reconfigure. */ 428 int objc, /* Number of elements in objv. */ 429 Tcl_Obj *CONST objv[], /* Arguments describing things to configure. */ 430 int flags) /* Flags to pass to Tk_ConfigureWidget. */ 431{ 432 ArcItem *arcPtr = (ArcItem *) itemPtr; 433 XGCValues gcValues; 434 GC newGC; 435 unsigned long mask; 436 int i; 437 Tk_Window tkwin; 438 Tk_TSOffset *tsoffset; 439 XColor *color; 440 Pixmap stipple; 441 Tk_State state; 442 443 tkwin = Tk_CanvasTkwin(canvas); 444 if (TCL_OK != Tk_ConfigureWidget(interp, tkwin, configSpecs, objc, 445 (CONST char **) objv, (char *) arcPtr, flags|TK_CONFIG_OBJS)) { 446 return TCL_ERROR; 447 } 448 449 state = itemPtr->state; 450 451 /* 452 * A few of the options require additional processing, such as style and 453 * graphics contexts. 454 */ 455 456 if (arcPtr->outline.activeWidth > arcPtr->outline.width || 457 arcPtr->outline.activeDash.number != 0 || 458 arcPtr->outline.activeColor != NULL || 459 arcPtr->outline.activeStipple != None || 460 arcPtr->activeFillColor != NULL || 461 arcPtr->activeFillStipple != None) { 462 itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; 463 } else { 464 itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; 465 } 466 467 tsoffset = &arcPtr->outline.tsoffset; 468 flags = tsoffset->flags; 469 if (flags & TK_OFFSET_LEFT) { 470 tsoffset->xoffset = (int) (arcPtr->bbox[0] + 0.5); 471 } else if (flags & TK_OFFSET_CENTER) { 472 tsoffset->xoffset = (int) ((arcPtr->bbox[0]+arcPtr->bbox[2]+1)/2); 473 } else if (flags & TK_OFFSET_RIGHT) { 474 tsoffset->xoffset = (int) (arcPtr->bbox[2] + 0.5); 475 } 476 if (flags & TK_OFFSET_TOP) { 477 tsoffset->yoffset = (int) (arcPtr->bbox[1] + 0.5); 478 } else if (flags & TK_OFFSET_MIDDLE) { 479 tsoffset->yoffset = (int) ((arcPtr->bbox[1]+arcPtr->bbox[3]+1)/2); 480 } else if (flags & TK_OFFSET_BOTTOM) { 481 tsoffset->yoffset = (int) (arcPtr->bbox[2] + 0.5); 482 } 483 484 i = (int) (arcPtr->start/360.0); 485 arcPtr->start -= i*360.0; 486 if (arcPtr->start < 0) { 487 arcPtr->start += 360.0; 488 } 489 i = (int) (arcPtr->extent/360.0); 490 arcPtr->extent -= i*360.0; 491 492 mask = Tk_ConfigOutlineGC(&gcValues, canvas, itemPtr, &(arcPtr->outline)); 493 if (mask) { 494 gcValues.cap_style = CapButt; 495 mask |= GCCapStyle; 496 newGC = Tk_GetGC(tkwin, mask, &gcValues); 497 } else { 498 newGC = None; 499 } 500 if (arcPtr->outline.gc != None) { 501 Tk_FreeGC(Tk_Display(tkwin), arcPtr->outline.gc); 502 } 503 arcPtr->outline.gc = newGC; 504 505 if(state == TK_STATE_NULL) { 506 state = ((TkCanvas *)canvas)->canvas_state; 507 } 508 if (state==TK_STATE_HIDDEN) { 509 ComputeArcBbox(canvas, arcPtr); 510 return TCL_OK; 511 } 512 513 color = arcPtr->fillColor; 514 stipple = arcPtr->fillStipple; 515 if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { 516 if (arcPtr->activeFillColor!=NULL) { 517 color = arcPtr->activeFillColor; 518 } 519 if (arcPtr->activeFillStipple!=None) { 520 stipple = arcPtr->activeFillStipple; 521 } 522 } else if (state==TK_STATE_DISABLED) { 523 if (arcPtr->disabledFillColor!=NULL) { 524 color = arcPtr->disabledFillColor; 525 } 526 if (arcPtr->disabledFillStipple!=None) { 527 stipple = arcPtr->disabledFillStipple; 528 } 529 } 530 531 if (arcPtr->style == ARC_STYLE) { 532 newGC = None; 533 } else if (color == NULL) { 534 newGC = None; 535 } else { 536 gcValues.foreground = color->pixel; 537 if (arcPtr->style == CHORD_STYLE) { 538 gcValues.arc_mode = ArcChord; 539 } else { 540 gcValues.arc_mode = ArcPieSlice; 541 } 542 mask = GCForeground|GCArcMode; 543 if (stipple != None) { 544 gcValues.stipple = stipple; 545 gcValues.fill_style = FillStippled; 546 mask |= GCStipple|GCFillStyle; 547 } 548 newGC = Tk_GetGC(tkwin, mask, &gcValues); 549 } 550 if (arcPtr->fillGC != None) { 551 Tk_FreeGC(Tk_Display(tkwin), arcPtr->fillGC); 552 } 553 arcPtr->fillGC = newGC; 554 555 tsoffset = &arcPtr->tsoffset; 556 flags = tsoffset->flags; 557 if (flags & TK_OFFSET_LEFT) { 558 tsoffset->xoffset = (int) (arcPtr->bbox[0] + 0.5); 559 } else if (flags & TK_OFFSET_CENTER) { 560 tsoffset->xoffset = (int) ((arcPtr->bbox[0]+arcPtr->bbox[2]+1)/2); 561 } else if (flags & TK_OFFSET_RIGHT) { 562 tsoffset->xoffset = (int) (arcPtr->bbox[2] + 0.5); 563 } 564 if (flags & TK_OFFSET_TOP) { 565 tsoffset->yoffset = (int) (arcPtr->bbox[1] + 0.5); 566 } else if (flags & TK_OFFSET_MIDDLE) { 567 tsoffset->yoffset = (int) ((arcPtr->bbox[1]+arcPtr->bbox[3]+1)/2); 568 } else if (flags & TK_OFFSET_BOTTOM) { 569 tsoffset->yoffset = (int) (arcPtr->bbox[3] + 0.5); 570 } 571 572 ComputeArcBbox(canvas, arcPtr); 573 return TCL_OK; 574} 575 576/* 577 *-------------------------------------------------------------- 578 * 579 * DeleteArc -- 580 * 581 * This function is called to clean up the data structure associated with 582 * an arc item. 583 * 584 * Results: 585 * None. 586 * 587 * Side effects: 588 * Resources associated with itemPtr are released. 589 * 590 *-------------------------------------------------------------- 591 */ 592 593static void 594DeleteArc( 595 Tk_Canvas canvas, /* Info about overall canvas. */ 596 Tk_Item *itemPtr, /* Item that is being deleted. */ 597 Display *display) /* Display containing window for canvas. */ 598{ 599 ArcItem *arcPtr = (ArcItem *) itemPtr; 600 601 Tk_DeleteOutline(display, &(arcPtr->outline)); 602 if (arcPtr->numOutlinePoints != 0) { 603 ckfree((char *) arcPtr->outlinePtr); 604 } 605 if (arcPtr->fillColor != NULL) { 606 Tk_FreeColor(arcPtr->fillColor); 607 } 608 if (arcPtr->activeFillColor != NULL) { 609 Tk_FreeColor(arcPtr->activeFillColor); 610 } 611 if (arcPtr->disabledFillColor != NULL) { 612 Tk_FreeColor(arcPtr->disabledFillColor); 613 } 614 if (arcPtr->fillStipple != None) { 615 Tk_FreeBitmap(display, arcPtr->fillStipple); 616 } 617 if (arcPtr->activeFillStipple != None) { 618 Tk_FreeBitmap(display, arcPtr->activeFillStipple); 619 } 620 if (arcPtr->disabledFillStipple != None) { 621 Tk_FreeBitmap(display, arcPtr->disabledFillStipple); 622 } 623 if (arcPtr->fillGC != None) { 624 Tk_FreeGC(display, arcPtr->fillGC); 625 } 626} 627 628/* 629 *-------------------------------------------------------------- 630 * 631 * ComputeArcBbox -- 632 * 633 * This function is invoked to compute the bounding box of all the pixels 634 * that may be drawn as part of an arc. 635 * 636 * Results: 637 * None. 638 * 639 * Side effects: 640 * The fields x1, y1, x2, and y2 are updated in the header for itemPtr. 641 * 642 *-------------------------------------------------------------- 643 */ 644 645 /* ARGSUSED */ 646static void 647ComputeArcBbox( 648 Tk_Canvas canvas, /* Canvas that contains item. */ 649 ArcItem *arcPtr) /* Item whose bbox is to be recomputed. */ 650{ 651 double tmp, center[2], point[2]; 652 double width; 653 Tk_State state = arcPtr->header.state; 654 655 if (state == TK_STATE_NULL) { 656 state = ((TkCanvas *)canvas)->canvas_state; 657 } 658 659 width = arcPtr->outline.width; 660 if (width < 1.0) { 661 width = 1.0; 662 } 663 if (state==TK_STATE_HIDDEN) { 664 arcPtr->header.x1 = arcPtr->header.x2 = 665 arcPtr->header.y1 = arcPtr->header.y2 = -1; 666 return; 667 } else if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *) arcPtr) { 668 if (arcPtr->outline.activeWidth>width) { 669 width = arcPtr->outline.activeWidth; 670 } 671 } else if (state==TK_STATE_DISABLED) { 672 if (arcPtr->outline.disabledWidth>0) { 673 width = arcPtr->outline.disabledWidth; 674 } 675 } 676 677 /* 678 * Make sure that the first coordinates are the lowest ones. 679 */ 680 681 if (arcPtr->bbox[1] > arcPtr->bbox[3]) { 682 double tmp = arcPtr->bbox[3]; 683 684 arcPtr->bbox[3] = arcPtr->bbox[1]; 685 arcPtr->bbox[1] = tmp; 686 } 687 if (arcPtr->bbox[0] > arcPtr->bbox[2]) { 688 double tmp = arcPtr->bbox[2]; 689 690 arcPtr->bbox[2] = arcPtr->bbox[0]; 691 arcPtr->bbox[0] = tmp; 692 } 693 694 ComputeArcOutline(canvas,arcPtr); 695 696 /* 697 * To compute the bounding box, start with the the bbox formed by the two 698 * endpoints of the arc. Then add in the center of the arc's oval (if 699 * relevant) and the 3-o'clock, 6-o'clock, 9-o'clock, and 12-o'clock 700 * positions, if they are relevant. 701 */ 702 703 arcPtr->header.x1 = arcPtr->header.x2 = (int) arcPtr->center1[0]; 704 arcPtr->header.y1 = arcPtr->header.y2 = (int) arcPtr->center1[1]; 705 TkIncludePoint((Tk_Item *) arcPtr, arcPtr->center2); 706 center[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2; 707 center[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2; 708 if (arcPtr->style == PIESLICE_STYLE) { 709 TkIncludePoint((Tk_Item *) arcPtr, center); 710 } 711 712 tmp = -arcPtr->start; 713 if (tmp < 0) { 714 tmp += 360.0; 715 } 716 if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { 717 point[0] = arcPtr->bbox[2]; 718 point[1] = center[1]; 719 TkIncludePoint((Tk_Item *) arcPtr, point); 720 } 721 tmp = 90.0 - arcPtr->start; 722 if (tmp < 0) { 723 tmp += 360.0; 724 } 725 if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { 726 point[0] = center[0]; 727 point[1] = arcPtr->bbox[1]; 728 TkIncludePoint((Tk_Item *) arcPtr, point); 729 } 730 tmp = 180.0 - arcPtr->start; 731 if (tmp < 0) { 732 tmp += 360.0; 733 } 734 if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { 735 point[0] = arcPtr->bbox[0]; 736 point[1] = center[1]; 737 TkIncludePoint((Tk_Item *) arcPtr, point); 738 } 739 tmp = 270.0 - arcPtr->start; 740 if (tmp < 0) { 741 tmp += 360.0; 742 } 743 if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { 744 point[0] = center[0]; 745 point[1] = arcPtr->bbox[3]; 746 TkIncludePoint((Tk_Item *) arcPtr, point); 747 } 748 749 /* 750 * Lastly, expand by the width of the arc (if the arc's outline is being 751 * drawn) and add one extra pixel just for safety. 752 */ 753 754 if (arcPtr->outline.gc == None) { 755 tmp = 1; 756 } else { 757 tmp = (int) ((width + 1.0)/2.0 + 1); 758 } 759 arcPtr->header.x1 -= (int) tmp; 760 arcPtr->header.y1 -= (int) tmp; 761 arcPtr->header.x2 += (int) tmp; 762 arcPtr->header.y2 += (int) tmp; 763} 764 765/* 766 *-------------------------------------------------------------- 767 * 768 * DisplayArc -- 769 * 770 * This function is invoked to draw an arc item in a given drawable. 771 * 772 * Results: 773 * None. 774 * 775 * Side effects: 776 * ItemPtr is drawn in drawable using the transformation information in 777 * canvas. 778 * 779 *-------------------------------------------------------------- 780 */ 781 782static void 783DisplayArc( 784 Tk_Canvas canvas, /* Canvas that contains item. */ 785 Tk_Item *itemPtr, /* Item to be displayed. */ 786 Display *display, /* Display on which to draw item. */ 787 Drawable drawable, /* Pixmap or window in which to draw item. */ 788 int x, int y, /* Describes region of canvas that must be */ 789 int width, int height) /* redisplayed (not used). */ 790{ 791 ArcItem *arcPtr = (ArcItem *) itemPtr; 792 short x1, y1, x2, y2; 793 int start, extent, dashnumber; 794 double lineWidth; 795 Tk_State state = itemPtr->state; 796 Pixmap stipple; 797 798 if (state == TK_STATE_NULL) { 799 state = ((TkCanvas *)canvas)->canvas_state; 800 } 801 lineWidth = arcPtr->outline.width; 802 if (lineWidth < 1.0) { 803 lineWidth = 1.0; 804 } 805 dashnumber = arcPtr->outline.dash.number; 806 stipple = arcPtr->fillStipple; 807 if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { 808 if (arcPtr->outline.activeWidth>lineWidth) { 809 lineWidth = arcPtr->outline.activeWidth; 810 } 811 if (arcPtr->outline.activeDash.number != 0) { 812 dashnumber = arcPtr->outline.activeDash.number; 813 } 814 if (arcPtr->activeFillStipple != None) { 815 stipple = arcPtr->activeFillStipple; 816 } 817 } else if (state == TK_STATE_DISABLED) { 818 if (arcPtr->outline.disabledWidth > 0) { 819 lineWidth = arcPtr->outline.disabledWidth; 820 } 821 if (arcPtr->outline.disabledDash.number != 0) { 822 dashnumber = arcPtr->outline.disabledDash.number; 823 } 824 if (arcPtr->disabledFillStipple != None) { 825 stipple = arcPtr->disabledFillStipple; 826 } 827 } 828 829 /* 830 * Compute the screen coordinates of the bounding box for the item, plus 831 * integer values for the angles. 832 */ 833 834 Tk_CanvasDrawableCoords(canvas, arcPtr->bbox[0], arcPtr->bbox[1], 835 &x1, &y1); 836 Tk_CanvasDrawableCoords(canvas, arcPtr->bbox[2], arcPtr->bbox[3], 837 &x2, &y2); 838 if (x2 <= x1) { 839 x2 = x1+1; 840 } 841 if (y2 <= y1) { 842 y2 = y1+1; 843 } 844 start = (int) ((64*arcPtr->start) + 0.5); 845 extent = (int) ((64*arcPtr->extent) + 0.5); 846 847 /* 848 * Display filled arc first (if wanted), then outline. If the extent is 849 * zero then don't invoke XFillArc or XDrawArc, since this causes some 850 * window servers to crash and should be a no-op anyway. 851 */ 852 853 if ((arcPtr->fillGC != None) && (extent != 0)) { 854 if (stipple != None) { 855 int w = 0; 856 int h = 0; 857 Tk_TSOffset *tsoffset = &arcPtr->tsoffset; 858 int flags = tsoffset->flags; 859 860 if (flags & (TK_OFFSET_CENTER|TK_OFFSET_MIDDLE)) { 861 Tk_SizeOfBitmap(display, stipple, &w, &h); 862 if (flags & TK_OFFSET_CENTER) { 863 w /= 2; 864 } else { 865 w = 0; 866 } 867 if (flags & TK_OFFSET_MIDDLE) { 868 h /= 2; 869 } else { 870 h = 0; 871 } 872 } 873 tsoffset->xoffset -= w; 874 tsoffset->yoffset -= h; 875 Tk_CanvasSetOffset(canvas, arcPtr->fillGC, tsoffset); 876 if (tsoffset) { 877 tsoffset->xoffset += w; 878 tsoffset->yoffset += h; 879 } 880 } 881 XFillArc(display, drawable, arcPtr->fillGC, x1, y1, (unsigned) (x2-x1), 882 (unsigned) (y2-y1), start, extent); 883 if (stipple != None) { 884 XSetTSOrigin(display, arcPtr->fillGC, 0, 0); 885 } 886 } 887 if (arcPtr->outline.gc != None) { 888 Tk_ChangeOutlineGC(canvas, itemPtr, &(arcPtr->outline)); 889 890 if (extent != 0) { 891 XDrawArc(display, drawable, arcPtr->outline.gc, x1, y1, 892 (unsigned) (x2-x1), (unsigned) (y2-y1), start, extent); 893 } 894 895 /* 896 * If the outline width is very thin, don't use polygons to draw the 897 * linear parts of the outline (this often results in nothing being 898 * displayed); just draw lines instead. The same is done if the 899 * outline is dashed, because then polygons don't work. 900 */ 901 902 if (lineWidth < 1.5 || dashnumber != 0) { 903 Tk_CanvasDrawableCoords(canvas, arcPtr->center1[0], 904 arcPtr->center1[1], &x1, &y1); 905 Tk_CanvasDrawableCoords(canvas, arcPtr->center2[0], 906 arcPtr->center2[1], &x2, &y2); 907 908 if (arcPtr->style == CHORD_STYLE) { 909 XDrawLine(display, drawable, arcPtr->outline.gc, 910 x1, y1, x2, y2); 911 } else if (arcPtr->style == PIESLICE_STYLE) { 912 short cx, cy; 913 914 Tk_CanvasDrawableCoords(canvas, 915 (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0, 916 (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0, &cx, &cy); 917 XDrawLine(display, drawable, arcPtr->outline.gc, 918 cx, cy, x1, y1); 919 XDrawLine(display, drawable, arcPtr->outline.gc, 920 cx, cy, x2, y2); 921 } 922 } else { 923 if (arcPtr->style == CHORD_STYLE) { 924 TkFillPolygon(canvas, arcPtr->outlinePtr, CHORD_OUTLINE_PTS, 925 display, drawable, arcPtr->outline.gc, None); 926 } else if (arcPtr->style == PIESLICE_STYLE) { 927 TkFillPolygon(canvas, arcPtr->outlinePtr, PIE_OUTLINE1_PTS, 928 display, drawable, arcPtr->outline.gc, None); 929 TkFillPolygon(canvas, arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS, 930 PIE_OUTLINE2_PTS, display, drawable, 931 arcPtr->outline.gc, None); 932 } 933 } 934 935 Tk_ResetOutlineGC(canvas, itemPtr, &(arcPtr->outline)); 936 } 937} 938 939/* 940 *-------------------------------------------------------------- 941 * 942 * ArcToPoint -- 943 * 944 * Computes the distance from a given point to a given arc, in canvas 945 * units. 946 * 947 * Results: 948 * The return value is 0 if the point whose x and y coordinates are 949 * coordPtr[0] and coordPtr[1] is inside the arc. If the point isn't 950 * inside the arc then the return value is the distance from the point to 951 * the arc. If itemPtr is filled, then anywhere in the interior is 952 * considered "inside"; if itemPtr isn't filled, then "inside" means only 953 * the area occupied by the outline. 954 * 955 * Side effects: 956 * None. 957 * 958 *-------------------------------------------------------------- 959 */ 960 961 /* ARGSUSED */ 962static double 963ArcToPoint( 964 Tk_Canvas canvas, /* Canvas containing item. */ 965 Tk_Item *itemPtr, /* Item to check against point. */ 966 double *pointPtr) /* Pointer to x and y coordinates. */ 967{ 968 ArcItem *arcPtr = (ArcItem *) itemPtr; 969 double vertex[2], pointAngle, diff, dist, newDist; 970 double poly[8], polyDist, width, t1, t2; 971 int filled, angleInRange; 972 Tk_State state = itemPtr->state; 973 974 if (state == TK_STATE_NULL) { 975 state = ((TkCanvas *)canvas)->canvas_state; 976 } 977 978 width = (double) arcPtr->outline.width; 979 if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { 980 if (arcPtr->outline.activeWidth>width) { 981 width = (double) arcPtr->outline.activeWidth; 982 } 983 } else if (state == TK_STATE_DISABLED) { 984 if (arcPtr->outline.disabledWidth>0) { 985 width = (double) arcPtr->outline.disabledWidth; 986 } 987 } 988 989 /* 990 * See if the point is within the angular range of the arc. Remember, X 991 * angles are backwards from the way we'd normally think of them. Also, 992 * compensate for any eccentricity of the oval. 993 */ 994 995 vertex[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0; 996 vertex[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0; 997 t1 = arcPtr->bbox[3] - arcPtr->bbox[1]; 998 if (t1 != 0.0) { 999 t1 = (pointPtr[1] - vertex[1]) / t1; 1000 } 1001 t2 = arcPtr->bbox[2] - arcPtr->bbox[0]; 1002 if (t2 != 0.0) { 1003 t2 = (pointPtr[0] - vertex[0]) / t2; 1004 } 1005 if ((t1 == 0.0) && (t2 == 0.0)) { 1006 pointAngle = 0; 1007 } else { 1008 pointAngle = -atan2(t1, t2)*180/PI; 1009 } 1010 diff = pointAngle - arcPtr->start; 1011 diff -= ((int) (diff/360.0) * 360.0); 1012 if (diff < 0) { 1013 diff += 360.0; 1014 } 1015 angleInRange = (diff <= arcPtr->extent) || 1016 ((arcPtr->extent < 0) && ((diff - 360.0) >= arcPtr->extent)); 1017 1018 /* 1019 * Now perform different tests depending on what kind of arc we're dealing 1020 * with. 1021 */ 1022 1023 if (arcPtr->style == ARC_STYLE) { 1024 if (angleInRange) { 1025 return TkOvalToPoint(arcPtr->bbox, width, 0, pointPtr); 1026 } 1027 dist = hypot(pointPtr[0] - arcPtr->center1[0], 1028 pointPtr[1] - arcPtr->center1[1]); 1029 newDist = hypot(pointPtr[0] - arcPtr->center2[0], 1030 pointPtr[1] - arcPtr->center2[1]); 1031 if (newDist < dist) { 1032 return newDist; 1033 } 1034 return dist; 1035 } 1036 1037 if ((arcPtr->fillGC != None) || (arcPtr->outline.gc == None)) { 1038 filled = 1; 1039 } else { 1040 filled = 0; 1041 } 1042 if (arcPtr->outline.gc == None) { 1043 width = 0.0; 1044 } 1045 1046 if (arcPtr->style == PIESLICE_STYLE) { 1047 if (width > 1.0) { 1048 dist = TkPolygonToPoint(arcPtr->outlinePtr, PIE_OUTLINE1_PTS, 1049 pointPtr); 1050 newDist = TkPolygonToPoint(arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS, 1051 PIE_OUTLINE2_PTS, pointPtr); 1052 } else { 1053 dist = TkLineToPoint(vertex, arcPtr->center1, pointPtr); 1054 newDist = TkLineToPoint(vertex, arcPtr->center2, pointPtr); 1055 } 1056 if (newDist < dist) { 1057 dist = newDist; 1058 } 1059 if (angleInRange) { 1060 newDist = TkOvalToPoint(arcPtr->bbox, width, filled, pointPtr); 1061 if (newDist < dist) { 1062 dist = newDist; 1063 } 1064 } 1065 return dist; 1066 } 1067 1068 /* 1069 * This is a chord-style arc. We have to deal specially with the 1070 * triangular piece that represents the difference between a chord-style 1071 * arc and a pie-slice arc (for small angles this piece is excluded here 1072 * where it would be included for pie slices; for large angles the piece 1073 * is included here but would be excluded for pie slices). 1074 */ 1075 1076 if (width > 1.0) { 1077 dist = TkPolygonToPoint(arcPtr->outlinePtr, CHORD_OUTLINE_PTS, 1078 pointPtr); 1079 } else { 1080 dist = TkLineToPoint(arcPtr->center1, arcPtr->center2, pointPtr); 1081 } 1082 poly[0] = poly[6] = vertex[0]; 1083 poly[1] = poly[7] = vertex[1]; 1084 poly[2] = arcPtr->center1[0]; 1085 poly[3] = arcPtr->center1[1]; 1086 poly[4] = arcPtr->center2[0]; 1087 poly[5] = arcPtr->center2[1]; 1088 polyDist = TkPolygonToPoint(poly, 4, pointPtr); 1089 if (angleInRange) { 1090 if ((arcPtr->extent < -180.0) || (arcPtr->extent > 180.0) 1091 || (polyDist > 0.0)) { 1092 newDist = TkOvalToPoint(arcPtr->bbox, width, filled, pointPtr); 1093 if (newDist < dist) { 1094 dist = newDist; 1095 } 1096 } 1097 } else { 1098 if ((arcPtr->extent < -180.0) || (arcPtr->extent > 180.0)) { 1099 if (filled && (polyDist < dist)) { 1100 dist = polyDist; 1101 } 1102 } 1103 } 1104 return dist; 1105} 1106 1107/* 1108 *-------------------------------------------------------------- 1109 * 1110 * ArcToArea -- 1111 * 1112 * This function is called to determine whether an item lies entirely 1113 * inside, entirely outside, or overlapping a given area. 1114 * 1115 * Results: 1116 * -1 is returned if the item is entirely outside the area given by 1117 * rectPtr, 0 if it overlaps, and 1 if it is entirely inside the given 1118 * area. 1119 * 1120 * Side effects: 1121 * None. 1122 * 1123 *-------------------------------------------------------------- 1124 */ 1125 1126 /* ARGSUSED */ 1127static int 1128ArcToArea( 1129 Tk_Canvas canvas, /* Canvas containing item. */ 1130 Tk_Item *itemPtr, /* Item to check against arc. */ 1131 double *rectPtr) /* Pointer to array of four coordinates (x1, 1132 * y1, x2, y2) describing rectangular area. */ 1133{ 1134 ArcItem *arcPtr = (ArcItem *) itemPtr; 1135 double rx, ry; /* Radii for transformed oval: these define an 1136 * oval centered at the origin. */ 1137 double tRect[4]; /* Transformed version of x1, y1, x2, y2, for 1138 * coord. system where arc is centered on the 1139 * origin. */ 1140 double center[2], width, angle, tmp; 1141 double points[20], *pointPtr; 1142 int numPoints, filled; 1143 int inside; /* Non-zero means every test so far suggests 1144 * that arc is inside rectangle. 0 means every 1145 * test so far shows arc to be outside of 1146 * rectangle. */ 1147 int newInside; 1148 Tk_State state = itemPtr->state; 1149 1150 if(state == TK_STATE_NULL) { 1151 state = ((TkCanvas *)canvas)->canvas_state; 1152 } 1153 width = (double) arcPtr->outline.width; 1154 if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { 1155 if (arcPtr->outline.activeWidth>width) { 1156 width = (double) arcPtr->outline.activeWidth; 1157 } 1158 } else if (state == TK_STATE_DISABLED) { 1159 if (arcPtr->outline.disabledWidth>0) { 1160 width = (double) arcPtr->outline.disabledWidth; 1161 } 1162 } 1163 1164 if ((arcPtr->fillGC != None) || (arcPtr->outline.gc == None)) { 1165 filled = 1; 1166 } else { 1167 filled = 0; 1168 } 1169 if (arcPtr->outline.gc == None) { 1170 width = 0.0; 1171 } 1172 1173 /* 1174 * Transform both the arc and the rectangle so that the arc's oval is 1175 * centered on the origin. 1176 */ 1177 1178 center[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0; 1179 center[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0; 1180 tRect[0] = rectPtr[0] - center[0]; 1181 tRect[1] = rectPtr[1] - center[1]; 1182 tRect[2] = rectPtr[2] - center[0]; 1183 tRect[3] = rectPtr[3] - center[1]; 1184 rx = arcPtr->bbox[2] - center[0] + width/2.0; 1185 ry = arcPtr->bbox[3] - center[1] + width/2.0; 1186 1187 /* 1188 * Find the extreme points of the arc and see whether these are all inside 1189 * the rectangle (in which case we're done), partly in and partly out (in 1190 * which case we're done), or all outside (in which case we have more work 1191 * to do). The extreme points include the following, which are checked in 1192 * order: 1193 * 1194 * 1. The outside points of the arc, corresponding to start and extent. 1195 * 2. The center of the arc (but only in pie-slice mode). 1196 * 3. The 12, 3, 6, and 9-o'clock positions (but only if the arc includes 1197 * those angles). 1198 */ 1199 1200 pointPtr = points; 1201 angle = -arcPtr->start*(PI/180.0); 1202 pointPtr[0] = rx*cos(angle); 1203 pointPtr[1] = ry*sin(angle); 1204 angle += -arcPtr->extent*(PI/180.0); 1205 pointPtr[2] = rx*cos(angle); 1206 pointPtr[3] = ry*sin(angle); 1207 numPoints = 2; 1208 pointPtr += 4; 1209 1210 if ((arcPtr->style == PIESLICE_STYLE) && (arcPtr->extent < 180.0)) { 1211 pointPtr[0] = 0.0; 1212 pointPtr[1] = 0.0; 1213 numPoints++; 1214 pointPtr += 2; 1215 } 1216 1217 tmp = -arcPtr->start; 1218 if (tmp < 0) { 1219 tmp += 360.0; 1220 } 1221 if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { 1222 pointPtr[0] = rx; 1223 pointPtr[1] = 0.0; 1224 numPoints++; 1225 pointPtr += 2; 1226 } 1227 tmp = 90.0 - arcPtr->start; 1228 if (tmp < 0) { 1229 tmp += 360.0; 1230 } 1231 if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { 1232 pointPtr[0] = 0.0; 1233 pointPtr[1] = -ry; 1234 numPoints++; 1235 pointPtr += 2; 1236 } 1237 tmp = 180.0 - arcPtr->start; 1238 if (tmp < 0) { 1239 tmp += 360.0; 1240 } 1241 if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { 1242 pointPtr[0] = -rx; 1243 pointPtr[1] = 0.0; 1244 numPoints++; 1245 pointPtr += 2; 1246 } 1247 tmp = 270.0 - arcPtr->start; 1248 if (tmp < 0) { 1249 tmp += 360.0; 1250 } 1251 if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { 1252 pointPtr[0] = 0.0; 1253 pointPtr[1] = ry; 1254 numPoints++; 1255 } 1256 1257 /* 1258 * Now that we've located the extreme points, loop through them all to see 1259 * which are inside the rectangle. 1260 */ 1261 1262 inside = (points[0] > tRect[0]) && (points[0] < tRect[2]) 1263 && (points[1] > tRect[1]) && (points[1] < tRect[3]); 1264 for (pointPtr = points+2; numPoints > 1; pointPtr += 2, numPoints--) { 1265 newInside = (pointPtr[0] > tRect[0]) && (pointPtr[0] < tRect[2]) 1266 && (pointPtr[1] > tRect[1]) && (pointPtr[1] < tRect[3]); 1267 if (newInside != inside) { 1268 return 0; 1269 } 1270 } 1271 1272 if (inside) { 1273 return 1; 1274 } 1275 1276 /* 1277 * So far, oval appears to be outside rectangle, but can't yet tell for 1278 * sure. Next, test each of the four sides of the rectangle against the 1279 * bounding region for the arc. If any intersections are found, then 1280 * return "overlapping". First, test against the polygon(s) forming the 1281 * sides of a chord or pie-slice. 1282 */ 1283 1284 if (arcPtr->style == PIESLICE_STYLE) { 1285 if (width >= 1.0) { 1286 if (TkPolygonToArea(arcPtr->outlinePtr, PIE_OUTLINE1_PTS, 1287 rectPtr) != -1) { 1288 return 0; 1289 } 1290 if (TkPolygonToArea(arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS, 1291 PIE_OUTLINE2_PTS, rectPtr) != -1) { 1292 return 0; 1293 } 1294 } else { 1295 if ((TkLineToArea(center, arcPtr->center1, rectPtr) != -1) || 1296 (TkLineToArea(center, arcPtr->center2, rectPtr) != -1)) { 1297 return 0; 1298 } 1299 } 1300 } else if (arcPtr->style == CHORD_STYLE) { 1301 if (width >= 1.0) { 1302 if (TkPolygonToArea(arcPtr->outlinePtr, CHORD_OUTLINE_PTS, 1303 rectPtr) != -1) { 1304 return 0; 1305 } 1306 } else { 1307 if (TkLineToArea(arcPtr->center1, arcPtr->center2, 1308 rectPtr) != -1) { 1309 return 0; 1310 } 1311 } 1312 } 1313 1314 /* 1315 * Next check for overlap between each of the four sides and the outer 1316 * perimiter of the arc. If the arc isn't filled, then also check the 1317 * inner perimeter of the arc. 1318 */ 1319 1320 if (HorizLineToArc(tRect[0], tRect[2], tRect[1], rx, ry, arcPtr->start, 1321 arcPtr->extent) 1322 || HorizLineToArc(tRect[0], tRect[2], tRect[3], rx, ry, 1323 arcPtr->start, arcPtr->extent) 1324 || VertLineToArc(tRect[0], tRect[1], tRect[3], rx, ry, 1325 arcPtr->start, arcPtr->extent) 1326 || VertLineToArc(tRect[2], tRect[1], tRect[3], rx, ry, 1327 arcPtr->start, arcPtr->extent)) { 1328 return 0; 1329 } 1330 if ((width > 1.0) && !filled) { 1331 rx -= width; 1332 ry -= width; 1333 if (HorizLineToArc(tRect[0], tRect[2], tRect[1], rx, ry, arcPtr->start, 1334 arcPtr->extent) 1335 || HorizLineToArc(tRect[0], tRect[2], tRect[3], rx, ry, 1336 arcPtr->start, arcPtr->extent) 1337 || VertLineToArc(tRect[0], tRect[1], tRect[3], rx, ry, 1338 arcPtr->start, arcPtr->extent) 1339 || VertLineToArc(tRect[2], tRect[1], tRect[3], rx, ry, 1340 arcPtr->start, arcPtr->extent)) { 1341 return 0; 1342 } 1343 } 1344 1345 /* 1346 * The arc still appears to be totally disjoint from the rectangle, but 1347 * it's also possible that the rectangle is totally inside the arc. Do one 1348 * last check, which is to check one point of the rectangle to see if it's 1349 * inside the arc. If it is, we've got overlap. If it isn't, the arc's 1350 * really outside the rectangle. 1351 */ 1352 1353 if (ArcToPoint(canvas, itemPtr, rectPtr) == 0.0) { 1354 return 0; 1355 } 1356 return -1; 1357} 1358 1359/* 1360 *-------------------------------------------------------------- 1361 * 1362 * ScaleArc -- 1363 * 1364 * This function is invoked to rescale an arc item. 1365 * 1366 * Results: 1367 * None. 1368 * 1369 * Side effects: 1370 * The arc referred to by itemPtr is rescaled so that the following 1371 * transformation is applied to all point coordinates: 1372 * x' = originX + scaleX*(x-originX) 1373 * y' = originY + scaleY*(y-originY) 1374 * 1375 *-------------------------------------------------------------- 1376 */ 1377 1378static void 1379ScaleArc( 1380 Tk_Canvas canvas, /* Canvas containing arc. */ 1381 Tk_Item *itemPtr, /* Arc to be scaled. */ 1382 double originX, /* Origin about which to scale rect. */ 1383 double originY, 1384 double scaleX, /* Amount to scale in X direction. */ 1385 double scaleY) /* Amount to scale in Y direction. */ 1386{ 1387 ArcItem *arcPtr = (ArcItem *) itemPtr; 1388 1389 arcPtr->bbox[0] = originX + scaleX*(arcPtr->bbox[0] - originX); 1390 arcPtr->bbox[1] = originY + scaleY*(arcPtr->bbox[1] - originY); 1391 arcPtr->bbox[2] = originX + scaleX*(arcPtr->bbox[2] - originX); 1392 arcPtr->bbox[3] = originY + scaleY*(arcPtr->bbox[3] - originY); 1393 ComputeArcBbox(canvas, arcPtr); 1394} 1395 1396/* 1397 *-------------------------------------------------------------- 1398 * 1399 * TranslateArc -- 1400 * 1401 * This function is called to move an arc by a given amount. 1402 * 1403 * Results: 1404 * None. 1405 * 1406 * Side effects: 1407 * The position of the arc is offset by (xDelta, yDelta), and the 1408 * bounding box is updated in the generic part of the item structure. 1409 * 1410 *-------------------------------------------------------------- 1411 */ 1412 1413static void 1414TranslateArc( 1415 Tk_Canvas canvas, /* Canvas containing item. */ 1416 Tk_Item *itemPtr, /* Item that is being moved. */ 1417 double deltaX, /* Amount by which item is to be moved. */ 1418 double deltaY) 1419{ 1420 ArcItem *arcPtr = (ArcItem *) itemPtr; 1421 1422 arcPtr->bbox[0] += deltaX; 1423 arcPtr->bbox[1] += deltaY; 1424 arcPtr->bbox[2] += deltaX; 1425 arcPtr->bbox[3] += deltaY; 1426 ComputeArcBbox(canvas, arcPtr); 1427} 1428 1429/* 1430 *-------------------------------------------------------------- 1431 * 1432 * ComputeArcOutline -- 1433 * 1434 * This function creates a polygon describing everything in the outline 1435 * for an arc except what's in the curved part. For a "pie slice" arc 1436 * this is a V-shaped chunk, and for a "chord" arc this is a linear chunk 1437 * (with cutaway corners). For "arc" arcs, this stuff isn't relevant. 1438 * 1439 * Results: 1440 * None. 1441 * 1442 * Side effects: 1443 * The information at arcPtr->outlinePtr gets modified, and storage for 1444 * arcPtr->outlinePtr may be allocated or freed. 1445 * 1446 *-------------------------------------------------------------- 1447 */ 1448 1449static void 1450ComputeArcOutline( 1451 Tk_Canvas canvas, /* Information about overall canvas. */ 1452 ArcItem *arcPtr) /* Information about arc. */ 1453{ 1454 double sin1, cos1, sin2, cos2, angle, width, halfWidth; 1455 double boxWidth, boxHeight; 1456 double vertex[2], corner1[2], corner2[2]; 1457 double *outlinePtr; 1458 Tk_State state = arcPtr->header.state; 1459 1460 /* 1461 * Make sure that the outlinePtr array is large enough to hold either a 1462 * chord or pie-slice outline. 1463 */ 1464 1465 if (arcPtr->numOutlinePoints == 0) { 1466 arcPtr->outlinePtr = (double *) ckalloc((unsigned) 1467 (26 * sizeof(double))); 1468 arcPtr->numOutlinePoints = 22; 1469 } 1470 outlinePtr = arcPtr->outlinePtr; 1471 1472 if (state == TK_STATE_NULL) { 1473 state = ((TkCanvas *)canvas)->canvas_state; 1474 } 1475 1476 /* 1477 * First compute the two points that lie at the centers of the ends of the 1478 * curved arc segment, which are marked with X's in the figure below: 1479 * 1480 * 1481 * * * * 1482 * * * 1483 * * * * * 1484 * * * * * 1485 * * * * * 1486 * X * * X 1487 * 1488 * The code is tricky because the arc can be ovular in shape. It computes 1489 * the position for a unit circle, and then scales to fit the shape of the 1490 * arc's bounding box. 1491 * 1492 * Also, watch out because angles go counter-clockwise like you might 1493 * expect, but the y-coordinate system is inverted. To handle this, just 1494 * negate the angles in all the computations. 1495 */ 1496 1497 boxWidth = arcPtr->bbox[2] - arcPtr->bbox[0]; 1498 boxHeight = arcPtr->bbox[3] - arcPtr->bbox[1]; 1499 angle = -arcPtr->start*PI/180.0; 1500 sin1 = sin(angle); 1501 cos1 = cos(angle); 1502 angle -= arcPtr->extent*PI/180.0; 1503 sin2 = sin(angle); 1504 cos2 = cos(angle); 1505 vertex[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0; 1506 vertex[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0; 1507 arcPtr->center1[0] = vertex[0] + cos1*boxWidth/2.0; 1508 arcPtr->center1[1] = vertex[1] + sin1*boxHeight/2.0; 1509 arcPtr->center2[0] = vertex[0] + cos2*boxWidth/2.0; 1510 arcPtr->center2[1] = vertex[1] + sin2*boxHeight/2.0; 1511 1512 /* 1513 * Next compute the "outermost corners" of the arc, which are marked with 1514 * X's in the figure below: 1515 * 1516 * * * * 1517 * * * 1518 * * * * * 1519 * * * * * 1520 * X * * X 1521 * * * 1522 * 1523 * The code below is tricky because it has to handle eccentricity in the 1524 * shape of the oval. The key in the code below is to realize that the 1525 * slope of the line from arcPtr->center1 to corner1 is (boxWidth*sin1) 1526 * divided by (boxHeight*cos1), and similarly for arcPtr->center2 and 1527 * corner2. These formulas can be computed from the formula for the oval. 1528 */ 1529 1530 width = arcPtr->outline.width; 1531 if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *) arcPtr) { 1532 if (arcPtr->outline.activeWidth>arcPtr->outline.width) { 1533 width = arcPtr->outline.activeWidth; 1534 } 1535 } else if (state == TK_STATE_DISABLED) { 1536 if (arcPtr->outline.disabledWidth>arcPtr->outline.width) { 1537 width = arcPtr->outline.disabledWidth; 1538 } 1539 } 1540 halfWidth = width/2.0; 1541 1542 if (((boxWidth*sin1) == 0.0) && ((boxHeight*cos1) == 0.0)) { 1543 angle = 0.0; 1544 } else { 1545 angle = atan2(boxWidth*sin1, boxHeight*cos1); 1546 } 1547 corner1[0] = arcPtr->center1[0] + cos(angle)*halfWidth; 1548 corner1[1] = arcPtr->center1[1] + sin(angle)*halfWidth; 1549 if (((boxWidth*sin2) == 0.0) && ((boxHeight*cos2) == 0.0)) { 1550 angle = 0.0; 1551 } else { 1552 angle = atan2(boxWidth*sin2, boxHeight*cos2); 1553 } 1554 corner2[0] = arcPtr->center2[0] + cos(angle)*halfWidth; 1555 corner2[1] = arcPtr->center2[1] + sin(angle)*halfWidth; 1556 1557 /* 1558 * For a chord outline, generate a six-sided polygon with three points for 1559 * each end of the chord. The first and third points for each end are butt 1560 * points generated on either side of the center point. The second point 1561 * is the corner point. 1562 */ 1563 1564 if (arcPtr->style == CHORD_STYLE) { 1565 outlinePtr[0] = outlinePtr[12] = corner1[0]; 1566 outlinePtr[1] = outlinePtr[13] = corner1[1]; 1567 TkGetButtPoints(arcPtr->center2, arcPtr->center1, 1568 width, 0, outlinePtr+10, outlinePtr+2); 1569 outlinePtr[4] = arcPtr->center2[0] + outlinePtr[2] 1570 - arcPtr->center1[0]; 1571 outlinePtr[5] = arcPtr->center2[1] + outlinePtr[3] 1572 - arcPtr->center1[1]; 1573 outlinePtr[6] = corner2[0]; 1574 outlinePtr[7] = corner2[1]; 1575 outlinePtr[8] = arcPtr->center2[0] + outlinePtr[10] 1576 - arcPtr->center1[0]; 1577 outlinePtr[9] = arcPtr->center2[1] + outlinePtr[11] 1578 - arcPtr->center1[1]; 1579 } else if (arcPtr->style == PIESLICE_STYLE) { 1580 /* 1581 * For pie slices, generate two polygons, one for each side of the pie 1582 * slice. The first arm has a shape like this, where the center of the 1583 * oval is X, arcPtr->center1 is at Y, and corner1 is at Z: 1584 * 1585 * _____________________ 1586 * | \ 1587 * | \ 1588 * X Y Z 1589 * | / 1590 * |_____________________/ 1591 */ 1592 1593 TkGetButtPoints(arcPtr->center1, vertex, width, 0, 1594 outlinePtr, outlinePtr+2); 1595 outlinePtr[4] = arcPtr->center1[0] + outlinePtr[2] - vertex[0]; 1596 outlinePtr[5] = arcPtr->center1[1] + outlinePtr[3] - vertex[1]; 1597 outlinePtr[6] = corner1[0]; 1598 outlinePtr[7] = corner1[1]; 1599 outlinePtr[8] = arcPtr->center1[0] + outlinePtr[0] - vertex[0]; 1600 outlinePtr[9] = arcPtr->center1[1] + outlinePtr[1] - vertex[1]; 1601 outlinePtr[10] = outlinePtr[0]; 1602 outlinePtr[11] = outlinePtr[1]; 1603 1604 /* 1605 * The second arm has a shape like this: 1606 * 1607 * ______________________ 1608 * / \ 1609 * / \ 1610 * Z Y X / 1611 * \ / 1612 * \______________________/ 1613 * 1614 * Similar to above X is the center of the oval/circle, Y is 1615 * arcPtr->center2, and Z is corner2. The extra jog out to the left of 1616 * X is needed in or to produce a butted joint with the first arm; the 1617 * corner to the right of X is one of the first two points of the 1618 * first arm, depending on extent. 1619 */ 1620 1621 TkGetButtPoints(arcPtr->center2, vertex, width, 0, 1622 outlinePtr+12, outlinePtr+16); 1623 if ((arcPtr->extent > 180) || 1624 ((arcPtr->extent < 0) && (arcPtr->extent > -180))) { 1625 outlinePtr[14] = outlinePtr[0]; 1626 outlinePtr[15] = outlinePtr[1]; 1627 } else { 1628 outlinePtr[14] = outlinePtr[2]; 1629 outlinePtr[15] = outlinePtr[3]; 1630 } 1631 outlinePtr[18] = arcPtr->center2[0] + outlinePtr[16] - vertex[0]; 1632 outlinePtr[19] = arcPtr->center2[1] + outlinePtr[17] - vertex[1]; 1633 outlinePtr[20] = corner2[0]; 1634 outlinePtr[21] = corner2[1]; 1635 outlinePtr[22] = arcPtr->center2[0] + outlinePtr[12] - vertex[0]; 1636 outlinePtr[23] = arcPtr->center2[1] + outlinePtr[13] - vertex[1]; 1637 outlinePtr[24] = outlinePtr[12]; 1638 outlinePtr[25] = outlinePtr[13]; 1639 } 1640} 1641 1642/* 1643 *-------------------------------------------------------------- 1644 * 1645 * HorizLineToArc -- 1646 * 1647 * Determines whether a horizontal line segment intersects a given arc. 1648 * 1649 * Results: 1650 * The return value is 1 if the given line intersects the infinitely-thin 1651 * arc section defined by rx, ry, start, and extent, and 0 otherwise. 1652 * Only the perimeter of the arc is checked: interior areas (e.g. chord 1653 * or pie-slice) are not checked. 1654 * 1655 * Side effects: 1656 * None. 1657 * 1658 *-------------------------------------------------------------- 1659 */ 1660 1661static int 1662HorizLineToArc( 1663 double x1, double x2, /* X-coords of endpoints of line segment. X1 1664 * must be <= x2. */ 1665 double y, /* Y-coordinate of line segment. */ 1666 double rx, double ry, /* These x- and y-radii define an oval 1667 * centered at the origin. */ 1668 double start, double extent)/* Angles that define extent of arc, in the 1669 * standard fashion for this module. */ 1670{ 1671 double tmp, x; 1672 double tx, ty; /* Coordinates of intersection point in 1673 * transformed coordinate system. */ 1674 1675 /* 1676 * Compute the x-coordinate of one possible intersection point between the 1677 * arc and the line. Use a transformed coordinate system where the oval is 1678 * a unit circle centered at the origin. Then scale back to get actual 1679 * x-coordinate. 1680 */ 1681 1682 ty = y/ry; 1683 tmp = 1 - ty*ty; 1684 if (tmp < 0) { 1685 return 0; 1686 } 1687 tx = sqrt(tmp); 1688 x = tx*rx; 1689 1690 /* 1691 * Test both intersection points. 1692 */ 1693 1694 if ((x >= x1) && (x <= x2) && AngleInRange(tx, ty, start, extent)) { 1695 return 1; 1696 } 1697 if ((-x >= x1) && (-x <= x2) && AngleInRange(-tx, ty, start, extent)) { 1698 return 1; 1699 } 1700 return 0; 1701} 1702 1703/* 1704 *-------------------------------------------------------------- 1705 * 1706 * VertLineToArc -- 1707 * 1708 * Determines whether a vertical line segment intersects a given arc. 1709 * 1710 * Results: 1711 * The return value is 1 if the given line intersects the infinitely-thin 1712 * arc section defined by rx, ry, start, and extent, and 0 otherwise. 1713 * Only the perimeter of the arc is checked: interior areas (e.g. chord 1714 * or pie-slice) are not checked. 1715 * 1716 * Side effects: 1717 * None. 1718 * 1719 *-------------------------------------------------------------- 1720 */ 1721 1722static int 1723VertLineToArc( 1724 double x, /* X-coordinate of line segment. */ 1725 double y1, double y2, /* Y-coords of endpoints of line segment. Y1 1726 * must be <= y2. */ 1727 double rx, double ry, /* These x- and y-radii define an oval 1728 * centered at the origin. */ 1729 double start, double extent)/* Angles that define extent of arc, in the 1730 * standard fashion for this module. */ 1731{ 1732 double tmp, y; 1733 double tx, ty; /* Coordinates of intersection point in 1734 * transformed coordinate system. */ 1735 1736 /* 1737 * Compute the y-coordinate of one possible intersection point between the 1738 * arc and the line. Use a transformed coordinate system where the oval is 1739 * a unit circle centered at the origin. Then scale back to get actual 1740 * y-coordinate. 1741 */ 1742 1743 tx = x/rx; 1744 tmp = 1 - tx*tx; 1745 if (tmp < 0) { 1746 return 0; 1747 } 1748 ty = sqrt(tmp); 1749 y = ty*ry; 1750 1751 /* 1752 * Test both intersection points. 1753 */ 1754 1755 if ((y > y1) && (y < y2) && AngleInRange(tx, ty, start, extent)) { 1756 return 1; 1757 } 1758 if ((-y > y1) && (-y < y2) && AngleInRange(tx, -ty, start, extent)) { 1759 return 1; 1760 } 1761 return 0; 1762} 1763 1764/* 1765 *-------------------------------------------------------------- 1766 * 1767 * AngleInRange -- 1768 * 1769 * Determine whether the angle from the origin to a given point is within 1770 * a given range. 1771 * 1772 * Results: 1773 * The return value is 1 if the angle from (0,0) to (x,y) is in the range 1774 * given by start and extent, where angles are interpreted in the 1775 * standard way for ovals (meaning backwards from normal interpretation). 1776 * Otherwise the return value is 0. 1777 * 1778 * Side effects: 1779 * None. 1780 * 1781 *-------------------------------------------------------------- 1782 */ 1783 1784static int 1785AngleInRange( 1786 double x, double y, /* Coordinate of point; angle measured from 1787 * origin to here, relative to x-axis. */ 1788 double start, /* First angle, degrees, >=0, <=360. */ 1789 double extent) /* Size of arc in degrees >=-360, <=360. */ 1790{ 1791 double diff; 1792 1793 if ((x == 0.0) && (y == 0.0)) { 1794 return 1; 1795 } 1796 diff = -atan2(y, x); 1797 diff = diff*(180.0/PI) - start; 1798 while (diff > 360.0) { 1799 diff -= 360.0; 1800 } 1801 while (diff < 0.0) { 1802 diff += 360.0; 1803 } 1804 if (extent >= 0) { 1805 return diff <= extent; 1806 } 1807 return (diff-360.0) >= extent; 1808} 1809 1810/* 1811 *-------------------------------------------------------------- 1812 * 1813 * ArcToPostscript -- 1814 * 1815 * This function is called to generate Postscript for arc items. 1816 * 1817 * Results: 1818 * The return value is a standard Tcl result. If an error occurs in 1819 * generating Postscript then an error message is left in the interp's 1820 * result, replacing whatever used to be there. If no error occurs, then 1821 * Postscript for the item is appended to the result. 1822 * 1823 * Side effects: 1824 * None. 1825 * 1826 *-------------------------------------------------------------- 1827 */ 1828 1829static int 1830ArcToPostscript( 1831 Tcl_Interp *interp, /* Leave Postscript or error message here. */ 1832 Tk_Canvas canvas, /* Information about overall canvas. */ 1833 Tk_Item *itemPtr, /* Item for which Postscript is wanted. */ 1834 int prepass) /* 1 means this is a prepass to collect font 1835 * information; 0 means final Postscript is 1836 * being created. */ 1837{ 1838 ArcItem *arcPtr = (ArcItem *) itemPtr; 1839 char buffer[400]; 1840 double y1, y2, ang1, ang2; 1841 XColor *color; 1842 Pixmap stipple; 1843 XColor *fillColor; 1844 Pixmap fillStipple; 1845 Tk_State state = itemPtr->state; 1846 1847 y1 = Tk_CanvasPsY(canvas, arcPtr->bbox[1]); 1848 y2 = Tk_CanvasPsY(canvas, arcPtr->bbox[3]); 1849 ang1 = arcPtr->start; 1850 ang2 = ang1 + arcPtr->extent; 1851 if (ang2 < ang1) { 1852 ang1 = ang2; 1853 ang2 = arcPtr->start; 1854 } 1855 1856 if (state == TK_STATE_NULL) { 1857 state = ((TkCanvas *)canvas)->canvas_state; 1858 } 1859 color = arcPtr->outline.color; 1860 stipple = arcPtr->outline.stipple; 1861 fillColor = arcPtr->fillColor; 1862 fillStipple = arcPtr->fillStipple; 1863 if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { 1864 if (arcPtr->outline.activeColor!=NULL) { 1865 color = arcPtr->outline.activeColor; 1866 } 1867 if (arcPtr->outline.activeStipple!=None) { 1868 stipple = arcPtr->outline.activeStipple; 1869 } 1870 if (arcPtr->activeFillColor!=NULL) { 1871 fillColor = arcPtr->activeFillColor; 1872 } 1873 if (arcPtr->activeFillStipple!=None) { 1874 fillStipple = arcPtr->activeFillStipple; 1875 } 1876 } else if (state == TK_STATE_DISABLED) { 1877 if (arcPtr->outline.disabledColor!=NULL) { 1878 color = arcPtr->outline.disabledColor; 1879 } 1880 if (arcPtr->outline.disabledStipple!=None) { 1881 stipple = arcPtr->outline.disabledStipple; 1882 } 1883 if (arcPtr->disabledFillColor!=NULL) { 1884 fillColor = arcPtr->disabledFillColor; 1885 } 1886 if (arcPtr->disabledFillStipple!=None) { 1887 fillStipple = arcPtr->disabledFillStipple; 1888 } 1889 } 1890 1891 /* 1892 * If the arc is filled, output Postscript for the interior region of the 1893 * arc. 1894 */ 1895 1896 if (arcPtr->fillGC != None) { 1897 sprintf(buffer, "matrix currentmatrix\n%.15g %.15g translate %.15g %.15g scale\n", 1898 (arcPtr->bbox[0] + arcPtr->bbox[2])/2, (y1 + y2)/2, 1899 (arcPtr->bbox[2] - arcPtr->bbox[0])/2, (y1 - y2)/2); 1900 Tcl_AppendResult(interp, buffer, NULL); 1901 if (arcPtr->style == CHORD_STYLE) { 1902 sprintf(buffer, "0 0 1 %.15g %.15g arc closepath\nsetmatrix\n", 1903 ang1, ang2); 1904 } else { 1905 sprintf(buffer, 1906 "0 0 moveto 0 0 1 %.15g %.15g arc closepath\nsetmatrix\n", 1907 ang1, ang2); 1908 } 1909 Tcl_AppendResult(interp, buffer, NULL); 1910 if (Tk_CanvasPsColor(interp, canvas, fillColor) != TCL_OK) { 1911 return TCL_ERROR; 1912 } 1913 if (fillStipple != None) { 1914 Tcl_AppendResult(interp, "clip ", NULL); 1915 if (Tk_CanvasPsStipple(interp, canvas, fillStipple) != TCL_OK) { 1916 return TCL_ERROR; 1917 } 1918 if (arcPtr->outline.gc != None) { 1919 Tcl_AppendResult(interp, "grestore gsave\n", NULL); 1920 } 1921 } else { 1922 Tcl_AppendResult(interp, "fill\n", NULL); 1923 } 1924 } 1925 1926 /* 1927 * If there's an outline for the arc, draw it. 1928 */ 1929 1930 if (arcPtr->outline.gc != None) { 1931 sprintf(buffer, "matrix currentmatrix\n%.15g %.15g translate %.15g %.15g scale\n", 1932 (arcPtr->bbox[0] + arcPtr->bbox[2])/2, (y1 + y2)/2, 1933 (arcPtr->bbox[2] - arcPtr->bbox[0])/2, (y1 - y2)/2); 1934 Tcl_AppendResult(interp, buffer, NULL); 1935 sprintf(buffer, "0 0 1 %.15g %.15g", ang1, ang2); 1936 Tcl_AppendResult(interp, buffer, 1937 " arc\nsetmatrix\n0 setlinecap\n", NULL); 1938 if (Tk_CanvasPsOutline(canvas, itemPtr, &(arcPtr->outline)) != TCL_OK){ 1939 return TCL_ERROR; 1940 } 1941 if (arcPtr->style != ARC_STYLE) { 1942 Tcl_AppendResult(interp, "grestore gsave\n", NULL); 1943 if (arcPtr->style == CHORD_STYLE) { 1944 Tk_CanvasPsPath(interp, canvas, arcPtr->outlinePtr, 1945 CHORD_OUTLINE_PTS); 1946 } else { 1947 Tk_CanvasPsPath(interp, canvas, arcPtr->outlinePtr, 1948 PIE_OUTLINE1_PTS); 1949 if (Tk_CanvasPsColor(interp, canvas, color) 1950 != TCL_OK) { 1951 return TCL_ERROR; 1952 } 1953 if (stipple != None) { 1954 Tcl_AppendResult(interp, "clip ", NULL); 1955 if (Tk_CanvasPsStipple(interp, canvas, stipple) != TCL_OK){ 1956 return TCL_ERROR; 1957 } 1958 } else { 1959 Tcl_AppendResult(interp, "fill\n", NULL); 1960 } 1961 Tcl_AppendResult(interp, "grestore gsave\n", NULL); 1962 Tk_CanvasPsPath(interp, canvas, 1963 arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS, 1964 PIE_OUTLINE2_PTS); 1965 } 1966 if (Tk_CanvasPsColor(interp, canvas, color) 1967 != TCL_OK) { 1968 return TCL_ERROR; 1969 } 1970 if (stipple != None) { 1971 Tcl_AppendResult(interp, "clip ", NULL); 1972 if (Tk_CanvasPsStipple(interp, canvas, stipple) != TCL_OK) { 1973 return TCL_ERROR; 1974 } 1975 } else { 1976 Tcl_AppendResult(interp, "fill\n", NULL); 1977 } 1978 } 1979 } 1980 1981 return TCL_OK; 1982} 1983 1984/* 1985 *-------------------------------------------------------------- 1986 * 1987 * StyleParseProc -- 1988 * 1989 * This function is invoked during option processing to handle the 1990 * "-style" option. 1991 * 1992 * Results: 1993 * A standard Tcl return value. 1994 * 1995 * Side effects: 1996 * The state for a given item gets replaced by the state indicated in the 1997 * value argument. 1998 * 1999 *-------------------------------------------------------------- 2000 */ 2001 2002static int 2003StyleParseProc( 2004 ClientData clientData, /* some flags.*/ 2005 Tcl_Interp *interp, /* Used for reporting errors. */ 2006 Tk_Window tkwin, /* Window containing canvas widget. */ 2007 CONST char *value, /* Value of option. */ 2008 char *widgRec, /* Pointer to record for item. */ 2009 int offset) /* Offset into item. */ 2010{ 2011 int c; 2012 size_t length; 2013 2014 register Style *stylePtr = (Style *) (widgRec + offset); 2015 2016 if (value == NULL || *value == 0) { 2017 *stylePtr = PIESLICE_STYLE; 2018 return TCL_OK; 2019 } 2020 2021 c = value[0]; 2022 length = strlen(value); 2023 2024 if ((c == 'a') && (strncmp(value, "arc", length) == 0)) { 2025 *stylePtr = ARC_STYLE; 2026 return TCL_OK; 2027 } 2028 if ((c == 'c') && (strncmp(value, "chord", length) == 0)) { 2029 *stylePtr = CHORD_STYLE; 2030 return TCL_OK; 2031 } 2032 if ((c == 'p') && (strncmp(value, "pieslice", length) == 0)) { 2033 *stylePtr = PIESLICE_STYLE; 2034 return TCL_OK; 2035 } 2036 2037 Tcl_AppendResult(interp, "bad -style option \"", value, 2038 "\": must be arc, chord, or pieslice", NULL); 2039 *stylePtr = PIESLICE_STYLE; 2040 return TCL_ERROR; 2041} 2042 2043/* 2044 *-------------------------------------------------------------- 2045 * 2046 * StylePrintProc -- 2047 * 2048 * This function is invoked by the Tk configuration code to produce a 2049 * printable string for the "-style" configuration option. 2050 * 2051 * Results: 2052 * The return value is a string describing the state for the item 2053 * referred to by "widgRec". In addition, *freeProcPtr is filled in with 2054 * the address of a function to call to free the result string when it's 2055 * no longer needed (or NULL to indicate that the string doesn't need to 2056 * be freed). 2057 * 2058 * Side effects: 2059 * None. 2060 * 2061 *-------------------------------------------------------------- 2062 */ 2063 2064static char * 2065StylePrintProc( 2066 ClientData clientData, /* Ignored. */ 2067 Tk_Window tkwin, /* Ignored. */ 2068 char *widgRec, /* Pointer to record for item. */ 2069 int offset, /* Offset into item. */ 2070 Tcl_FreeProc **freeProcPtr) /* Pointer to variable to fill in with 2071 * information about how to reclaim storage 2072 * for return string. */ 2073{ 2074 register Style *stylePtr = (Style *) (widgRec + offset); 2075 2076 if (*stylePtr == ARC_STYLE) { 2077 return "arc"; 2078 } else if (*stylePtr == CHORD_STYLE) { 2079 return "chord"; 2080 } else { 2081 return "pieslice"; 2082 } 2083} 2084 2085/* 2086 * Local Variables: 2087 * mode: c 2088 * c-basic-offset: 4 2089 * fill-column: 78 2090 * End: 2091 */ 2092