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