home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / generic / tkCanvPoly.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  28.9 KB  |  999 lines  |  [TEXT/CWIE]

  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.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * SCCS: @(#) tkCanvPoly.c 1.37 97/04/29 15:39:16
  13.  */
  14.  
  15. #include <stdio.h>
  16. #include "tkInt.h"
  17. #include "tkPort.h"
  18.  
  19. /*
  20.  * The structure below defines the record for each polygon item.
  21.  */
  22.  
  23. typedef struct PolygonItem  {
  24.     Tk_Item header;        /* Generic stuff that's the same for all
  25.                  * types.  MUST BE FIRST IN STRUCTURE. */
  26.     int numPoints;        /* Number of points in polygon (always >= 3).
  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 width;            /* Width of outline. */
  35.     XColor *outlineColor;    /* Color for outline. */
  36.     GC outlineGC;        /* Graphics context for drawing outline. */
  37.     XColor *fillColor;        /* Foreground color for polygon. */
  38.     Pixmap fillStipple;        /* Stipple bitmap for filling polygon. */
  39.     GC fillGC;            /* Graphics context for filling polygon. */
  40.     int smooth;            /* Non-zero means draw shape smoothed (i.e.
  41.                  * with Bezier splines). */
  42.     int splineSteps;        /* Number of steps in each spline segment. */
  43.     int autoClosed;        /* Zero means the given polygon was closed,
  44.                    one means that we auto closed it. */
  45. } PolygonItem;
  46.  
  47. /*
  48.  * Information used for parsing configuration specs:
  49.  */
  50.  
  51. static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc,
  52.     Tk_CanvasTagsPrintProc, (ClientData) NULL
  53. };
  54.  
  55. static Tk_ConfigSpec configSpecs[] = {
  56.     {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL,
  57.     "black", Tk_Offset(PolygonItem, fillColor), TK_CONFIG_NULL_OK},
  58.     {TK_CONFIG_COLOR, "-outline", (char *) NULL, (char *) NULL,
  59.     (char *) NULL, Tk_Offset(PolygonItem, outlineColor), TK_CONFIG_NULL_OK},
  60.     {TK_CONFIG_BOOLEAN, "-smooth", (char *) NULL, (char *) NULL,
  61.     "0", Tk_Offset(PolygonItem, smooth), TK_CONFIG_DONT_SET_DEFAULT},
  62.     {TK_CONFIG_INT, "-splinesteps", (char *) NULL, (char *) NULL,
  63.     "12", Tk_Offset(PolygonItem, splineSteps), TK_CONFIG_DONT_SET_DEFAULT},
  64.     {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL,
  65.     (char *) NULL, Tk_Offset(PolygonItem, fillStipple), TK_CONFIG_NULL_OK},
  66.     {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL,
  67.     (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption},
  68.     {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL,
  69.     "1", Tk_Offset(PolygonItem, width), TK_CONFIG_DONT_SET_DEFAULT},
  70.     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  71.     (char *) NULL, 0, 0}
  72. };
  73.  
  74. /*
  75.  * Prototypes for procedures defined in this file:
  76.  */
  77.  
  78. static void        ComputePolygonBbox _ANSI_ARGS_((Tk_Canvas canvas,
  79.                 PolygonItem *polyPtr));
  80. static int        ConfigurePolygon _ANSI_ARGS_((Tcl_Interp *interp,
  81.                 Tk_Canvas canvas, Tk_Item *itemPtr, int argc,
  82.                 char **argv, int flags));
  83. static int        CreatePolygon _ANSI_ARGS_((Tcl_Interp *interp,
  84.                 Tk_Canvas canvas, struct Tk_Item *itemPtr,
  85.                 int argc, char **argv));
  86. static void        DeletePolygon _ANSI_ARGS_((Tk_Canvas canvas,
  87.                 Tk_Item *itemPtr,  Display *display));
  88. static void        DisplayPolygon _ANSI_ARGS_((Tk_Canvas canvas,
  89.                 Tk_Item *itemPtr, Display *display, Drawable dst,
  90.                 int x, int y, int width, int height));
  91. static int        PolygonCoords _ANSI_ARGS_((Tcl_Interp *interp,
  92.                 Tk_Canvas canvas, Tk_Item *itemPtr,
  93.                 int argc, char **argv));
  94. static int        PolygonToArea _ANSI_ARGS_((Tk_Canvas canvas,
  95.                 Tk_Item *itemPtr, double *rectPtr));
  96. static double        PolygonToPoint _ANSI_ARGS_((Tk_Canvas canvas,
  97.                 Tk_Item *itemPtr, double *pointPtr));
  98. static int        PolygonToPostscript _ANSI_ARGS_((Tcl_Interp *interp,
  99.                 Tk_Canvas canvas, Tk_Item *itemPtr, int prepass));
  100. static void        ScalePolygon _ANSI_ARGS_((Tk_Canvas canvas,
  101.                 Tk_Item *itemPtr, double originX, double originY,
  102.                 double scaleX, double scaleY));
  103. static void        TranslatePolygon _ANSI_ARGS_((Tk_Canvas canvas,
  104.                 Tk_Item *itemPtr, double deltaX, double deltaY));
  105.  
  106. /*
  107.  * The structures below defines the polygon item type by means
  108.  * of procedures that can be invoked by generic item code.
  109.  */
  110.  
  111. Tk_ItemType tkPolygonType = {
  112.     "polygon",                /* name */
  113.     sizeof(PolygonItem),        /* itemSize */
  114.     CreatePolygon,            /* createProc */
  115.     configSpecs,            /* configSpecs */
  116.     ConfigurePolygon,            /* configureProc */
  117.     PolygonCoords,            /* coordProc */
  118.     DeletePolygon,            /* deleteProc */
  119.     DisplayPolygon,            /* displayProc */
  120.     0,                    /* alwaysRedraw */
  121.     PolygonToPoint,            /* pointProc */
  122.     PolygonToArea,            /* areaProc */
  123.     PolygonToPostscript,        /* postscriptProc */
  124.     ScalePolygon,            /* scaleProc */
  125.     TranslatePolygon,            /* translateProc */
  126.     (Tk_ItemIndexProc *) NULL,        /* indexProc */
  127.     (Tk_ItemCursorProc *) NULL,        /* icursorProc */
  128.     (Tk_ItemSelectionProc *) NULL,    /* selectionProc */
  129.     (Tk_ItemInsertProc *) NULL,        /* insertProc */
  130.     (Tk_ItemDCharsProc *) NULL,        /* dTextProc */
  131.     (Tk_ItemType *) NULL        /* nextPtr */
  132. };
  133.  
  134. /*
  135.  * The definition below determines how large are static arrays
  136.  * used to hold spline points (splines larger than this have to
  137.  * have their arrays malloc-ed).
  138.  */
  139.  
  140. #define MAX_STATIC_POINTS 200
  141.  
  142. /*
  143.  *--------------------------------------------------------------
  144.  *
  145.  * CreatePolygon --
  146.  *
  147.  *    This procedure is invoked to create a new polygon item in
  148.  *    a canvas.
  149.  *
  150.  * Results:
  151.  *    A standard Tcl return value.  If an error occurred in
  152.  *    creating the item, then an error message is left in
  153.  *    interp->result;  in this case itemPtr is
  154.  *    left uninitialized, so it can be safely freed by the
  155.  *    caller.
  156.  *
  157.  * Side effects:
  158.  *    A new polygon item is created.
  159.  *
  160.  *--------------------------------------------------------------
  161.  */
  162.  
  163. static int
  164. CreatePolygon(interp, canvas, itemPtr, argc, argv)
  165.     Tcl_Interp *interp;            /* Interpreter for error reporting. */
  166.     Tk_Canvas canvas;            /* Canvas to hold new item. */
  167.     Tk_Item *itemPtr;            /* Record to hold new item;  header
  168.                      * has been initialized by caller. */
  169.     int argc;                /* Number of arguments in argv. */
  170.     char **argv;            /* Arguments describing polygon. */
  171. {
  172.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  173.     int i;
  174.  
  175.     if (argc < 6) {
  176.     Tcl_AppendResult(interp, "wrong # args: should be \"",
  177.         Tk_PathName(Tk_CanvasTkwin(canvas)), " create ",
  178.         itemPtr->typePtr->name,
  179.         " x1 y1 x2 y2 x3 y3 ?x4 y4 ...? ?options?\"", (char *) NULL);
  180.     return TCL_ERROR;
  181.     }
  182.  
  183.     /*
  184.      * Carry out initialization that is needed in order to clean
  185.      * up after errors during the the remainder of this procedure.
  186.      */
  187.  
  188.     polyPtr->numPoints = 0;
  189.     polyPtr->pointsAllocated = 0;
  190.     polyPtr->coordPtr = NULL;
  191.     polyPtr->width = 1;
  192.     polyPtr->outlineColor = NULL;
  193.     polyPtr->outlineGC = None;
  194.     polyPtr->fillColor = NULL;
  195.     polyPtr->fillStipple = None;
  196.     polyPtr->fillGC = None;
  197.     polyPtr->smooth = 0;
  198.     polyPtr->splineSteps = 12;
  199.     polyPtr->autoClosed = 0;
  200.  
  201.     /*
  202.      * Count the number of points and then parse them into a point
  203.      * array.  Leading arguments are assumed to be points if they
  204.      * start with a digit or a minus sign followed by a digit.
  205.      */
  206.  
  207.     for (i = 4; i < (argc-1); i+=2) {
  208.     if ((!isdigit(UCHAR(argv[i][0]))) &&
  209.         ((argv[i][0] != '-') || (!isdigit(UCHAR(argv[i][1]))))) {
  210.         break;
  211.     }
  212.     }
  213.     if (PolygonCoords(interp, canvas, itemPtr, i, argv) != TCL_OK) {
  214.     goto error;
  215.     }
  216.  
  217.     if (ConfigurePolygon(interp, canvas, itemPtr, argc-i, argv+i, 0)
  218.         == TCL_OK) {
  219.     return TCL_OK;
  220.     }
  221.  
  222.     error:
  223.     DeletePolygon(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas)));
  224.     return TCL_ERROR;
  225. }
  226.  
  227. /*
  228.  *--------------------------------------------------------------
  229.  *
  230.  * PolygonCoords --
  231.  *
  232.  *    This procedure is invoked to process the "coords" widget
  233.  *    command on polygons.  See the user documentation for details
  234.  *    on what it does.
  235.  *
  236.  * Results:
  237.  *    Returns TCL_OK or TCL_ERROR, and sets interp->result.
  238.  *
  239.  * Side effects:
  240.  *    The coordinates for the given item may be changed.
  241.  *
  242.  *--------------------------------------------------------------
  243.  */
  244.  
  245. static int
  246. PolygonCoords(interp, canvas, itemPtr, argc, argv)
  247.     Tcl_Interp *interp;            /* Used for error reporting. */
  248.     Tk_Canvas canvas;            /* Canvas containing item. */
  249.     Tk_Item *itemPtr;            /* Item whose coordinates are to be
  250.                      * read or modified. */
  251.     int argc;                /* Number of coordinates supplied in
  252.                      * argv. */
  253.     char **argv;            /* Array of coordinates: x1, y1,
  254.                      * x2, y2, ... */
  255. {
  256.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  257.     char buffer[TCL_DOUBLE_SPACE];
  258.     int i, numPoints;
  259.  
  260.     if (argc == 0) {
  261.     /*
  262.      * Print the coords used to create the polygon.  If we auto
  263.      * closed the polygon then we don't report the last point.
  264.      */
  265.     for (i = 0; i < 2*(polyPtr->numPoints - polyPtr->autoClosed); i++) {
  266.         Tcl_PrintDouble(interp, polyPtr->coordPtr[i], buffer);
  267.         Tcl_AppendElement(interp, buffer);
  268.     }
  269.     } else if (argc < 6) {
  270.     Tcl_AppendResult(interp,
  271.         "too few coordinates for polygon: must have at least 6",
  272.         (char *) NULL);
  273.     return TCL_ERROR;
  274.     } else if (argc & 1) {
  275.     Tcl_AppendResult(interp,
  276.         "odd number of coordinates specified for polygon",
  277.         (char *) NULL);
  278.     return TCL_ERROR;
  279.     } else {
  280.     numPoints = argc/2;
  281.     if (polyPtr->pointsAllocated <= numPoints) {
  282.         if (polyPtr->coordPtr != NULL) {
  283.         ckfree((char *) polyPtr->coordPtr);
  284.         }
  285.  
  286.         /*
  287.          * One extra point gets allocated here, just in case we have
  288.          * to add another point to close the polygon.
  289.          */
  290.  
  291.         polyPtr->coordPtr = (double *) ckalloc((unsigned)
  292.             (sizeof(double) * (argc+2)));
  293.         polyPtr->pointsAllocated = numPoints+1;
  294.     }
  295.     for (i = argc-1; i >= 0; i--) {
  296.         if (Tk_CanvasGetCoord(interp, canvas, argv[i],
  297.             &polyPtr->coordPtr[i]) != TCL_OK) {
  298.         return TCL_ERROR;
  299.         }
  300.     }
  301.     polyPtr->numPoints = numPoints;
  302.     polyPtr->autoClosed = 0;
  303.     
  304.     /*
  305.      * Close the polygon if it isn't already closed.
  306.      */
  307.     
  308.     if ((polyPtr->coordPtr[argc-2] != polyPtr->coordPtr[0])
  309.         || (polyPtr->coordPtr[argc-1] != polyPtr->coordPtr[1])) {
  310.         polyPtr->autoClosed = 1;
  311.         polyPtr->numPoints++;
  312.         polyPtr->coordPtr[argc] = polyPtr->coordPtr[0];
  313.         polyPtr->coordPtr[argc+1] = polyPtr->coordPtr[1];
  314.     }
  315.     ComputePolygonBbox(canvas, polyPtr);
  316.     }
  317.     return TCL_OK;
  318. }
  319.  
  320. /*
  321.  *--------------------------------------------------------------
  322.  *
  323.  * ConfigurePolygon --
  324.  *
  325.  *    This procedure is invoked to configure various aspects
  326.  *    of a polygon item such as its background color.
  327.  *
  328.  * Results:
  329.  *    A standard Tcl result code.  If an error occurs, then
  330.  *    an error message is left in interp->result.
  331.  *
  332.  * Side effects:
  333.  *    Configuration information, such as colors and stipple
  334.  *    patterns, may be set for itemPtr.
  335.  *
  336.  *--------------------------------------------------------------
  337.  */
  338.  
  339. static int
  340. ConfigurePolygon(interp, canvas, itemPtr, argc, argv, flags)
  341.     Tcl_Interp *interp;        /* Interpreter for error reporting. */
  342.     Tk_Canvas canvas;        /* Canvas containing itemPtr. */
  343.     Tk_Item *itemPtr;        /* Polygon item to reconfigure. */
  344.     int argc;            /* Number of elements in argv.  */
  345.     char **argv;        /* Arguments describing things to configure. */
  346.     int flags;            /* Flags to pass to Tk_ConfigureWidget. */
  347. {
  348.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  349.     XGCValues gcValues;
  350.     GC newGC;
  351.     unsigned long mask;
  352.     Tk_Window tkwin;
  353.  
  354.     tkwin = Tk_CanvasTkwin(canvas);
  355.     if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv,
  356.         (char *) polyPtr, flags) != TCL_OK) {
  357.     return TCL_ERROR;
  358.     }
  359.  
  360.     /*
  361.      * A few of the options require additional processing, such as
  362.      * graphics contexts.
  363.      */
  364.  
  365.     if (polyPtr->width < 1) {
  366.     polyPtr->width = 1;
  367.     }
  368.     if (polyPtr->outlineColor == NULL) {
  369.     newGC = None;
  370.     } else {
  371.     gcValues.foreground = polyPtr->outlineColor->pixel;
  372.     gcValues.line_width = polyPtr->width;
  373.     gcValues.cap_style = CapRound;
  374.     gcValues.join_style = JoinRound;
  375.     mask = GCForeground|GCLineWidth|GCCapStyle|GCJoinStyle;
  376.     newGC = Tk_GetGC(tkwin, mask, &gcValues);
  377.     }
  378.     if (polyPtr->outlineGC != None) {
  379.     Tk_FreeGC(Tk_Display(tkwin), polyPtr->outlineGC);
  380.     }
  381.     polyPtr->outlineGC = newGC;
  382.  
  383.     if (polyPtr->fillColor == NULL) {
  384.     newGC = None;
  385.     } else {
  386.     gcValues.foreground = polyPtr->fillColor->pixel;
  387.     mask = GCForeground;
  388.     if (polyPtr->fillStipple != None) {
  389.         gcValues.stipple = polyPtr->fillStipple;
  390.         gcValues.fill_style = FillStippled;
  391.         mask |= GCStipple|GCFillStyle;
  392.     }
  393.     newGC = Tk_GetGC(tkwin, mask, &gcValues);
  394.     }
  395.     if (polyPtr->fillGC != None) {
  396.     Tk_FreeGC(Tk_Display(tkwin), polyPtr->fillGC);
  397.     }
  398.     polyPtr->fillGC = newGC;
  399.  
  400.     /*
  401.      * Keep spline parameters within reasonable limits.
  402.      */
  403.  
  404.     if (polyPtr->splineSteps < 1) {
  405.     polyPtr->splineSteps = 1;
  406.     } else if (polyPtr->splineSteps > 100) {
  407.     polyPtr->splineSteps = 100;
  408.     }
  409.  
  410.     ComputePolygonBbox(canvas, polyPtr);
  411.     return TCL_OK;
  412. }
  413.  
  414. /*
  415.  *--------------------------------------------------------------
  416.  *
  417.  * DeletePolygon --
  418.  *
  419.  *    This procedure is called to clean up the data structure
  420.  *    associated with a polygon item.
  421.  *
  422.  * Results:
  423.  *    None.
  424.  *
  425.  * Side effects:
  426.  *    Resources associated with itemPtr are released.
  427.  *
  428.  *--------------------------------------------------------------
  429.  */
  430.  
  431. static void
  432. DeletePolygon(canvas, itemPtr, display)
  433.     Tk_Canvas canvas;            /* Info about overall canvas widget. */
  434.     Tk_Item *itemPtr;            /* Item that is being deleted. */
  435.     Display *display;            /* Display containing window for
  436.                      * canvas. */
  437. {
  438.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  439.  
  440.     if (polyPtr->coordPtr != NULL) {
  441.     ckfree((char *) polyPtr->coordPtr);
  442.     }
  443.     if (polyPtr->fillColor != NULL) {
  444.     Tk_FreeColor(polyPtr->fillColor);
  445.     }
  446.     if (polyPtr->fillStipple != None) {
  447.     Tk_FreeBitmap(display, polyPtr->fillStipple);
  448.     }
  449.     if (polyPtr->outlineColor != NULL) {
  450.     Tk_FreeColor(polyPtr->outlineColor);
  451.     }
  452.     if (polyPtr->outlineGC != None) {
  453.     Tk_FreeGC(display, polyPtr->outlineGC);
  454.     }
  455.     if (polyPtr->fillGC != None) {
  456.     Tk_FreeGC(display, polyPtr->fillGC);
  457.     }
  458. }
  459.  
  460. /*
  461.  *--------------------------------------------------------------
  462.  *
  463.  * ComputePolygonBbox --
  464.  *
  465.  *    This procedure is invoked to compute the bounding box of
  466.  *    all the pixels that may be drawn as part of a polygon.
  467.  *
  468.  * Results:
  469.  *    None.
  470.  *
  471.  * Side effects:
  472.  *    The fields x1, y1, x2, and y2 are updated in the header
  473.  *    for itemPtr.
  474.  *
  475.  *--------------------------------------------------------------
  476.  */
  477.  
  478. static void
  479. ComputePolygonBbox(canvas, polyPtr)
  480.     Tk_Canvas canvas;            /* Canvas that contains item. */
  481.     PolygonItem *polyPtr;        /* Item whose bbox is to be
  482.                      * recomputed. */
  483. {
  484.     double *coordPtr;
  485.     int i;
  486.  
  487.     coordPtr = polyPtr->coordPtr;
  488.     polyPtr->header.x1 = polyPtr->header.x2 = (int) *coordPtr;
  489.     polyPtr->header.y1 = polyPtr->header.y2 = (int) coordPtr[1];
  490.  
  491.     for (i = 1, coordPtr = polyPtr->coordPtr+2; i < polyPtr->numPoints;
  492.         i++, coordPtr += 2) {
  493.     TkIncludePoint((Tk_Item *) polyPtr, coordPtr);
  494.     }
  495.  
  496.     /*
  497.      * Expand bounding box in all directions to account for the outline,
  498.      * which can stick out beyond the polygon.  Add one extra pixel of
  499.      * fudge, just in case X rounds differently than we do.
  500.      */
  501.  
  502.     i = (polyPtr->width+1)/2 + 1;
  503.     polyPtr->header.x1 -= i;
  504.     polyPtr->header.x2 += i;
  505.     polyPtr->header.y1 -= i;
  506.     polyPtr->header.y2 += i;
  507. }
  508.  
  509. /*
  510.  *--------------------------------------------------------------
  511.  *
  512.  * TkFillPolygon --
  513.  *
  514.  *    This procedure is invoked to convert a polygon to screen
  515.  *    coordinates and display it using a particular GC.
  516.  *
  517.  * Results:
  518.  *    None.
  519.  *
  520.  * Side effects:
  521.  *    ItemPtr is drawn in drawable using the transformation
  522.  *    information in canvas.
  523.  *
  524.  *--------------------------------------------------------------
  525.  */
  526.  
  527. void
  528. TkFillPolygon(canvas, coordPtr, numPoints, display, drawable, gc, outlineGC)
  529.     Tk_Canvas canvas;            /* Canvas whose coordinate system
  530.                      * is to be used for drawing. */
  531.     double *coordPtr;            /* Array of coordinates for polygon:
  532.                      * x1, y1, x2, y2, .... */
  533.     int numPoints;            /* Twice this many coordinates are
  534.                      * present at *coordPtr. */
  535.     Display *display;            /* Display on which to draw polygon. */
  536.     Drawable drawable;            /* Pixmap or window in which to draw
  537.                      * polygon. */
  538.     GC gc;                /* Graphics context for drawing. */
  539.     GC outlineGC;            /* If not None, use this to draw an
  540.                      * outline around the polygon after
  541.                      * filling it. */
  542. {
  543.     XPoint staticPoints[MAX_STATIC_POINTS];
  544.     XPoint *pointPtr;
  545.     XPoint *pPtr;
  546.     int i;
  547.  
  548.     /*
  549.      * Build up an array of points in screen coordinates.  Use a
  550.      * static array unless the polygon has an enormous number of points;
  551.      * in this case, dynamically allocate an array.
  552.      */
  553.  
  554.     if (numPoints <= MAX_STATIC_POINTS) {
  555.     pointPtr = staticPoints;
  556.     } else {
  557.     pointPtr = (XPoint *) ckalloc((unsigned) (numPoints * sizeof(XPoint)));
  558.     }
  559.  
  560.     for (i = 0, pPtr = pointPtr; i < numPoints; i += 1, coordPtr += 2, pPtr++) {
  561.     Tk_CanvasDrawableCoords(canvas, coordPtr[0], coordPtr[1], &pPtr->x,
  562.         &pPtr->y);
  563.     }
  564.  
  565.     /*
  566.      * Display polygon, then free up polygon storage if it was dynamically
  567.      * allocated.
  568.      */
  569.  
  570.     if (gc != None) {
  571.     XFillPolygon(display, drawable, gc, pointPtr, numPoints, Complex,
  572.         CoordModeOrigin);
  573.     }
  574.     if (outlineGC != None) {
  575.     XDrawLines(display, drawable, outlineGC, pointPtr,
  576.         numPoints, CoordModeOrigin);
  577.     }
  578.     if (pointPtr != staticPoints) {
  579.     ckfree((char *) pointPtr);
  580.     }
  581. }
  582.  
  583. /*
  584.  *--------------------------------------------------------------
  585.  *
  586.  * DisplayPolygon --
  587.  *
  588.  *    This procedure is invoked to draw a polygon item in a given
  589.  *    drawable.
  590.  *
  591.  * Results:
  592.  *    None.
  593.  *
  594.  * Side effects:
  595.  *    ItemPtr is drawn in drawable using the transformation
  596.  *    information in canvas.
  597.  *
  598.  *--------------------------------------------------------------
  599.  */
  600.  
  601. static void
  602. DisplayPolygon(canvas, itemPtr, display, drawable, x, y, width, height)
  603.     Tk_Canvas canvas;            /* Canvas that contains item. */
  604.     Tk_Item *itemPtr;            /* Item to be displayed. */
  605.     Display *display;            /* Display on which to draw item. */
  606.     Drawable drawable;            /* Pixmap or window in which to draw
  607.                      * item. */
  608.     int x, y, width, height;        /* Describes region of canvas that
  609.                      * must be redisplayed (not used). */
  610. {
  611.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  612.  
  613.     if ((polyPtr->fillGC == None) && (polyPtr->outlineGC == None)) {
  614.     return;
  615.     }
  616.  
  617.     /*
  618.      * If we're stippling then modify the stipple offset in the GC.  Be
  619.      * sure to reset the offset when done, since the GC is supposed to be
  620.      * read-only.
  621.      */
  622.  
  623.     if ((polyPtr->fillStipple != None) && (polyPtr->fillGC != None)) {
  624.     Tk_CanvasSetStippleOrigin(canvas, polyPtr->fillGC);
  625.     }
  626.  
  627.     if (!polyPtr->smooth) {
  628.     TkFillPolygon(canvas, polyPtr->coordPtr, polyPtr->numPoints,
  629.         display, drawable, polyPtr->fillGC, polyPtr->outlineGC);
  630.     } else {
  631.     int numPoints;
  632.     XPoint staticPoints[MAX_STATIC_POINTS];
  633.     XPoint *pointPtr;
  634.  
  635.     /*
  636.      * This is a smoothed polygon.  Display using a set of generated
  637.      * spline points rather than the original points.
  638.      */
  639.  
  640.     numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps;
  641.     if (numPoints <= MAX_STATIC_POINTS) {
  642.         pointPtr = staticPoints;
  643.     } else {
  644.         pointPtr = (XPoint *) ckalloc((unsigned)
  645.             (numPoints * sizeof(XPoint)));
  646.     }
  647.     numPoints = TkMakeBezierCurve(canvas, polyPtr->coordPtr,
  648.         polyPtr->numPoints, polyPtr->splineSteps, pointPtr,
  649.         (double *) NULL);
  650.     if (polyPtr->fillGC != None) {
  651.         XFillPolygon(display, drawable, polyPtr->fillGC, pointPtr,
  652.             numPoints, Complex, CoordModeOrigin);
  653.     }
  654.     if (polyPtr->outlineGC != None) {
  655.         XDrawLines(display, drawable, polyPtr->outlineGC, pointPtr,
  656.             numPoints, CoordModeOrigin);
  657.     }
  658.     if (pointPtr != staticPoints) {
  659.         ckfree((char *) pointPtr);
  660.     }
  661.     }
  662.     if ((polyPtr->fillStipple != None) && (polyPtr->fillGC != None)) {
  663.     XSetTSOrigin(display, polyPtr->fillGC, 0, 0);
  664.     }
  665. }
  666.  
  667. /*
  668.  *--------------------------------------------------------------
  669.  *
  670.  * PolygonToPoint --
  671.  *
  672.  *    Computes the distance from a given point to a given
  673.  *    polygon, in canvas units.
  674.  *
  675.  * Results:
  676.  *    The return value is 0 if the point whose x and y coordinates
  677.  *    are pointPtr[0] and pointPtr[1] is inside the polygon.  If the
  678.  *    point isn't inside the polygon then the return value is the
  679.  *    distance from the point to the polygon.
  680.  *
  681.  * Side effects:
  682.  *    None.
  683.  *
  684.  *--------------------------------------------------------------
  685.  */
  686.  
  687.     /* ARGSUSED */
  688. static double
  689. PolygonToPoint(canvas, itemPtr, pointPtr)
  690.     Tk_Canvas canvas;        /* Canvas containing item. */
  691.     Tk_Item *itemPtr;        /* Item to check against point. */
  692.     double *pointPtr;        /* Pointer to x and y coordinates. */
  693. {
  694.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  695.     double *coordPtr, distance;
  696.     double staticSpace[2*MAX_STATIC_POINTS];
  697.     int numPoints;
  698.  
  699.     if (!polyPtr->smooth) {
  700.     distance = TkPolygonToPoint(polyPtr->coordPtr, polyPtr->numPoints,
  701.         pointPtr);
  702.     } else {
  703.     /*
  704.      * Smoothed polygon.  Generate a new set of points and use them
  705.      * for comparison.
  706.      */
  707.     
  708.     numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps;
  709.     if (numPoints <= MAX_STATIC_POINTS) {
  710.         coordPtr = staticSpace;
  711.     } else {
  712.         coordPtr = (double *) ckalloc((unsigned)
  713.             (2*numPoints*sizeof(double)));
  714.     }
  715.     numPoints = TkMakeBezierCurve(canvas, polyPtr->coordPtr,
  716.         polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL,
  717.         coordPtr);
  718.     distance = TkPolygonToPoint(coordPtr, numPoints, pointPtr);
  719.     if (coordPtr != staticSpace) {
  720.         ckfree((char *) coordPtr);
  721.     }
  722.     }
  723.     if (polyPtr->outlineColor != NULL) {
  724.     distance -= polyPtr->width/2.0;
  725.     if (distance < 0) {
  726.         distance = 0;
  727.     }
  728.     }
  729.     return distance;
  730. }
  731.  
  732. /*
  733.  *--------------------------------------------------------------
  734.  *
  735.  * PolygonToArea --
  736.  *
  737.  *    This procedure is called to determine whether an item
  738.  *    lies entirely inside, entirely outside, or overlapping
  739.  *    a given rectangular area.
  740.  *
  741.  * Results:
  742.  *    -1 is returned if the item is entirely outside the area
  743.  *    given by rectPtr, 0 if it overlaps, and 1 if it is entirely
  744.  *    inside the given area.
  745.  *
  746.  * Side effects:
  747.  *    None.
  748.  *
  749.  *--------------------------------------------------------------
  750.  */
  751.  
  752.     /* ARGSUSED */
  753. static int
  754. PolygonToArea(canvas, itemPtr, rectPtr)
  755.     Tk_Canvas canvas;        /* Canvas containing item. */
  756.     Tk_Item *itemPtr;        /* Item to check against polygon. */
  757.     double *rectPtr;        /* Pointer to array of four coordinates
  758.                  * (x1, y1, x2, y2) describing rectangular
  759.                  * area.  */
  760. {
  761.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  762.     double *coordPtr, rect2[4], halfWidth;
  763.     double staticSpace[2*MAX_STATIC_POINTS];
  764.     int numPoints, result;
  765.  
  766.     /*
  767.      * Handle smoothed polygons by generating an expanded set of points
  768.      * against which to do the check.
  769.      */
  770.  
  771.     if (polyPtr->smooth) {
  772.     numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps;
  773.     if (numPoints <= MAX_STATIC_POINTS) {
  774.         coordPtr = staticSpace;
  775.     } else {
  776.         coordPtr = (double *) ckalloc((unsigned)
  777.             (2*numPoints*sizeof(double)));
  778.     }
  779.     numPoints = TkMakeBezierCurve(canvas, polyPtr->coordPtr,
  780.         polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL,
  781.         coordPtr);
  782.     } else {
  783.     numPoints = polyPtr->numPoints;
  784.     coordPtr = polyPtr->coordPtr;
  785.     }
  786.  
  787.     if (polyPtr->width <= 1) {
  788.     /*
  789.      * The outline of the polygon doesn't stick out, so we can
  790.      * do a simple check.
  791.      */
  792.  
  793.     result = TkPolygonToArea(coordPtr, numPoints, rectPtr);
  794.     } else {
  795.     /*
  796.      * The polygon has a wide outline, so the check is more complicated.
  797.      * First, check the line segments to see if they overlap the area.
  798.      */
  799.  
  800.     result = TkThickPolyLineToArea(coordPtr, numPoints, 
  801.         (double) polyPtr->width, CapRound, JoinRound, rectPtr);
  802.     if (result >= 0) {
  803.         goto done;
  804.     }
  805.  
  806.     /*
  807.      * There is no overlap between the polygon's outline and the
  808.      * rectangle.  This means either the rectangle is entirely outside
  809.      * the polygon or entirely inside.  To tell the difference,
  810.      * see whether the polygon (with 0 outline width) overlaps the
  811.      * rectangle bloated by half the outline width.
  812.      */
  813.  
  814.     halfWidth = polyPtr->width/2.0;
  815.     rect2[0] = rectPtr[0] - halfWidth;
  816.     rect2[1] = rectPtr[1] - halfWidth;
  817.     rect2[2] = rectPtr[2] + halfWidth;
  818.     rect2[3] = rectPtr[3] + halfWidth;
  819.     if (TkPolygonToArea(coordPtr, numPoints, rect2) == -1) {
  820.         result = -1;
  821.     } else {
  822.         result = 0;
  823.     }
  824.     }
  825.  
  826.     done:
  827.     if ((coordPtr != staticSpace) && (coordPtr != polyPtr->coordPtr)) {
  828.     ckfree((char *) coordPtr);
  829.     }
  830.     return result;
  831. }
  832.  
  833. /*
  834.  *--------------------------------------------------------------
  835.  *
  836.  * ScalePolygon --
  837.  *
  838.  *    This procedure is invoked to rescale a polygon item.
  839.  *
  840.  * Results:
  841.  *    None.
  842.  *
  843.  * Side effects:
  844.  *    The polygon referred to by itemPtr is rescaled so that the
  845.  *    following transformation is applied to all point
  846.  *    coordinates:
  847.  *        x' = originX + scaleX*(x-originX)
  848.  *        y' = originY + scaleY*(y-originY)
  849.  *
  850.  *--------------------------------------------------------------
  851.  */
  852.  
  853. static void
  854. ScalePolygon(canvas, itemPtr, originX, originY, scaleX, scaleY)
  855.     Tk_Canvas canvas;            /* Canvas containing polygon. */
  856.     Tk_Item *itemPtr;            /* Polygon to be scaled. */
  857.     double originX, originY;        /* Origin about which to scale rect. */
  858.     double scaleX;            /* Amount to scale in X direction. */
  859.     double scaleY;            /* Amount to scale in Y direction. */
  860. {
  861.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  862.     double *coordPtr;
  863.     int i;
  864.  
  865.     for (i = 0, coordPtr = polyPtr->coordPtr; i < polyPtr->numPoints;
  866.         i++, coordPtr += 2) {
  867.     *coordPtr = originX + scaleX*(*coordPtr - originX);
  868.     coordPtr[1] = originY + scaleY*(coordPtr[1] - originY);
  869.     }
  870.     ComputePolygonBbox(canvas, polyPtr);
  871. }
  872.  
  873. /*
  874.  *--------------------------------------------------------------
  875.  *
  876.  * TranslatePolygon --
  877.  *
  878.  *    This procedure is called to move a polygon by a given
  879.  *    amount.
  880.  *
  881.  * Results:
  882.  *    None.
  883.  *
  884.  * Side effects:
  885.  *    The position of the polygon is offset by (xDelta, yDelta),
  886.  *    and the bounding box is updated in the generic part of the
  887.  *    item structure.
  888.  *
  889.  *--------------------------------------------------------------
  890.  */
  891.  
  892. static void
  893. TranslatePolygon(canvas, itemPtr, deltaX, deltaY)
  894.     Tk_Canvas canvas;            /* Canvas containing item. */
  895.     Tk_Item *itemPtr;            /* Item that is being moved. */
  896.     double deltaX, deltaY;        /* Amount by which item is to be
  897.                      * moved. */
  898. {
  899.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  900.     double *coordPtr;
  901.     int i;
  902.  
  903.     for (i = 0, coordPtr = polyPtr->coordPtr; i < polyPtr->numPoints;
  904.         i++, coordPtr += 2) {
  905.     *coordPtr += deltaX;
  906.     coordPtr[1] += deltaY;
  907.     }
  908.     ComputePolygonBbox(canvas, polyPtr);
  909. }
  910.  
  911. /*
  912.  *--------------------------------------------------------------
  913.  *
  914.  * PolygonToPostscript --
  915.  *
  916.  *    This procedure is called to generate Postscript for
  917.  *    polygon items.
  918.  *
  919.  * Results:
  920.  *    The return value is a standard Tcl result.  If an error
  921.  *    occurs in generating Postscript then an error message is
  922.  *    left in interp->result, replacing whatever used
  923.  *    to be there.  If no error occurs, then Postscript for the
  924.  *    item is appended to the result.
  925.  *
  926.  * Side effects:
  927.  *    None.
  928.  *
  929.  *--------------------------------------------------------------
  930.  */
  931.  
  932. static int
  933. PolygonToPostscript(interp, canvas, itemPtr, prepass)
  934.     Tcl_Interp *interp;            /* Leave Postscript or error message
  935.                      * here. */
  936.     Tk_Canvas canvas;            /* Information about overall canvas. */
  937.     Tk_Item *itemPtr;            /* Item for which Postscript is
  938.                      * wanted. */
  939.     int prepass;            /* 1 means this is a prepass to
  940.                      * collect font information;  0 means
  941.                      * final Postscript is being created. */
  942. {
  943.     char string[100];
  944.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  945.  
  946.     /*
  947.      * Fill the area of the polygon.
  948.      */
  949.  
  950.     if (polyPtr->fillColor != NULL) {
  951.     if (!polyPtr->smooth) {
  952.         Tk_CanvasPsPath(interp, canvas, polyPtr->coordPtr,
  953.             polyPtr->numPoints);
  954.     } else {
  955.         TkMakeBezierPostscript(interp, canvas, polyPtr->coordPtr,
  956.             polyPtr->numPoints);
  957.     }
  958.     if (Tk_CanvasPsColor(interp, canvas, polyPtr->fillColor) != TCL_OK) {
  959.         return TCL_ERROR;
  960.     }
  961.     if (polyPtr->fillStipple != None) {
  962.         Tcl_AppendResult(interp, "eoclip ", (char *) NULL);
  963.         if (Tk_CanvasPsStipple(interp, canvas, polyPtr->fillStipple)
  964.             != TCL_OK) {
  965.         return TCL_ERROR;
  966.         }
  967.         if (polyPtr->outlineColor != NULL) {
  968.         Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL);
  969.         }
  970.     } else {
  971.         Tcl_AppendResult(interp, "eofill\n", (char *) NULL);
  972.     }
  973.     }
  974.  
  975.     /*
  976.      * Now draw the outline, if there is one.
  977.      */
  978.  
  979.     if (polyPtr->outlineColor != NULL) {
  980.     if (!polyPtr->smooth) {
  981.         Tk_CanvasPsPath(interp, canvas, polyPtr->coordPtr,
  982.         polyPtr->numPoints);
  983.     } else {
  984.         TkMakeBezierPostscript(interp, canvas, polyPtr->coordPtr,
  985.         polyPtr->numPoints);
  986.     }
  987.  
  988.     sprintf(string, "%d setlinewidth\n", polyPtr->width);
  989.     Tcl_AppendResult(interp, string,
  990.         "1 setlinecap\n1 setlinejoin\n", (char *) NULL);
  991.     if (Tk_CanvasPsColor(interp, canvas, polyPtr->outlineColor)
  992.         != TCL_OK) {
  993.         return TCL_ERROR;
  994.     }
  995.     Tcl_AppendResult(interp, "stroke\n", (char *) NULL);
  996.     }
  997.     return TCL_OK;
  998. }
  999.