tkCanvPoly.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:58k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkCanvPoly.c --
  3.  *
  4.  * This file implements polygon items for canvas widgets.
  5.  *
  6.  * Copyright (c) 1991-1994 The Regents of the University of California.
  7.  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
  8.  * Copyright (c) 1998-2000 Ajuba Solutions.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  * RCS: @(#) $Id: tkCanvPoly.c,v 1.10.2.3 2006/10/16 15:35:50 das Exp $
  14.  */
  15. #include <stdio.h>
  16. #include "tkInt.h"
  17. #include "tkPort.h"
  18. #include "tkCanvas.h"
  19. /*
  20.  * The structure below defines the record for each polygon item.
  21.  */
  22. typedef struct PolygonItem  {
  23.     Tk_Item header; /* Generic stuff that's the same for all
  24.  * types.  MUST BE FIRST IN STRUCTURE. */
  25.     Tk_Outline outline; /* Outline structure */
  26.     int numPoints; /* Number of points in polygon.
  27.  * Polygon is always closed. */
  28.     int pointsAllocated; /* Number of points for which space is
  29.  * allocated at *coordPtr. */
  30.     double *coordPtr; /* Pointer to malloc-ed array containing
  31.  * x- and y-coords of all points in polygon.
  32.  * X-coords are even-valued indices, y-coords
  33.  * are corresponding odd-valued indices. */
  34.     int joinStyle; /* Join style for outline */
  35.     Tk_TSOffset tsoffset;
  36.     XColor *fillColor; /* Foreground color for polygon. */
  37.     XColor *activeFillColor; /* Foreground color for polygon if state is active. */
  38.     XColor *disabledFillColor; /* Foreground color for polygon if state is disabled. */
  39.     Pixmap fillStipple; /* Stipple bitmap for filling polygon. */
  40.     Pixmap activeFillStipple; /* Stipple bitmap for filling polygon if state is active. */
  41.     Pixmap disabledFillStipple; /* Stipple bitmap for filling polygon if state is disabled. */
  42.     GC fillGC; /* Graphics context for filling polygon. */
  43.     Tk_SmoothMethod *smooth; /* Non-zero means draw shape smoothed (i.e.
  44.  * with Bezier splines). */
  45.     int splineSteps; /* Number of steps in each spline segment. */
  46.     int autoClosed; /* Zero means the given polygon was closed,
  47.    one means that we auto closed it. */
  48. } PolygonItem;
  49. /*
  50.  * Information used for parsing configuration specs:
  51.  */
  52. static Tk_CustomOption smoothOption = {
  53.     (Tk_OptionParseProc *) TkSmoothParseProc,
  54.     TkSmoothPrintProc, (ClientData) NULL
  55. };
  56. static Tk_CustomOption stateOption = {
  57.     (Tk_OptionParseProc *) TkStateParseProc,
  58.     TkStatePrintProc, (ClientData) 2
  59. };
  60. static Tk_CustomOption tagsOption = {
  61.     (Tk_OptionParseProc *) Tk_CanvasTagsParseProc,
  62.     Tk_CanvasTagsPrintProc, (ClientData) NULL
  63. };
  64. static Tk_CustomOption dashOption = {
  65.     (Tk_OptionParseProc *) TkCanvasDashParseProc,
  66.     TkCanvasDashPrintProc, (ClientData) NULL
  67. };
  68. static Tk_CustomOption offsetOption = {
  69.     (Tk_OptionParseProc *) TkOffsetParseProc,
  70.     TkOffsetPrintProc,
  71.     (ClientData) (TK_OFFSET_RELATIVE|TK_OFFSET_INDEX)
  72. };
  73. static Tk_CustomOption pixelOption = {
  74.     (Tk_OptionParseProc *) TkPixelParseProc,
  75.     TkPixelPrintProc, (ClientData) NULL
  76. };
  77. static Tk_ConfigSpec configSpecs[] = {
  78.     {TK_CONFIG_CUSTOM, "-activedash", (char *) NULL, (char *) NULL,
  79. (char *) NULL, Tk_Offset(PolygonItem, outline.activeDash),
  80. TK_CONFIG_NULL_OK, &dashOption},
  81.     {TK_CONFIG_COLOR, "-activefill", (char *) NULL, (char *) NULL,
  82. (char *) NULL, Tk_Offset(PolygonItem, activeFillColor),
  83. TK_CONFIG_NULL_OK},
  84.     {TK_CONFIG_COLOR, "-activeoutline", (char *) NULL, (char *) NULL,
  85. (char *) NULL, Tk_Offset(PolygonItem, outline.activeColor),
  86. TK_CONFIG_NULL_OK},
  87.     {TK_CONFIG_BITMAP, "-activeoutlinestipple", (char *) NULL, (char *) NULL,
  88. (char *) NULL, Tk_Offset(PolygonItem, outline.activeStipple),
  89. TK_CONFIG_NULL_OK},
  90.     {TK_CONFIG_BITMAP, "-activestipple", (char *) NULL, (char *) NULL,
  91. (char *) NULL, Tk_Offset(PolygonItem, activeFillStipple),
  92. TK_CONFIG_NULL_OK},
  93.     {TK_CONFIG_CUSTOM, "-activewidth", (char *) NULL, (char *) NULL,
  94. "0.0", Tk_Offset(PolygonItem, outline.activeWidth),
  95. TK_CONFIG_DONT_SET_DEFAULT, &pixelOption},
  96.     {TK_CONFIG_CUSTOM, "-dash", (char *) NULL, (char *) NULL,
  97. (char *) NULL, Tk_Offset(PolygonItem, outline.dash),
  98. TK_CONFIG_NULL_OK, &dashOption},
  99.     {TK_CONFIG_PIXELS, "-dashoffset", (char *) NULL, (char *) NULL,
  100. "0", Tk_Offset(PolygonItem, outline.offset),
  101. TK_CONFIG_DONT_SET_DEFAULT},
  102.     {TK_CONFIG_CUSTOM, "-disableddash", (char *) NULL, (char *) NULL,
  103. (char *) NULL, Tk_Offset(PolygonItem, outline.disabledDash),
  104. TK_CONFIG_NULL_OK, &dashOption},
  105.     {TK_CONFIG_COLOR, "-disabledfill", (char *) NULL, (char *) NULL,
  106. (char *) NULL, Tk_Offset(PolygonItem, disabledFillColor),
  107. TK_CONFIG_NULL_OK},
  108.     {TK_CONFIG_COLOR, "-disabledoutline", (char *) NULL, (char *) NULL,
  109. (char *) NULL, Tk_Offset(PolygonItem, outline.disabledColor),
  110. TK_CONFIG_NULL_OK},
  111.     {TK_CONFIG_BITMAP, "-disabledoutlinestipple", (char *) NULL, (char *) NULL,
  112. (char *) NULL, Tk_Offset(PolygonItem, outline.disabledStipple),
  113. TK_CONFIG_NULL_OK},
  114.     {TK_CONFIG_BITMAP, "-disabledstipple", (char *) NULL, (char *) NULL,
  115. (char *) NULL, Tk_Offset(PolygonItem, disabledFillStipple),
  116. TK_CONFIG_NULL_OK},
  117.     {TK_CONFIG_CUSTOM, "-disabledwidth", (char *) NULL, (char *) NULL,
  118. "0.0", Tk_Offset(PolygonItem, outline.disabledWidth),
  119. TK_CONFIG_DONT_SET_DEFAULT, &pixelOption},
  120.     {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL,
  121. "black", Tk_Offset(PolygonItem, fillColor), TK_CONFIG_NULL_OK},
  122.     {TK_CONFIG_JOIN_STYLE, "-joinstyle", (char *) NULL, (char *) NULL,
  123. "round", Tk_Offset(PolygonItem, joinStyle), TK_CONFIG_DONT_SET_DEFAULT},
  124.     {TK_CONFIG_CUSTOM, "-offset", (char *) NULL, (char *) NULL,
  125. "0,0", Tk_Offset(PolygonItem, tsoffset),
  126. TK_CONFIG_NULL_OK, &offsetOption},
  127.     {TK_CONFIG_COLOR, "-outline", (char *) NULL, (char *) NULL,
  128. (char *) NULL, Tk_Offset(PolygonItem, outline.color),
  129. TK_CONFIG_NULL_OK},
  130.     {TK_CONFIG_CUSTOM, "-outlineoffset", (char *) NULL, (char *) NULL,
  131. "0,0", Tk_Offset(PolygonItem, outline.tsoffset),
  132. TK_CONFIG_NULL_OK, &offsetOption},
  133.     {TK_CONFIG_BITMAP, "-outlinestipple", (char *) NULL, (char *) NULL,
  134. (char *) NULL, Tk_Offset(PolygonItem, outline.stipple),
  135. TK_CONFIG_NULL_OK},
  136.     {TK_CONFIG_CUSTOM, "-smooth", (char *) NULL, (char *) NULL,
  137. "0", Tk_Offset(PolygonItem, smooth),
  138. TK_CONFIG_DONT_SET_DEFAULT, &smoothOption},
  139.     {TK_CONFIG_INT, "-splinesteps", (char *) NULL, (char *) NULL,
  140. "12", Tk_Offset(PolygonItem, splineSteps), TK_CONFIG_DONT_SET_DEFAULT},
  141.     {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL,
  142. (char *) NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK,
  143. &stateOption},
  144.     {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL,
  145. (char *) NULL, Tk_Offset(PolygonItem, fillStipple), TK_CONFIG_NULL_OK},
  146.     {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL,
  147. (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption},
  148.     {TK_CONFIG_CUSTOM, "-width", (char *) NULL, (char *) NULL,
  149. "1.0", Tk_Offset(PolygonItem, outline.width),
  150. TK_CONFIG_DONT_SET_DEFAULT, &pixelOption},
  151.     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  152. (char *) NULL, 0, 0}
  153. };
  154. /*
  155.  * Prototypes for procedures defined in this file:
  156.  */
  157. static void ComputePolygonBbox _ANSI_ARGS_((Tk_Canvas canvas,
  158.     PolygonItem *polyPtr));
  159. static int ConfigurePolygon _ANSI_ARGS_((Tcl_Interp *interp,
  160.     Tk_Canvas canvas, Tk_Item *itemPtr, int objc,
  161.     Tcl_Obj *CONST objv[], int flags));
  162. static int CreatePolygon _ANSI_ARGS_((Tcl_Interp *interp,
  163.     Tk_Canvas canvas, struct Tk_Item *itemPtr,
  164.     int objc, Tcl_Obj *CONST objv[]));
  165. static void DeletePolygon _ANSI_ARGS_((Tk_Canvas canvas,
  166.     Tk_Item *itemPtr,  Display *display));
  167. static void DisplayPolygon _ANSI_ARGS_((Tk_Canvas canvas,
  168.     Tk_Item *itemPtr, Display *display, Drawable dst,
  169.     int x, int y, int width, int height));
  170. static int GetPolygonIndex _ANSI_ARGS_((Tcl_Interp *interp,
  171.     Tk_Canvas canvas, Tk_Item *itemPtr,
  172.     Tcl_Obj *obj, int *indexPtr));
  173. static int PolygonCoords _ANSI_ARGS_((Tcl_Interp *interp,
  174.     Tk_Canvas canvas, Tk_Item *itemPtr,
  175.     int objc, Tcl_Obj *CONST objv[]));
  176. static void PolygonDeleteCoords _ANSI_ARGS_((Tk_Canvas canvas,
  177.     Tk_Item *itemPtr, int first, int last));
  178. static void PolygonInsert _ANSI_ARGS_((Tk_Canvas canvas,
  179.     Tk_Item *itemPtr, int beforeThis, Tcl_Obj *obj));
  180. static int PolygonToArea _ANSI_ARGS_((Tk_Canvas canvas,
  181.     Tk_Item *itemPtr, double *rectPtr));
  182. static double PolygonToPoint _ANSI_ARGS_((Tk_Canvas canvas,
  183.     Tk_Item *itemPtr, double *pointPtr));
  184. static int PolygonToPostscript _ANSI_ARGS_((Tcl_Interp *interp,
  185.     Tk_Canvas canvas, Tk_Item *itemPtr, int prepass));
  186. static void ScalePolygon _ANSI_ARGS_((Tk_Canvas canvas,
  187.     Tk_Item *itemPtr, double originX, double originY,
  188.     double scaleX, double scaleY));
  189. static void TranslatePolygon _ANSI_ARGS_((Tk_Canvas canvas,
  190.     Tk_Item *itemPtr, double deltaX, double deltaY));
  191. /*
  192.  * The structures below defines the polygon item type by means
  193.  * of procedures that can be invoked by generic item code.
  194.  */
  195. Tk_ItemType tkPolygonType = {
  196.     "polygon", /* name */
  197.     sizeof(PolygonItem), /* itemSize */
  198.     CreatePolygon, /* createProc */
  199.     configSpecs, /* configSpecs */
  200.     ConfigurePolygon, /* configureProc */
  201.     PolygonCoords, /* coordProc */
  202.     DeletePolygon, /* deleteProc */
  203.     DisplayPolygon, /* displayProc */
  204.     TK_CONFIG_OBJS, /* flags */
  205.     PolygonToPoint, /* pointProc */
  206.     PolygonToArea, /* areaProc */
  207.     PolygonToPostscript, /* postscriptProc */
  208.     ScalePolygon, /* scaleProc */
  209.     TranslatePolygon, /* translateProc */
  210.     (Tk_ItemIndexProc *) GetPolygonIndex,/* indexProc */
  211.     (Tk_ItemCursorProc *) NULL, /* icursorProc */
  212.     (Tk_ItemSelectionProc *) NULL, /* selectionProc */
  213.     (Tk_ItemInsertProc *) PolygonInsert,/* insertProc */
  214.     PolygonDeleteCoords, /* dTextProc */
  215.     (Tk_ItemType *) NULL, /* nextPtr */
  216. };
  217. /*
  218.  * The definition below determines how large are static arrays
  219.  * used to hold spline points (splines larger than this have to
  220.  * have their arrays malloc-ed).
  221.  */
  222. #define MAX_STATIC_POINTS 200
  223. /*
  224.  *--------------------------------------------------------------
  225.  *
  226.  * CreatePolygon --
  227.  *
  228.  * This procedure is invoked to create a new polygon item in
  229.  * a canvas.
  230.  *
  231.  * Results:
  232.  * A standard Tcl return value.  If an error occurred in
  233.  * creating the item, then an error message is left in
  234.  * the interp's result;  in this case itemPtr is
  235.  * left uninitialized, so it can be safely freed by the
  236.  * caller.
  237.  *
  238.  * Side effects:
  239.  * A new polygon item is created.
  240.  *
  241.  *--------------------------------------------------------------
  242.  */
  243. static int
  244. CreatePolygon(interp, canvas, itemPtr, objc, objv)
  245.     Tcl_Interp *interp; /* Interpreter for error reporting. */
  246.     Tk_Canvas canvas; /* Canvas to hold new item. */
  247.     Tk_Item *itemPtr; /* Record to hold new item;  header
  248.  * has been initialized by caller. */
  249.     int objc; /* Number of arguments in objv. */
  250.     Tcl_Obj *CONST objv[]; /* Arguments describing polygon. */
  251. {
  252.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  253.     int i;
  254.     if (objc == 0) {
  255. panic("canvas did not pass any coordsn");
  256.     }
  257.     /*
  258.      * Carry out initialization that is needed in order to clean
  259.      * up after errors during the the remainder of this procedure.
  260.      */
  261.     Tk_CreateOutline(&(polyPtr->outline));
  262.     polyPtr->numPoints = 0;
  263.     polyPtr->pointsAllocated = 0;
  264.     polyPtr->coordPtr = NULL;
  265.     polyPtr->joinStyle = JoinRound;
  266.     polyPtr->tsoffset.flags = 0;
  267.     polyPtr->tsoffset.xoffset = 0;
  268.     polyPtr->tsoffset.yoffset = 0;
  269.     polyPtr->fillColor = NULL;
  270.     polyPtr->activeFillColor = NULL;
  271.     polyPtr->disabledFillColor = NULL;
  272.     polyPtr->fillStipple = None;
  273.     polyPtr->activeFillStipple = None;
  274.     polyPtr->disabledFillStipple = None;
  275.     polyPtr->fillGC = None;
  276.     polyPtr->smooth = (Tk_SmoothMethod *) NULL;
  277.     polyPtr->splineSteps = 12;
  278.     polyPtr->autoClosed = 0;
  279.     /*
  280.      * Count the number of points and then parse them into a point
  281.      * array.  Leading arguments are assumed to be points if they
  282.      * start with a digit or a minus sign followed by a digit.
  283.      */
  284.     for (i = 0; i < objc; i++) {
  285. char *arg = Tcl_GetString(objv[i]);
  286. if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) {
  287.     break;
  288. }
  289.     }
  290.     if (i && PolygonCoords(interp, canvas, itemPtr, i, objv) != TCL_OK) {
  291. goto error;
  292.     }
  293.     if (ConfigurePolygon(interp, canvas, itemPtr, objc-i, objv+i, 0)
  294.     == TCL_OK) {
  295. return TCL_OK;
  296.     }
  297.     error:
  298.     DeletePolygon(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas)));
  299.     return TCL_ERROR;
  300. }
  301. /*
  302.  *--------------------------------------------------------------
  303.  *
  304.  * PolygonCoords --
  305.  *
  306.  * This procedure is invoked to process the "coords" widget
  307.  * command on polygons.  See the user documentation for details
  308.  * on what it does.
  309.  *
  310.  * Results:
  311.  * Returns TCL_OK or TCL_ERROR, and sets the interp's result.
  312.  *
  313.  * Side effects:
  314.  * The coordinates for the given item may be changed.
  315.  *
  316.  *--------------------------------------------------------------
  317.  */
  318. static int
  319. PolygonCoords(interp, canvas, itemPtr, objc, objv)
  320.     Tcl_Interp *interp; /* Used for error reporting. */
  321.     Tk_Canvas canvas; /* Canvas containing item. */
  322.     Tk_Item *itemPtr; /* Item whose coordinates are to be
  323.  * read or modified. */
  324.     int objc; /* Number of coordinates supplied in
  325.  * objv. */
  326.     Tcl_Obj *CONST objv[]; /* Array of coordinates: x1, y1,
  327.  * x2, y2, ... */
  328. {
  329.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  330.     int i, numPoints;
  331.     if (objc == 0) {
  332. /*
  333.  * Print the coords used to create the polygon.  If we auto
  334.  * closed the polygon then we don't report the last point.
  335.  */
  336. Tcl_Obj *subobj, *obj = Tcl_NewObj();
  337. for (i = 0; i < 2*(polyPtr->numPoints - polyPtr->autoClosed); i++) {
  338.     subobj = Tcl_NewDoubleObj(polyPtr->coordPtr[i]);
  339.     Tcl_ListObjAppendElement(interp, obj, subobj);
  340. }
  341. Tcl_SetObjResult(interp, obj);
  342. return TCL_OK;
  343.     }
  344.     if (objc == 1) {
  345. if (Tcl_ListObjGetElements(interp, objv[0], &objc,
  346. (Tcl_Obj ***) &objv) != TCL_OK) {
  347.     return TCL_ERROR;
  348. }
  349.     }
  350.     if (objc & 1) {
  351. char buf[64 + TCL_INTEGER_SPACE];
  352. sprintf(buf, "wrong # coordinates: expected an even number, got %d",
  353. objc);
  354. Tcl_SetResult(interp, buf, TCL_VOLATILE);
  355. return TCL_ERROR;
  356.     } else {
  357. numPoints = objc/2;
  358. if (polyPtr->pointsAllocated <= numPoints) {
  359.     if (polyPtr->coordPtr != NULL) {
  360. ckfree((char *) polyPtr->coordPtr);
  361.     }
  362.     /*
  363.      * One extra point gets allocated here, because we always
  364.      * add another point to close the polygon.
  365.      */
  366.     polyPtr->coordPtr = (double *) ckalloc((unsigned)
  367.     (sizeof(double) * (objc+2)));
  368.     polyPtr->pointsAllocated = numPoints+1;
  369. }
  370. for (i = objc-1; i >= 0; i--) {
  371.     if (Tk_CanvasGetCoordFromObj(interp, canvas, objv[i],
  372.     &polyPtr->coordPtr[i]) != TCL_OK) {
  373. return TCL_ERROR;
  374.     }
  375. }
  376. polyPtr->numPoints = numPoints;
  377. polyPtr->autoClosed = 0;
  378. /*
  379.  * Close the polygon if it isn't already closed.
  380.  */
  381.     
  382. if (objc>2 && ((polyPtr->coordPtr[objc-2] != polyPtr->coordPtr[0])
  383. || (polyPtr->coordPtr[objc-1] != polyPtr->coordPtr[1]))) {
  384.     polyPtr->autoClosed = 1;
  385.     polyPtr->numPoints++;
  386.     polyPtr->coordPtr[objc] = polyPtr->coordPtr[0];
  387.     polyPtr->coordPtr[objc+1] = polyPtr->coordPtr[1];
  388. }
  389. ComputePolygonBbox(canvas, polyPtr);
  390.     }
  391.     return TCL_OK;
  392. }
  393. /*
  394.  *--------------------------------------------------------------
  395.  *
  396.  * ConfigurePolygon --
  397.  *
  398.  * This procedure is invoked to configure various aspects
  399.  * of a polygon item such as its background color.
  400.  *
  401.  * Results:
  402.  * A standard Tcl result code.  If an error occurs, then
  403.  * an error message is left in the interp's result.
  404.  *
  405.  * Side effects:
  406.  * Configuration information, such as colors and stipple
  407.  * patterns, may be set for itemPtr.
  408.  *
  409.  *--------------------------------------------------------------
  410.  */
  411. static int
  412. ConfigurePolygon(interp, canvas, itemPtr, objc, objv, flags)
  413.     Tcl_Interp *interp; /* Interpreter for error reporting. */
  414.     Tk_Canvas canvas; /* Canvas containing itemPtr. */
  415.     Tk_Item *itemPtr; /* Polygon item to reconfigure. */
  416.     int objc; /* Number of elements in objv.  */
  417.     Tcl_Obj *CONST objv[]; /* Arguments describing things to configure. */
  418.     int flags; /* Flags to pass to Tk_ConfigureWidget. */
  419. {
  420.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  421.     XGCValues gcValues;
  422.     GC newGC;
  423.     unsigned long mask;
  424.     Tk_Window tkwin;
  425.     XColor *color;
  426.     Pixmap stipple;
  427.     Tk_State state;
  428.     tkwin = Tk_CanvasTkwin(canvas);
  429.     if (TCL_OK != Tk_ConfigureWidget(interp, tkwin, configSpecs, objc,
  430.     (CONST char **) objv, (char *) polyPtr, flags|TK_CONFIG_OBJS)) {
  431. return TCL_ERROR;
  432.     }
  433.     /*
  434.      * A few of the options require additional processing, such as
  435.      * graphics contexts.
  436.      */
  437.     state = itemPtr->state;
  438.     if (polyPtr->outline.activeWidth > polyPtr->outline.width ||
  439.     polyPtr->outline.activeDash.number != 0 ||
  440.     polyPtr->outline.activeColor != NULL ||
  441.     polyPtr->outline.activeStipple != None ||
  442.     polyPtr->activeFillColor != NULL ||
  443.     polyPtr->activeFillStipple != None) {
  444. itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT;
  445.     } else {
  446. itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT;
  447.     }
  448.     if(state == TK_STATE_NULL) {
  449. state = ((TkCanvas *)canvas)->canvas_state;
  450.     }
  451.     if (state==TK_STATE_HIDDEN) {
  452. ComputePolygonBbox(canvas, polyPtr);
  453. return TCL_OK;
  454.     }
  455.     mask = Tk_ConfigOutlineGC(&gcValues, canvas, itemPtr, &(polyPtr->outline));
  456.     if (mask) {
  457. gcValues.cap_style = CapRound;
  458. gcValues.join_style = polyPtr->joinStyle;
  459. mask |= GCCapStyle|GCJoinStyle;
  460. newGC = Tk_GetGC(tkwin, mask, &gcValues);
  461.     } else {
  462. newGC = None;
  463.     }
  464.     if (polyPtr->outline.gc != None) {
  465. Tk_FreeGC(Tk_Display(tkwin), polyPtr->outline.gc);
  466.     }
  467.     polyPtr->outline.gc = newGC;
  468.     color = polyPtr->fillColor;
  469.     stipple = polyPtr->fillStipple;
  470.     if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) {
  471. if (polyPtr->activeFillColor!=NULL) {
  472.     color = polyPtr->activeFillColor;
  473. }
  474. if (polyPtr->activeFillStipple!=None) {
  475.     stipple = polyPtr->activeFillStipple;
  476. }
  477.     } else if (state==TK_STATE_DISABLED) {
  478. if (polyPtr->disabledFillColor!=NULL) {
  479.     color = polyPtr->disabledFillColor;
  480. }
  481. if (polyPtr->disabledFillStipple!=None) {
  482.     stipple = polyPtr->disabledFillStipple;
  483. }
  484.     }
  485.     if (color == NULL) {
  486. newGC = None;
  487.     } else {
  488. gcValues.foreground = color->pixel;
  489. mask = GCForeground;
  490. if (stipple != None) {
  491.     gcValues.stipple = stipple;
  492.     gcValues.fill_style = FillStippled;
  493.     mask |= GCStipple|GCFillStyle;
  494. }
  495. #ifdef MAC_OSX_TK
  496. /*
  497.  * Mac OS X CG drawing needs access to the outline linewidth
  498.  * even for fills (as linewidth controls antialiasing).
  499.  */
  500. gcValues.line_width = polyPtr->outline.gc != None ? 
  501. polyPtr->outline.gc->line_width : 0;
  502. mask |= GCLineWidth;
  503. #endif
  504. newGC = Tk_GetGC(tkwin, mask, &gcValues);
  505.     }
  506.     if (polyPtr->fillGC != None) {
  507. Tk_FreeGC(Tk_Display(tkwin), polyPtr->fillGC);
  508.     }
  509.     polyPtr->fillGC = newGC;
  510.     /*
  511.      * Keep spline parameters within reasonable limits.
  512.      */
  513.     if (polyPtr->splineSteps < 1) {
  514. polyPtr->splineSteps = 1;
  515.     } else if (polyPtr->splineSteps > 100) {
  516. polyPtr->splineSteps = 100;
  517.     }
  518.     ComputePolygonBbox(canvas, polyPtr);
  519.     return TCL_OK;
  520. }
  521. /*
  522.  *--------------------------------------------------------------
  523.  *
  524.  * DeletePolygon --
  525.  *
  526.  * This procedure is called to clean up the data structure
  527.  * associated with a polygon item.
  528.  *
  529.  * Results:
  530.  * None.
  531.  *
  532.  * Side effects:
  533.  * Resources associated with itemPtr are released.
  534.  *
  535.  *--------------------------------------------------------------
  536.  */
  537. static void
  538. DeletePolygon(canvas, itemPtr, display)
  539.     Tk_Canvas canvas; /* Info about overall canvas widget. */
  540.     Tk_Item *itemPtr; /* Item that is being deleted. */
  541.     Display *display; /* Display containing window for
  542.  * canvas. */
  543. {
  544.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  545.     Tk_DeleteOutline(display,&(polyPtr->outline));
  546.     if (polyPtr->coordPtr != NULL) {
  547. ckfree((char *) polyPtr->coordPtr);
  548.     }
  549.     if (polyPtr->fillColor != NULL) {
  550. Tk_FreeColor(polyPtr->fillColor);
  551.     }
  552.     if (polyPtr->activeFillColor != NULL) {
  553. Tk_FreeColor(polyPtr->activeFillColor);
  554.     }
  555.     if (polyPtr->disabledFillColor != NULL) {
  556. Tk_FreeColor(polyPtr->disabledFillColor);
  557.     }
  558.     if (polyPtr->fillStipple != None) {
  559. Tk_FreeBitmap(display, polyPtr->fillStipple);
  560.     }
  561.     if (polyPtr->activeFillStipple != None) {
  562. Tk_FreeBitmap(display, polyPtr->activeFillStipple);
  563.     }
  564.     if (polyPtr->disabledFillStipple != None) {
  565. Tk_FreeBitmap(display, polyPtr->disabledFillStipple);
  566.     }
  567.     if (polyPtr->fillGC != None) {
  568. Tk_FreeGC(display, polyPtr->fillGC);
  569.     }
  570. }
  571. /*
  572.  *--------------------------------------------------------------
  573.  *
  574.  * ComputePolygonBbox --
  575.  *
  576.  * This procedure is invoked to compute the bounding box of
  577.  * all the pixels that may be drawn as part of a polygon.
  578.  *
  579.  * Results:
  580.  * None.
  581.  *
  582.  * Side effects:
  583.  * The fields x1, y1, x2, and y2 are updated in the header
  584.  * for itemPtr.
  585.  *
  586.  *--------------------------------------------------------------
  587.  */
  588. static void
  589. ComputePolygonBbox(canvas, polyPtr)
  590.     Tk_Canvas canvas; /* Canvas that contains item. */
  591.     PolygonItem *polyPtr; /* Item whose bbox is to be
  592.  * recomputed. */
  593. {
  594.     double *coordPtr;
  595.     int i;
  596.     double width;
  597.     Tk_State state = polyPtr->header.state;
  598.     Tk_TSOffset *tsoffset;
  599.     if(state == TK_STATE_NULL) {
  600. state = ((TkCanvas *)canvas)->canvas_state;
  601.     }
  602.     width = polyPtr->outline.width;
  603.     if (polyPtr->coordPtr == NULL || (polyPtr->numPoints < 1) || (state==TK_STATE_HIDDEN)) {
  604. polyPtr->header.x1 = polyPtr->header.x2 =
  605. polyPtr->header.y1 = polyPtr->header.y2 = -1;
  606. return;
  607.     }
  608.     if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)polyPtr) {
  609. if (polyPtr->outline.activeWidth>width) {
  610.     width = polyPtr->outline.activeWidth;
  611. }
  612.     } else if (state==TK_STATE_DISABLED) {
  613. if (polyPtr->outline.disabledWidth>0.0) {
  614.     width = polyPtr->outline.disabledWidth;
  615. }
  616.     }
  617.     coordPtr = polyPtr->coordPtr;
  618.     polyPtr->header.x1 = polyPtr->header.x2 = (int) *coordPtr;
  619.     polyPtr->header.y1 = polyPtr->header.y2 = (int) coordPtr[1];
  620.     /*
  621.      * Compute the bounding box of all the points in the polygon,
  622.      * then expand in all directions by the outline's width to take
  623.      * care of butting or rounded corners and projecting or
  624.      * rounded caps.  This expansion is an overestimate (worst-case
  625.      * is square root of two over two) but it's simple.  Don't do
  626.      * anything special for curves.  This causes an additional
  627.      * overestimate in the bounding box, but is faster.
  628.      */
  629.     for (i = 1, coordPtr = polyPtr->coordPtr+2; i < polyPtr->numPoints-1;
  630.     i++, coordPtr += 2) {
  631. TkIncludePoint((Tk_Item *) polyPtr, coordPtr);
  632.     }
  633.     tsoffset = &polyPtr->tsoffset;
  634.     if (tsoffset->flags & TK_OFFSET_INDEX) {
  635. int index = tsoffset->flags & ~TK_OFFSET_INDEX;
  636. if (tsoffset->flags == INT_MAX) {
  637.     index = (polyPtr->numPoints - polyPtr->autoClosed) * 2;
  638.     if (index < 0) {
  639. index = 0;
  640.     }
  641. }
  642. index %= (polyPtr->numPoints - polyPtr->autoClosed) * 2;
  643. if (index <0) {
  644.     index += (polyPtr->numPoints - polyPtr->autoClosed) * 2;
  645. }
  646.   tsoffset->xoffset = (int) (polyPtr->coordPtr[index] + 0.5);
  647. tsoffset->yoffset = (int) (polyPtr->coordPtr[index+1] + 0.5);
  648.     } else {
  649. if (tsoffset->flags & TK_OFFSET_LEFT) {
  650.     tsoffset->xoffset = polyPtr->header.x1;
  651. } else if (tsoffset->flags & TK_OFFSET_CENTER) {
  652.     tsoffset->xoffset = (polyPtr->header.x1 + polyPtr->header.x2)/2;
  653. } else if (tsoffset->flags & TK_OFFSET_RIGHT) {
  654.     tsoffset->xoffset = polyPtr->header.x2;
  655. }
  656. if (tsoffset->flags & TK_OFFSET_TOP) {
  657.     tsoffset->yoffset = polyPtr->header.y1;
  658. } else if (tsoffset->flags & TK_OFFSET_MIDDLE) {
  659.     tsoffset->yoffset = (polyPtr->header.y1 + polyPtr->header.y2)/2;
  660. } else if (tsoffset->flags & TK_OFFSET_BOTTOM) {
  661.     tsoffset->yoffset = polyPtr->header.y2;
  662. }
  663.     }
  664.     if (polyPtr->outline.gc != None) {
  665. tsoffset = &polyPtr->outline.tsoffset;
  666. if (tsoffset) {
  667.     if (tsoffset->flags & TK_OFFSET_INDEX) {
  668. int index = tsoffset->flags & ~TK_OFFSET_INDEX;
  669. if (tsoffset->flags == INT_MAX) {
  670.     index = (polyPtr->numPoints - 1) * 2;
  671. }
  672. index %= (polyPtr->numPoints - 1) * 2;
  673. if (index <0) {
  674.     index += (polyPtr->numPoints - 1) * 2;
  675. }
  676. tsoffset->xoffset = (int) (polyPtr->coordPtr[index] + 0.5);
  677. tsoffset->yoffset = (int) (polyPtr->coordPtr[index+1] + 0.5);
  678.     } else {
  679. if (tsoffset->flags & TK_OFFSET_LEFT) {
  680.     tsoffset->xoffset = polyPtr->header.x1;
  681. } else if (tsoffset->flags & TK_OFFSET_CENTER) {
  682.     tsoffset->xoffset = (polyPtr->header.x1 + polyPtr->header.x2)/2;
  683. } else if (tsoffset->flags & TK_OFFSET_RIGHT) {
  684.     tsoffset->xoffset = polyPtr->header.x2;
  685. }
  686. if (tsoffset->flags & TK_OFFSET_TOP) {
  687.     tsoffset->yoffset = polyPtr->header.y1;
  688. } else if (tsoffset->flags & TK_OFFSET_MIDDLE) {
  689.     tsoffset->yoffset = (polyPtr->header.y1 + polyPtr->header.y2)/2;
  690. } else if (tsoffset->flags & TK_OFFSET_BOTTOM) {
  691.     tsoffset->yoffset = polyPtr->header.y2;
  692. }
  693.     }
  694. }
  695. i = (int) ((width+1.5)/2.0);
  696. polyPtr->header.x1 -= i;
  697. polyPtr->header.x2 += i;
  698. polyPtr->header.y1 -= i;
  699. polyPtr->header.y2 += i;
  700. /*
  701.  * For mitered lines, make a second pass through all the points.
  702.  * Compute the locations of the two miter vertex points and add
  703.  * those into the bounding box.
  704.  */
  705. if (polyPtr->joinStyle == JoinMiter) {
  706.     double miter[4];
  707.     int j;
  708.     coordPtr = polyPtr->coordPtr;
  709.     if (polyPtr->numPoints>3) {
  710. if (TkGetMiterPoints(coordPtr+2*(polyPtr->numPoints-2),
  711. coordPtr, coordPtr+2, width,
  712. miter, miter+2)) {
  713.     for (j = 0; j < 4; j += 2) {
  714. TkIncludePoint((Tk_Item *) polyPtr, miter+j);
  715.     }
  716. }
  717.      }
  718.     for (i = polyPtr->numPoints ; i >= 3;
  719.     i--, coordPtr += 2) {
  720.     
  721. if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4,
  722. width, miter, miter+2)) {
  723.     for (j = 0; j < 4; j += 2) {
  724. TkIncludePoint((Tk_Item *) polyPtr, miter+j);
  725.     }
  726. }
  727.     }
  728. }
  729.     }
  730.     /*
  731.      * Add one more pixel of fudge factor just to be safe (e.g.
  732.      * X may round differently than we do).
  733.      */
  734.     polyPtr->header.x1 -= 1;
  735.     polyPtr->header.x2 += 1;
  736.     polyPtr->header.y1 -= 1;
  737.     polyPtr->header.y2 += 1;
  738. }
  739. /*
  740.  *--------------------------------------------------------------
  741.  *
  742.  * TkFillPolygon --
  743.  *
  744.  * This procedure is invoked to convert a polygon to screen
  745.  * coordinates and display it using a particular GC.
  746.  *
  747.  * Results:
  748.  * None.
  749.  *
  750.  * Side effects:
  751.  * ItemPtr is drawn in drawable using the transformation
  752.  * information in canvas.
  753.  *
  754.  *--------------------------------------------------------------
  755.  */
  756. void
  757. TkFillPolygon(canvas, coordPtr, numPoints, display, drawable, gc, outlineGC)
  758.     Tk_Canvas canvas; /* Canvas whose coordinate system
  759.  * is to be used for drawing. */
  760.     double *coordPtr; /* Array of coordinates for polygon:
  761.  * x1, y1, x2, y2, .... */
  762.     int numPoints; /* Twice this many coordinates are
  763.  * present at *coordPtr. */
  764.     Display *display; /* Display on which to draw polygon. */
  765.     Drawable drawable; /* Pixmap or window in which to draw
  766.  * polygon. */
  767.     GC gc; /* Graphics context for drawing. */
  768.     GC outlineGC; /* If not None, use this to draw an
  769.  * outline around the polygon after
  770.  * filling it. */
  771. {
  772.     XPoint staticPoints[MAX_STATIC_POINTS];
  773.     XPoint *pointPtr;
  774.     XPoint *pPtr;
  775.     int i;
  776.     /*
  777.      * Build up an array of points in screen coordinates.  Use a
  778.      * static array unless the polygon has an enormous number of points;
  779.      * in this case, dynamically allocate an array.
  780.      */
  781.     if (numPoints <= MAX_STATIC_POINTS) {
  782. pointPtr = staticPoints;
  783.     } else {
  784. pointPtr = (XPoint *) ckalloc((unsigned) (numPoints * sizeof(XPoint)));
  785.     }
  786.     for (i = 0, pPtr = pointPtr; i < numPoints; i += 1, coordPtr += 2, pPtr++) {
  787. Tk_CanvasDrawableCoords(canvas, coordPtr[0], coordPtr[1], &pPtr->x,
  788. &pPtr->y);
  789.     }
  790.     /*
  791.      * Display polygon, then free up polygon storage if it was dynamically
  792.      * allocated.
  793.      */
  794.     if (gc != None && numPoints>3) {
  795. XFillPolygon(display, drawable, gc, pointPtr, numPoints, Complex,
  796. CoordModeOrigin);
  797.     }
  798.     if (outlineGC != None) {
  799. XDrawLines(display, drawable, outlineGC, pointPtr,
  800.     numPoints, CoordModeOrigin);
  801.     }
  802.     if (pointPtr != staticPoints) {
  803. ckfree((char *) pointPtr);
  804.     }
  805. }
  806. /*
  807.  *--------------------------------------------------------------
  808.  *
  809.  * DisplayPolygon --
  810.  *
  811.  * This procedure is invoked to draw a polygon item in a given
  812.  * drawable.
  813.  *
  814.  * Results:
  815.  * None.
  816.  *
  817.  * Side effects:
  818.  * ItemPtr is drawn in drawable using the transformation
  819.  * information in canvas.
  820.  *
  821.  *--------------------------------------------------------------
  822.  */
  823. static void
  824. DisplayPolygon(canvas, itemPtr, display, drawable, x, y, width, height)
  825.     Tk_Canvas canvas; /* Canvas that contains item. */
  826.     Tk_Item *itemPtr; /* Item to be displayed. */
  827.     Display *display; /* Display on which to draw item. */
  828.     Drawable drawable; /* Pixmap or window in which to draw
  829.  * item. */
  830.     int x, y, width, height; /* Describes region of canvas that
  831.  * must be redisplayed (not used). */
  832. {
  833.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  834.     Tk_State state = itemPtr->state;
  835.     Pixmap stipple = polyPtr->fillStipple;
  836.     double linewidth = polyPtr->outline.width;
  837.     if (((polyPtr->fillGC == None) && (polyPtr->outline.gc == None)) ||
  838.     (polyPtr->numPoints < 1) ||
  839.     (polyPtr->numPoints < 3 && polyPtr->outline.gc == None)) {
  840. return;
  841.     }
  842.     if(state == TK_STATE_NULL) {
  843. state = ((TkCanvas *)canvas)->canvas_state;
  844.     }
  845.     if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) {
  846. if (polyPtr->outline.activeWidth>linewidth) {
  847.     linewidth = polyPtr->outline.activeWidth;
  848. }
  849. if (polyPtr->activeFillStipple != None) {
  850.     stipple = polyPtr->activeFillStipple;
  851. }
  852.     } else if (state==TK_STATE_DISABLED) {
  853. if (polyPtr->outline.disabledWidth>0.0) {
  854.     linewidth = polyPtr->outline.disabledWidth;
  855. }
  856. if (polyPtr->disabledFillStipple != None) {
  857.     stipple = polyPtr->disabledFillStipple;
  858. }
  859.     }
  860.     /*
  861.      * If we're stippling then modify the stipple offset in the GC.  Be
  862.      * sure to reset the offset when done, since the GC is supposed to be
  863.      * read-only.
  864.      */
  865.     if ((stipple != None) && (polyPtr->fillGC != None)) {
  866. Tk_TSOffset *tsoffset = &polyPtr->tsoffset;
  867. int w=0; int h=0;
  868. int flags = tsoffset->flags;
  869. if (!(flags & TK_OFFSET_INDEX) && (flags & (TK_OFFSET_CENTER|TK_OFFSET_MIDDLE))) {
  870.     Tk_SizeOfBitmap(display, stipple, &w, &h);
  871.     if (flags & TK_OFFSET_CENTER) {
  872. w /= 2;
  873.     } else {
  874. w = 0;
  875.     }
  876.     if (flags & TK_OFFSET_MIDDLE) {
  877. h /= 2;
  878.     } else {
  879. h = 0;
  880.     }
  881. }
  882. tsoffset->xoffset -= w;
  883. tsoffset->yoffset -= h;
  884. Tk_CanvasSetOffset(canvas, polyPtr->fillGC, tsoffset);
  885. tsoffset->xoffset += w;
  886. tsoffset->yoffset += h;
  887.     }
  888.     Tk_ChangeOutlineGC(canvas, itemPtr, &(polyPtr->outline));
  889.     if(polyPtr->numPoints < 3) {
  890. short x,y;
  891. int intLineWidth = (int) (linewidth + 0.5);
  892. if (intLineWidth < 1) {
  893.     intLineWidth = 1;
  894. }
  895. Tk_CanvasDrawableCoords(canvas, polyPtr->coordPtr[0],
  896.     polyPtr->coordPtr[1], &x,&y);
  897. XFillArc(display, drawable, polyPtr->outline.gc,
  898. x - intLineWidth/2, y - intLineWidth/2,
  899. (unsigned int)intLineWidth+1, (unsigned int)intLineWidth+1,
  900. 0, 64*360);
  901.     } else if (!polyPtr->smooth || polyPtr->numPoints < 4) {
  902. TkFillPolygon(canvas, polyPtr->coordPtr, polyPtr->numPoints,
  903.     display, drawable, polyPtr->fillGC, polyPtr->outline.gc);
  904.     } else {
  905. int numPoints;
  906. XPoint staticPoints[MAX_STATIC_POINTS];
  907. XPoint *pointPtr;
  908. /*
  909.  * This is a smoothed polygon.  Display using a set of generated
  910.  * spline points rather than the original points.
  911.  */
  912. numPoints = polyPtr->smooth->coordProc(canvas, (double *) NULL,
  913. polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL,
  914. (double *) NULL);
  915. if (numPoints <= MAX_STATIC_POINTS) {
  916.     pointPtr = staticPoints;
  917. } else {
  918.     pointPtr = (XPoint *) ckalloc((unsigned)
  919.     (numPoints * sizeof(XPoint)));
  920. }
  921. numPoints = polyPtr->smooth->coordProc(canvas, polyPtr->coordPtr,
  922. polyPtr->numPoints, polyPtr->splineSteps, pointPtr,
  923. (double *) NULL);
  924. if (polyPtr->fillGC != None) {
  925.     XFillPolygon(display, drawable, polyPtr->fillGC, pointPtr,
  926.     numPoints, Complex, CoordModeOrigin);
  927. }
  928. if (polyPtr->outline.gc != None) {
  929.     XDrawLines(display, drawable, polyPtr->outline.gc, pointPtr,
  930.     numPoints, CoordModeOrigin);
  931. }
  932. if (pointPtr != staticPoints) {
  933.     ckfree((char *) pointPtr);
  934. }
  935.     }
  936.     Tk_ResetOutlineGC(canvas, itemPtr, &(polyPtr->outline));
  937.     if ((stipple != None) && (polyPtr->fillGC != None)) {
  938. XSetTSOrigin(display, polyPtr->fillGC, 0, 0);
  939.     }
  940. }
  941. /*
  942.  *--------------------------------------------------------------
  943.  *
  944.  * PolygonInsert --
  945.  *
  946.  * Insert coords into a polugon item at a given index.
  947.  *
  948.  * Results:
  949.  * None.
  950.  *
  951.  * Side effects:
  952.  * The coords in the given item is modified.
  953.  *
  954.  *--------------------------------------------------------------
  955.  */
  956. static void
  957. PolygonInsert(canvas, itemPtr, beforeThis, obj)
  958.     Tk_Canvas canvas; /* Canvas containing text item. */
  959.     Tk_Item *itemPtr; /* Line item to be modified. */
  960.     int beforeThis; /* Index before which new coordinates
  961.  * are to be inserted. */
  962.     Tcl_Obj *obj; /* New coordinates to be inserted. */
  963. {
  964.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  965.     int length, objc, i;
  966.     Tcl_Obj **objv;
  967.     double *new;
  968.     Tk_State state = itemPtr->state;
  969.     if (state == TK_STATE_NULL) {
  970. state = ((TkCanvas *)canvas)->canvas_state;
  971.     }
  972.     if (!obj || (Tcl_ListObjGetElements((Tcl_Interp *) NULL, obj, &objc, &objv) != TCL_OK)
  973.     || !objc || objc&1) {
  974. return;
  975.     }
  976.     length = 2*(polyPtr->numPoints - polyPtr->autoClosed);
  977.     while(beforeThis>length) beforeThis-=length;
  978.     while(beforeThis<0) beforeThis+=length;
  979.     new = (double *) ckalloc((unsigned)(sizeof(double) * (length + 2 + objc)));
  980.     for (i=0; i<beforeThis; i++) {
  981. new[i] = polyPtr->coordPtr[i];
  982.     }
  983.     for (i=0; i<objc; i++) {
  984. if (Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,objv[i],
  985. new+(i+beforeThis))!=TCL_OK) {
  986.     ckfree((char *) new);
  987.     return;
  988. }
  989.     }
  990.     for(i=beforeThis; i<length; i++) {
  991. new[i+objc] = polyPtr->coordPtr[i];
  992.     }
  993.     if(polyPtr->coordPtr) ckfree((char *) polyPtr->coordPtr);
  994.     length+=objc;
  995.     polyPtr->coordPtr = new;
  996.     polyPtr->numPoints = (length/2) + polyPtr->autoClosed;
  997.     /*
  998.      * Close the polygon if it isn't already closed, or remove autoclosing
  999.      * if the user's coordinates are now closed.
  1000.      */
  1001.     if (polyPtr->autoClosed) {
  1002. if ((new[length-2] == new[0]) && (new[length-1] == new[1])) {
  1003.     polyPtr->autoClosed = 0;
  1004.     polyPtr->numPoints--;
  1005. }
  1006.     }
  1007.     else {
  1008. if ((new[length-2] != new[0]) || (new[length-1] != new[1])) {
  1009.     polyPtr->autoClosed = 1;
  1010.     polyPtr->numPoints++;
  1011. }
  1012.     }
  1013.     new[length] = new[0];
  1014.     new[length+1] = new[1];
  1015.     if (((length-objc)>3) && (state != TK_STATE_HIDDEN)) {
  1016. /*
  1017.  * This is some optimizing code that will result that only the part
  1018.  * of the polygon that changed (and the objects that are overlapping
  1019.  * with that part) need to be redrawn. A special flag is set that
  1020.  * instructs the general canvas code not to redraw the whole
  1021.  * object. If this flag is not set, the canvas will do the redrawing,
  1022.  * otherwise I have to do it here.
  1023.  */
  1024.      double width;
  1025. int j;
  1026. itemPtr->redraw_flags |= TK_ITEM_DONT_REDRAW;
  1027. /*
  1028.  * The header elements that normally are used for the
  1029.  * bounding box, are now used to calculate the bounding
  1030.  * box for only the part that has to be redrawn. That
  1031.  * doesn't matter, because afterwards the bounding
  1032.  * box has to be re-calculated anyway.
  1033.  */
  1034. itemPtr->x1 = itemPtr->x2 = (int) polyPtr->coordPtr[beforeThis];
  1035. itemPtr->y1 = itemPtr->y2 = (int) polyPtr->coordPtr[beforeThis+1];
  1036. beforeThis-=2; objc+=4;
  1037. if(polyPtr->smooth) {
  1038.     beforeThis-=2; objc+=4;
  1039. } /* be carefull; beforeThis could now be negative */
  1040. for(i=beforeThis; i<beforeThis+objc; i+=2) {
  1041. j=i;
  1042. if(j<0) j+=length;
  1043. if(j>=length) j-=length;
  1044. TkIncludePoint(itemPtr, polyPtr->coordPtr+j);
  1045. }
  1046. width = polyPtr->outline.width;
  1047. if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) {
  1048. if (polyPtr->outline.activeWidth>width) {
  1049.     width = polyPtr->outline.activeWidth;
  1050. }
  1051. } else if (state==TK_STATE_DISABLED) {
  1052. if (polyPtr->outline.disabledWidth>0.0) {
  1053.     width = polyPtr->outline.disabledWidth;
  1054. }
  1055. }
  1056. itemPtr->x1 -= (int) width; itemPtr->y1 -= (int) width;
  1057. itemPtr->x2 += (int) width; itemPtr->y2 += (int) width;
  1058. Tk_CanvasEventuallyRedraw(canvas,
  1059. itemPtr->x1, itemPtr->y1,
  1060. itemPtr->x2, itemPtr->y2);
  1061.     }
  1062.     ComputePolygonBbox(canvas, polyPtr);
  1063. }
  1064. /*
  1065.  *--------------------------------------------------------------
  1066.  *
  1067.  * PolygonDeleteCoords --
  1068.  *
  1069.  * Delete one or more coordinates from a polygon item.
  1070.  *
  1071.  * Results:
  1072.  * None.
  1073.  *
  1074.  * Side effects:
  1075.  * Characters between "first" and "last", inclusive, get
  1076.  * deleted from itemPtr.
  1077.  *
  1078.  *--------------------------------------------------------------
  1079.  */
  1080. static void
  1081. PolygonDeleteCoords(canvas, itemPtr, first, last)
  1082.     Tk_Canvas canvas; /* Canvas containing itemPtr. */
  1083.     Tk_Item *itemPtr; /* Item in which to delete characters. */
  1084.     int first; /* Index of first character to delete. */
  1085.     int last; /* Index of last character to delete. */
  1086. {
  1087.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  1088.     int count, i;
  1089.     int length = 2*(polyPtr->numPoints - polyPtr->autoClosed);
  1090.     while(first>=length) first-=length;
  1091.     while(first<0)  first+=length;
  1092.     while(last>=length)  last-=length;
  1093.     while(last<0)  last+=length;
  1094.     first &= -2;
  1095.     last &= -2;
  1096.     count = last + 2 - first;
  1097.     if(count<=0) count +=length;
  1098.     if(count >= length) {
  1099. polyPtr->numPoints = 0;
  1100. if(polyPtr->coordPtr != NULL) {
  1101.     ckfree((char *) polyPtr->coordPtr);
  1102. }
  1103. ComputePolygonBbox(canvas, polyPtr);
  1104. return;
  1105.     }
  1106.     if(last>=first) {
  1107. for(i=last+2; i<length; i++) {
  1108.     polyPtr->coordPtr[i-count] = polyPtr->coordPtr[i];
  1109. }
  1110.     } else {
  1111. for(i=last; i<=first; i++) {
  1112.     polyPtr->coordPtr[i-last] = polyPtr->coordPtr[i];
  1113. }
  1114.     }
  1115.     polyPtr->coordPtr[length-count] = polyPtr->coordPtr[0];
  1116.     polyPtr->coordPtr[length-count+1] = polyPtr->coordPtr[1];
  1117.     polyPtr->numPoints -= count/2;
  1118.     ComputePolygonBbox(canvas, polyPtr);
  1119. }
  1120. /*
  1121.  *--------------------------------------------------------------
  1122.  *
  1123.  * PolygonToPoint --
  1124.  *
  1125.  * Computes the distance from a given point to a given
  1126.  * polygon, in canvas units.
  1127.  *
  1128.  * Results:
  1129.  * The return value is 0 if the point whose x and y coordinates
  1130.  * are pointPtr[0] and pointPtr[1] is inside the polygon.  If the
  1131.  * point isn't inside the polygon then the return value is the
  1132.  * distance from the point to the polygon.
  1133.  *
  1134.  * Side effects:
  1135.  * None.
  1136.  *
  1137.  *--------------------------------------------------------------
  1138.  */
  1139. /* ARGSUSED */
  1140. static double
  1141. PolygonToPoint(canvas, itemPtr, pointPtr)
  1142.     Tk_Canvas canvas; /* Canvas containing item. */
  1143.     Tk_Item *itemPtr; /* Item to check against point. */
  1144.     double *pointPtr; /* Pointer to x and y coordinates. */
  1145. {
  1146.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  1147.     double *coordPtr, *polyPoints;
  1148.     double staticSpace[2*MAX_STATIC_POINTS];
  1149.     double poly[10];
  1150.     double radius;
  1151.     double bestDist, dist;
  1152.     int numPoints, count;
  1153.     int changedMiterToBevel; /* Non-zero means that a mitered corner
  1154.  * had to be treated as beveled after all
  1155.  * because the angle was < 11 degrees. */
  1156.     double width;
  1157.     Tk_State state = itemPtr->state;
  1158.     bestDist = 1.0e36;
  1159.     if(state == TK_STATE_NULL) {
  1160. state = ((TkCanvas *)canvas)->canvas_state;
  1161.     }
  1162.     width = polyPtr->outline.width;
  1163.     if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) {
  1164. if (polyPtr->outline.activeWidth>width) {
  1165.     width = polyPtr->outline.activeWidth;
  1166. }
  1167.     } else if (state==TK_STATE_DISABLED) {
  1168. if (polyPtr->outline.disabledWidth>0.0) {
  1169.     width = polyPtr->outline.disabledWidth;
  1170. }
  1171.     }
  1172.     radius = width/2.0;
  1173.     /*
  1174.      * Handle smoothed polygons by generating an expanded set of points
  1175.      * against which to do the check.
  1176.      */
  1177.     if ((polyPtr->smooth) && (polyPtr->numPoints>2)) {
  1178. numPoints = polyPtr->smooth->coordProc(canvas, (double *) NULL,
  1179. polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL,
  1180. (double *) NULL);
  1181. if (numPoints <= MAX_STATIC_POINTS) {
  1182.     polyPoints = staticSpace;
  1183. } else {
  1184.     polyPoints = (double *) ckalloc((unsigned)
  1185.     (2*numPoints*sizeof(double)));
  1186. }
  1187. numPoints = polyPtr->smooth->coordProc(canvas, polyPtr->coordPtr,
  1188. polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL,
  1189. polyPoints);
  1190.     } else {
  1191. numPoints = polyPtr->numPoints;
  1192. polyPoints = polyPtr->coordPtr;
  1193.     }
  1194.     bestDist = TkPolygonToPoint(polyPoints, numPoints, pointPtr);
  1195.     if (bestDist<=0.0) {
  1196. goto donepoint;
  1197.     }
  1198.     if ((polyPtr->outline.gc != None) && (polyPtr->joinStyle == JoinRound)) {
  1199. dist = bestDist - radius;
  1200. if (dist <= 0.0) {
  1201.     bestDist = 0.0;
  1202.     goto donepoint;
  1203. } else {
  1204.     bestDist = dist;
  1205. }
  1206.     }
  1207.     if ((polyPtr->outline.gc == None) || (width <= 1)) goto donepoint;
  1208.     /*
  1209.      * The overall idea is to iterate through all of the edges of
  1210.      * the line, computing a polygon for each edge and testing the
  1211.      * point against that polygon.  In addition, there are additional
  1212.      * tests to deal with rounded joints and caps.
  1213.      */
  1214.     changedMiterToBevel = 0;
  1215.     for (count = numPoints, coordPtr = polyPoints; count >= 2;
  1216.     count--, coordPtr += 2) {
  1217. /*
  1218.  * If rounding is done around the first point then compute
  1219.  * the distance between the point and the point.
  1220.  */
  1221. if (polyPtr->joinStyle == JoinRound) {
  1222.     dist = hypot(coordPtr[0] - pointPtr[0], coordPtr[1] - pointPtr[1])
  1223.     - radius;
  1224.     if (dist <= 0.0) {
  1225. bestDist = 0.0;
  1226. goto donepoint;
  1227.     } else if (dist < bestDist) {
  1228. bestDist = dist;
  1229.     }
  1230. }
  1231. /*
  1232.  * Compute the polygonal shape corresponding to this edge,
  1233.  * consisting of two points for the first point of the edge
  1234.  * and two points for the last point of the edge.
  1235.  */
  1236. if (count == numPoints) {
  1237.     TkGetButtPoints(coordPtr+2, coordPtr, (double) width,
  1238.     0, poly, poly+2);
  1239. } else if ((polyPtr->joinStyle == JoinMiter) && !changedMiterToBevel) {
  1240.     poly[0] = poly[6];
  1241.     poly[1] = poly[7];
  1242.     poly[2] = poly[4];
  1243.     poly[3] = poly[5];
  1244. } else {
  1245.     TkGetButtPoints(coordPtr+2, coordPtr, (double) width, 0,
  1246.     poly, poly+2);
  1247.     /*
  1248.      * If this line uses beveled joints, then check the distance
  1249.      * to a polygon comprising the last two points of the previous
  1250.      * polygon and the first two from this polygon;  this checks
  1251.      * the wedges that fill the mitered joint.
  1252.      */
  1253.     if ((polyPtr->joinStyle == JoinBevel) || changedMiterToBevel) {
  1254. poly[8] = poly[0];
  1255. poly[9] = poly[1];
  1256. dist = TkPolygonToPoint(poly, 5, pointPtr);
  1257. if (dist <= 0.0) {
  1258.     bestDist = 0.0;
  1259.     goto donepoint;
  1260. } else if (dist < bestDist) {
  1261.     bestDist = dist;
  1262. }
  1263. changedMiterToBevel = 0;
  1264.     }
  1265. }
  1266. if (count == 2) {
  1267.     TkGetButtPoints(coordPtr, coordPtr+2, (double) width,
  1268.     0, poly+4, poly+6);
  1269. } else if (polyPtr->joinStyle == JoinMiter) {
  1270.     if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4,
  1271.     (double) width, poly+4, poly+6) == 0) {
  1272. changedMiterToBevel = 1;
  1273. TkGetButtPoints(coordPtr, coordPtr+2, (double) width,
  1274. 0, poly+4, poly+6);
  1275.     }
  1276. } else {
  1277.     TkGetButtPoints(coordPtr, coordPtr+2, (double) width, 0,
  1278.     poly+4, poly+6);
  1279. }
  1280. poly[8] = poly[0];
  1281. poly[9] = poly[1];
  1282. dist = TkPolygonToPoint(poly, 5, pointPtr);
  1283. if (dist <= 0.0) {
  1284.     bestDist = 0.0;
  1285.     goto donepoint;
  1286. } else if (dist < bestDist) {
  1287.     bestDist = dist;
  1288. }
  1289.     }
  1290.     donepoint:
  1291.     if ((polyPoints != staticSpace) && polyPoints != polyPtr->coordPtr) {
  1292. ckfree((char *) polyPoints);
  1293.     }
  1294.     return bestDist;
  1295. }
  1296. /*
  1297.  *--------------------------------------------------------------
  1298.  *
  1299.  * PolygonToArea --
  1300.  *
  1301.  * This procedure is called to determine whether an item
  1302.  * lies entirely inside, entirely outside, or overlapping
  1303.  * a given rectangular area.
  1304.  *
  1305.  * Results:
  1306.  * -1 is returned if the item is entirely outside the area
  1307.  * given by rectPtr, 0 if it overlaps, and 1 if it is entirely
  1308.  * inside the given area.
  1309.  *
  1310.  * Side effects:
  1311.  * None.
  1312.  *
  1313.  *--------------------------------------------------------------
  1314.  */
  1315. /* ARGSUSED */
  1316. static int
  1317. PolygonToArea(canvas, itemPtr, rectPtr)
  1318.     Tk_Canvas canvas; /* Canvas containing item. */
  1319.     Tk_Item *itemPtr; /* Item to check against polygon. */
  1320.     double *rectPtr; /* Pointer to array of four coordinates
  1321.  * (x1, y1, x2, y2) describing rectangular
  1322.  * area.  */
  1323. {
  1324.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  1325.     double *coordPtr;
  1326.     double staticSpace[2*MAX_STATIC_POINTS];
  1327.     double *polyPoints, poly[10];
  1328.     double radius;
  1329.     int numPoints, count;
  1330.     int changedMiterToBevel; /* Non-zero means that a mitered corner
  1331.  * had to be treated as beveled after all
  1332.  * because the angle was < 11 degrees. */
  1333.     int inside; /* Tentative guess about what to return,
  1334.  * based on all points seen so far:  one
  1335.  * means everything seen so far was
  1336.  * inside the area;  -1 means everything
  1337.  * was outside the area.  0 means overlap
  1338.  * has been found. */ 
  1339.     double width;
  1340.     Tk_State state = itemPtr->state;
  1341.     if(state == TK_STATE_NULL) {
  1342. state = ((TkCanvas *)canvas)->canvas_state;
  1343.     }
  1344.     width = polyPtr->outline.width;
  1345.     if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) {
  1346. if (polyPtr->outline.activeWidth>width) {
  1347.     width = polyPtr->outline.activeWidth;
  1348. }
  1349.     } else if (state==TK_STATE_DISABLED) {
  1350. if (polyPtr->outline.disabledWidth>0.0) {
  1351.     width = polyPtr->outline.disabledWidth;
  1352. }
  1353.     }
  1354.     radius = width/2.0;
  1355.     inside = -1;
  1356.     if ((state==TK_STATE_HIDDEN) || polyPtr->numPoints<2) {
  1357. return -1;
  1358.     } else if (polyPtr->numPoints <3) {
  1359. double oval[4];
  1360. oval[0] = polyPtr->coordPtr[0]-radius;
  1361. oval[1] = polyPtr->coordPtr[1]-radius;
  1362. oval[2] = polyPtr->coordPtr[0]+radius;
  1363. oval[3] = polyPtr->coordPtr[1]+radius;
  1364. return TkOvalToArea(oval, rectPtr);
  1365.     }
  1366.     /*
  1367.      * Handle smoothed polygons by generating an expanded set of points
  1368.      * against which to do the check.
  1369.      */
  1370.     if (polyPtr->smooth) {
  1371. numPoints = polyPtr->smooth->coordProc(canvas, (double *) NULL,
  1372. polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL,
  1373. (double *) NULL);
  1374. if (numPoints <= MAX_STATIC_POINTS) {
  1375.     polyPoints = staticSpace;
  1376. } else {
  1377.     polyPoints = (double *) ckalloc((unsigned)
  1378.     (2*numPoints*sizeof(double)));
  1379. }
  1380. numPoints = polyPtr->smooth->coordProc(canvas, polyPtr->coordPtr,
  1381. polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL,
  1382. polyPoints);
  1383.     } else {
  1384. numPoints = polyPtr->numPoints;
  1385. polyPoints = polyPtr->coordPtr;
  1386.     }
  1387.     /*
  1388.      * Simple test to see if we are in the polygon.  Polygons are
  1389.      * different from othe canvas items in that they register points
  1390.      * being inside even if it isn't filled.
  1391.      */
  1392.     inside = TkPolygonToArea(polyPoints, numPoints, rectPtr);
  1393.     if (inside==0) goto donearea;
  1394.     if (polyPtr->outline.gc == None) goto donearea ;
  1395.     /*
  1396.      * Iterate through all of the edges of the line, computing a polygon
  1397.      * for each edge and testing the area against that polygon.  In
  1398.      * addition, there are additional tests to deal with rounded joints
  1399.      * and caps.
  1400.      */
  1401.     changedMiterToBevel = 0;
  1402.     for (count = numPoints, coordPtr = polyPoints; count >= 2;
  1403.     count--, coordPtr += 2) {
  1404.  
  1405. /*
  1406.  * If rounding is done around the first point of the edge
  1407.  * then test a circular region around the point with the
  1408.  * area.
  1409.  */
  1410. if (polyPtr->joinStyle == JoinRound) {
  1411.     poly[0] = coordPtr[0] - radius;
  1412.     poly[1] = coordPtr[1] - radius;
  1413.     poly[2] = coordPtr[0] + radius;
  1414.     poly[3] = coordPtr[1] + radius;
  1415.     if (TkOvalToArea(poly, rectPtr) != inside) {
  1416. inside = 0;
  1417. goto donearea;
  1418.     }
  1419. }
  1420. /*
  1421.  * Compute the polygonal shape corresponding to this edge,
  1422.  * consisting of two points for the first point of the edge
  1423.  * and two points for the last point of the edge.
  1424.  */
  1425. if (count == numPoints) {
  1426.     TkGetButtPoints(coordPtr+2, coordPtr, width,
  1427.     0, poly, poly+2);
  1428. } else if ((polyPtr->joinStyle == JoinMiter) && !changedMiterToBevel) {
  1429.     poly[0] = poly[6];
  1430.     poly[1] = poly[7];
  1431.     poly[2] = poly[4];
  1432.     poly[3] = poly[5];
  1433. } else {
  1434.     TkGetButtPoints(coordPtr+2, coordPtr, width, 0,
  1435.     poly, poly+2);
  1436.     /*
  1437.      * If the last joint was beveled, then also check a
  1438.      * polygon comprising the last two points of the previous
  1439.      * polygon and the first two from this polygon;  this checks
  1440.      * the wedges that fill the beveled joint.
  1441.      */
  1442.     if ((polyPtr->joinStyle == JoinBevel) || changedMiterToBevel) {
  1443. poly[8] = poly[0];
  1444. poly[9] = poly[1];
  1445. if (TkPolygonToArea(poly, 5, rectPtr) != inside) {
  1446.     inside = 0;
  1447.     goto donearea;
  1448. }
  1449. changedMiterToBevel = 0;
  1450.     }
  1451. }
  1452. if (count == 2) {
  1453.     TkGetButtPoints(coordPtr, coordPtr+2, width,
  1454.     0, poly+4, poly+6);
  1455. } else if (polyPtr->joinStyle == JoinMiter) {
  1456.     if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4,
  1457.     width, poly+4, poly+6) == 0) {
  1458. changedMiterToBevel = 1;
  1459. TkGetButtPoints(coordPtr, coordPtr+2, width,
  1460. 0, poly+4, poly+6);
  1461.     }
  1462. } else {
  1463.     TkGetButtPoints(coordPtr, coordPtr+2, width, 0,
  1464.     poly+4, poly+6);
  1465. }
  1466. poly[8] = poly[0];
  1467. poly[9] = poly[1];
  1468. if (TkPolygonToArea(poly, 5, rectPtr) != inside) {
  1469.     inside = 0;
  1470.     goto donearea;
  1471. }
  1472.     }
  1473.     donearea:
  1474.     if ((polyPoints != staticSpace) && (polyPoints != polyPtr->coordPtr)) {
  1475. ckfree((char *) polyPoints);
  1476.     }
  1477.     return inside;
  1478. }
  1479. /*
  1480.  *--------------------------------------------------------------
  1481.  *
  1482.  * ScalePolygon --
  1483.  *
  1484.  * This procedure is invoked to rescale a polygon item.
  1485.  *
  1486.  * Results:
  1487.  * None.
  1488.  *
  1489.  * Side effects:
  1490.  * The polygon referred to by itemPtr is rescaled so that the
  1491.  * following transformation is applied to all point
  1492.  * coordinates:
  1493.  * x' = originX + scaleX*(x-originX)
  1494.  * y' = originY + scaleY*(y-originY)
  1495.  *
  1496.  *--------------------------------------------------------------
  1497.  */
  1498. static void
  1499. ScalePolygon(canvas, itemPtr, originX, originY, scaleX, scaleY)
  1500.     Tk_Canvas canvas; /* Canvas containing polygon. */
  1501.     Tk_Item *itemPtr; /* Polygon to be scaled. */
  1502.     double originX, originY; /* Origin about which to scale rect. */
  1503.     double scaleX; /* Amount to scale in X direction. */
  1504.     double scaleY; /* Amount to scale in Y direction. */
  1505. {
  1506.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  1507.     double *coordPtr;
  1508.     int i;
  1509.     for (i = 0, coordPtr = polyPtr->coordPtr; i < polyPtr->numPoints;
  1510.     i++, coordPtr += 2) {
  1511. *coordPtr = originX + scaleX*(*coordPtr - originX);
  1512. coordPtr[1] = originY + scaleY*(coordPtr[1] - originY);
  1513.     }
  1514.     ComputePolygonBbox(canvas, polyPtr);
  1515. }
  1516. /*
  1517.  *--------------------------------------------------------------
  1518.  *
  1519.  * GetPolygonIndex --
  1520.  *
  1521.  * Parse an index into a polygon item and return either its value
  1522.  * or an error.
  1523.  *
  1524.  * Results:
  1525.  * A standard Tcl result.  If all went well, then *indexPtr is
  1526.  * filled in with the index (into itemPtr) corresponding to
  1527.  * string.  Otherwise an error message is left in
  1528.  * interp->result.
  1529.  *
  1530.  * Side effects:
  1531.  * None.
  1532.  *
  1533.  *--------------------------------------------------------------
  1534.  */
  1535. static int
  1536. GetPolygonIndex(interp, canvas, itemPtr, obj, indexPtr)
  1537.     Tcl_Interp *interp; /* Used for error reporting. */
  1538.     Tk_Canvas canvas; /* Canvas containing item. */
  1539.     Tk_Item *itemPtr; /* Item for which the index is being
  1540.  * specified. */
  1541.     Tcl_Obj *obj; /* Specification of a particular coord
  1542.  * in itemPtr's line. */
  1543.     int *indexPtr; /* Where to store converted index. */
  1544. {
  1545.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  1546.     int length;
  1547.     char *string = Tcl_GetStringFromObj(obj, &length);
  1548.     if (string[0] == 'e') {
  1549. if (strncmp(string, "end", (unsigned) length) == 0) {
  1550.     *indexPtr = 2*(polyPtr->numPoints - polyPtr->autoClosed);
  1551. } else {
  1552.     badIndex:
  1553.     /*
  1554.      * Some of the paths here leave messages in interp->result,
  1555.      * so we have to clear it out before storing our own message.
  1556.      */
  1557.     Tcl_SetResult(interp, (char *) NULL, TCL_STATIC);
  1558.     Tcl_AppendResult(interp, "bad index "", string, """,
  1559.     (char *) NULL);
  1560.     return TCL_ERROR;
  1561. }
  1562.     } else if (string[0] == '@') {
  1563. int i;
  1564. double x ,y, bestDist, dist, *coordPtr;
  1565. char *end, *p;
  1566. p = string+1;
  1567. x = strtod(p, &end);
  1568. if ((end == p) || (*end != ',')) {
  1569.     goto badIndex;
  1570. }
  1571. p = end+1;
  1572. y = strtod(p, &end);
  1573. if ((end == p) || (*end != 0)) {
  1574.     goto badIndex;
  1575. }
  1576. bestDist = 1.0e36;
  1577. coordPtr = polyPtr->coordPtr;
  1578. *indexPtr = 0;
  1579. for(i=0; i<(polyPtr->numPoints-1); i++) {
  1580.     dist = hypot(coordPtr[0] - x, coordPtr[1] - y);
  1581.     if (dist<bestDist) {
  1582. bestDist = dist;
  1583. *indexPtr = 2*i;
  1584.     }
  1585.     coordPtr += 2;
  1586. }
  1587.     } else {
  1588. int count = 2*(polyPtr->numPoints - polyPtr->autoClosed);
  1589. if (Tcl_GetIntFromObj(interp, obj, indexPtr) != TCL_OK) {
  1590.     goto badIndex;
  1591. }
  1592. *indexPtr &= -2; /* if odd, make it even */
  1593. if (count) {
  1594.     if (*indexPtr > 0) {
  1595. *indexPtr = ((*indexPtr - 2) % count) + 2;
  1596.     } else {
  1597. *indexPtr = -((-(*indexPtr)) % count);
  1598.     }
  1599. } else {
  1600.     *indexPtr = 0;
  1601. }
  1602.     }
  1603.     return TCL_OK;
  1604. }
  1605. /*
  1606.  *--------------------------------------------------------------
  1607.  *
  1608.  * TranslatePolygon --
  1609.  *
  1610.  * This procedure is called to move a polygon by a given
  1611.  * amount.
  1612.  *
  1613.  * Results:
  1614.  * None.
  1615.  *
  1616.  * Side effects:
  1617.  * The position of the polygon is offset by (xDelta, yDelta),
  1618.  * and the bounding box is updated in the generic part of the
  1619.  * item structure.
  1620.  *
  1621.  *--------------------------------------------------------------
  1622.  */
  1623. static void
  1624. TranslatePolygon(canvas, itemPtr, deltaX, deltaY)
  1625.     Tk_Canvas canvas; /* Canvas containing item. */
  1626.     Tk_Item *itemPtr; /* Item that is being moved. */
  1627.     double deltaX, deltaY; /* Amount by which item is to be
  1628.  * moved. */
  1629. {
  1630.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  1631.     double *coordPtr;
  1632.     int i;
  1633.     for (i = 0, coordPtr = polyPtr->coordPtr; i < polyPtr->numPoints;
  1634.     i++, coordPtr += 2) {
  1635. *coordPtr += deltaX;
  1636. coordPtr[1] += deltaY;
  1637.     }
  1638.     ComputePolygonBbox(canvas, polyPtr);
  1639. }
  1640. /*
  1641.  *--------------------------------------------------------------
  1642.  *
  1643.  * PolygonToPostscript --
  1644.  *
  1645.  * This procedure is called to generate Postscript for
  1646.  * polygon items.
  1647.  *
  1648.  * Results:
  1649.  * The return value is a standard Tcl result.  If an error
  1650.  * occurs in generating Postscript then an error message is
  1651.  * left in the interp's result, replacing whatever used
  1652.  * to be there.  If no error occurs, then Postscript for the
  1653.  * item is appended to the result.
  1654.  *
  1655.  * Side effects:
  1656.  * None.
  1657.  *
  1658.  *--------------------------------------------------------------
  1659.  */
  1660. static int
  1661. PolygonToPostscript(interp, canvas, itemPtr, prepass)
  1662.     Tcl_Interp *interp; /* Leave Postscript or error message
  1663.  * here. */
  1664.     Tk_Canvas canvas; /* Information about overall canvas. */
  1665.     Tk_Item *itemPtr; /* Item for which Postscript is
  1666.  * wanted. */
  1667.     int prepass; /* 1 means this is a prepass to
  1668.  * collect font information;  0 means
  1669.  * final Postscript is being created. */
  1670. {
  1671.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  1672.     char *style;
  1673.     XColor *color;
  1674.     XColor *fillColor;
  1675.     Pixmap stipple;
  1676.     Pixmap fillStipple;
  1677.     Tk_State state = itemPtr->state;
  1678.     double width;
  1679.     if (polyPtr->numPoints<2 || polyPtr->coordPtr==NULL) {
  1680. return TCL_OK;
  1681.     }
  1682.     if(state == TK_STATE_NULL) {
  1683. state = ((TkCanvas *)canvas)->canvas_state;
  1684.     }
  1685.     width = polyPtr->outline.width;
  1686.     color = polyPtr->outline.color;
  1687.     stipple = polyPtr->fillStipple;
  1688.     fillColor = polyPtr->fillColor;
  1689.     fillStipple = polyPtr->fillStipple;
  1690.     if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) {
  1691. if (polyPtr->outline.activeWidth>width) {
  1692.     width = polyPtr->outline.activeWidth;
  1693. }
  1694. if (polyPtr->outline.activeColor!=NULL) {
  1695.     color = polyPtr->outline.activeColor;
  1696. }
  1697. if (polyPtr->outline.activeStipple!=None) {
  1698.     stipple = polyPtr->outline.activeStipple;
  1699. }
  1700. if (polyPtr->activeFillColor!=NULL) {
  1701.     fillColor = polyPtr->activeFillColor;
  1702. }
  1703. if (polyPtr->activeFillStipple!=None) {
  1704.     fillStipple = polyPtr->activeFillStipple;
  1705. }
  1706.     } else if (state==TK_STATE_DISABLED) {
  1707. if (polyPtr->outline.disabledWidth>0.0) {
  1708.     width = polyPtr->outline.disabledWidth;
  1709. }
  1710. if (polyPtr->outline.disabledColor!=NULL) {
  1711.     color = polyPtr->outline.disabledColor;
  1712. }
  1713. if (polyPtr->outline.disabledStipple!=None) {
  1714.     stipple = polyPtr->outline.disabledStipple;
  1715. }
  1716. if (polyPtr->disabledFillColor!=NULL) {
  1717.     fillColor = polyPtr->disabledFillColor;
  1718. }
  1719. if (polyPtr->disabledFillStipple!=None) {
  1720.     fillStipple = polyPtr->disabledFillStipple;
  1721. }
  1722.     }
  1723.     if (polyPtr->numPoints==2) {
  1724. char string[128];
  1725. if (color == NULL) {
  1726.     return TCL_OK;
  1727. }
  1728. sprintf(string, "%.15g %.15g translate %.15g %.15g",
  1729. polyPtr->coordPtr[0], Tk_CanvasPsY(canvas, polyPtr->coordPtr[1]),
  1730. width/2.0, width/2.0);
  1731. Tcl_AppendResult(interp, "matrix currentmatrixn",string,
  1732. " scale 1 0 moveto 0 0 1 0 360 arcnsetmatrixn", (char *) NULL);
  1733. if (Tk_CanvasPsColor(interp, canvas, color) != TCL_OK) {
  1734.     return TCL_ERROR;
  1735. }
  1736. if (stipple != None) {
  1737.     Tcl_AppendResult(interp, "clip ", (char *) NULL);
  1738.     if (Tk_CanvasPsStipple(interp, canvas, stipple) != TCL_OK) {
  1739. return TCL_ERROR;
  1740.     }
  1741. } else {
  1742.     Tcl_AppendResult(interp, "filln", (char *) NULL);
  1743. }
  1744. return TCL_OK;
  1745.     }
  1746.     /*
  1747.      * Fill the area of the polygon.
  1748.      */
  1749.     if (fillColor != NULL && polyPtr->numPoints>3) {
  1750. if (!polyPtr->smooth || !polyPtr->smooth->postscriptProc) {
  1751.     Tk_CanvasPsPath(interp, canvas, polyPtr->coordPtr,
  1752.     polyPtr->numPoints);
  1753. } else {
  1754.     polyPtr->smooth->postscriptProc(interp, canvas, polyPtr->coordPtr,
  1755.     polyPtr->numPoints, polyPtr->splineSteps);
  1756. }
  1757. if (Tk_CanvasPsColor(interp, canvas, fillColor) != TCL_OK) {
  1758.     return TCL_ERROR;
  1759. }
  1760. if (fillStipple != None) {
  1761.     Tcl_AppendResult(interp, "eoclip ", (char *) NULL);
  1762.     if (Tk_CanvasPsStipple(interp, canvas, fillStipple)
  1763.     != TCL_OK) {
  1764. return TCL_ERROR;
  1765.     }
  1766.     if (color != NULL) {
  1767. Tcl_AppendResult(interp, "grestore gsaven", (char *) NULL);
  1768.     }
  1769. } else {
  1770.     Tcl_AppendResult(interp, "eofilln", (char *) NULL);
  1771. }
  1772.     }
  1773.     /*
  1774.      * Now draw the outline, if there is one.
  1775.      */
  1776.     if (color != NULL) {
  1777. if (!polyPtr->smooth || !polyPtr->smooth->postscriptProc) {
  1778.     Tk_CanvasPsPath(interp, canvas, polyPtr->coordPtr,
  1779. polyPtr->numPoints);
  1780. } else {
  1781.     polyPtr->smooth->postscriptProc(interp, canvas, polyPtr->coordPtr,
  1782. polyPtr->numPoints, polyPtr->splineSteps);
  1783. }
  1784. if (polyPtr->joinStyle == JoinRound) {
  1785.     style = "1";
  1786. } else if (polyPtr->joinStyle == JoinBevel) {
  1787.     style = "2";
  1788. } else {
  1789.     style = "0";
  1790. }
  1791. Tcl_AppendResult(interp, style," setlinejoin 1 setlinecapn",
  1792. (char *) NULL);
  1793. if (Tk_CanvasPsOutline(canvas, itemPtr,
  1794. &(polyPtr->outline)) != TCL_OK) {
  1795.     return TCL_ERROR;
  1796. }
  1797.     }
  1798.     return TCL_OK;
  1799. }