home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tkisrc04.zip / tk / os2 / tkCanvPoly.c < prev    next >
C/C++ Source or Header  |  1998-08-07  |  29KB  |  990 lines

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