OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tk/] [generic/] [tkCanvPoly.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
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
 * RCS: @(#) $Id: tkCanvPoly.c,v 1.1.1.1 2002-01-16 10:25:51 markom Exp $
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_GetGCColor(tkwin, mask, &gcValues, polyPtr->outlineColor,
377
                              NULL);
378
    }
379
    if (polyPtr->outlineGC != None) {
380
        Tk_FreeGC(Tk_Display(tkwin), polyPtr->outlineGC);
381
    }
382
    polyPtr->outlineGC = newGC;
383
 
384
    if (polyPtr->fillColor == NULL) {
385
        newGC = None;
386
    } else {
387
        gcValues.foreground = polyPtr->fillColor->pixel;
388
        mask = GCForeground;
389
        if (polyPtr->fillStipple != None) {
390
            gcValues.stipple = polyPtr->fillStipple;
391
            gcValues.fill_style = FillStippled;
392
            mask |= GCStipple|GCFillStyle;
393
        }
394
        newGC = Tk_GetGCColor(tkwin, mask, &gcValues, polyPtr->fillColor,
395
                              NULL);
396
    }
397
    if (polyPtr->fillGC != None) {
398
        Tk_FreeGC(Tk_Display(tkwin), polyPtr->fillGC);
399
    }
400
    polyPtr->fillGC = newGC;
401
 
402
    /*
403
     * Keep spline parameters within reasonable limits.
404
     */
405
 
406
    if (polyPtr->splineSteps < 1) {
407
        polyPtr->splineSteps = 1;
408
    } else if (polyPtr->splineSteps > 100) {
409
        polyPtr->splineSteps = 100;
410
    }
411
 
412
    ComputePolygonBbox(canvas, polyPtr);
413
    return TCL_OK;
414
}
415
 
416
/*
417
 *--------------------------------------------------------------
418
 *
419
 * DeletePolygon --
420
 *
421
 *      This procedure is called to clean up the data structure
422
 *      associated with a polygon item.
423
 *
424
 * Results:
425
 *      None.
426
 *
427
 * Side effects:
428
 *      Resources associated with itemPtr are released.
429
 *
430
 *--------------------------------------------------------------
431
 */
432
 
433
static void
434
DeletePolygon(canvas, itemPtr, display)
435
    Tk_Canvas canvas;                   /* Info about overall canvas widget. */
436
    Tk_Item *itemPtr;                   /* Item that is being deleted. */
437
    Display *display;                   /* Display containing window for
438
                                         * canvas. */
439
{
440
    PolygonItem *polyPtr = (PolygonItem *) itemPtr;
441
 
442
    if (polyPtr->coordPtr != NULL) {
443
        ckfree((char *) polyPtr->coordPtr);
444
    }
445
    if (polyPtr->fillColor != NULL) {
446
        Tk_FreeColor(polyPtr->fillColor);
447
    }
448
    if (polyPtr->fillStipple != None) {
449
        Tk_FreeBitmap(display, polyPtr->fillStipple);
450
    }
451
    if (polyPtr->outlineColor != NULL) {
452
        Tk_FreeColor(polyPtr->outlineColor);
453
    }
454
    if (polyPtr->outlineGC != None) {
455
        Tk_FreeGC(display, polyPtr->outlineGC);
456
    }
457
    if (polyPtr->fillGC != None) {
458
        Tk_FreeGC(display, polyPtr->fillGC);
459
    }
460
}
461
 
462
/*
463
 *--------------------------------------------------------------
464
 *
465
 * ComputePolygonBbox --
466
 *
467
 *      This procedure is invoked to compute the bounding box of
468
 *      all the pixels that may be drawn as part of a polygon.
469
 *
470
 * Results:
471
 *      None.
472
 *
473
 * Side effects:
474
 *      The fields x1, y1, x2, and y2 are updated in the header
475
 *      for itemPtr.
476
 *
477
 *--------------------------------------------------------------
478
 */
479
 
480
static void
481
ComputePolygonBbox(canvas, polyPtr)
482
    Tk_Canvas canvas;                   /* Canvas that contains item. */
483
    PolygonItem *polyPtr;               /* Item whose bbox is to be
484
                                         * recomputed. */
485
{
486
    double *coordPtr;
487
    int i;
488
 
489
    coordPtr = polyPtr->coordPtr;
490
    polyPtr->header.x1 = polyPtr->header.x2 = (int) *coordPtr;
491
    polyPtr->header.y1 = polyPtr->header.y2 = (int) coordPtr[1];
492
 
493
    for (i = 1, coordPtr = polyPtr->coordPtr+2; i < polyPtr->numPoints;
494
            i++, coordPtr += 2) {
495
        TkIncludePoint((Tk_Item *) polyPtr, coordPtr);
496
    }
497
 
498
    /*
499
     * Expand bounding box in all directions to account for the outline,
500
     * which can stick out beyond the polygon.  Add one extra pixel of
501
     * fudge, just in case X rounds differently than we do.
502
     */
503
 
504
    i = (polyPtr->width+1)/2 + 1;
505
    polyPtr->header.x1 -= i;
506
    polyPtr->header.x2 += i;
507
    polyPtr->header.y1 -= i;
508
    polyPtr->header.y2 += i;
509
}
510
 
511
/*
512
 *--------------------------------------------------------------
513
 *
514
 * TkFillPolygon --
515
 *
516
 *      This procedure is invoked to convert a polygon to screen
517
 *      coordinates and display it using a particular GC.
518
 *
519
 * Results:
520
 *      None.
521
 *
522
 * Side effects:
523
 *      ItemPtr is drawn in drawable using the transformation
524
 *      information in canvas.
525
 *
526
 *--------------------------------------------------------------
527
 */
528
 
529
void
530
TkFillPolygon(canvas, coordPtr, numPoints, display, drawable, gc, outlineGC)
531
    Tk_Canvas canvas;                   /* Canvas whose coordinate system
532
                                         * is to be used for drawing. */
533
    double *coordPtr;                   /* Array of coordinates for polygon:
534
                                         * x1, y1, x2, y2, .... */
535
    int numPoints;                      /* Twice this many coordinates are
536
                                         * present at *coordPtr. */
537
    Display *display;                   /* Display on which to draw polygon. */
538
    Drawable drawable;                  /* Pixmap or window in which to draw
539
                                         * polygon. */
540
    GC gc;                              /* Graphics context for drawing. */
541
    GC outlineGC;                       /* If not None, use this to draw an
542
                                         * outline around the polygon after
543
                                         * filling it. */
544
{
545
    XPoint staticPoints[MAX_STATIC_POINTS];
546
    XPoint *pointPtr;
547
    XPoint *pPtr;
548
    int i;
549
 
550
    /*
551
     * Build up an array of points in screen coordinates.  Use a
552
     * static array unless the polygon has an enormous number of points;
553
     * in this case, dynamically allocate an array.
554
     */
555
 
556
    if (numPoints <= MAX_STATIC_POINTS) {
557
        pointPtr = staticPoints;
558
    } else {
559
        pointPtr = (XPoint *) ckalloc((unsigned) (numPoints * sizeof(XPoint)));
560
    }
561
 
562
    for (i = 0, pPtr = pointPtr; i < numPoints; i += 1, coordPtr += 2, pPtr++) {
563
        Tk_CanvasDrawableCoords(canvas, coordPtr[0], coordPtr[1], &pPtr->x,
564
                &pPtr->y);
565
    }
566
 
567
    /*
568
     * Display polygon, then free up polygon storage if it was dynamically
569
     * allocated.
570
     */
571
 
572
    if (gc != None) {
573
        XFillPolygon(display, drawable, gc, pointPtr, numPoints, Complex,
574
                CoordModeOrigin);
575
    }
576
    if (outlineGC != None) {
577
        XDrawLines(display, drawable, outlineGC, pointPtr,
578
            numPoints, CoordModeOrigin);
579
    }
580
    if (pointPtr != staticPoints) {
581
        ckfree((char *) pointPtr);
582
    }
583
}
584
 
585
/*
586
 *--------------------------------------------------------------
587
 *
588
 * DisplayPolygon --
589
 *
590
 *      This procedure is invoked to draw a polygon item in a given
591
 *      drawable.
592
 *
593
 * Results:
594
 *      None.
595
 *
596
 * Side effects:
597
 *      ItemPtr is drawn in drawable using the transformation
598
 *      information in canvas.
599
 *
600
 *--------------------------------------------------------------
601
 */
602
 
603
static void
604
DisplayPolygon(canvas, itemPtr, display, drawable, x, y, width, height)
605
    Tk_Canvas canvas;                   /* Canvas that contains item. */
606
    Tk_Item *itemPtr;                   /* Item to be displayed. */
607
    Display *display;                   /* Display on which to draw item. */
608
    Drawable drawable;                  /* Pixmap or window in which to draw
609
                                         * item. */
610
    int x, y, width, height;            /* Describes region of canvas that
611
                                         * must be redisplayed (not used). */
612
{
613
    PolygonItem *polyPtr = (PolygonItem *) itemPtr;
614
 
615
    if ((polyPtr->fillGC == None) && (polyPtr->outlineGC == None)) {
616
        return;
617
    }
618
 
619
    /*
620
     * If we're stippling then modify the stipple offset in the GC.  Be
621
     * sure to reset the offset when done, since the GC is supposed to be
622
     * read-only.
623
     */
624
 
625
    if ((polyPtr->fillStipple != None) && (polyPtr->fillGC != None)) {
626
        Tk_CanvasSetStippleOrigin(canvas, polyPtr->fillGC);
627
    }
628
 
629
    if (!polyPtr->smooth) {
630
        TkFillPolygon(canvas, polyPtr->coordPtr, polyPtr->numPoints,
631
                display, drawable, polyPtr->fillGC, polyPtr->outlineGC);
632
    } else {
633
        int numPoints;
634
        XPoint staticPoints[MAX_STATIC_POINTS];
635
        XPoint *pointPtr;
636
 
637
        /*
638
         * This is a smoothed polygon.  Display using a set of generated
639
         * spline points rather than the original points.
640
         */
641
 
642
        numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps;
643
        if (numPoints <= MAX_STATIC_POINTS) {
644
            pointPtr = staticPoints;
645
        } else {
646
            pointPtr = (XPoint *) ckalloc((unsigned)
647
                    (numPoints * sizeof(XPoint)));
648
        }
649
        numPoints = TkMakeBezierCurve(canvas, polyPtr->coordPtr,
650
                polyPtr->numPoints, polyPtr->splineSteps, pointPtr,
651
                (double *) NULL);
652
        if (polyPtr->fillGC != None) {
653
            XFillPolygon(display, drawable, polyPtr->fillGC, pointPtr,
654
                    numPoints, Complex, CoordModeOrigin);
655
        }
656
        if (polyPtr->outlineGC != None) {
657
            XDrawLines(display, drawable, polyPtr->outlineGC, pointPtr,
658
                    numPoints, CoordModeOrigin);
659
        }
660
        if (pointPtr != staticPoints) {
661
            ckfree((char *) pointPtr);
662
        }
663
    }
664
    if ((polyPtr->fillStipple != None) && (polyPtr->fillGC != None)) {
665
        XSetTSOrigin(display, polyPtr->fillGC, 0, 0);
666
    }
667
}
668
 
669
/*
670
 *--------------------------------------------------------------
671
 *
672
 * PolygonToPoint --
673
 *
674
 *      Computes the distance from a given point to a given
675
 *      polygon, in canvas units.
676
 *
677
 * Results:
678
 *      The return value is 0 if the point whose x and y coordinates
679
 *      are pointPtr[0] and pointPtr[1] is inside the polygon.  If the
680
 *      point isn't inside the polygon then the return value is the
681
 *      distance from the point to the polygon.
682
 *
683
 * Side effects:
684
 *      None.
685
 *
686
 *--------------------------------------------------------------
687
 */
688
 
689
        /* ARGSUSED */
690
static double
691
PolygonToPoint(canvas, itemPtr, pointPtr)
692
    Tk_Canvas canvas;           /* Canvas containing item. */
693
    Tk_Item *itemPtr;           /* Item to check against point. */
694
    double *pointPtr;           /* Pointer to x and y coordinates. */
695
{
696
    PolygonItem *polyPtr = (PolygonItem *) itemPtr;
697
    double *coordPtr, distance;
698
    double staticSpace[2*MAX_STATIC_POINTS];
699
    int numPoints;
700
 
701
    if (!polyPtr->smooth) {
702
        distance = TkPolygonToPoint(polyPtr->coordPtr, polyPtr->numPoints,
703
                pointPtr);
704
    } else {
705
        /*
706
         * Smoothed polygon.  Generate a new set of points and use them
707
         * for comparison.
708
         */
709
 
710
        numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps;
711
        if (numPoints <= MAX_STATIC_POINTS) {
712
            coordPtr = staticSpace;
713
        } else {
714
            coordPtr = (double *) ckalloc((unsigned)
715
                    (2*numPoints*sizeof(double)));
716
        }
717
        numPoints = TkMakeBezierCurve(canvas, polyPtr->coordPtr,
718
                polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL,
719
                coordPtr);
720
        distance = TkPolygonToPoint(coordPtr, numPoints, pointPtr);
721
        if (coordPtr != staticSpace) {
722
            ckfree((char *) coordPtr);
723
        }
724
    }
725
    if (polyPtr->outlineColor != NULL) {
726
        distance -= polyPtr->width/2.0;
727
        if (distance < 0) {
728
            distance = 0;
729
        }
730
    }
731
    return distance;
732
}
733
 
734
/*
735
 *--------------------------------------------------------------
736
 *
737
 * PolygonToArea --
738
 *
739
 *      This procedure is called to determine whether an item
740
 *      lies entirely inside, entirely outside, or overlapping
741
 *      a given rectangular area.
742
 *
743
 * Results:
744
 *      -1 is returned if the item is entirely outside the area
745
 *      given by rectPtr, 0 if it overlaps, and 1 if it is entirely
746
 *      inside the given area.
747
 *
748
 * Side effects:
749
 *      None.
750
 *
751
 *--------------------------------------------------------------
752
 */
753
 
754
        /* ARGSUSED */
755
static int
756
PolygonToArea(canvas, itemPtr, rectPtr)
757
    Tk_Canvas canvas;           /* Canvas containing item. */
758
    Tk_Item *itemPtr;           /* Item to check against polygon. */
759
    double *rectPtr;            /* Pointer to array of four coordinates
760
                                 * (x1, y1, x2, y2) describing rectangular
761
                                 * area.  */
762
{
763
    PolygonItem *polyPtr = (PolygonItem *) itemPtr;
764
    double *coordPtr, rect2[4], halfWidth;
765
    double staticSpace[2*MAX_STATIC_POINTS];
766
    int numPoints, result;
767
 
768
    /*
769
     * Handle smoothed polygons by generating an expanded set of points
770
     * against which to do the check.
771
     */
772
 
773
    if (polyPtr->smooth) {
774
        numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps;
775
        if (numPoints <= MAX_STATIC_POINTS) {
776
            coordPtr = staticSpace;
777
        } else {
778
            coordPtr = (double *) ckalloc((unsigned)
779
                    (2*numPoints*sizeof(double)));
780
        }
781
        numPoints = TkMakeBezierCurve(canvas, polyPtr->coordPtr,
782
                polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL,
783
                coordPtr);
784
    } else {
785
        numPoints = polyPtr->numPoints;
786
        coordPtr = polyPtr->coordPtr;
787
    }
788
 
789
    if (polyPtr->width <= 1) {
790
        /*
791
         * The outline of the polygon doesn't stick out, so we can
792
         * do a simple check.
793
         */
794
 
795
        result = TkPolygonToArea(coordPtr, numPoints, rectPtr);
796
    } else {
797
        /*
798
         * The polygon has a wide outline, so the check is more complicated.
799
         * First, check the line segments to see if they overlap the area.
800
         */
801
 
802
        result = TkThickPolyLineToArea(coordPtr, numPoints,
803
            (double) polyPtr->width, CapRound, JoinRound, rectPtr);
804
        if (result >= 0) {
805
            goto done;
806
        }
807
 
808
        /*
809
         * There is no overlap between the polygon's outline and the
810
         * rectangle.  This means either the rectangle is entirely outside
811
         * the polygon or entirely inside.  To tell the difference,
812
         * see whether the polygon (with 0 outline width) overlaps the
813
         * rectangle bloated by half the outline width.
814
         */
815
 
816
        halfWidth = polyPtr->width/2.0;
817
        rect2[0] = rectPtr[0] - halfWidth;
818
        rect2[1] = rectPtr[1] - halfWidth;
819
        rect2[2] = rectPtr[2] + halfWidth;
820
        rect2[3] = rectPtr[3] + halfWidth;
821
        if (TkPolygonToArea(coordPtr, numPoints, rect2) == -1) {
822
            result = -1;
823
        } else {
824
            result = 0;
825
        }
826
    }
827
 
828
    done:
829
    if ((coordPtr != staticSpace) && (coordPtr != polyPtr->coordPtr)) {
830
        ckfree((char *) coordPtr);
831
    }
832
    return result;
833
}
834
 
835
/*
836
 *--------------------------------------------------------------
837
 *
838
 * ScalePolygon --
839
 *
840
 *      This procedure is invoked to rescale a polygon item.
841
 *
842
 * Results:
843
 *      None.
844
 *
845
 * Side effects:
846
 *      The polygon referred to by itemPtr is rescaled so that the
847
 *      following transformation is applied to all point
848
 *      coordinates:
849
 *              x' = originX + scaleX*(x-originX)
850
 *              y' = originY + scaleY*(y-originY)
851
 *
852
 *--------------------------------------------------------------
853
 */
854
 
855
static void
856
ScalePolygon(canvas, itemPtr, originX, originY, scaleX, scaleY)
857
    Tk_Canvas canvas;                   /* Canvas containing polygon. */
858
    Tk_Item *itemPtr;                   /* Polygon to be scaled. */
859
    double originX, originY;            /* Origin about which to scale rect. */
860
    double scaleX;                      /* Amount to scale in X direction. */
861
    double scaleY;                      /* Amount to scale in Y direction. */
862
{
863
    PolygonItem *polyPtr = (PolygonItem *) itemPtr;
864
    double *coordPtr;
865
    int i;
866
 
867
    for (i = 0, coordPtr = polyPtr->coordPtr; i < polyPtr->numPoints;
868
            i++, coordPtr += 2) {
869
        *coordPtr = originX + scaleX*(*coordPtr - originX);
870
        coordPtr[1] = originY + scaleY*(coordPtr[1] - originY);
871
    }
872
    ComputePolygonBbox(canvas, polyPtr);
873
}
874
 
875
/*
876
 *--------------------------------------------------------------
877
 *
878
 * TranslatePolygon --
879
 *
880
 *      This procedure is called to move a polygon by a given
881
 *      amount.
882
 *
883
 * Results:
884
 *      None.
885
 *
886
 * Side effects:
887
 *      The position of the polygon is offset by (xDelta, yDelta),
888
 *      and the bounding box is updated in the generic part of the
889
 *      item structure.
890
 *
891
 *--------------------------------------------------------------
892
 */
893
 
894
static void
895
TranslatePolygon(canvas, itemPtr, deltaX, deltaY)
896
    Tk_Canvas canvas;                   /* Canvas containing item. */
897
    Tk_Item *itemPtr;                   /* Item that is being moved. */
898
    double deltaX, deltaY;              /* Amount by which item is to be
899
                                         * moved. */
900
{
901
    PolygonItem *polyPtr = (PolygonItem *) itemPtr;
902
    double *coordPtr;
903
    int i;
904
 
905
    for (i = 0, coordPtr = polyPtr->coordPtr; i < polyPtr->numPoints;
906
            i++, coordPtr += 2) {
907
        *coordPtr += deltaX;
908
        coordPtr[1] += deltaY;
909
    }
910
    ComputePolygonBbox(canvas, polyPtr);
911
}
912
 
913
/*
914
 *--------------------------------------------------------------
915
 *
916
 * PolygonToPostscript --
917
 *
918
 *      This procedure is called to generate Postscript for
919
 *      polygon items.
920
 *
921
 * Results:
922
 *      The return value is a standard Tcl result.  If an error
923
 *      occurs in generating Postscript then an error message is
924
 *      left in interp->result, replacing whatever used
925
 *      to be there.  If no error occurs, then Postscript for the
926
 *      item is appended to the result.
927
 *
928
 * Side effects:
929
 *      None.
930
 *
931
 *--------------------------------------------------------------
932
 */
933
 
934
static int
935
PolygonToPostscript(interp, canvas, itemPtr, prepass)
936
    Tcl_Interp *interp;                 /* Leave Postscript or error message
937
                                         * here. */
938
    Tk_Canvas canvas;                   /* Information about overall canvas. */
939
    Tk_Item *itemPtr;                   /* Item for which Postscript is
940
                                         * wanted. */
941
    int prepass;                        /* 1 means this is a prepass to
942
                                         * collect font information;  0 means
943
                                         * final Postscript is being created. */
944
{
945
    char string[100];
946
    PolygonItem *polyPtr = (PolygonItem *) itemPtr;
947
 
948
    /*
949
     * Fill the area of the polygon.
950
     */
951
 
952
    if (polyPtr->fillColor != NULL) {
953
        if (!polyPtr->smooth) {
954
            Tk_CanvasPsPath(interp, canvas, polyPtr->coordPtr,
955
                    polyPtr->numPoints);
956
        } else {
957
            TkMakeBezierPostscript(interp, canvas, polyPtr->coordPtr,
958
                    polyPtr->numPoints);
959
        }
960
        if (Tk_CanvasPsColor(interp, canvas, polyPtr->fillColor) != TCL_OK) {
961
            return TCL_ERROR;
962
        }
963
        if (polyPtr->fillStipple != None) {
964
            Tcl_AppendResult(interp, "eoclip ", (char *) NULL);
965
            if (Tk_CanvasPsStipple(interp, canvas, polyPtr->fillStipple)
966
                    != TCL_OK) {
967
                return TCL_ERROR;
968
            }
969
            if (polyPtr->outlineColor != NULL) {
970
                Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL);
971
            }
972
        } else {
973
            Tcl_AppendResult(interp, "eofill\n", (char *) NULL);
974
        }
975
    }
976
 
977
    /*
978
     * Now draw the outline, if there is one.
979
     */
980
 
981
    if (polyPtr->outlineColor != NULL) {
982
        if (!polyPtr->smooth) {
983
            Tk_CanvasPsPath(interp, canvas, polyPtr->coordPtr,
984
                polyPtr->numPoints);
985
        } else {
986
            TkMakeBezierPostscript(interp, canvas, polyPtr->coordPtr,
987
                polyPtr->numPoints);
988
        }
989
 
990
        sprintf(string, "%d setlinewidth\n", polyPtr->width);
991
        Tcl_AppendResult(interp, string,
992
                "1 setlinecap\n1 setlinejoin\n", (char *) NULL);
993
        if (Tk_CanvasPsColor(interp, canvas, polyPtr->outlineColor)
994
                != TCL_OK) {
995
            return TCL_ERROR;
996
        }
997
        Tcl_AppendResult(interp, "stroke\n", (char *) NULL);
998
    }
999
    return TCL_OK;
1000
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.