home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / tcl / tk3.3b1 / tkCanvPoly.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-26  |  25.2 KB  |  870 lines

  1. /* 
  2.  * tkCanvPoly.c --
  3.  *
  4.  *    This file implements polygon items for canvas widgets.
  5.  *
  6.  * Copyright (c) 1991-1993 The Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * Permission is hereby granted, without written agreement and without
  10.  * license or royalty fees, to use, copy, modify, and distribute this
  11.  * software and its documentation for any purpose, provided that the
  12.  * above copyright notice and the following two paragraphs appear in
  13.  * all copies of this software.
  14.  * 
  15.  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  16.  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  17.  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
  18.  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  19.  *
  20.  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  21.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  22.  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  23.  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
  24.  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  25.  */
  26.  
  27. #ifndef lint
  28. static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkCanvPoly.c,v 1.14 93/06/26 16:46:07 ouster Exp $ SPRITE (Berkeley)";
  29. #endif
  30.  
  31. #include <stdio.h>
  32. #include <math.h>
  33. #include "tkInt.h"
  34. #include "tkCanvas.h"
  35. #include "tkConfig.h"
  36.  
  37. /*
  38.  * The structure below defines the record for each polygon item.
  39.  */
  40.  
  41. typedef struct PolygonItem  {
  42.     Tk_Item header;        /* Generic stuff that's the same for all
  43.                  * types.  MUST BE FIRST IN STRUCTURE. */
  44.     int numPoints;        /* Number of points in polygon (always >= 3).
  45.                  * Polygon is always closed. */
  46.     int pointsAllocated;    /* Number of points for which space is
  47.                  * allocated at *coordPtr. */
  48.     double *coordPtr;        /* Pointer to malloc-ed array containing
  49.                  * x- and y-coords of all points in polygon.
  50.                  * X-coords are even-valued indices, y-coords
  51.                  * are corresponding odd-valued indices. */
  52.     XColor *fg;            /* Foreground color for polygon. */
  53.     Pixmap fillStipple;        /* Stipple bitmap for filling polygon. */
  54.     GC gc;            /* Graphics context for filling polygon. */
  55.     int smooth;            /* Non-zero means draw shape smoothed (i.e.
  56.                  * with Bezier splines). */
  57.     int splineSteps;        /* Number of steps in each spline segment. */
  58. } PolygonItem;
  59.  
  60. /*
  61.  * Information used for parsing configuration specs:
  62.  */
  63.  
  64. static Tk_ConfigSpec configSpecs[] = {
  65.     {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL,
  66.     "black", Tk_Offset(PolygonItem, fg), TK_CONFIG_NULL_OK},
  67.     {TK_CONFIG_BOOLEAN, "-smooth", (char *) NULL, (char *) NULL,
  68.     "0", Tk_Offset(PolygonItem, smooth), TK_CONFIG_DONT_SET_DEFAULT},
  69.     {TK_CONFIG_INT, "-splinesteps", (char *) NULL, (char *) NULL,
  70.     "12", Tk_Offset(PolygonItem, splineSteps), TK_CONFIG_DONT_SET_DEFAULT},
  71.     {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL,
  72.     (char *) NULL, Tk_Offset(PolygonItem, fillStipple), TK_CONFIG_NULL_OK},
  73.     {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL,
  74.     (char *) NULL, 0, TK_CONFIG_NULL_OK, &tkCanvasTagsOption},
  75.     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  76.     (char *) NULL, 0, 0}
  77. };
  78.  
  79. /*
  80.  * Prototypes for procedures defined in this file:
  81.  */
  82.  
  83. static void        ComputePolygonBbox _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  84.                 PolygonItem *polyPtr));
  85. static int        ConfigurePolygon _ANSI_ARGS_((
  86.                 Tk_Canvas *canvasPtr, Tk_Item *itemPtr, int argc,
  87.                 char **argv, int flags));
  88. static int        CreatePolygon _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  89.                 struct Tk_Item *itemPtr, int argc, char **argv));
  90. static void        DeletePolygon _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  91.                 Tk_Item *itemPtr));
  92. static void        DisplayPolygon _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  93.                 Tk_Item *itemPtr, Drawable dst));
  94. static int        PolygonCoords _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  95.                 Tk_Item *itemPtr, int argc, char **argv));
  96. static int        PolygonToArea _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  97.                 Tk_Item *itemPtr, double *rectPtr));
  98. static double        PolygonToPoint _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  99.                 Tk_Item *itemPtr, double *pointPtr));
  100. static int        PolygonToPostscript _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  101.                 Tk_Item *itemPtr, Tk_PostscriptInfo *psInfoPtr));
  102. static void        ScalePolygon _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  103.                 Tk_Item *itemPtr, double originX, double originY,
  104.                 double scaleX, double scaleY));
  105. static void        TranslatePolygon _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  106.                 Tk_Item *itemPtr, double deltaX, double deltaY));
  107.  
  108. /*
  109.  * The structures below defines the polygon item type by means
  110.  * of procedures that can be invoked by generic item code.
  111.  */
  112.  
  113. Tk_ItemType TkPolygonType = {
  114.     "polygon",                /* name */
  115.     sizeof(PolygonItem),        /* itemSize */
  116.     CreatePolygon,            /* createProc */
  117.     configSpecs,            /* configSpecs */
  118.     ConfigurePolygon,            /* configureProc */
  119.     PolygonCoords,            /* coordProc */
  120.     DeletePolygon,            /* deleteProc */
  121.     DisplayPolygon,            /* displayProc */
  122.     0,                    /* alwaysRedraw */
  123.     PolygonToPoint,            /* pointProc */
  124.     PolygonToArea,            /* areaProc */
  125.     PolygonToPostscript,        /* postscriptProc */
  126.     ScalePolygon,            /* scaleProc */
  127.     TranslatePolygon,            /* translateProc */
  128.     (Tk_ItemIndexProc *) NULL,        /* indexProc */
  129.     (Tk_ItemCursorProc *) NULL,        /* icursorProc */
  130.     (Tk_ItemSelectionProc *) NULL,    /* selectionProc */
  131.     (Tk_ItemInsertProc *) NULL,        /* insertProc */
  132.     (Tk_ItemDCharsProc *) NULL,        /* dTextProc */
  133.     (Tk_ItemType *) NULL        /* nextPtr */
  134. };
  135.  
  136. /*
  137.  * The definition below determines how large are static arrays
  138.  * used to hold spline points (splines larger than this have to
  139.  * have their arrays malloc-ed).
  140.  */
  141.  
  142. #define MAX_STATIC_POINTS 200
  143.  
  144. /*
  145.  *--------------------------------------------------------------
  146.  *
  147.  * CreatePolygon --
  148.  *
  149.  *    This procedure is invoked to create a new polygon item in
  150.  *    a canvas.
  151.  *
  152.  * Results:
  153.  *    A standard Tcl return value.  If an error occurred in
  154.  *    creating the item, then an error message is left in
  155.  *    canvasPtr->interp->result;  in this case itemPtr is
  156.  *    left uninitialized, so it can be safely freed by the
  157.  *    caller.
  158.  *
  159.  * Side effects:
  160.  *    A new polygon item is created.
  161.  *
  162.  *--------------------------------------------------------------
  163.  */
  164.  
  165. static int
  166. CreatePolygon(canvasPtr, itemPtr, argc, argv)
  167.     register Tk_Canvas *canvasPtr;    /* Canvas to hold new item. */
  168.     Tk_Item *itemPtr;            /* Record to hold new item;  header
  169.                      * has been initialized by caller. */
  170.     int argc;                /* Number of arguments in argv. */
  171.     char **argv;            /* Arguments describing polygon. */
  172. {
  173.     register PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  174.     int i;
  175.  
  176.     if (argc < 6) {
  177.     Tcl_AppendResult(canvasPtr->interp, "wrong # args:  should be \"",
  178.         Tk_PathName(canvasPtr->tkwin),
  179.         "\" create x1 y1 x2 y2 x3 y3 ?x4 y4 ...? ?options?",
  180.         (char *) NULL);
  181.     return TCL_ERROR;
  182.     }
  183.  
  184.     /*
  185.      * Carry out initialization that is needed in order to clean
  186.      * up after errors during the the remainder of this procedure.
  187.      */
  188.  
  189.     polyPtr->numPoints = 0;
  190.     polyPtr->pointsAllocated = 0;
  191.     polyPtr->coordPtr = NULL;
  192.     polyPtr->fg = None;
  193.     polyPtr->fillStipple = None;
  194.     polyPtr->gc = None;
  195.     polyPtr->smooth = 0;
  196.     polyPtr->splineSteps = 12;
  197.  
  198.     /*
  199.      * Count the number of points and then parse them into a point
  200.      * array.  Leading arguments are assumed to be points if they
  201.      * start with a digit or a minus sign followed by a digit.
  202.      */
  203.  
  204.     for (i = 4; i < (argc-1); i+=2) {
  205.     if ((!isdigit(argv[i][0])) &&
  206.         ((argv[i][0] != '-') || (!isdigit(argv[i][1])))) {
  207.         break;
  208.     }
  209.     }
  210.     if (PolygonCoords(canvasPtr, itemPtr, i, argv) != TCL_OK) {
  211.     goto error;
  212.     }
  213.  
  214.     if (ConfigurePolygon(canvasPtr, itemPtr, argc-i, argv+i, 0) == TCL_OK) {
  215.     return TCL_OK;
  216.     }
  217.  
  218.     error:
  219.     DeletePolygon(canvasPtr, itemPtr);
  220.     return TCL_ERROR;
  221. }
  222.  
  223. /*
  224.  *--------------------------------------------------------------
  225.  *
  226.  * PolygonCoords --
  227.  *
  228.  *    This procedure is invoked to process the "coords" widget
  229.  *    command on polygons.  See the user documentation for details
  230.  *    on what it does.
  231.  *
  232.  * Results:
  233.  *    Returns TCL_OK or TCL_ERROR, and sets canvasPtr->interp->result.
  234.  *
  235.  * Side effects:
  236.  *    The coordinates for the given item may be changed.
  237.  *
  238.  *--------------------------------------------------------------
  239.  */
  240.  
  241. static int
  242. PolygonCoords(canvasPtr, itemPtr, argc, argv)
  243.     register Tk_Canvas *canvasPtr;    /* Canvas containing item. */
  244.     Tk_Item *itemPtr;            /* Item whose coordinates are to be
  245.                      * read or modified. */
  246.     int argc;                /* Number of coordinates supplied in
  247.                      * argv. */
  248.     char **argv;            /* Array of coordinates: x1, y1,
  249.                      * x2, y2, ... */
  250. {
  251.     register PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  252.     char buffer[TCL_DOUBLE_SPACE];
  253.     int i, numPoints;
  254.  
  255.     if (argc == 0) {
  256.     for (i = 0; i < 2*polyPtr->numPoints; i++) {
  257.         Tcl_PrintDouble(canvasPtr->interp, polyPtr->coordPtr[i], buffer);
  258.         Tcl_AppendElement(canvasPtr->interp, buffer);
  259.     }
  260.     } else if (argc < 6) {
  261.     Tcl_AppendResult(canvasPtr->interp,
  262.         "too few coordinates for polygon:  must have at least 6",
  263.         (char *) NULL);
  264.     return TCL_ERROR;
  265.     } else if (argc & 1) {
  266.     Tcl_AppendResult(canvasPtr->interp,
  267.         "odd number of coordinates specified for polygon",
  268.         (char *) NULL);
  269.     return TCL_ERROR;
  270.     } else {
  271.     numPoints = argc/2;
  272.     if (polyPtr->pointsAllocated <= numPoints) {
  273.         if (polyPtr->coordPtr != NULL) {
  274.         ckfree((char *) polyPtr->coordPtr);
  275.         }
  276.  
  277.         /*
  278.          * One extra point gets allocated here, just in case we have
  279.          * to add another point to close the polygon.
  280.          */
  281.  
  282.         polyPtr->coordPtr = (double *) ckalloc((unsigned)
  283.             (sizeof(double) * (argc+2)));
  284.         polyPtr->pointsAllocated = polyPtr->numPoints = numPoints;
  285.     }
  286.     for (i = argc-1; i >= 0; i--) {
  287.         if (TkGetCanvasCoord(canvasPtr, argv[i], &polyPtr->coordPtr[i])
  288.             != TCL_OK) {
  289.         return TCL_ERROR;
  290.         }
  291.     }
  292.     
  293.     /*
  294.      * Close the polygon if it isn't already closed.
  295.      */
  296.     
  297.     if ((polyPtr->coordPtr[argc-2] != polyPtr->coordPtr[0])
  298.         || (polyPtr->coordPtr[argc-1] != polyPtr->coordPtr[1])) {
  299.         polyPtr->numPoints++;
  300.         polyPtr->coordPtr[argc] = polyPtr->coordPtr[0];
  301.         polyPtr->coordPtr[argc+1] = polyPtr->coordPtr[1];
  302.     }
  303.     ComputePolygonBbox(canvasPtr, polyPtr);
  304.     }
  305.     return TCL_OK;
  306. }
  307.  
  308. /*
  309.  *--------------------------------------------------------------
  310.  *
  311.  * ConfigurePolygon --
  312.  *
  313.  *    This procedure is invoked to configure various aspects
  314.  *    of a polygon item such as its background color.
  315.  *
  316.  * Results:
  317.  *    A standard Tcl result code.  If an error occurs, then
  318.  *    an error message is left in canvasPtr->interp->result.
  319.  *
  320.  * Side effects:
  321.  *    Configuration information, such as colors and stipple
  322.  *    patterns, may be set for itemPtr.
  323.  *
  324.  *--------------------------------------------------------------
  325.  */
  326.  
  327. static int
  328. ConfigurePolygon(canvasPtr, itemPtr, argc, argv, flags)
  329.     Tk_Canvas *canvasPtr;    /* Canvas containing itemPtr. */
  330.     Tk_Item *itemPtr;        /* Polygon item to reconfigure. */
  331.     int argc;            /* Number of elements in argv.  */
  332.     char **argv;        /* Arguments describing things to configure. */
  333.     int flags;            /* Flags to pass to Tk_ConfigureWidget. */
  334. {
  335.     register PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  336.     XGCValues gcValues;
  337.     GC newGC;
  338.     unsigned long mask;
  339.  
  340.     if (Tk_ConfigureWidget(canvasPtr->interp, canvasPtr->tkwin,
  341.         configSpecs, argc, argv, (char *) polyPtr, flags) != TCL_OK) {
  342.     return TCL_ERROR;
  343.     }
  344.  
  345.     /*
  346.      * A few of the options require additional processing, such as
  347.      * graphics contexts.
  348.      */
  349.  
  350.     if (polyPtr->fg == NULL) {
  351.     newGC = None;
  352.     } else {
  353.     gcValues.foreground = polyPtr->fg->pixel;
  354.     mask = GCForeground;
  355.     if (polyPtr->fillStipple != None) {
  356.         gcValues.stipple = polyPtr->fillStipple;
  357.         gcValues.fill_style = FillStippled;
  358.         mask |= GCStipple|GCFillStyle;
  359.     }
  360.     newGC = Tk_GetGC(canvasPtr->tkwin, mask, &gcValues);
  361.     }
  362.     if (polyPtr->gc != None) {
  363.     Tk_FreeGC(canvasPtr->display, polyPtr->gc);
  364.     }
  365.     polyPtr->gc = newGC;
  366.  
  367.     /*
  368.      * Keep spline parameters within reasonable limits.
  369.      */
  370.  
  371.     if (polyPtr->splineSteps < 1) {
  372.     polyPtr->splineSteps = 1;
  373.     } else if (polyPtr->splineSteps > 100) {
  374.     polyPtr->splineSteps = 100;
  375.     }
  376.  
  377.     ComputePolygonBbox(canvasPtr, polyPtr);
  378.     return TCL_OK;
  379. }
  380.  
  381. /*
  382.  *--------------------------------------------------------------
  383.  *
  384.  * DeletePolygon --
  385.  *
  386.  *    This procedure is called to clean up the data structure
  387.  *    associated with a polygon item.
  388.  *
  389.  * Results:
  390.  *    None.
  391.  *
  392.  * Side effects:
  393.  *    Resources associated with itemPtr are released.
  394.  *
  395.  *--------------------------------------------------------------
  396.  */
  397.  
  398. static void
  399. DeletePolygon(canvasPtr, itemPtr)
  400.     Tk_Canvas *canvasPtr;        /* Info about overall canvas widget. */
  401.     Tk_Item *itemPtr;            /* Item that is being deleted. */
  402. {
  403.     register PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  404.  
  405.     if (polyPtr->coordPtr != NULL) {
  406.     ckfree((char *) polyPtr->coordPtr);
  407.     }
  408.     if (polyPtr->fg != NULL) {
  409.     Tk_FreeColor(polyPtr->fg);
  410.     }
  411.     if (polyPtr->fillStipple != None) {
  412.     Tk_FreeBitmap(canvasPtr->display, polyPtr->fillStipple);
  413.     }
  414.     if (polyPtr->gc != None) {
  415.     Tk_FreeGC(canvasPtr->display, polyPtr->gc);
  416.     }
  417. }
  418.  
  419. /*
  420.  *--------------------------------------------------------------
  421.  *
  422.  * ComputePolygonBbox --
  423.  *
  424.  *    This procedure is invoked to compute the bounding box of
  425.  *    all the pixels that may be drawn as part of a polygon.
  426.  *
  427.  * Results:
  428.  *    None.
  429.  *
  430.  * Side effects:
  431.  *    The fields x1, y1, x2, and y2 are updated in the header
  432.  *    for itemPtr.
  433.  *
  434.  *--------------------------------------------------------------
  435.  */
  436.  
  437. static void
  438. ComputePolygonBbox(canvasPtr, polyPtr)
  439.     register Tk_Canvas *canvasPtr;    /* Canvas that contains item. */
  440.     PolygonItem *polyPtr;        /* Item whose bbox is to be
  441.                      * recomputed. */
  442. {
  443.     register double *coordPtr;
  444.     int i;
  445.  
  446.     coordPtr = polyPtr->coordPtr;
  447.     polyPtr->header.x1 = polyPtr->header.x2 = *coordPtr;
  448.     polyPtr->header.y1 = polyPtr->header.y2 = coordPtr[1];
  449.  
  450.     for (i = 1, coordPtr = polyPtr->coordPtr+2; i < polyPtr->numPoints;
  451.         i++, coordPtr += 2) {
  452.     TkIncludePoint(canvasPtr, (Tk_Item *) polyPtr, coordPtr);
  453.     }
  454.  
  455.     /*
  456.      * Add one more pixel of fudge factor just to be safe (e.g.
  457.      * X may round differently than we do).
  458.      */
  459.  
  460.     polyPtr->header.x1 -= 1;
  461.     polyPtr->header.x2 += 1;
  462.     polyPtr->header.y1 -= 1;
  463.     polyPtr->header.y2 += 1;
  464. }
  465.  
  466. /*
  467.  *--------------------------------------------------------------
  468.  *
  469.  * TkFillPolygon --
  470.  *
  471.  *    This procedure is invoked to convert a polygon to screen
  472.  *    coordinates and display it using a particular GC.
  473.  *
  474.  * Results:
  475.  *    None.
  476.  *
  477.  * Side effects:
  478.  *    ItemPtr is drawn in drawable using the transformation
  479.  *    information in canvasPtr.
  480.  *
  481.  *--------------------------------------------------------------
  482.  */
  483.  
  484. void
  485. TkFillPolygon(canvasPtr, coordPtr, numPoints, drawable, gc)
  486.     register Tk_Canvas *canvasPtr;    /* Canvas whose coordinate system
  487.                      * is to be used for drawing. */
  488.     double *coordPtr;            /* Array of coordinates for polygon:
  489.                      * x1, y1, x2, y2, .... */
  490.     int numPoints;            /* Twice this many coordinates are
  491.                      * present at *coordPtr. */
  492.     Drawable drawable;            /* Pixmap or window in which to draw
  493.                      * polygon. */
  494.     GC gc;                /* Graphics context for drawing. */
  495. {
  496.     XPoint staticPoints[MAX_STATIC_POINTS];
  497.     XPoint *pointPtr;
  498.     register XPoint *pPtr;
  499.     int i;
  500.  
  501.     /*
  502.      * Build up an array of points in screen coordinates.  Use a
  503.      * static array unless the polygon has an enormous number of points;
  504.      * in this case, dynamically allocate an array.
  505.      */
  506.  
  507.     if (numPoints <= MAX_STATIC_POINTS) {
  508.     pointPtr = staticPoints;
  509.     } else {
  510.     pointPtr = (XPoint *) ckalloc((unsigned) (numPoints * sizeof(XPoint)));
  511.     }
  512.  
  513.     for (i = 0, pPtr = pointPtr; i < numPoints; i += 1, coordPtr += 2, pPtr++) {
  514.     pPtr->x = SCREEN_X(canvasPtr, coordPtr[0]);
  515.     pPtr->y = SCREEN_Y(canvasPtr, coordPtr[1]);
  516.     }
  517.  
  518.     /*
  519.      * Display polygon, then free up polygon storage if it was dynamically
  520.      * allocated.
  521.      */
  522.  
  523.     XFillPolygon(Tk_Display(canvasPtr->tkwin), drawable, gc, pointPtr,
  524.         numPoints, Complex, CoordModeOrigin);
  525.     if (pointPtr != staticPoints) {
  526.     ckfree((char *) pointPtr);
  527.     }
  528.  
  529. }
  530.  
  531. /*
  532.  *--------------------------------------------------------------
  533.  *
  534.  * DisplayPolygon --
  535.  *
  536.  *    This procedure is invoked to draw a polygon item in a given
  537.  *    drawable.
  538.  *
  539.  * Results:
  540.  *    None.
  541.  *
  542.  * Side effects:
  543.  *    ItemPtr is drawn in drawable using the transformation
  544.  *    information in canvasPtr.
  545.  *
  546.  *--------------------------------------------------------------
  547.  */
  548.  
  549. static void
  550. DisplayPolygon(canvasPtr, itemPtr, drawable)
  551.     register Tk_Canvas *canvasPtr;    /* Canvas that contains item. */
  552.     Tk_Item *itemPtr;            /* Item to be displayed. */
  553.     Drawable drawable;            /* Pixmap or window in which to draw
  554.                      * item. */
  555. {
  556.     register PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  557.  
  558.     if (polyPtr->gc == None) {
  559.     return;
  560.     }
  561.  
  562.     /*
  563.      * If we're stippling then modify the stipple offset in the GC.  Be
  564.      * sure to reset the offset when done, since the GC is supposed to be
  565.      * read-only.
  566.      */
  567.  
  568.     if (polyPtr->fillStipple != None) {
  569.     XSetTSOrigin(Tk_Display(canvasPtr->tkwin), polyPtr->gc,
  570.         -canvasPtr->drawableXOrigin, -canvasPtr->drawableYOrigin);
  571.     }
  572.  
  573.     if (!polyPtr->smooth) {
  574.     TkFillPolygon(canvasPtr, polyPtr->coordPtr, polyPtr->numPoints,
  575.         drawable, polyPtr->gc);
  576.     } else {
  577.     int numPoints;
  578.     XPoint staticPoints[MAX_STATIC_POINTS];
  579.     XPoint *pointPtr;
  580.  
  581.     /*
  582.      * This is a smoothed polygon.  Display using a set of generated
  583.      * spline points rather than the original points.
  584.      */
  585.  
  586.     numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps;
  587.     if (numPoints <= MAX_STATIC_POINTS) {
  588.         pointPtr = staticPoints;
  589.     } else {
  590.         pointPtr = (XPoint *) ckalloc((unsigned)
  591.             (numPoints * sizeof(XPoint)));
  592.     }
  593.     numPoints = TkMakeBezierCurve(canvasPtr, polyPtr->coordPtr,
  594.         polyPtr->numPoints, polyPtr->splineSteps, pointPtr,
  595.         (double *) NULL);
  596.     XFillPolygon(Tk_Display(canvasPtr->tkwin), drawable, polyPtr->gc,
  597.         pointPtr, numPoints, Complex, CoordModeOrigin);
  598.     if (pointPtr != staticPoints) {
  599.         ckfree((char *) pointPtr);
  600.     }
  601.     }
  602.     if (polyPtr->fillStipple != None) {
  603.     XSetTSOrigin(Tk_Display(canvasPtr->tkwin), polyPtr->gc, 0, 0);
  604.     }
  605. }
  606.  
  607. /*
  608.  *--------------------------------------------------------------
  609.  *
  610.  * PolygonToPoint --
  611.  *
  612.  *    Computes the distance from a given point to a given
  613.  *    polygon, in canvas units.
  614.  *
  615.  * Results:
  616.  *    The return value is 0 if the point whose x and y coordinates
  617.  *    are pointPtr[0] and pointPtr[1] is inside the polygon.  If the
  618.  *    point isn't inside the polygon then the return value is the
  619.  *    distance from the point to the polygon.
  620.  *
  621.  * Side effects:
  622.  *    None.
  623.  *
  624.  *--------------------------------------------------------------
  625.  */
  626.  
  627.     /* ARGSUSED */
  628. static double
  629. PolygonToPoint(canvasPtr, itemPtr, pointPtr)
  630.     Tk_Canvas *canvasPtr;    /* Canvas containing item. */
  631.     Tk_Item *itemPtr;        /* Item to check against point. */
  632.     double *pointPtr;        /* Pointer to x and y coordinates. */
  633. {
  634.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  635.     double *coordPtr, distance;
  636.     double staticSpace[2*MAX_STATIC_POINTS];
  637.     int numPoints;
  638.  
  639.     if (!polyPtr->smooth) {
  640.     return TkPolygonToPoint(polyPtr->coordPtr, polyPtr->numPoints,
  641.         pointPtr);
  642.     }
  643.  
  644.     /*
  645.      * Smoothed polygon.  Generate a new set of points and use them
  646.      * for comparison.
  647.      */
  648.  
  649.     numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps;
  650.     if (numPoints <= MAX_STATIC_POINTS) {
  651.     coordPtr = staticSpace;
  652.     } else {
  653.     coordPtr = (double *) ckalloc((unsigned)
  654.         (2*numPoints*sizeof(double)));
  655.     }
  656.     numPoints = TkMakeBezierCurve(canvasPtr, polyPtr->coordPtr,
  657.         polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL,
  658.         coordPtr);
  659.     distance = TkPolygonToPoint(coordPtr, numPoints, pointPtr);
  660.     if (coordPtr != staticSpace) {
  661.     ckfree((char *) coordPtr);
  662.     }
  663.     return distance;
  664. }
  665.  
  666. /*
  667.  *--------------------------------------------------------------
  668.  *
  669.  * PolygonToArea --
  670.  *
  671.  *    This procedure is called to determine whether an item
  672.  *    lies entirely inside, entirely outside, or overlapping
  673.  *    a given rectangular area.
  674.  *
  675.  * Results:
  676.  *    -1 is returned if the item is entirely outside the area
  677.  *    given by rectPtr, 0 if it overlaps, and 1 if it is entirely
  678.  *    inside the given area.
  679.  *
  680.  * Side effects:
  681.  *    None.
  682.  *
  683.  *--------------------------------------------------------------
  684.  */
  685.  
  686.     /* ARGSUSED */
  687. static int
  688. PolygonToArea(canvasPtr, itemPtr, rectPtr)
  689.     Tk_Canvas *canvasPtr;    /* Canvas containing item. */
  690.     Tk_Item *itemPtr;        /* Item to check against polygon. */
  691.     double *rectPtr;        /* Pointer to array of four coordinates
  692.                  * (x1, y1, x2, y2) describing rectangular
  693.                  * area.  */
  694. {
  695.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  696.     double *coordPtr;
  697.     double staticSpace[2*MAX_STATIC_POINTS];
  698.     int numPoints, result;
  699.  
  700.     if (!polyPtr->smooth) {
  701.     return TkPolygonToArea(polyPtr->coordPtr, polyPtr->numPoints, rectPtr);
  702.     }
  703.  
  704.     /*
  705.      * Smoothed polygon.  Generate a new set of points and use them
  706.      * for comparison.
  707.      */
  708.  
  709.     numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps;
  710.     if (numPoints <= MAX_STATIC_POINTS) {
  711.     coordPtr = staticSpace;
  712.     } else {
  713.     coordPtr = (double *) ckalloc((unsigned)
  714.         (2*numPoints*sizeof(double)));
  715.     }
  716.     numPoints = TkMakeBezierCurve(canvasPtr, polyPtr->coordPtr,
  717.         polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL,
  718.         coordPtr);
  719.     result = TkPolygonToArea(coordPtr, numPoints, rectPtr);
  720.     if (coordPtr != staticSpace) {
  721.     ckfree((char *) coordPtr);
  722.     }
  723.     return result;
  724. }
  725.  
  726. /*
  727.  *--------------------------------------------------------------
  728.  *
  729.  * ScalePolygon --
  730.  *
  731.  *    This procedure is invoked to rescale a polygon item.
  732.  *
  733.  * Results:
  734.  *    None.
  735.  *
  736.  * Side effects:
  737.  *    The polygon referred to by itemPtr is rescaled so that the
  738.  *    following transformation is applied to all point
  739.  *    coordinates:
  740.  *        x' = originX + scaleX*(x-originX)
  741.  *        y' = originY + scaleY*(y-originY)
  742.  *
  743.  *--------------------------------------------------------------
  744.  */
  745.  
  746. static void
  747. ScalePolygon(canvasPtr, itemPtr, originX, originY, scaleX, scaleY)
  748.     Tk_Canvas *canvasPtr;        /* Canvas containing polygon. */
  749.     Tk_Item *itemPtr;            /* Polygon to be scaled. */
  750.     double originX, originY;        /* Origin about which to scale rect. */
  751.     double scaleX;            /* Amount to scale in X direction. */
  752.     double scaleY;            /* Amount to scale in Y direction. */
  753. {
  754.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  755.     register double *coordPtr;
  756.     int i;
  757.  
  758.     for (i = 0, coordPtr = polyPtr->coordPtr; i < polyPtr->numPoints;
  759.         i++, coordPtr += 2) {
  760.     *coordPtr = originX + scaleX*(*coordPtr - originX);
  761.     coordPtr[1] = originY + scaleY*(coordPtr[1] - originY);
  762.     }
  763.     ComputePolygonBbox(canvasPtr, polyPtr);
  764. }
  765.  
  766. /*
  767.  *--------------------------------------------------------------
  768.  *
  769.  * TranslatePolygon --
  770.  *
  771.  *    This procedure is called to move a polygon by a given
  772.  *    amount.
  773.  *
  774.  * Results:
  775.  *    None.
  776.  *
  777.  * Side effects:
  778.  *    The position of the polygon is offset by (xDelta, yDelta),
  779.  *    and the bounding box is updated in the generic part of the
  780.  *    item structure.
  781.  *
  782.  *--------------------------------------------------------------
  783.  */
  784.  
  785. static void
  786. TranslatePolygon(canvasPtr, itemPtr, deltaX, deltaY)
  787.     Tk_Canvas *canvasPtr;        /* Canvas containing item. */
  788.     Tk_Item *itemPtr;            /* Item that is being moved. */
  789.     double deltaX, deltaY;        /* Amount by which item is to be
  790.                      * moved. */
  791. {
  792.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  793.     register double *coordPtr;
  794.     int i;
  795.  
  796.     for (i = 0, coordPtr = polyPtr->coordPtr; i < polyPtr->numPoints;
  797.         i++, coordPtr += 2) {
  798.     *coordPtr += deltaX;
  799.     coordPtr[1] += deltaY;
  800.     }
  801.     ComputePolygonBbox(canvasPtr, polyPtr);
  802. }
  803.  
  804. /*
  805.  *--------------------------------------------------------------
  806.  *
  807.  * PolygonToPostscript --
  808.  *
  809.  *    This procedure is called to generate Postscript for
  810.  *    polygon items.
  811.  *
  812.  * Results:
  813.  *    The return value is a standard Tcl result.  If an error
  814.  *    occurs in generating Postscript then an error message is
  815.  *    left in canvasPtr->interp->result, replacing whatever used
  816.  *    to be there.  If no error occurs, then Postscript for the
  817.  *    item is appended to the result.
  818.  *
  819.  * Side effects:
  820.  *    None.
  821.  *
  822.  *--------------------------------------------------------------
  823.  */
  824.  
  825. static int
  826. PolygonToPostscript(canvasPtr, itemPtr, psInfoPtr)
  827.     Tk_Canvas *canvasPtr;        /* Information about overall canvas. */
  828.     Tk_Item *itemPtr;            /* Item for which Postscript is
  829.                      * wanted. */
  830.     Tk_PostscriptInfo *psInfoPtr;    /* Information about the Postscript;
  831.                      * must be passed back to Postscript
  832.                      * utility procedures. */
  833. {
  834.     register PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  835.  
  836.     if (polyPtr->fg == NULL) {
  837.     return TCL_OK;
  838.     }
  839.  
  840.     /*
  841.      * Generate a path for the polygon's outline (do this differently
  842.      * for smoothed and linear polygons).
  843.      */
  844.  
  845.     if (!polyPtr->smooth) {
  846.     TkCanvPsPath(canvasPtr->interp, polyPtr->coordPtr,
  847.         polyPtr->numPoints, psInfoPtr);
  848.     } else {
  849.     TkMakeBezierPostscript(canvasPtr->interp, polyPtr->coordPtr,
  850.         polyPtr->numPoints, psInfoPtr);
  851.     }
  852.  
  853.     /*
  854.      * Fill the area of the polygon.
  855.      */
  856.  
  857.     if (TkCanvPsColor(canvasPtr, psInfoPtr, polyPtr->fg) != TCL_OK) {
  858.     return TCL_ERROR;
  859.     };
  860.     if (polyPtr->fillStipple != None) {
  861.     if (TkCanvPsStipple(canvasPtr, psInfoPtr, polyPtr->fillStipple, 1)
  862.         != TCL_OK) {
  863.         return TCL_ERROR;
  864.     }
  865.     } else {
  866.     Tcl_AppendResult(canvasPtr->interp, "eofill\n", (char *) NULL);
  867.     }
  868.     return TCL_OK;
  869. }
  870.