source: trunk/kitgen/8.x/blt/generic/bltGrLine.c@ 176

Last change on this file since 176 was 175, checked in by demin, 12 years ago

initial commit

File size: 156.7 KB
RevLine 
[175]1
2/*
3 * bltGrLine.c --
4 *
5 * This module implements line graph and stripchart elements for
6 * the BLT graph widget.
7 *
8 * Copyright 1993-1998 Lucent Technologies, Inc.
9 *
10 * Permission to use, copy, modify, and distribute this software and
11 * its documentation for any purpose and without fee is hereby
12 * granted, provided that the above copyright notice appear in all
13 * copies and that both that the copyright notice and warranty
14 * disclaimer appear in supporting documentation, and that the names
15 * of Lucent Technologies any of their entities not be used in
16 * advertising or publicity pertaining to distribution of the software
17 * without specific, written prior permission.
18 *
19 * Lucent Technologies disclaims all warranties with regard to this
20 * software, including all implied warranties of merchantability and
21 * fitness. In no event shall Lucent Technologies be liable for any
22 * special, indirect or consequential damages or any damages
23 * whatsoever resulting from loss of use, data or profits, whether in
24 * an action of contract, negligence or other tortuous action, arising
25 * out of or in connection with the use or performance of this
26 * software.
27 */
28#include "bltGraph.h"
29#include "bltChain.h"
30#include <X11/Xutil.h>
31
32#include "bltGrElem.h"
33
34#define COLOR_DEFAULT (XColor *)1
35#define PATTERN_SOLID ((Pixmap)1)
36
37#define PEN_INCREASING 1 /* Draw line segments for only those
38 * data points whose abscissas are
39 * monotonically increasing in
40 * order */
41#define PEN_DECREASING 2 /* Lines will be drawn between only
42 * those points whose abscissas are
43 * decreasing in order */
44
45#define PEN_BOTH_DIRECTIONS (PEN_INCREASING | PEN_DECREASING)
46 /* Lines will be drawn between points regardless of the ordering of
47 * the abscissas */
48
49#define BROKEN_TRACE(dir,last,next) \
50 (((((dir) & PEN_DECREASING) == 0) && ((next) < (last))) || \
51 ((((dir) & PEN_INCREASING) == 0) && ((next) > (last))))
52
53#define DRAW_SYMBOL(linePtr) \
54 (((linePtr)->symbolCounter % (linePtr)->symbolInterval) == 0)
55
56typedef enum {
57 PEN_SMOOTH_NONE, /* Line segments */
58 PEN_SMOOTH_STEP, /* Step-and-hold */
59 PEN_SMOOTH_NATURAL, /* Natural cubic spline */
60 PEN_SMOOTH_QUADRATIC, /* Quadratic spline */
61 PEN_SMOOTH_CATROM, /* Catrom parametric spline */
62 PEN_SMOOTH_LAST /* Sentinel */
63} Smoothing;
64
65typedef struct {
66 char *name;
67 Smoothing value;
68} SmoothingInfo;
69
70static SmoothingInfo smoothingInfo[] = {
71 { "linear", PEN_SMOOTH_NONE },
72 { "step", PEN_SMOOTH_STEP },
73 { "natural", PEN_SMOOTH_NATURAL },
74 { "cubic", PEN_SMOOTH_NATURAL },
75 { "quadratic", PEN_SMOOTH_QUADRATIC },
76 { "catrom", PEN_SMOOTH_CATROM },
77 { (char *)NULL, PEN_SMOOTH_LAST }
78};
79
80
81typedef struct {
82 Point2D *screenPts; /* Array of transformed coordinates */
83 int nScreenPts; /* Number of coordinates */
84 int *dataToStyle; /* Index of pen styles */
85 int *indices; /* Maps segments/traces to data points */
86
87} MapInfo;
88
89/*
90 * Symbol types for line elements
91 */
92typedef enum {
93 SYMBOL_NONE,
94 SYMBOL_SQUARE,
95 SYMBOL_CIRCLE,
96 SYMBOL_DIAMOND,
97 SYMBOL_PLUS,
98 SYMBOL_CROSS,
99 SYMBOL_SPLUS,
100 SYMBOL_SCROSS,
101 SYMBOL_TRIANGLE,
102 SYMBOL_ARROW,
103 SYMBOL_BITMAP
104} SymbolType;
105
106typedef struct {
107 SymbolType type; /* Type of symbol to be drawn/printed */
108
109 int size; /* Requested size of symbol in pixels */
110
111 XColor *outlineColor; /* Outline color */
112
113 int outlineWidth; /* Width of the outline */
114
115 GC outlineGC; /* Outline graphics context */
116
117 XColor *fillColor; /* Normal fill color */
118
119 GC fillGC; /* Fill graphics context */
120
121 /* The last two fields are used only for bitmap symbols. */
122
123 Pixmap bitmap; /* Bitmap to determine foreground/background
124 * pixels of the symbol */
125
126 Pixmap mask; /* Bitmap representing the transparent
127 * pixels of the symbol */
128
129} Symbol;
130
131typedef struct {
132 int start; /* Index into the X-Y coordinate
133 * arrays indicating where trace
134 * starts. */
135
136 int nScreenPts; /* Number of points in the continuous
137 * trace */
138
139 Point2D *screenPts; /* Array of screen coordinates
140 * (malloc-ed) representing the
141 * trace. */
142
143 int *symbolToData; /* Reverse mapping of screen
144 * coordinate indices back to their
145 * data coordinates */
146} Trace;
147
148typedef struct {
149 char *name; /* Name of pen style. If the pen was
150 * statically allocated the name will
151 * be NULL. */
152
153 Blt_Uid classUid; /* Type of pen */
154
155 char *typeId; /* String token identifying the type
156 * of pen */
157
158 unsigned int flags; /* Indicates if the pen element is
159 * active or normal */
160
161 int refCount; /* Reference count for elements using
162 * this pen. */
163 Blt_HashEntry *hashPtr;
164
165 Tk_ConfigSpec *configSpecs; /* Configuration specifications */
166
167 PenConfigureProc *configProc;
168 PenDestroyProc *destroyProc;
169
170 /* Symbol attributes. */
171 Symbol symbol; /* Element symbol type */
172
173 /* Trace attributes. */
174 int traceWidth; /* Width of the line segments. If
175 * lineWidth is 0, no line will be
176 * drawn, only symbols. */
177
178 Blt_Dashes traceDashes; /* Dash on-off list value */
179
180 XColor *traceColor; /* Line segment color */
181
182 XColor *traceOffColor; /* Line segment dash gap color */
183
184 GC traceGC; /* Line segment graphics context */
185
186 /* Error bar attributes. */
187 int errorBarShow; /* Describes which error bars to
188 * display: none, x, y, or * both. */
189
190 int errorBarLineWidth; /* Width of the error bar segments. */
191
192 int errorBarCapWidth; /* Width of the cap on error bars. */
193
194 XColor *errorBarColor; /* Color of the error bar. */
195
196 GC errorBarGC; /* Error bar graphics context. */
197
198 /* Show value attributes. */
199 int valueShow; /* Indicates whether to display data
200 * value. Values are x, y, both, or
201 * none. */
202 char *valueFormat; /* A printf format string. */
203
204 TextStyle valueStyle; /* Text attributes (color, font,
205 * rotation, etc.) of the value. */
206
207} LinePen;
208
209typedef struct {
210 Weight weight; /* Weight range where this pen is valid. */
211
212 LinePen *penPtr; /* Pen used to draw symbols, traces, error
213 * bars, segments, etc. */
214
215 Segment2D *xErrorBars; /* Point to start of this pen's X-error bar
216 * segments in the element's array. */
217 Segment2D *yErrorBars; /* Point to start of this pen's Y-error bar
218 * segments in the element's array. */
219 int xErrorBarCnt; /* # of error bars for this pen. */
220 int yErrorBarCnt; /* # of error bars for this pen. */
221
222 int errorBarCapWidth; /* Length of the cap ends on each
223 * error bar. */
224
225 int symbolSize; /* Size of the pen's symbol scaled to the
226 * current graph size. */
227
228 /* Graph specific data. */
229
230 Point2D *symbolPts; /* Points to start of array for this pen. */
231
232 int nSymbolPts; /* # of points for this pen. */
233
234 /* The last two fields are used only for stripcharts. */
235
236 Segment2D *strips; /* Points to start of the line segments
237 * for this pen. */
238
239 int nStrips; /* # of line segments for this pen. */
240
241} LinePenStyle;
242
243typedef struct {
244 char *name; /* Identifier used to refer the
245 * element. Used in the "insert",
246 * "delete", or "show", operations. */
247
248 Blt_Uid classUid; /* Type of element */
249
250 Graph *graphPtr; /* Graph widget of element*/
251
252 unsigned int flags; /* Indicates if the entire element is
253 * active, or if coordinates need to
254 * be calculated */
255
256 char **tags;
257
258 int hidden; /* If non-zero, don't display the
259 * element. */
260
261 Blt_HashEntry *hashPtr;
262
263 char *label; /* Label displayed in legend */
264
265 int labelRelief; /* Relief of label in legend. */
266
267 Axis2D axes;
268
269 ElemVector x, y, w; /* Contains array of numeric values */
270
271 ElemVector xError; /* Relative/symmetric X error values. */
272 ElemVector yError; /* Relative/symmetric Y error values. */
273 ElemVector xHigh, xLow; /* Absolute/asymmetric X-coordinate high/low
274 error values. */
275 ElemVector yHigh, yLow; /* Absolute/asymmetric Y-coordinate high/low
276 error values. */
277
278 int *activeIndices; /* Array of indices (malloc-ed) that
279 * indicate the data points are active
280 * (drawn with "active" colors). */
281
282 int nActiveIndices; /* Number of active data points.
283 * Special case: if < 0 then all data
284 * points are drawn active. */
285
286 ElementProcs *procsPtr;
287 Tk_ConfigSpec *configSpecs; /* Configuration specifications */
288
289 Segment2D *xErrorBars; /* Point to start of this pen's X-error bar
290 * segments in the element's array. */
291 Segment2D *yErrorBars; /* Point to start of this pen's Y-error bar
292 * segments in the element's array. */
293 int xErrorBarCnt; /* # of error bars for this pen. */
294 int yErrorBarCnt; /* # of error bars for this pen. */
295
296 int *xErrorToData; /* Maps individual error bar segments back
297 * to the data point associated with it. */
298 int *yErrorToData; /* Maps individual error bar segments back
299 * to the data point associated with it. */
300
301 int errorBarCapWidth; /* Length of cap on error bars */
302
303 LinePen *activePenPtr; /* Pen to draw "active" elements. */
304 LinePen *normalPenPtr; /* Pen to draw elements normally. */
305
306 Blt_Chain *palette; /* Array of pen styles: pens are associated
307 * with specific ranges of data.*/
308
309 /* Symbol scaling */
310 int scaleSymbols; /* If non-zero, the symbols will scale
311 * in size as the graph is zoomed
312 * in/out. */
313
314 double xRange, yRange; /* Initial X-axis and Y-axis ranges:
315 * used to scale the size of element's
316 * symbol. */
317
318 int state;
319 /*
320 * Line specific configurable attributes
321 */
322 LinePen builtinPen;
323
324 /* Line smoothing */
325 Smoothing reqSmooth; /* Requested smoothing function to use
326 * for connecting the data points */
327
328 Smoothing smooth; /* Smoothing function used. */
329
330 double rTolerance; /* Tolerance to reduce the number of
331 * points displayed. */
332 /*
333 * Drawing related data structures.
334 */
335
336 /* Area-under-curve fill attributes. */
337 XColor *fillFgColor;
338 XColor *fillBgColor;
339 GC fillGC;
340
341 Blt_Tile fillTile; /* Tile for fill area. */
342 Pixmap fillStipple; /* Stipple for fill area. */
343
344 int nFillPts;
345 Point2D *fillPts; /* Array of points used to draw
346 * polygon to fill area under the
347 * curve */
348
349 /* Symbol points */
350 Point2D *symbolPts; /* Holds the screen coordinates of all
351 * the data points for the element. */
352 int nSymbolPts; /* Number of points */
353
354 int *symbolToData; /* Contains indices of data points.
355 * It's first used to map pens to the
356 * visible points to sort them by pen
357 * style, and later to find data
358 * points from the index of a visible
359 * point. */
360
361 /* Active symbol points */
362 Point2D *activePts; /* Array of indices representing the
363 * "active" points. */
364 int nActivePts; /* Number of indices in the above array. */
365
366 int *activeToData; /* Contains indices of data points.
367 * It's first used to map pens to the
368 * visible points to sort them by pen
369 * style, and later to find data
370 * points from the index of a visible
371 * point. */
372
373 int reqMaxSymbols;
374 int symbolInterval;
375 int symbolCounter;
376
377 /* X-Y graph-specific fields */
378
379 int penDir; /* Indicates if a change in the pen
380 * direction should be considered a
381 * retrace (line segment is not
382 * drawn). */
383
384 Blt_Chain *traces; /* List of traces (a trace is a series
385 * of contiguous line segments). New
386 * traces are generated when either
387 * the next segment changes the pen
388 * direction, or the end point is
389 * clipped by the plotting area. */
390
391 /* Stripchart-specific fields */
392
393 Segment2D *strips; /* Holds the the line segments of the
394 * element trace. The segments are
395 * grouped by pen style. */
396 int nStrips; /* Number of line segments to be drawn. */
397 int *stripToData; /* Pen to visible line segment mapping. */
398
399} Line;
400
401static Tk_OptionParseProc StringToPattern;
402static Tk_OptionPrintProc PatternToString;
403static Tk_OptionParseProc StringToSmooth;
404static Tk_OptionPrintProc SmoothToString;
405extern Tk_OptionParseProc Blt_StringToStyles;
406extern Tk_OptionPrintProc Blt_StylesToString;
407static Tk_OptionParseProc StringToPenDir;
408static Tk_OptionPrintProc PenDirToString;
409static Tk_OptionParseProc StringToSymbol;
410static Tk_OptionPrintProc SymbolToString;
411
412static Tk_CustomOption patternOption =
413{
414 StringToPattern, PatternToString, (ClientData)0
415};
416static Tk_CustomOption smoothOption =
417{
418 StringToSmooth, SmoothToString, (ClientData)0
419};
420static Tk_CustomOption stylesOption =
421{
422 Blt_StringToStyles, Blt_StylesToString, (ClientData)sizeof(LinePenStyle)
423};
424static Tk_CustomOption penDirOption =
425{
426 StringToPenDir, PenDirToString, (ClientData)0
427};
428static Tk_CustomOption symbolOption =
429{
430 StringToSymbol, SymbolToString, (ClientData)0
431};
432extern Tk_CustomOption bltColorOption;
433extern Tk_CustomOption bltDashesOption;
434extern Tk_CustomOption bltDataOption;
435extern Tk_CustomOption bltDataPairsOption;
436extern Tk_CustomOption bltDistanceOption;
437extern Tk_CustomOption bltListOption;
438extern Tk_CustomOption bltLinePenOption;
439extern Tk_CustomOption bltShadowOption;
440extern Tk_CustomOption bltXAxisOption;
441extern Tk_CustomOption bltYAxisOption;
442extern Tk_CustomOption bltTileOption;
443extern Tk_CustomOption bltFillOption;
444extern Tk_CustomOption bltStateOption;
445
446#define DEF_LINE_ACTIVE_PEN "activeLine"
447#define DEF_LINE_AXIS_X "x"
448#define DEF_LINE_AXIS_Y "y"
449#define DEF_LINE_DASHES (char *)NULL
450#define DEF_LINE_DATA (char *)NULL
451#define DEF_LINE_FILL_COLOR "defcolor"
452#define DEF_LINE_FILL_MONO "defcolor"
453#define DEF_LINE_HIDE "no"
454#define DEF_LINE_LABEL (char *)NULL
455#define DEF_LINE_LABEL_RELIEF "flat"
456#define DEF_LINE_MAX_SYMBOLS "0"
457#define DEF_LINE_OFFDASH_COLOR (char *)NULL
458#define DEF_LINE_OFFDASH_MONO (char *)NULL
459#define DEF_LINE_OUTLINE_COLOR "defcolor"
460#define DEF_LINE_OUTLINE_MONO "defcolor"
461#define DEF_LINE_OUTLINE_WIDTH "1"
462#define DEF_LINE_PATTERN (char *)NULL
463#define DEF_LINE_PATTERN_BG "white"
464#define DEF_LINE_PATTERN_FG "black"
465#define DEF_LINE_PATTERN_TILE (char *)NULL
466#define DEF_LINE_PEN_COLOR RGB_NAVYBLUE
467#define DEF_LINE_PEN_DIRECTION "both"
468#define DEF_LINE_PEN_MONO RGB_BLACK
469#define DEF_LINE_PEN_WIDTH "1"
470#define DEF_LINE_PIXELS "0.125i"
471#define DEF_LINE_REDUCE "0.0"
472#define DEF_LINE_SCALE_SYMBOLS "yes"
473#define DEF_LINE_SMOOTH "linear"
474#define DEF_LINE_STATE "normal"
475#define DEF_LINE_STIPPLE (char *)NULL
476#define DEF_LINE_STYLES ""
477#define DEF_LINE_SYMBOL "circle"
478#define DEF_LINE_TAGS "all"
479#define DEF_LINE_X_DATA (char *)NULL
480#define DEF_LINE_Y_DATA (char *)NULL
481
482#define DEF_LINE_ERRORBAR_COLOR "defcolor"
483#define DEF_LINE_ERRORBAR_LINE_WIDTH "1"
484#define DEF_LINE_ERRORBAR_CAP_WIDTH "1"
485#define DEF_LINE_SHOW_ERRORBARS "both"
486
487#define DEF_PEN_ACTIVE_COLOR RGB_BLUE
488#define DEF_PEN_ACTIVE_MONO RGB_BLACK
489#define DEF_PEN_DASHES (char *)NULL
490#define DEF_PEN_FILL_COLOR "defcolor"
491#define DEF_PEN_FILL_MONO "defcolor"
492#define DEF_PEN_LINE_WIDTH "1"
493#define DEF_PEN_NORMAL_COLOR RGB_NAVYBLUE
494#define DEF_PEN_NORMAL_MONO RGB_BLACK
495#define DEF_PEN_OFFDASH_COLOR (char *)NULL
496#define DEF_PEN_OFFDASH_MONO (char *)NULL
497#define DEF_PEN_OUTLINE_COLOR "defcolor"
498#define DEF_PEN_OUTLINE_MONO "defcolor"
499#define DEF_PEN_OUTLINE_WIDTH "1"
500#define DEF_PEN_PIXELS "0.125i"
501#define DEF_PEN_SYMBOL "circle"
502#define DEF_PEN_TYPE "line"
503#define DEF_PEN_VALUE_ANCHOR "s"
504#define DEF_PEN_VALUE_COLOR RGB_BLACK
505#define DEF_PEN_VALUE_FONT STD_FONT_SMALL
506#define DEF_PEN_VALUE_FORMAT "%g"
507#define DEF_PEN_VALUE_ROTATE (char *)NULL
508#define DEF_PEN_VALUE_SHADOW (char *)NULL
509#define DEF_PEN_SHOW_VALUES "no"
510
511static Tk_ConfigSpec lineElemConfigSpecs[] =
512{
513 {TK_CONFIG_CUSTOM, "-activepen", "activePen", "ActivePen",
514 DEF_LINE_ACTIVE_PEN, Tk_Offset(Line, activePenPtr),
515 TK_CONFIG_NULL_OK, &bltLinePenOption},
516 {TK_CONFIG_CUSTOM, "-areapattern", "areaPattern", "AreaPattern",
517 DEF_LINE_PATTERN, Tk_Offset(Line, fillStipple),
518 TK_CONFIG_NULL_OK, &patternOption},
519 {TK_CONFIG_COLOR, "-areaforeground", "areaForeground", "areaForeground",
520 DEF_LINE_PATTERN_FG, Tk_Offset(Line, fillFgColor), TK_CONFIG_NULL_OK},
521 {TK_CONFIG_COLOR, "-areabackground", "areaBackground", "areaBackground",
522 DEF_LINE_PATTERN_BG, Tk_Offset(Line, fillBgColor), TK_CONFIG_NULL_OK},
523 {TK_CONFIG_CUSTOM, "-areatile", "areaTile", "AreaTile",
524 DEF_LINE_PATTERN_TILE, Tk_Offset(Line, fillTile),
525 TK_CONFIG_NULL_OK, &bltTileOption},
526 {TK_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags",
527 DEF_LINE_TAGS, Tk_Offset(Line, tags),
528 TK_CONFIG_NULL_OK, &bltListOption},
529 {TK_CONFIG_COLOR, "-color", "color", "Color",
530 DEF_LINE_PEN_COLOR, Tk_Offset(Line, builtinPen.traceColor),
531 TK_CONFIG_COLOR_ONLY},
532 {TK_CONFIG_COLOR, "-color", "color", "Color",
533 DEF_LINE_PEN_MONO, Tk_Offset(Line, builtinPen.traceColor),
534 TK_CONFIG_MONO_ONLY},
535 {TK_CONFIG_CUSTOM, "-dashes", "dashes", "Dashes",
536 DEF_LINE_DASHES, Tk_Offset(Line, builtinPen.traceDashes),
537 TK_CONFIG_NULL_OK, &bltDashesOption},
538 {TK_CONFIG_CUSTOM, "-data", "data", "Data",
539 DEF_LINE_DATA, 0, 0, &bltDataPairsOption},
540 {TK_CONFIG_CUSTOM, "-errorbarcolor", "errorBarColor", "ErrorBarColor",
541 DEF_LINE_ERRORBAR_COLOR, Tk_Offset(Line, builtinPen.errorBarColor),
542 0, &bltColorOption},
543 {TK_CONFIG_CUSTOM, "-errorbarwidth", "errorBarWidth", "ErrorBarWidth",
544 DEF_LINE_ERRORBAR_LINE_WIDTH,
545 Tk_Offset(Line, builtinPen.errorBarLineWidth),
546 TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
547 {TK_CONFIG_CUSTOM, "-errorbarcap", "errorBarCap", "ErrorBarCap",
548 DEF_LINE_ERRORBAR_CAP_WIDTH,
549 Tk_Offset(Line, builtinPen.errorBarCapWidth),
550 TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
551 {TK_CONFIG_CUSTOM, "-fill", "fill", "Fill",
552 DEF_LINE_FILL_COLOR, Tk_Offset(Line, builtinPen.symbol.fillColor),
553 TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY, &bltColorOption},
554 {TK_CONFIG_CUSTOM, "-fill", "fill", "Fill",
555 DEF_LINE_FILL_MONO, Tk_Offset(Line, builtinPen.symbol.fillColor),
556 TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY, &bltColorOption},
557 {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide",
558 DEF_LINE_HIDE, Tk_Offset(Line, hidden), TK_CONFIG_DONT_SET_DEFAULT},
559 {TK_CONFIG_STRING, "-label", "label", "Label",
560 (char *)NULL, Tk_Offset(Line, label), TK_CONFIG_NULL_OK},
561 {TK_CONFIG_RELIEF, "-labelrelief", "labelRelief", "LabelRelief",
562 DEF_LINE_LABEL_RELIEF, Tk_Offset(Line, labelRelief),
563 TK_CONFIG_DONT_SET_DEFAULT},
564 {TK_CONFIG_CUSTOM, "-linewidth", "lineWidth", "LineWidth",
565 DEF_LINE_PEN_WIDTH, Tk_Offset(Line, builtinPen.traceWidth),
566 TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
567 {TK_CONFIG_CUSTOM, "-mapx", "mapX", "MapX",
568 DEF_LINE_AXIS_X, Tk_Offset(Line, axes.x), 0, &bltXAxisOption},
569 {TK_CONFIG_CUSTOM, "-mapy", "mapY", "MapY",
570 DEF_LINE_AXIS_Y, Tk_Offset(Line, axes.y), 0, &bltYAxisOption},
571 {TK_CONFIG_CUSTOM, "-maxsymbols", "maxSymbols", "MaxSymbols",
572 DEF_LINE_MAX_SYMBOLS, Tk_Offset(Line, reqMaxSymbols),
573 TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
574 {TK_CONFIG_CUSTOM, "-offdash", "offDash", "OffDash",
575 DEF_LINE_OFFDASH_COLOR, Tk_Offset(Line, builtinPen.traceOffColor),
576 TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY, &bltColorOption},
577 {TK_CONFIG_CUSTOM, "-offdash", "offDash", "OffDash",
578 DEF_LINE_OFFDASH_MONO, Tk_Offset(Line, builtinPen.traceOffColor),
579 TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY, &bltColorOption},
580 {TK_CONFIG_CUSTOM, "-outline", "outline", "Outline",
581 DEF_LINE_OUTLINE_COLOR, Tk_Offset(Line, builtinPen.symbol.outlineColor),
582 TK_CONFIG_COLOR_ONLY, &bltColorOption},
583 {TK_CONFIG_CUSTOM, "-outline", "outline", "Outline",
584 DEF_LINE_OUTLINE_MONO, Tk_Offset(Line, builtinPen.symbol.outlineColor),
585 TK_CONFIG_MONO_ONLY, &bltColorOption},
586 {TK_CONFIG_CUSTOM, "-outlinewidth", "outlineWidth", "OutlineWidth",
587 DEF_LINE_OUTLINE_WIDTH, Tk_Offset(Line, builtinPen.symbol.outlineWidth),
588 TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
589 {TK_CONFIG_CUSTOM, "-pen", "pen", "Pen",
590 (char *)NULL, Tk_Offset(Line, normalPenPtr),
591 TK_CONFIG_NULL_OK, &bltLinePenOption},
592 {TK_CONFIG_CUSTOM, "-pixels", "pixels", "Pixels",
593 DEF_LINE_PIXELS, Tk_Offset(Line, builtinPen.symbol.size),
594 GRAPH | STRIPCHART, &bltDistanceOption},
595 {TK_CONFIG_DOUBLE, "-reduce", "reduce", "Reduce",
596 DEF_LINE_REDUCE, Tk_Offset(Line, rTolerance),
597 GRAPH | STRIPCHART | TK_CONFIG_DONT_SET_DEFAULT},
598 {TK_CONFIG_BOOLEAN, "-scalesymbols", "scaleSymbols", "ScaleSymbols",
599 DEF_LINE_SCALE_SYMBOLS, Tk_Offset(Line, scaleSymbols),
600 TK_CONFIG_DONT_SET_DEFAULT},
601 {TK_CONFIG_CUSTOM, "-showerrorbars", "showErrorBars", "ShowErrorBars",
602 DEF_LINE_SHOW_ERRORBARS, Tk_Offset(Line, builtinPen.errorBarShow),
603 TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption},
604 {TK_CONFIG_CUSTOM, "-showvalues", "showValues", "ShowValues",
605 DEF_PEN_SHOW_VALUES, Tk_Offset(Line, builtinPen.valueShow),
606 TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption},
607 {TK_CONFIG_CUSTOM, "-smooth", "smooth", "Smooth",
608 DEF_LINE_SMOOTH, Tk_Offset(Line, reqSmooth),
609 TK_CONFIG_DONT_SET_DEFAULT, &smoothOption},
610 {TK_CONFIG_CUSTOM, "-state", "state", "State",
611 DEF_LINE_STATE, Tk_Offset(Line, state),
612 TK_CONFIG_DONT_SET_DEFAULT, &bltStateOption},
613 {TK_CONFIG_CUSTOM, "-styles", "styles", "Styles",
614 DEF_LINE_STYLES, Tk_Offset(Line, palette),
615 TK_CONFIG_NULL_OK, &stylesOption},
616 {TK_CONFIG_CUSTOM, "-symbol", "symbol", "Symbol",
617 DEF_LINE_SYMBOL, Tk_Offset(Line, builtinPen.symbol),
618 TK_CONFIG_DONT_SET_DEFAULT, &symbolOption},
619 {TK_CONFIG_CUSTOM, "-trace", "trace", "Trace",
620 DEF_LINE_PEN_DIRECTION, Tk_Offset(Line, penDir),
621 TK_CONFIG_DONT_SET_DEFAULT, &penDirOption},
622 {TK_CONFIG_ANCHOR, "-valueanchor", "valueAnchor", "ValueAnchor",
623 DEF_PEN_VALUE_ANCHOR,
624 Tk_Offset(Line, builtinPen.valueStyle.anchor), 0},
625 {TK_CONFIG_COLOR, "-valuecolor", "valueColor", "ValueColor",
626 DEF_PEN_VALUE_COLOR, Tk_Offset(Line, builtinPen.valueStyle.color), 0},
627 {TK_CONFIG_FONT, "-valuefont", "valueFont", "ValueFont",
628 DEF_PEN_VALUE_FONT, Tk_Offset(Line, builtinPen.valueStyle.font), 0},
629 {TK_CONFIG_STRING, "-valueformat", "valueFormat", "ValueFormat",
630 DEF_PEN_VALUE_FORMAT, Tk_Offset(Line, builtinPen.valueFormat),
631 TK_CONFIG_NULL_OK},
632 {TK_CONFIG_DOUBLE, "-valuerotate", "valueRotate", "ValueRotate",
633 DEF_PEN_VALUE_ROTATE, Tk_Offset(Line, builtinPen.valueStyle.theta), 0},
634 {TK_CONFIG_CUSTOM, "-valueshadow", "valueShadow", "ValueShadow",
635 DEF_PEN_VALUE_SHADOW, Tk_Offset(Line, builtinPen.valueStyle.shadow),
636 0, &bltShadowOption},
637 {TK_CONFIG_CUSTOM, "-weights", "weights", "Weights",
638 (char *)NULL, Tk_Offset(Line, w), 0, &bltDataOption},
639 {TK_CONFIG_CUSTOM, "-x", "xData", "XData",
640 (char *)NULL, Tk_Offset(Line, x), 0, &bltDataOption},
641 {TK_CONFIG_CUSTOM, "-xdata", "xData", "XData",
642 (char *)NULL, Tk_Offset(Line, x), 0, &bltDataOption},
643 {TK_CONFIG_CUSTOM, "-xerror", "xError", "XError",
644 (char *)NULL, Tk_Offset(Line, xError), 0, &bltDataOption},
645 {TK_CONFIG_CUSTOM, "-xhigh", "xHigh", "XHigh",
646 (char *)NULL, Tk_Offset(Line, xHigh), 0, &bltDataOption},
647 {TK_CONFIG_CUSTOM, "-xlow", "xLow", "XLow",
648 (char *)NULL, Tk_Offset(Line, xLow), 0, &bltDataOption},
649 {TK_CONFIG_CUSTOM, "-y", "yData", "YData",
650 (char *)NULL, Tk_Offset(Line, y), 0, &bltDataOption},
651 {TK_CONFIG_CUSTOM, "-ydata", "yData", "YData",
652 (char *)NULL, Tk_Offset(Line, y), 0, &bltDataOption},
653 {TK_CONFIG_CUSTOM, "-yerror", "yError", "YError",
654 (char *)NULL, Tk_Offset(Line, yError), 0, &bltDataOption},
655 {TK_CONFIG_CUSTOM, "-yhigh", "yHigh", "YHigh",
656 (char *)NULL, Tk_Offset(Line, yHigh), 0, &bltDataOption},
657 {TK_CONFIG_CUSTOM, "-ylow", "yLow", "YLow",
658 (char *)NULL, Tk_Offset(Line, yLow), 0, &bltDataOption},
659 {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
660};
661
662
663static Tk_ConfigSpec stripElemConfigSpecs[] =
664{
665 {TK_CONFIG_CUSTOM, "-activepen", "activePen", "ActivePen",
666 DEF_LINE_ACTIVE_PEN, Tk_Offset(Line, activePenPtr),
667 TK_CONFIG_NULL_OK, &bltLinePenOption},
668 {TK_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags",
669 DEF_LINE_TAGS, Tk_Offset(Line, tags),
670 TK_CONFIG_NULL_OK, &bltListOption},
671 {TK_CONFIG_COLOR, "-color", "color", "Color",
672 DEF_LINE_PEN_COLOR, Tk_Offset(Line, builtinPen.traceColor),
673 TK_CONFIG_COLOR_ONLY},
674 {TK_CONFIG_COLOR, "-color", "color", "Color",
675 DEF_LINE_PEN_MONO, Tk_Offset(Line, builtinPen.traceColor),
676 TK_CONFIG_MONO_ONLY},
677 {TK_CONFIG_CUSTOM, "-dashes", "dashes", "Dashes",
678 DEF_LINE_DASHES, Tk_Offset(Line, builtinPen.traceDashes),
679 TK_CONFIG_NULL_OK, &bltDashesOption},
680 {TK_CONFIG_CUSTOM, "-data", "data", "Data",
681 DEF_LINE_DATA, 0, 0, &bltDataPairsOption},
682 {TK_CONFIG_CUSTOM, "-errorbarcolor", "errorBarColor", "ErrorBarColor",
683 DEF_LINE_ERRORBAR_COLOR, Tk_Offset(Line, builtinPen.errorBarColor),
684 0, &bltColorOption},
685 {TK_CONFIG_CUSTOM, "-errorbarwidth", "errorBarWidth", "ErrorBarWidth",
686 DEF_LINE_ERRORBAR_LINE_WIDTH,
687 Tk_Offset(Line, builtinPen.errorBarLineWidth),
688 TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
689 {TK_CONFIG_CUSTOM, "-errorbarcap", "errorBarCap",
690 "ErrorBarCap", DEF_LINE_ERRORBAR_CAP_WIDTH,
691 Tk_Offset(Line, builtinPen.errorBarCapWidth),
692 TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
693 {TK_CONFIG_CUSTOM, "-fill", "fill", "Fill",
694 DEF_LINE_FILL_COLOR, Tk_Offset(Line, builtinPen.symbol.fillColor),
695 TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY, &bltColorOption},
696 {TK_CONFIG_CUSTOM, "-fill", "fill", "Fill",
697 DEF_LINE_FILL_MONO, Tk_Offset(Line, builtinPen.symbol.fillColor),
698 TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY, &bltColorOption},
699 {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide",
700 DEF_LINE_HIDE, Tk_Offset(Line, hidden), TK_CONFIG_DONT_SET_DEFAULT},
701 {TK_CONFIG_STRING, "-label", "label", "Label",
702 (char *)NULL, Tk_Offset(Line, label), TK_CONFIG_NULL_OK},
703 {TK_CONFIG_RELIEF, "-labelrelief", "labelRelief", "LabelRelief",
704 DEF_LINE_LABEL_RELIEF, Tk_Offset(Line, labelRelief),
705 TK_CONFIG_DONT_SET_DEFAULT},
706 {TK_CONFIG_CUSTOM, "-linewidth", "lineWidth", "LineWidth",
707 DEF_LINE_PEN_WIDTH, Tk_Offset(Line, builtinPen.traceWidth),
708 TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
709 {TK_CONFIG_CUSTOM, "-mapx", "mapX", "MapX",
710 DEF_LINE_AXIS_X, Tk_Offset(Line, axes.x), 0, &bltXAxisOption},
711 {TK_CONFIG_CUSTOM, "-mapy", "mapY", "MapY",
712 DEF_LINE_AXIS_Y, Tk_Offset(Line, axes.y), 0, &bltYAxisOption},
713 {TK_CONFIG_CUSTOM, "-maxsymbols", "maxSymbols", "MaxSymbols",
714 DEF_LINE_MAX_SYMBOLS, Tk_Offset(Line, reqMaxSymbols),
715 TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
716 {TK_CONFIG_CUSTOM, "-offdash", "offDash", "OffDash",
717 DEF_LINE_OFFDASH_COLOR, Tk_Offset(Line, builtinPen.traceOffColor),
718 TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY, &bltColorOption},
719 {TK_CONFIG_CUSTOM, "-offdash", "offDash", "OffDash",
720 DEF_LINE_OFFDASH_MONO, Tk_Offset(Line, builtinPen.traceOffColor),
721 TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY, &bltColorOption},
722 {TK_CONFIG_CUSTOM, "-outline", "outline", "Outline",
723 DEF_LINE_OUTLINE_COLOR, Tk_Offset(Line, builtinPen.symbol.outlineColor),
724 TK_CONFIG_COLOR_ONLY, &bltColorOption},
725 {TK_CONFIG_CUSTOM, "-outline", "outline", "Outline",
726 DEF_LINE_OUTLINE_MONO, Tk_Offset(Line, builtinPen.symbol.outlineColor),
727 TK_CONFIG_MONO_ONLY, &bltColorOption},
728 {TK_CONFIG_CUSTOM, "-outlinewidth", "outlineWidth", "OutlineWidth",
729 DEF_LINE_OUTLINE_WIDTH, Tk_Offset(Line, builtinPen.symbol.outlineWidth),
730 TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
731 {TK_CONFIG_CUSTOM, "-pen", "pen", "Pen",
732 (char *)NULL, Tk_Offset(Line, normalPenPtr),
733 TK_CONFIG_NULL_OK, &bltLinePenOption},
734 {TK_CONFIG_CUSTOM, "-pixels", "pixels", "Pixels",
735 DEF_LINE_PIXELS, Tk_Offset(Line, builtinPen.symbol.size), 0,
736 &bltDistanceOption},
737 {TK_CONFIG_BOOLEAN, "-scalesymbols", "scaleSymbols", "ScaleSymbols",
738 DEF_LINE_SCALE_SYMBOLS, Tk_Offset(Line, scaleSymbols),
739 TK_CONFIG_DONT_SET_DEFAULT},
740 {TK_CONFIG_CUSTOM, "-showerrorbars", "showErrorBars", "ShowErrorBars",
741 DEF_LINE_SHOW_ERRORBARS, Tk_Offset(Line, builtinPen.errorBarShow),
742 TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption},
743 {TK_CONFIG_CUSTOM, "-showvalues", "showValues", "ShowValues",
744 DEF_PEN_SHOW_VALUES, Tk_Offset(Line, builtinPen.valueShow),
745 TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption},
746 {TK_CONFIG_CUSTOM, "-smooth", "smooth", "Smooth",
747 DEF_LINE_SMOOTH, Tk_Offset(Line, reqSmooth),
748 TK_CONFIG_DONT_SET_DEFAULT, &smoothOption},
749 {TK_CONFIG_CUSTOM, "-styles", "styles", "Styles",
750 DEF_LINE_STYLES, Tk_Offset(Line, palette),
751 TK_CONFIG_NULL_OK, &stylesOption},
752 {TK_CONFIG_CUSTOM, "-symbol", "symbol", "Symbol",
753 DEF_LINE_SYMBOL, Tk_Offset(Line, builtinPen.symbol),
754 TK_CONFIG_DONT_SET_DEFAULT, &symbolOption},
755 {TK_CONFIG_ANCHOR, "-valueanchor", "valueAnchor", "ValueAnchor",
756 DEF_PEN_VALUE_ANCHOR,
757 Tk_Offset(Line, builtinPen.valueStyle.anchor), 0},
758 {TK_CONFIG_COLOR, "-valuecolor", "valueColor", "ValueColor",
759 DEF_PEN_VALUE_COLOR, Tk_Offset(Line, builtinPen.valueStyle.color), 0},
760 {TK_CONFIG_FONT, "-valuefont", "valueFont", "ValueFont",
761 DEF_PEN_VALUE_FONT, Tk_Offset(Line, builtinPen.valueStyle.font), 0},
762 {TK_CONFIG_STRING, "-valueformat", "valueFormat", "ValueFormat",
763 DEF_PEN_VALUE_FORMAT, Tk_Offset(Line, builtinPen.valueFormat),
764 TK_CONFIG_NULL_OK},
765 {TK_CONFIG_DOUBLE, "-valuerotate", "valueRotate", "ValueRotate",
766 DEF_PEN_VALUE_ROTATE, Tk_Offset(Line, builtinPen.valueStyle.theta), 0},
767 {TK_CONFIG_CUSTOM, "-valueshadow", "valueShadow", "ValueShadow",
768 DEF_PEN_VALUE_SHADOW, Tk_Offset(Line, builtinPen.valueStyle.shadow), 0,
769 &bltShadowOption},
770 {TK_CONFIG_CUSTOM, "-weights", "weights", "Weights",
771 (char *)NULL, Tk_Offset(Line, w), 0, &bltDataOption},
772 {TK_CONFIG_CUSTOM, "-x", "xData", "XData",
773 (char *)NULL, Tk_Offset(Line, x), 0, &bltDataOption},
774 {TK_CONFIG_CUSTOM, "-xdata", "xData", "XData",
775 (char *)NULL, Tk_Offset(Line, x), 0, &bltDataOption},
776 {TK_CONFIG_CUSTOM, "-y", "yData", "YData",
777 (char *)NULL, Tk_Offset(Line, y), 0, &bltDataOption},
778 {TK_CONFIG_CUSTOM, "-xerror", "xError", "XError", (char *)NULL,
779 Tk_Offset(Line, xError), 0, &bltDataOption},
780 {TK_CONFIG_CUSTOM, "-ydata", "yData", "YData",
781 (char *)NULL, Tk_Offset(Line, y), 0, &bltDataOption},
782 {TK_CONFIG_CUSTOM, "-yerror", "yError", "YError", (char *)NULL,
783 Tk_Offset(Line, yError), 0, &bltDataOption},
784 {TK_CONFIG_CUSTOM, "-xhigh", "xHigh", "XHigh", (char *)NULL,
785 Tk_Offset(Line, xHigh), 0, &bltDataOption},
786 {TK_CONFIG_CUSTOM, "-xlow", "xLow", "XLow", (char *)NULL,
787 Tk_Offset(Line, xLow), 0, &bltDataOption},
788 {TK_CONFIG_CUSTOM, "-yhigh", "yHigh", "YHigh", (char *)NULL,
789 Tk_Offset(Line, xHigh), 0, &bltDataOption},
790 {TK_CONFIG_CUSTOM, "-ylow", "yLow", "YLow", (char *)NULL,
791 Tk_Offset(Line, yLow), 0, &bltDataOption},
792 {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
793};
794
795static Tk_ConfigSpec linePenConfigSpecs[] =
796{
797 {TK_CONFIG_COLOR, "-color", "color", "Color",
798 DEF_PEN_ACTIVE_COLOR, Tk_Offset(LinePen, traceColor),
799 TK_CONFIG_COLOR_ONLY | ACTIVE_PEN},
800 {TK_CONFIG_COLOR, "-color", "color", "Color",
801 DEF_PEN_ACTIVE_MONO, Tk_Offset(LinePen, traceColor),
802 TK_CONFIG_MONO_ONLY | ACTIVE_PEN},
803 {TK_CONFIG_COLOR, "-color", "color", "Color",
804 DEF_PEN_NORMAL_COLOR, Tk_Offset(LinePen, traceColor),
805 TK_CONFIG_COLOR_ONLY | NORMAL_PEN},
806 {TK_CONFIG_COLOR, "-color", "color", "Color",
807 DEF_PEN_NORMAL_MONO, Tk_Offset(LinePen, traceColor),
808 TK_CONFIG_MONO_ONLY | NORMAL_PEN},
809 {TK_CONFIG_CUSTOM, "-dashes", "dashes", "Dashes",
810 DEF_PEN_DASHES, Tk_Offset(LinePen, traceDashes),
811 TK_CONFIG_NULL_OK | ALL_PENS, &bltDashesOption},
812 {TK_CONFIG_CUSTOM, "-errorbarcolor", "errorBarColor", "ErrorBarColor",
813 DEF_LINE_ERRORBAR_COLOR, Tk_Offset(LinePen, errorBarColor),
814 ALL_PENS, &bltColorOption},
815 {TK_CONFIG_CUSTOM, "-errorbarwidth", "errorBarWidth", "ErrorBarWidth",
816 DEF_LINE_ERRORBAR_LINE_WIDTH, Tk_Offset(LinePen, errorBarLineWidth),
817 ALL_PENS | TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
818 {TK_CONFIG_CUSTOM, "-errorbarcap", "errorBarCap",
819 "ErrorBarCap", DEF_LINE_ERRORBAR_CAP_WIDTH,
820 Tk_Offset(LinePen, errorBarCapWidth),
821 TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
822 {TK_CONFIG_CUSTOM, "-fill", "fill", "Fill",
823 DEF_PEN_FILL_COLOR, Tk_Offset(LinePen, symbol.fillColor),
824 TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY | ALL_PENS, &bltColorOption},
825 {TK_CONFIG_CUSTOM, "-fill", "fill", "Fill",
826 DEF_PEN_FILL_MONO, Tk_Offset(LinePen, symbol.fillColor),
827 TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY | ALL_PENS, &bltColorOption},
828 {TK_CONFIG_CUSTOM, "-linewidth", "lineWidth", "LineWidth",
829 (char *)NULL, Tk_Offset(LinePen, traceWidth),
830 ALL_PENS | TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
831 {TK_CONFIG_CUSTOM, "-offdash", "offDash", "OffDash",
832 DEF_PEN_OFFDASH_COLOR, Tk_Offset(LinePen, traceOffColor),
833 TK_CONFIG_NULL_OK | TK_CONFIG_COLOR_ONLY | ALL_PENS, &bltColorOption},
834 {TK_CONFIG_CUSTOM, "-offdash", "offDash", "OffDash",
835 DEF_PEN_OFFDASH_MONO, Tk_Offset(LinePen, traceOffColor),
836 TK_CONFIG_NULL_OK | TK_CONFIG_MONO_ONLY | ALL_PENS, &bltColorOption},
837 {TK_CONFIG_CUSTOM, "-outline", "outline", "Outline",
838 DEF_PEN_OUTLINE_COLOR, Tk_Offset(LinePen, symbol.outlineColor),
839 TK_CONFIG_COLOR_ONLY | ALL_PENS, &bltColorOption},
840 {TK_CONFIG_CUSTOM, "-outline", "outline", "Outline",
841 DEF_PEN_OUTLINE_MONO, Tk_Offset(LinePen, symbol.outlineColor),
842 TK_CONFIG_MONO_ONLY | ALL_PENS, &bltColorOption},
843 {TK_CONFIG_CUSTOM, "-outlinewidth", "outlineWidth", "OutlineWidth",
844 DEF_PEN_OUTLINE_WIDTH, Tk_Offset(LinePen, symbol.outlineWidth),
845 TK_CONFIG_DONT_SET_DEFAULT | ALL_PENS, &bltDistanceOption},
846 {TK_CONFIG_CUSTOM, "-pixels", "pixels", "Pixels",
847 DEF_PEN_PIXELS, Tk_Offset(LinePen, symbol.size),
848 ALL_PENS, &bltDistanceOption},
849 {TK_CONFIG_CUSTOM, "-showerrorbars", "showErrorBars", "ShowErrorBars",
850 DEF_LINE_SHOW_ERRORBARS, Tk_Offset(LinePen, errorBarShow),
851 TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption},
852 {TK_CONFIG_CUSTOM, "-showvalues", "showValues", "ShowValues",
853 DEF_PEN_SHOW_VALUES, Tk_Offset(LinePen, valueShow),
854 ALL_PENS | TK_CONFIG_DONT_SET_DEFAULT, &bltFillOption},
855 {TK_CONFIG_CUSTOM, "-symbol", "symbol", "Symbol",
856 DEF_PEN_SYMBOL, Tk_Offset(LinePen, symbol),
857 TK_CONFIG_DONT_SET_DEFAULT | ALL_PENS, &symbolOption},
858 {TK_CONFIG_STRING, "-type", (char *)NULL, (char *)NULL,
859 DEF_PEN_TYPE, Tk_Offset(Pen, typeId), ALL_PENS | TK_CONFIG_NULL_OK},
860 {TK_CONFIG_ANCHOR, "-valueanchor", "valueAnchor", "ValueAnchor",
861 DEF_PEN_VALUE_ANCHOR, Tk_Offset(LinePen, valueStyle.anchor), ALL_PENS},
862 {TK_CONFIG_COLOR, "-valuecolor", "valueColor", "ValueColor",
863 DEF_PEN_VALUE_COLOR, Tk_Offset(LinePen, valueStyle.color), ALL_PENS},
864 {TK_CONFIG_FONT, "-valuefont", "valueFont", "ValueFont",
865 DEF_PEN_VALUE_FONT, Tk_Offset(LinePen, valueStyle.font), ALL_PENS},
866 {TK_CONFIG_STRING, "-valueformat", "valueFormat", "ValueFormat",
867 DEF_PEN_VALUE_FORMAT, Tk_Offset(LinePen, valueFormat),
868 ALL_PENS | TK_CONFIG_NULL_OK},
869 {TK_CONFIG_DOUBLE, "-valuerotate", "valueRotate", "ValueRotate",
870 DEF_PEN_VALUE_ROTATE, Tk_Offset(LinePen, valueStyle.theta), ALL_PENS},
871 {TK_CONFIG_CUSTOM, "-valueshadow", "valueShadow", "ValueShadow",
872 DEF_PEN_VALUE_SHADOW, Tk_Offset(LinePen, valueStyle.shadow),
873 ALL_PENS, &bltShadowOption},
874 {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
875};
876
877typedef double (DistanceProc) _ANSI_ARGS_((int x, int y, Point2D *p,
878 Point2D *q, Point2D *t));
879
880/* Forward declarations */
881static PenConfigureProc ConfigurePen;
882static PenDestroyProc DestroyPen;
883static ElementClosestProc ClosestLine;
884static ElementConfigProc ConfigureLine;
885static ElementDestroyProc DestroyLine;
886static ElementDrawProc DrawActiveLine;
887static ElementDrawProc DrawNormalLine;
888static ElementDrawSymbolProc DrawSymbol;
889static ElementExtentsProc GetLineExtents;
890static ElementToPostScriptProc ActiveLineToPostScript;
891static ElementToPostScriptProc NormalLineToPostScript;
892static ElementSymbolToPostScriptProc SymbolToPostScript;
893static ElementMapProc MapLine;
894static DistanceProc DistanceToY;
895static DistanceProc DistanceToX;
896static DistanceProc DistanceToLine;
897static Blt_TileChangedProc TileChangedProc;
898
899#ifdef WIN32
900
901static int tkpWinRopModes[] =
902{
903 R2_BLACK, /* GXclear */
904 R2_MASKPEN, /* GXand */
905 R2_MASKPENNOT, /* GXandReverse */
906 R2_COPYPEN, /* GXcopy */
907 R2_MASKNOTPEN, /* GXandInverted */
908 R2_NOT, /* GXnoop */
909 R2_XORPEN, /* GXxor */
910 R2_MERGEPEN, /* GXor */
911 R2_NOTMERGEPEN, /* GXnor */
912 R2_NOTXORPEN, /* GXequiv */
913 R2_NOT, /* GXinvert */
914 R2_MERGEPENNOT, /* GXorReverse */
915 R2_NOTCOPYPEN, /* GXcopyInverted */
916 R2_MERGENOTPEN, /* GXorInverted */
917 R2_NOTMASKPEN, /* GXnand */
918 R2_WHITE /* GXset */
919};
920
921#endif
922
923INLINE static int
924Round(x)
925 register double x;
926{
927 return (int) (x + ((x < 0.0) ? -0.5 : 0.5));
928}
929
930/*
931 * ----------------------------------------------------------------------
932 * Custom configuration option (parse and print) routines
933 * ----------------------------------------------------------------------
934 */
935
936static int
937StringToBitmap(interp, tkwin, symbolPtr, string)
938 Tcl_Interp *interp;
939 Tk_Window tkwin;
940 Symbol *symbolPtr;
941 char *string;
942{
943 Pixmap bitmap, mask;
944 char **elemArr;
945 int nElems;
946 int result;
947
948 if (Tcl_SplitList(interp, string, &nElems, &elemArr) != TCL_OK) {
949 return TCL_ERROR;
950 }
951
952 if (nElems > 2) {
953 Tcl_AppendResult(interp, "too many elements in bitmap list \"", string,
954 "\": should be \"bitmap mask\"", (char *)NULL);
955 result = TCL_ERROR;
956 goto error;
957 }
958 mask = None;
959 bitmap = Tk_GetBitmap(interp, tkwin, Tk_GetUid(elemArr[0]));
960 if (bitmap == None) {
961 result = TCL_BREAK;
962 Tcl_ResetResult(interp);
963 goto error;
964 }
965 if ((nElems > 1) && (elemArr[1][0] != '\0')) {
966 mask = Tk_GetBitmap(interp, tkwin, Tk_GetUid(elemArr[1]));
967 if (mask == None) {
968 Tk_FreeBitmap(Tk_Display(tkwin), bitmap);
969 result = TCL_ERROR;
970 goto error;
971 }
972 }
973 Blt_Free(elemArr);
974 if (symbolPtr->bitmap != None) {
975 Tk_FreeBitmap(Tk_Display(tkwin), symbolPtr->bitmap);
976 }
977 symbolPtr->bitmap = bitmap;
978 if (symbolPtr->mask != None) {
979 Tk_FreeBitmap(Tk_Display(tkwin), symbolPtr->mask);
980 }
981 symbolPtr->mask = mask;
982 return TCL_OK;
983 error:
984 Blt_Free(elemArr);
985 return result;
986}
987
988/*ARGSUSED*/
989static char *
990PatternToString(clientData, tkwin, widgRec, offset, freeProcPtr)
991 ClientData clientData; /* Not used. */
992 Tk_Window tkwin;
993 char *widgRec; /* Element information record */
994 int offset; /* Offset of field in record */
995 Tcl_FreeProc **freeProcPtr; /* Not used. */
996{
997 Pixmap stipple = *(Pixmap *)(widgRec + offset);
998
999 if (stipple == None) {
1000 return "";
1001 }
1002 if (stipple == PATTERN_SOLID) {
1003 return "solid";
1004 }
1005 return Tk_NameOfBitmap(Tk_Display(tkwin), stipple);
1006}
1007
1008/*ARGSUSED*/
1009static int
1010StringToPattern(clientData, interp, tkwin, string, widgRec, offset)
1011 ClientData clientData; /* Not used. */
1012 Tcl_Interp *interp; /* Interpreter to send results back to */
1013 Tk_Window tkwin; /* Not used. */
1014 char *string; /* String representing field */
1015 char *widgRec; /* Element information record */
1016 int offset; /* Offset of field in record */
1017{
1018 Pixmap *stipplePtr = (Pixmap *)(widgRec + offset);
1019 Pixmap stipple;
1020
1021 if ((string == NULL) || (string[0] == '\0')) {
1022 stipple = None;
1023 } else if (strcmp(string, "solid") == 0) {
1024 stipple = PATTERN_SOLID;
1025 } else {
1026 stipple = Tk_GetBitmap(interp, tkwin, Tk_GetUid(string));
1027 if (stipple == None) {
1028 return TCL_ERROR;
1029 }
1030 }
1031 if ((*stipplePtr != None) && (*stipplePtr != PATTERN_SOLID)) {
1032 Tk_FreeBitmap(Tk_Display(tkwin), *stipplePtr);
1033 }
1034 *stipplePtr = stipple;
1035 return TCL_OK;
1036}
1037
1038
1039/*
1040 *----------------------------------------------------------------------
1041 *
1042 * NameOfSymbol --
1043 *
1044 * Converts the symbol value into its string representation.
1045 *
1046 * Results:
1047 * The static string representing the symbol type is returned.
1048 *
1049 *----------------------------------------------------------------------
1050 */
1051static char *
1052NameOfSymbol(symbolPtr)
1053 Symbol *symbolPtr;
1054{
1055 switch (symbolPtr->type) {
1056 case SYMBOL_NONE:
1057 return "none";
1058 case SYMBOL_SQUARE:
1059 return "square";
1060 case SYMBOL_CIRCLE:
1061 return "circle";
1062 case SYMBOL_DIAMOND:
1063 return "diamond";
1064 case SYMBOL_PLUS:
1065 return "plus";
1066 case SYMBOL_CROSS:
1067 return "cross";
1068 case SYMBOL_SPLUS:
1069 return "splus";
1070 case SYMBOL_SCROSS:
1071 return "scross";
1072 case SYMBOL_TRIANGLE:
1073 return "triangle";
1074 case SYMBOL_ARROW:
1075 return "arrow";
1076 case SYMBOL_BITMAP:
1077 return "bitmap";
1078 }
1079 return NULL;
1080}
1081
1082/*
1083 *----------------------------------------------------------------------
1084 *
1085 * StringToSymbol --
1086 *
1087 * Convert the string representation of a line style or symbol name
1088 * into its numeric form.
1089 *
1090 * Results:
1091 * The return value is a standard Tcl result. The symbol type is
1092 * written into the widget record.
1093 *
1094 *----------------------------------------------------------------------
1095 */
1096/*ARGSUSED*/
1097static int
1098StringToSymbol(clientData, interp, tkwin, string, widgRec, offset)
1099 ClientData clientData; /* Not used. */
1100 Tcl_Interp *interp; /* Interpreter to send results back to */
1101 Tk_Window tkwin; /* Not used. */
1102 char *string; /* String representing symbol type */
1103 char *widgRec; /* Element information record */
1104 int offset; /* Offset of symbol type field in record */
1105{
1106 Symbol *symbolPtr = (Symbol *)(widgRec + offset);
1107 unsigned int length;
1108 char c;
1109
1110 c = string[0];
1111 length = strlen(string);
1112 if (c == '\0') {
1113 symbolPtr->type = SYMBOL_NONE;
1114 } else if ((c == 'n') && (strncmp(string, "none", length) == 0)) {
1115 symbolPtr->type = SYMBOL_NONE;
1116 } else if ((c == 'c') && (length > 1) &&
1117 (strncmp(string, "circle", length) == 0)) {
1118 symbolPtr->type = SYMBOL_CIRCLE;
1119 } else if ((c == 's') && (length > 1) &&
1120 (strncmp(string, "square", length) == 0)) {
1121 symbolPtr->type = SYMBOL_SQUARE;
1122 } else if ((c == 'd') && (strncmp(string, "diamond", length) == 0)) {
1123 symbolPtr->type = SYMBOL_DIAMOND;
1124 } else if ((c == 'p') && (strncmp(string, "plus", length) == 0)) {
1125 symbolPtr->type = SYMBOL_PLUS;
1126 } else if ((c == 'c') && (length > 1) &&
1127 (strncmp(string, "cross", length) == 0)) {
1128 symbolPtr->type = SYMBOL_CROSS;
1129 } else if ((c == 's') && (length > 1) &&
1130 (strncmp(string, "splus", length) == 0)) {
1131 symbolPtr->type = SYMBOL_SPLUS;
1132 } else if ((c == 's') && (length > 1) &&
1133 (strncmp(string, "scross", length) == 0)) {
1134 symbolPtr->type = SYMBOL_SCROSS;
1135 } else if ((c == 't') && (strncmp(string, "triangle", length) == 0)) {
1136 symbolPtr->type = SYMBOL_TRIANGLE;
1137 } else if ((c == 'a') && (strncmp(string, "arrow", length) == 0)) {
1138 symbolPtr->type = SYMBOL_ARROW;
1139 } else {
1140 int result;
1141
1142 result = StringToBitmap(interp, tkwin, symbolPtr, string);
1143 if (result != TCL_OK) {
1144 if (result != TCL_ERROR) {
1145 Tcl_AppendResult(interp, "bad symbol \"", string,
1146"\": should be \"none\", \"circle\", \"square\", \"diamond\", \"plus\", \
1147\"cross\", \"splus\", \"scross\", \"triangle\", \"arrow\" \
1148or the name of a bitmap", (char *)NULL);
1149 }
1150 return TCL_ERROR;
1151 }
1152 symbolPtr->type = SYMBOL_BITMAP;
1153 }
1154 return TCL_OK;
1155}
1156
1157/*
1158 *----------------------------------------------------------------------
1159 *
1160 * SymbolToString --
1161 *
1162 * Convert the symbol value into a string.
1163 *
1164 * Results:
1165 * The string representing the symbol type or line style is returned.
1166 *
1167 *----------------------------------------------------------------------
1168 */
1169/*ARGSUSED*/
1170static char *
1171SymbolToString(clientData, tkwin, widgRec, offset, freeProcPtr)
1172 ClientData clientData; /* Not used. */
1173 Tk_Window tkwin;
1174 char *widgRec; /* Element information record */
1175 int offset; /* Offset of symbol type field in record */
1176 Tcl_FreeProc **freeProcPtr; /* Not used. */
1177{
1178 Symbol *symbolPtr = (Symbol *)(widgRec + offset);
1179 char *result;
1180
1181 if (symbolPtr->type == SYMBOL_BITMAP) {
1182 Tcl_DString dString;
1183
1184 Tcl_DStringInit(&dString);
1185 Tcl_DStringAppendElement(&dString,
1186 Tk_NameOfBitmap(Tk_Display(tkwin), symbolPtr->bitmap));
1187 Tcl_DStringAppendElement(&dString, (symbolPtr->mask == None) ? "" :
1188 Tk_NameOfBitmap(Tk_Display(tkwin), symbolPtr->mask));
1189 result = Blt_Strdup(Tcl_DStringValue(&dString));
1190 Tcl_DStringFree(&dString);
1191 *freeProcPtr = (Tcl_FreeProc *)Blt_Free;
1192 } else {
1193 result = NameOfSymbol(symbolPtr);
1194 }
1195 return result;
1196}
1197
1198/*
1199 *----------------------------------------------------------------------
1200 *
1201 * NameOfSmooth --
1202 *
1203 * Converts the smooth value into its string representation.
1204 *
1205 * Results:
1206 * The static string representing the smooth type is returned.
1207 *
1208 *----------------------------------------------------------------------
1209 */
1210static char *
1211NameOfSmooth(value)
1212 Smoothing value;
1213{
1214 if ((value < 0) || (value >= PEN_SMOOTH_LAST)) {
1215 return "unknown smooth value";
1216 }
1217 return smoothingInfo[value].name;
1218}
1219
1220/*
1221 *----------------------------------------------------------------------
1222 *
1223 * StringToSmooth --
1224 *
1225 * Convert the string representation of a line style or smooth name
1226 * into its numeric form.
1227 *
1228 * Results:
1229 * The return value is a standard Tcl result. The smooth type is
1230 * written into the widget record.
1231 *
1232 *----------------------------------------------------------------------
1233 */
1234/*ARGSUSED*/
1235static int
1236StringToSmooth(clientData, interp, tkwin, string, widgRec, offset)
1237 ClientData clientData; /* Not used. */
1238 Tcl_Interp *interp; /* Interpreter to send results back to */
1239 Tk_Window tkwin; /* Not used. */
1240 char *string; /* String representing smooth type */
1241 char *widgRec; /* Element information record */
1242 int offset; /* Offset of smooth type field in record */
1243{
1244 Smoothing *valuePtr = (Smoothing *)(widgRec + offset);
1245 register SmoothingInfo *siPtr;
1246
1247 for (siPtr = smoothingInfo; siPtr->name != NULL; siPtr++) {
1248 if (strcmp(string, siPtr->name) == 0) {
1249 *valuePtr = siPtr->value;
1250 return TCL_OK;
1251 }
1252 }
1253 Tcl_AppendResult(interp, "bad smooth value \"", string, "\": should be \
1254linear, step, natural, or quadratic", (char *)NULL);
1255 return TCL_ERROR;
1256}
1257
1258/*
1259 *----------------------------------------------------------------------
1260 *
1261 * SmoothToString --
1262 *
1263 * Convert the smooth value into a string.
1264 *
1265 * Results:
1266 * The string representing the smooth type or line style is returned.
1267 *
1268 *----------------------------------------------------------------------
1269 */
1270/*ARGSUSED*/
1271static char *
1272SmoothToString(clientData, tkwin, widgRec, offset, freeProcPtr)
1273 ClientData clientData; /* Not used. */
1274 Tk_Window tkwin; /* Not used. */
1275 char *widgRec; /* Element information record */
1276 int offset; /* Offset of smooth type field in record */
1277 Tcl_FreeProc **freeProcPtr; /* Not used. */
1278{
1279 int smooth = *(int *)(widgRec + offset);
1280
1281 return NameOfSmooth(smooth);
1282}
1283
1284/*
1285 *----------------------------------------------------------------------
1286 *
1287 * StringToPenDir --
1288 *
1289 * Convert the string representation of a line style or symbol name
1290 * into its numeric form.
1291 *
1292 * Results:
1293 * The return value is a standard Tcl result. The symbol type is
1294 * written into the widget record.
1295 *
1296 *----------------------------------------------------------------------
1297 */
1298/*ARGSUSED*/
1299static int
1300StringToPenDir(clientData, interp, tkwin, string, widgRec, offset)
1301 ClientData clientData; /* Not used. */
1302 Tcl_Interp *interp; /* Interpreter to send results back to */
1303 Tk_Window tkwin; /* Not used. */
1304 char *string; /* String representing pen direction */
1305 char *widgRec; /* Element information record */
1306 int offset; /* Offset of pen direction field in record */
1307{
1308 int *penDirPtr = (int *)(widgRec + offset);
1309 unsigned int length;
1310 char c;
1311
1312 c = string[0];
1313 length = strlen(string);
1314 if ((c == 'i') && (strncmp(string, "increasing", length) == 0)) {
1315 *penDirPtr = PEN_INCREASING;
1316 } else if ((c == 'd') && (strncmp(string, "decreasing", length) == 0)) {
1317 *penDirPtr = PEN_DECREASING;
1318 } else if ((c == 'b') && (strncmp(string, "both", length) == 0)) {
1319 *penDirPtr = PEN_BOTH_DIRECTIONS;
1320 } else {
1321 Tcl_AppendResult(interp, "bad trace value \"", string,
1322 "\" : should be \"increasing\", \"decreasing\", or \"both\"",
1323 (char *)NULL);
1324 return TCL_ERROR;
1325 }
1326 return TCL_OK;
1327}
1328
1329/*
1330 *----------------------------------------------------------------------
1331 *
1332 * NameOfPenDir --
1333 *
1334 * Convert the pen direction into a string.
1335 *
1336 * Results:
1337 * The static string representing the pen direction is returned.
1338 *
1339 *----------------------------------------------------------------------
1340 */
1341static char *
1342NameOfPenDir(penDir)
1343 int penDir; /* Direction for pen drawing between points */
1344{
1345 switch (penDir) {
1346 case PEN_INCREASING:
1347 return "increasing";
1348 case PEN_DECREASING:
1349 return "decreasing";
1350 case PEN_BOTH_DIRECTIONS:
1351 return "both";
1352 default:
1353 return "unknown trace direction";
1354 }
1355}
1356
1357/*
1358 *----------------------------------------------------------------------
1359 *
1360 * PenDirToString --
1361 *
1362 * Convert the pen direction into a string.
1363 *
1364 * Results:
1365 * The string representing the pen drawing direction is returned.
1366 *
1367 *----------------------------------------------------------------------
1368 */
1369/*ARGSUSED*/
1370static char *
1371PenDirToString(clientData, tkwin, widgRec, offset, freeProcPtr)
1372 ClientData clientData; /* Not used. */
1373 Tk_Window tkwin; /* Not used. */
1374 char *widgRec; /* Element information record */
1375 int offset; /* Offset of pen direction field in record */
1376 Tcl_FreeProc **freeProcPtr; /* Not used. */
1377{
1378 int penDir = *(int *)(widgRec + offset);
1379
1380 return NameOfPenDir(penDir);
1381}
1382
1383
1384/*
1385 * Clear the number of points and segments, in case there are no
1386 * segments or points
1387 */
1388static void
1389ClearPalette(palette)
1390 Blt_Chain *palette;
1391{
1392 register LinePenStyle *stylePtr;
1393 Blt_ChainLink *linkPtr;
1394
1395 for (linkPtr = Blt_ChainFirstLink(palette); linkPtr != NULL;
1396 linkPtr = Blt_ChainNextLink(linkPtr)) {
1397 stylePtr = Blt_ChainGetValue(linkPtr);
1398 stylePtr->nStrips = stylePtr->nSymbolPts = 0;
1399 stylePtr->xErrorBarCnt = stylePtr->yErrorBarCnt = 0;
1400 }
1401}
1402
1403
1404
1405/*
1406 *----------------------------------------------------------------------
1407 *
1408 * ConfigurePen --
1409 *
1410 * Sets up the appropriate configuration parameters in the GC.
1411 * It is assumed the parameters have been previously set by
1412 * a call to Tk_ConfigureWidget.
1413 *
1414 * Results:
1415 * The return value is a standard Tcl result. If TCL_ERROR is
1416 * returned, then interp->result contains an error message.
1417 *
1418 * Side effects:
1419 * Configuration information such as line width, line style, color
1420 * etc. get set in a new GC.
1421 *
1422 *----------------------------------------------------------------------
1423 */
1424/*ARGSUSED*/
1425static int
1426ConfigurePen(graphPtr, penPtr)
1427 Graph *graphPtr;
1428 Pen *penPtr;
1429{
1430 LinePen *lpPtr = (LinePen *)penPtr;
1431 unsigned long gcMask;
1432 GC newGC;
1433 XGCValues gcValues;
1434 XColor *colorPtr;
1435
1436 Blt_ResetTextStyle(graphPtr->tkwin, &(lpPtr->valueStyle));
1437 /*
1438 * Set the outline GC for this pen: GCForeground is outline color.
1439 * GCBackground is the fill color (only used for bitmap symbols).
1440 */
1441 gcMask = (GCLineWidth | GCForeground);
1442 colorPtr = lpPtr->symbol.outlineColor;
1443 if (colorPtr == COLOR_DEFAULT) {
1444 colorPtr = lpPtr->traceColor;
1445 }
1446 gcValues.foreground = colorPtr->pixel;
1447 if (lpPtr->symbol.type == SYMBOL_BITMAP) {
1448 colorPtr = lpPtr->symbol.fillColor;
1449 if (colorPtr == COLOR_DEFAULT) {
1450 colorPtr = lpPtr->traceColor;
1451 }
1452 /*
1453 * Set a clip mask if either
1454 * 1) no background color was designated or
1455 * 2) a masking bitmap was specified.
1456 *
1457 * These aren't necessarily the bitmaps we'll be using for
1458 * clipping. But this makes it unlikely that anyone else will
1459 * be sharing this GC when we set the clip origin (at the time
1460 * the bitmap is drawn).
1461 */
1462 if (colorPtr != NULL) {
1463 gcValues.background = colorPtr->pixel;
1464 gcMask |= GCBackground;
1465 if (lpPtr->symbol.mask != None) {
1466 gcValues.clip_mask = lpPtr->symbol.mask;
1467 gcMask |= GCClipMask;
1468 }
1469 } else {
1470 gcValues.clip_mask = lpPtr->symbol.bitmap;
1471 gcMask |= GCClipMask;
1472 }
1473 }
1474 gcValues.line_width = LineWidth(lpPtr->symbol.outlineWidth);
1475 newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues);
1476 if (lpPtr->symbol.outlineGC != NULL) {
1477 Tk_FreeGC(graphPtr->display, lpPtr->symbol.outlineGC);
1478 }
1479 lpPtr->symbol.outlineGC = newGC;
1480
1481 /* Fill GC for symbols: GCForeground is fill color */
1482
1483 gcMask = (GCLineWidth | GCForeground);
1484 colorPtr = lpPtr->symbol.fillColor;
1485 if (colorPtr == COLOR_DEFAULT) {
1486 colorPtr = lpPtr->traceColor;
1487 }
1488 newGC = NULL;
1489 if (colorPtr != NULL) {
1490 gcValues.foreground = colorPtr->pixel;
1491 newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues);
1492 }
1493 if (lpPtr->symbol.fillGC != NULL) {
1494 Tk_FreeGC(graphPtr->display, lpPtr->symbol.fillGC);
1495 }
1496 lpPtr->symbol.fillGC = newGC;
1497
1498 /* Line segments */
1499
1500 gcMask = (GCLineWidth | GCForeground | GCLineStyle | GCCapStyle |
1501 GCJoinStyle);
1502 gcValues.cap_style = CapButt;
1503 gcValues.join_style = JoinRound;
1504 gcValues.line_style = LineSolid;
1505 gcValues.line_width = LineWidth(lpPtr->traceWidth);
1506
1507 colorPtr = lpPtr->traceOffColor;
1508 if (colorPtr == COLOR_DEFAULT) {
1509 colorPtr = lpPtr->traceColor;
1510 }
1511 if (colorPtr != NULL) {
1512 gcMask |= GCBackground;
1513 gcValues.background = colorPtr->pixel;
1514 }
1515 gcValues.foreground = lpPtr->traceColor->pixel;
1516 if (LineIsDashed(lpPtr->traceDashes)) {
1517 gcValues.line_width = lpPtr->traceWidth;
1518 gcValues.line_style =
1519 (colorPtr == NULL) ? LineOnOffDash : LineDoubleDash;
1520 }
1521 newGC = Blt_GetPrivateGC(graphPtr->tkwin, gcMask, &gcValues);
1522 if (lpPtr->traceGC != NULL) {
1523 Blt_FreePrivateGC(graphPtr->display, lpPtr->traceGC);
1524 }
1525 if (LineIsDashed(lpPtr->traceDashes)) {
1526 lpPtr->traceDashes.offset = lpPtr->traceDashes.values[0] / 2;
1527 Blt_SetDashes(graphPtr->display, newGC, &(lpPtr->traceDashes));
1528 }
1529 lpPtr->traceGC = newGC;
1530
1531 gcMask = (GCLineWidth | GCForeground);
1532 colorPtr = lpPtr->errorBarColor;
1533 if (colorPtr == COLOR_DEFAULT) {
1534 colorPtr = lpPtr->traceColor;
1535 }
1536 gcValues.line_width = LineWidth(lpPtr->errorBarLineWidth);
1537 gcValues.foreground = colorPtr->pixel;
1538 newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues);
1539 if (lpPtr->errorBarGC != NULL) {
1540 Tk_FreeGC(graphPtr->display, lpPtr->errorBarGC);
1541 }
1542 lpPtr->errorBarGC = newGC;
1543
1544 return TCL_OK;
1545}
1546
1547/*
1548 *----------------------------------------------------------------------
1549 *
1550 * DestroyPen --
1551 *
1552 * Release memory and resources allocated for the style.
1553 *
1554 * Results:
1555 * None.
1556 *
1557 * Side effects:
1558 * Everything associated with the pen style is freed up.
1559 *
1560 *----------------------------------------------------------------------
1561 */
1562static void
1563DestroyPen(graphPtr, penPtr)
1564 Graph *graphPtr;
1565 Pen *penPtr;
1566{
1567 LinePen *lpPtr = (LinePen *)penPtr;
1568
1569 Blt_FreeTextStyle(graphPtr->display, &(lpPtr->valueStyle));
1570 if (lpPtr->symbol.outlineGC != NULL) {
1571 Tk_FreeGC(graphPtr->display, lpPtr->symbol.outlineGC);
1572 }
1573 if (lpPtr->symbol.fillGC != NULL) {
1574 Tk_FreeGC(graphPtr->display, lpPtr->symbol.fillGC);
1575 }
1576 if (lpPtr->errorBarGC != NULL) {
1577 Tk_FreeGC(graphPtr->display, lpPtr->errorBarGC);
1578 }
1579 if (lpPtr->traceGC != NULL) {
1580 Blt_FreePrivateGC(graphPtr->display, lpPtr->traceGC);
1581 }
1582 if (lpPtr->symbol.bitmap != None) {
1583 Tk_FreeBitmap(graphPtr->display, lpPtr->symbol.bitmap);
1584 lpPtr->symbol.bitmap = None;
1585 }
1586 if (lpPtr->symbol.mask != None) {
1587 Tk_FreeBitmap(graphPtr->display, lpPtr->symbol.mask);
1588 lpPtr->symbol.mask = None;
1589 }
1590}
1591
1592
1593static void
1594InitPen(penPtr)
1595 LinePen *penPtr;
1596{
1597 Blt_InitTextStyle(&penPtr->valueStyle);
1598 penPtr->configProc = ConfigurePen;
1599 penPtr->configSpecs = linePenConfigSpecs;
1600 penPtr->destroyProc = DestroyPen;
1601 penPtr->errorBarLineWidth = 1;
1602 penPtr->errorBarShow = SHOW_BOTH;
1603 penPtr->flags = NORMAL_PEN;
1604 penPtr->name = "";
1605 penPtr->symbol.bitmap = penPtr->symbol.mask = None;
1606 penPtr->symbol.outlineColor = penPtr->symbol.fillColor = COLOR_DEFAULT;
1607 penPtr->symbol.outlineWidth = penPtr->traceWidth = 1;
1608 penPtr->symbol.type = SYMBOL_CIRCLE;
1609 penPtr->valueShow = SHOW_NONE;
1610}
1611
1612Pen *
1613Blt_LinePen(penName)
1614 char *penName;
1615{
1616 LinePen *penPtr;
1617
1618 penPtr = Blt_Calloc(1, sizeof(LinePen));
1619 assert(penPtr);
1620 InitPen(penPtr);
1621 penPtr->name = Blt_Strdup(penName);
1622 if (strcmp(penName, "activeLine") == 0) {
1623 penPtr->flags = ACTIVE_PEN;
1624 }
1625 return (Pen *)penPtr;
1626}
1627
1628/*
1629 * ----------------------------------------------------------------------
1630 *
1631 * In this section, the routines deal with building and filling
1632 * the element's data structures with transformed screen
1633 * coordinates. They are triggered from TranformLine which is
1634 * called whenever the data or coordinates axes have changed and
1635 * new screen coordinates need to be calculated.
1636 *
1637 * ----------------------------------------------------------------------
1638 */
1639
1640/*
1641 *----------------------------------------------------------------------
1642 *
1643 * ScaleSymbol --
1644 *
1645 * Returns the scaled size for the line element. Scaling depends
1646 * upon when the base line ranges for the element were set and
1647 * the current range of the graph.
1648 *
1649 * Results:
1650 * The new size of the symbol, after considering how much the
1651 * graph has been scaled, is returned.
1652 *
1653 *----------------------------------------------------------------------
1654 */
1655static int
1656ScaleSymbol(elemPtr, normalSize)
1657 Element *elemPtr;
1658 int normalSize;
1659{
1660 int maxSize;
1661 double scale;
1662 int newSize;
1663
1664 scale = 1.0;
1665 if (elemPtr->scaleSymbols) {
1666 double xRange, yRange;
1667
1668 xRange = (elemPtr->axes.x->max - elemPtr->axes.x->min);
1669 yRange = (elemPtr->axes.y->max - elemPtr->axes.y->min);
1670 if (elemPtr->flags & SCALE_SYMBOL) {
1671 /* Save the ranges as a baseline for future scaling. */
1672 elemPtr->xRange = xRange;
1673 elemPtr->yRange = yRange;
1674 elemPtr->flags &= ~SCALE_SYMBOL;
1675 } else {
1676 double xScale, yScale;
1677
1678 /* Scale the symbol by the smallest change in the X or Y axes */
1679 xScale = elemPtr->xRange / xRange;
1680 yScale = elemPtr->yRange / yRange;
1681 scale = MIN(xScale, yScale);
1682 }
1683 }
1684 newSize = Round(normalSize * scale);
1685
1686 /*
1687 * Don't let the size of symbols go unbounded. Both X and Win32
1688 * drawing routines assume coordinates to be a signed short int.
1689 */
1690 maxSize = (int)MIN(elemPtr->graphPtr->hRange, elemPtr->graphPtr->vRange);
1691 if (newSize > maxSize) {
1692 newSize = maxSize;
1693 }
1694
1695 /* Make the symbol size odd so that its center is a single pixel. */
1696 newSize |= 0x01;
1697 return newSize;
1698}
1699
1700/*
1701 *----------------------------------------------------------------------
1702 *
1703 * GetScreenPoints --
1704 *
1705 * Generates a coordinate array of transformed screen coordinates
1706 * from the data points.
1707 *
1708 * Results:
1709 * The transformed screen coordinates are returned.
1710 *
1711 * Side effects:
1712 * Memory is allocated for the coordinate array.
1713 *
1714 *----------------------------------------------------------------------
1715 */
1716static void
1717GetScreenPoints(graphPtr, linePtr, mapPtr)
1718 Graph *graphPtr;
1719 Line *linePtr;
1720 MapInfo *mapPtr;
1721{
1722 double *x, *y;
1723 register int i, n;
1724 register int count;
1725 register Point2D *screenPts;
1726 register int *indices;
1727
1728 n = NumberOfPoints(linePtr);
1729 x = linePtr->x.valueArr;
1730 y = linePtr->y.valueArr;
1731 screenPts = Blt_Malloc(sizeof(Point2D) * n);
1732 assert(screenPts);
1733 indices = Blt_Malloc(sizeof(int) * n);
1734 assert(indices);
1735
1736 count = 0; /* Count the valid screen coordinates */
1737 if (graphPtr->inverted) {
1738 for (i = 0; i < n; i++) {
1739 if ((FINITE(x[i])) && (FINITE(y[i]))) {
1740 screenPts[count].x = Blt_HMap(graphPtr, linePtr->axes.y, y[i]);
1741 screenPts[count].y = Blt_VMap(graphPtr, linePtr->axes.x, x[i]);
1742 indices[count] = i;
1743 count++;
1744 }
1745 }
1746 } else {
1747 for (i = 0; i < n; i++) {
1748 if ((FINITE(x[i])) && (FINITE(y[i]))) {
1749 screenPts[count].x = Blt_HMap(graphPtr, linePtr->axes.x, x[i]);
1750 screenPts[count].y = Blt_VMap(graphPtr, linePtr->axes.y, y[i]);
1751 indices[count] = i;
1752 count++;
1753 }
1754 }
1755 }
1756 mapPtr->screenPts = screenPts;
1757 mapPtr->nScreenPts = count;
1758 mapPtr->indices = indices;
1759}
1760
1761/*
1762 *----------------------------------------------------------------------
1763 *
1764 * ReducePoints --
1765 *
1766 * Generates a coordinate array of transformed screen coordinates
1767 * from the data points.
1768 *
1769 * Results:
1770 * The transformed screen coordinates are returned.
1771 *
1772 * Side effects:
1773 * Memory is allocated for the coordinate array.
1774 *
1775 *----------------------------------------------------------------------
1776 */
1777static void
1778ReducePoints(mapPtr, tolerance)
1779 MapInfo *mapPtr;
1780 double tolerance;
1781{
1782 register int i, k, n;
1783 Point2D *screenPts;
1784 int *indices, *simple;
1785
1786 simple = Blt_Malloc(sizeof(int) * mapPtr->nScreenPts);
1787 indices = Blt_Malloc(sizeof(int) * mapPtr->nScreenPts);
1788 screenPts = Blt_Malloc(sizeof(Point2D) * mapPtr->nScreenPts);
1789 n = Blt_SimplifyLine(mapPtr->screenPts, 0, mapPtr->nScreenPts - 1,
1790 tolerance, simple);
1791 for (i = 0; i < n; i++) {
1792 k = simple[i];
1793 screenPts[i] = mapPtr->screenPts[k];
1794 indices[i] = mapPtr->indices[k];
1795 }
1796#ifdef notdef
1797 if (n < mapPtr->nScreenPts) {
1798 fprintf(stderr, "reduced from %d to %d\n", mapPtr->nScreenPts, n);
1799 }
1800#endif
1801 Blt_Free(mapPtr->screenPts);
1802 Blt_Free(mapPtr->indices);
1803 Blt_Free(simple);
1804 mapPtr->screenPts = screenPts;
1805 mapPtr->indices = indices;
1806 mapPtr->nScreenPts = n;
1807}
1808
1809/*
1810 *----------------------------------------------------------------------
1811 *
1812 * GenerateSteps --
1813 *
1814 * Resets the coordinate and pen index arrays adding new points
1815 * for step-and-hold type smoothing.
1816 *
1817 * Results:
1818 * None.
1819 *
1820 * Side Effects:
1821 * The temporary arrays for screen coordinates and pen indices
1822 * are updated.
1823 *
1824 *----------------------------------------------------------------------
1825 */
1826static void
1827GenerateSteps(mapPtr)
1828 MapInfo *mapPtr;
1829{
1830 int newSize;
1831 register int i, count;
1832 Point2D *screenPts;
1833 int *indices;
1834
1835 newSize = ((mapPtr->nScreenPts - 1) * 2) + 1;
1836 screenPts = Blt_Malloc(newSize * sizeof(Point2D));
1837 assert(screenPts);
1838 indices = Blt_Malloc(sizeof(int) * newSize);
1839 assert(indices);
1840
1841 screenPts[0] = mapPtr->screenPts[0];
1842 indices[0] = 0;
1843
1844 count = 1;
1845 for (i = 1; i < mapPtr->nScreenPts; i++) {
1846 screenPts[count + 1] = mapPtr->screenPts[i];
1847
1848 /* Hold last y-coordinate, use new x-coordinate */
1849 screenPts[count].x = screenPts[count + 1].x;
1850 screenPts[count].y = screenPts[count - 1].y;
1851
1852 /* Use the same style for both the hold and the step points */
1853 indices[count] = indices[count + 1] = mapPtr->indices[i];
1854 count += 2;
1855 }
1856 Blt_Free(mapPtr->screenPts);
1857 Blt_Free(mapPtr->indices);
1858 mapPtr->indices = indices;
1859 mapPtr->screenPts = screenPts;
1860 mapPtr->nScreenPts = newSize;
1861}
1862
1863/*
1864 *----------------------------------------------------------------------
1865 *
1866 * GenerateSpline --
1867 *
1868 * Computes a spline based upon the data points, returning a new
1869 * (larger) coordinate array or points.
1870 *
1871 * Results:
1872 * None.
1873 *
1874 * Side Effects:
1875 * The temporary arrays for screen coordinates and data indices
1876 * are updated based upon spline.
1877 *
1878 * FIXME: Can't interpolate knots along the Y-axis. Need to break
1879 * up point array into interchangable X and Y vectors earlier.
1880 * Pass extents (left/right or top/bottom) as parameters.
1881 *
1882 *----------------------------------------------------------------------
1883 */
1884static void
1885GenerateSpline(graphPtr, linePtr, mapPtr)
1886 Graph *graphPtr;
1887 Line *linePtr;
1888 MapInfo *mapPtr;
1889{
1890 int extra;
1891 register int i, j, count;
1892 Point2D *origPts, *intpPts;
1893 int *indices;
1894 int nIntpPts, nOrigPts;
1895 int result;
1896 int x;
1897
1898 nOrigPts = mapPtr->nScreenPts;
1899 origPts = mapPtr->screenPts;
1900 assert(mapPtr->nScreenPts > 0);
1901 for (i = 0, j = 1; j < nOrigPts; i++, j++) {
1902 if (origPts[j].x <= origPts[i].x) {
1903 return; /* Points are not monotonically increasing */
1904 }
1905 }
1906 if (((origPts[0].x > (double)graphPtr->right)) ||
1907 ((origPts[mapPtr->nScreenPts - 1].x < (double)graphPtr->left))) {
1908 return; /* All points are clipped */
1909 }
1910 /*
1911 * The spline is computed in screen coordinates instead of data
1912 * points so that we can select the abscissas of the interpolated
1913 * points from each pixel horizontally across the plotting area.
1914 */
1915 extra = (graphPtr->right - graphPtr->left) + 1;
1916 if (extra < 1) {
1917 return;
1918 }
1919 nIntpPts = nOrigPts + extra + 1;
1920 intpPts = Blt_Malloc(nIntpPts * sizeof(Point2D));
1921 assert(intpPts);
1922
1923 indices = Blt_Malloc(sizeof(int) * nIntpPts);
1924 assert(indices);
1925
1926 /* Populate the x2 array with both the original X-coordinates and
1927 * extra X-coordinates for each horizontal pixel that the line
1928 * segment contains. */
1929 count = 0;
1930 for (i = 0, j = 1; j < nOrigPts; i++, j++) {
1931
1932 /* Add the original x-coordinate */
1933 intpPts[count].x = origPts[i].x;
1934
1935 /* Include the starting offset of the point in the offset array */
1936 indices[count] = mapPtr->indices[i];
1937 count++;
1938
1939 /* Is any part of the interval (line segment) in the plotting
1940 * area? */
1941 if ((origPts[j].x >= (double)graphPtr->left) ||
1942 (origPts[i].x <= (double)graphPtr->right)) {
1943 int last;
1944
1945 x = (int)(origPts[i].x + 1.0);
1946
1947 /*
1948 * Since the line segment may be partially clipped on the
1949 * left or right side, the points to interpolate are
1950 * always interior to the plotting area.
1951 *
1952 * left right
1953 * x1----|--------------------------|---x2
1954 *
1955 * Pick the max of the starting X-coordinate and the
1956 * left edge and the min of the last X-coordinate and
1957 * the right edge.
1958 */
1959 x = MAX(x, graphPtr->left);
1960 last = (int)MIN(origPts[j].x, graphPtr->right);
1961
1962 /* Add the extra x-coordinates to the interval. */
1963 while (x < last) {
1964 indices[count] = mapPtr->indices[i];
1965 intpPts[count++].x = (double)x;
1966 x++;
1967 }
1968 }
1969 }
1970 nIntpPts = count;
1971 result = FALSE;
1972 if (linePtr->smooth == PEN_SMOOTH_NATURAL) {
1973 result = Blt_NaturalSpline(origPts, nOrigPts, intpPts, nIntpPts);
1974 } else if (linePtr->smooth == PEN_SMOOTH_QUADRATIC) {
1975 result = Blt_QuadraticSpline(origPts, nOrigPts, intpPts, nIntpPts);
1976 }
1977 if (!result) {
1978 /* The spline interpolation failed. We'll fallback to the
1979 * current coordinates and do no smoothing (standard line
1980 * segments). */
1981 linePtr->smooth = PEN_SMOOTH_NONE;
1982 Blt_Free(intpPts);
1983 Blt_Free(indices);
1984 } else {
1985 Blt_Free(mapPtr->screenPts);
1986 Blt_Free(mapPtr->indices);
1987 mapPtr->indices = indices;
1988 mapPtr->screenPts = intpPts;
1989 mapPtr->nScreenPts = nIntpPts;
1990 }
1991}
1992
1993
1994/*
1995 *----------------------------------------------------------------------
1996 *
1997 * GenerateParametricSpline --
1998 *
1999 * Computes a spline based upon the data points, returning a new
2000 * (larger) coordinate array or points.
2001 *
2002 * Results:
2003 * None.
2004 *
2005 * Side Effects:
2006 * The temporary arrays for screen coordinates and data indices
2007 * are updated based upon spline.
2008 *
2009 * FIXME: Can't interpolate knots along the Y-axis. Need to break
2010 * up point array into interchangable X and Y vectors earlier.
2011 * Pass extents (left/right or top/bottom) as parameters.
2012 *
2013 *----------------------------------------------------------------------
2014 */
2015static void
2016GenerateParametricSpline(graphPtr, linePtr, mapPtr)
2017 Graph *graphPtr;
2018 Line *linePtr;
2019 MapInfo *mapPtr;
2020{
2021 Extents2D exts;
2022 Point2D *origPts, *intpPts;
2023 Point2D p, q;
2024 double dist;
2025 int *indices;
2026 int nIntpPts, nOrigPts;
2027 int result;
2028 register int i, j, count;
2029
2030 nOrigPts = mapPtr->nScreenPts;
2031 origPts = mapPtr->screenPts;
2032 assert(mapPtr->nScreenPts > 0);
2033
2034 Blt_GraphExtents(graphPtr, &exts);
2035
2036 /*
2037 * Populate the x2 array with both the original X-coordinates and
2038 * extra X-coordinates for each horizontal pixel that the line
2039 * segment contains.
2040 */
2041 count = 1;
2042 for (i = 0, j = 1; j < nOrigPts; i++, j++) {
2043 p = origPts[i];
2044 q = origPts[j];
2045 count++;
2046 if (Blt_LineRectClip(&exts, &p, &q)) {
2047 count += (int)(hypot(q.x - p.x, q.y - p.y) * 0.5);
2048 }
2049 }
2050 nIntpPts = count;
2051 intpPts = Blt_Malloc(nIntpPts * sizeof(Point2D));
2052 assert(intpPts);
2053
2054 indices = Blt_Malloc(sizeof(int) * nIntpPts);
2055 assert(indices);
2056
2057 /*
2058 * FIXME: This is just plain wrong. The spline should be computed
2059 * and evaluated in separate steps. This will mean breaking
2060 * up this routine since the catrom coefficients can be
2061 * independently computed for original data point. This
2062 * also handles the problem of allocating enough points
2063 * since evaluation is independent of the number of points
2064 * to be evalualted. The interpolated
2065 * line segments should be clipped, not the original segments.
2066 */
2067 count = 0;
2068 for (i = 0, j = 1; j < nOrigPts; i++, j++) {
2069 p = origPts[i];
2070 q = origPts[j];
2071
2072 dist = hypot(q.x - p.x, q.y - p.y);
2073 /* Add the original x-coordinate */
2074 intpPts[count].x = (double)i;
2075 intpPts[count].y = 0.0;
2076
2077 /* Include the starting offset of the point in the offset array */
2078 indices[count] = mapPtr->indices[i];
2079 count++;
2080
2081 /* Is any part of the interval (line segment) in the plotting
2082 * area? */
2083
2084 if (Blt_LineRectClip(&exts, &p, &q)) {
2085 double distP, distQ;
2086
2087 distP = hypot(p.x - origPts[i].x, p.y - origPts[i].y);
2088 distQ = hypot(q.x - origPts[i].x, q.y - origPts[i].y);
2089 distP += 2.0;
2090 while(distP <= distQ) {
2091 /* Point is indicated by its interval and parameter t. */
2092 intpPts[count].x = (double)i;
2093 intpPts[count].y = distP / dist;
2094 indices[count] = mapPtr->indices[i];
2095 count++;
2096 distP += 2.0;
2097 }
2098 }
2099 }
2100 intpPts[count].x = (double)i;
2101 intpPts[count].y = 0.0;
2102 indices[count] = mapPtr->indices[i];
2103 count++;
2104 nIntpPts = count;
2105 result = FALSE;
2106 if (linePtr->smooth == PEN_SMOOTH_NATURAL) {
2107 result = Blt_NaturalParametricSpline(origPts, nOrigPts, &exts, FALSE,
2108 intpPts, nIntpPts);
2109 } else if (linePtr->smooth == PEN_SMOOTH_CATROM) {
2110 result = Blt_CatromParametricSpline(origPts, nOrigPts, intpPts,
2111 nIntpPts);
2112 }
2113 if (!result) {
2114 /* The spline interpolation failed. We'll fallback to the
2115 * current coordinates and do no smoothing (standard line
2116 * segments). */
2117 linePtr->smooth = PEN_SMOOTH_NONE;
2118 Blt_Free(intpPts);
2119 Blt_Free(indices);
2120 } else {
2121 Blt_Free(mapPtr->screenPts);
2122 Blt_Free(mapPtr->indices);
2123 mapPtr->indices = indices;
2124 mapPtr->screenPts = intpPts;
2125 mapPtr->nScreenPts = nIntpPts;
2126 }
2127}
2128
2129
2130/*
2131 *----------------------------------------------------------------------
2132 *
2133 * MapSymbols --
2134 *
2135 * Creates two arrays of points and pen indices, filled with
2136 * the screen coordinates of the visible
2137 *
2138 * Results:
2139 * None.
2140 *
2141 * Side effects:
2142 * Memory is freed and allocated for the index array.
2143 *
2144 *----------------------------------------------------------------------
2145 */
2146static void
2147MapSymbols(graphPtr, linePtr, mapPtr)
2148 Graph *graphPtr;
2149 Line *linePtr;
2150 MapInfo *mapPtr;
2151{
2152 Extents2D exts;
2153 Point2D *symbolPts;
2154 int *indices;
2155 register int i, count;
2156
2157 symbolPts = Blt_Malloc(sizeof(Point2D) * mapPtr->nScreenPts);
2158 assert(symbolPts);
2159
2160 indices = Blt_Malloc(sizeof(int) * mapPtr->nScreenPts);
2161 assert(indices);
2162
2163 Blt_GraphExtents(graphPtr, &exts);
2164 count = 0; /* Count the number of visible points */
2165
2166 for (i = 0; i < mapPtr->nScreenPts; i++) {
2167 if (PointInRegion(&exts, mapPtr->screenPts[i].x,
2168 mapPtr->screenPts[i].y)) {
2169 symbolPts[count].x = mapPtr->screenPts[i].x;
2170 symbolPts[count].y = mapPtr->screenPts[i].y;
2171 indices[count] = mapPtr->indices[i];
2172 count++;
2173 }
2174 }
2175 linePtr->symbolPts = symbolPts;
2176 linePtr->nSymbolPts = count;
2177 linePtr->symbolToData = indices;
2178}
2179
2180/*
2181 *----------------------------------------------------------------------
2182 *
2183 * MapActiveSymbols --
2184 *
2185 * Creates an array of points of the active graph coordinates.
2186 *
2187 * Results:
2188 * None.
2189 *
2190 * Side effects:
2191 * Memory is freed and allocated for the active point array.
2192 *
2193 *----------------------------------------------------------------------
2194 */
2195static void
2196MapActiveSymbols(graphPtr, linePtr)
2197 Graph *graphPtr;
2198 Line *linePtr;
2199{
2200 Extents2D exts;
2201 double x, y;
2202 int count;
2203 Point2D *activePts;
2204 register int i;
2205 int pointIndex;
2206 int nPoints;
2207 int *activeToData;
2208
2209 if (linePtr->activePts != NULL) {
2210 Blt_Free(linePtr->activePts);
2211 linePtr->activePts = NULL;
2212 }
2213 if (linePtr->activeToData != NULL) {
2214 Blt_Free(linePtr->activeToData);
2215 linePtr->activeToData = NULL;
2216 }
2217 Blt_GraphExtents(graphPtr, &exts);
2218 activePts = Blt_Malloc(sizeof(Point2D) * linePtr->nActiveIndices);
2219 assert(activePts);
2220 activeToData = Blt_Malloc(sizeof(int) * linePtr->nActiveIndices);
2221 nPoints = NumberOfPoints(linePtr);
2222 count = 0; /* Count the visible active points */
2223 for (i = 0; i < linePtr->nActiveIndices; i++) {
2224 pointIndex = linePtr->activeIndices[i];
2225 if (pointIndex >= nPoints) {
2226 continue; /* Index not available */
2227 }
2228 x = linePtr->x.valueArr[pointIndex];
2229 y = linePtr->y.valueArr[pointIndex];
2230 activePts[count] = Blt_Map2D(graphPtr, x, y, &(linePtr->axes));
2231 activeToData[count] = pointIndex;
2232 if (PointInRegion(&exts, activePts[count].x, activePts[count].y)) {
2233 count++;
2234 }
2235 }
2236 if (count > 0) {
2237 linePtr->activePts = activePts;
2238 linePtr->activeToData = activeToData;
2239 } else {
2240 /* No active points were visible. */
2241 Blt_Free(activePts);
2242 Blt_Free(activeToData);
2243 }
2244 linePtr->nActivePts = count;
2245 linePtr->flags &= ~ACTIVE_PENDING;
2246}
2247
2248/*
2249 *----------------------------------------------------------------------
2250 *
2251 * MapStrip --
2252 *
2253 * Creates an array of line segments of the graph coordinates.
2254 *
2255 * Results:
2256 * None.
2257 *
2258 * Side effects:
2259 * Memory is allocated for the line segment array.
2260 *
2261 *----------------------------------------------------------------------
2262 */
2263static void
2264MapStrip(graphPtr, linePtr, mapPtr)
2265 Graph *graphPtr;
2266 Line *linePtr;
2267 MapInfo *mapPtr;
2268{
2269 Extents2D exts;
2270 Segment2D *strips;
2271 int *indices, *indexPtr;
2272 register Point2D *endPtr, *pointPtr;
2273 register Segment2D *segPtr;
2274 register int count;
2275
2276 indices = Blt_Malloc(sizeof(int) * mapPtr->nScreenPts);
2277 assert(indices);
2278
2279 /*
2280 * Create array to hold points for line segments (not polyline
2281 * coordinates). So allocate twice the number of points.
2282 */
2283 segPtr = strips = Blt_Malloc(mapPtr->nScreenPts * sizeof(Segment2D));
2284 assert(strips);
2285
2286 Blt_GraphExtents(graphPtr, &exts);
2287 count = 0; /* Count the number of segments. */
2288 indexPtr = mapPtr->indices;
2289 for (pointPtr = mapPtr->screenPts,
2290 endPtr = mapPtr->screenPts + (mapPtr->nScreenPts - 1);
2291 pointPtr < endPtr; pointPtr++, indexPtr++) {
2292 segPtr->p = pointPtr[0];
2293 segPtr->q = pointPtr[1];
2294 if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) {
2295 segPtr++;
2296 indices[count] = *indexPtr;
2297 count++;
2298 }
2299 }
2300 linePtr->stripToData = indices;
2301 linePtr->nStrips = count;
2302 linePtr->strips = strips;
2303}
2304
2305/*
2306 *----------------------------------------------------------------------
2307 *
2308 * MergePens --
2309 *
2310 * Reorders the both arrays of points and segments to merge pens.
2311 *
2312 * Results:
2313 * None.
2314 *
2315 * Side effects:
2316 * The old arrays are freed and new ones allocated containing
2317 * the reordered points and segments.
2318 *
2319 *----------------------------------------------------------------------
2320 */
2321static void
2322MergePens(linePtr, dataToStyle)
2323 Line *linePtr;
2324 PenStyle **dataToStyle;
2325{
2326 LinePenStyle *stylePtr;
2327 register int i;
2328 Blt_ChainLink *linkPtr;
2329
2330 if (Blt_ChainGetLength(linePtr->palette) < 2) {
2331 linkPtr = Blt_ChainFirstLink(linePtr->palette);
2332 stylePtr = Blt_ChainGetValue(linkPtr);
2333 stylePtr->nStrips = linePtr->nStrips;
2334 stylePtr->strips = linePtr->strips;
2335 stylePtr->nSymbolPts = linePtr->nSymbolPts;
2336 stylePtr->symbolPts = linePtr->symbolPts;
2337 stylePtr->xErrorBarCnt = linePtr->xErrorBarCnt;
2338 stylePtr->yErrorBarCnt = linePtr->yErrorBarCnt;
2339 stylePtr->xErrorBars = linePtr->xErrorBars;
2340 stylePtr->yErrorBars = linePtr->yErrorBars;
2341 stylePtr->errorBarCapWidth = linePtr->errorBarCapWidth;
2342 return;
2343 }
2344
2345 /* We have more than one style. Group line segments and points of
2346 * like pen styles. */
2347
2348 if (linePtr->nStrips > 0) {
2349 Segment2D *strips;
2350 int *stripToData;
2351 register Segment2D *segPtr;
2352 register int *indexPtr;
2353 int dataIndex;
2354
2355 strips = Blt_Malloc(linePtr->nStrips * sizeof(Segment2D));
2356 stripToData = Blt_Malloc(linePtr->nStrips * sizeof(int));
2357 assert(strips && stripToData);
2358 segPtr = strips, indexPtr = stripToData;
2359 for (linkPtr = Blt_ChainFirstLink(linePtr->palette); linkPtr != NULL;
2360 linkPtr = Blt_ChainNextLink(linkPtr)) {
2361 stylePtr = Blt_ChainGetValue(linkPtr);
2362 stylePtr->strips = segPtr;
2363 for (i = 0; i < linePtr->nStrips; i++) {
2364 dataIndex = linePtr->stripToData[i];
2365 if (dataToStyle[dataIndex] == (PenStyle *)stylePtr) {
2366 *segPtr++ = linePtr->strips[i];
2367 *indexPtr++ = dataIndex;
2368 }
2369 }
2370 stylePtr->nStrips = segPtr - stylePtr->strips;
2371 }
2372 Blt_Free(linePtr->strips);
2373 linePtr->strips = strips;
2374 Blt_Free(linePtr->stripToData);
2375 linePtr->stripToData = stripToData;
2376 }
2377 if (linePtr->nSymbolPts > 0) {
2378 int *indexPtr;
2379 register Point2D *symbolPts, *pointPtr;
2380 register int *symbolToData;
2381 int dataIndex;
2382
2383 symbolPts = Blt_Malloc(linePtr->nSymbolPts * sizeof(Point2D));
2384 symbolToData = Blt_Malloc(linePtr->nSymbolPts * sizeof(int));
2385 assert(symbolPts && symbolToData);
2386 pointPtr = symbolPts, indexPtr = symbolToData;
2387 for (linkPtr = Blt_ChainFirstLink(linePtr->palette); linkPtr != NULL;
2388 linkPtr = Blt_ChainNextLink(linkPtr)) {
2389 stylePtr = Blt_ChainGetValue(linkPtr);
2390 stylePtr->symbolPts = pointPtr;
2391 for (i = 0; i < linePtr->nSymbolPts; i++) {
2392 dataIndex = linePtr->symbolToData[i];
2393 if (dataToStyle[dataIndex] == (PenStyle *)stylePtr) {
2394 *pointPtr++ = linePtr->symbolPts[i];
2395 *indexPtr++ = dataIndex;
2396 }
2397 }
2398 stylePtr->nSymbolPts = pointPtr - stylePtr->symbolPts;
2399 }
2400 Blt_Free(linePtr->symbolPts);
2401 linePtr->symbolPts = symbolPts;
2402 Blt_Free(linePtr->symbolToData);
2403 linePtr->symbolToData = symbolToData;
2404 }
2405 if (linePtr->xErrorBarCnt > 0) {
2406 Segment2D *xErrorBars, *segPtr;
2407 int *xErrorToData, *indexPtr;
2408 int dataIndex;
2409
2410 xErrorBars = Blt_Malloc(linePtr->xErrorBarCnt * sizeof(Segment2D));
2411 xErrorToData = Blt_Malloc(linePtr->xErrorBarCnt * sizeof(int));
2412 assert(xErrorBars);
2413 segPtr = xErrorBars, indexPtr = xErrorToData;
2414 for (linkPtr = Blt_ChainFirstLink(linePtr->palette);
2415 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
2416 stylePtr = Blt_ChainGetValue(linkPtr);
2417 stylePtr->xErrorBars = segPtr;
2418 for (i = 0; i < linePtr->xErrorBarCnt; i++) {
2419 dataIndex = linePtr->xErrorToData[i];
2420 if (dataToStyle[dataIndex] == (PenStyle *)stylePtr) {
2421 *segPtr++ = linePtr->xErrorBars[i];
2422 *indexPtr++ = dataIndex;
2423 }
2424 }
2425 stylePtr->xErrorBarCnt = segPtr - stylePtr->xErrorBars;
2426 }
2427 Blt_Free(linePtr->xErrorBars);
2428 linePtr->xErrorBars = xErrorBars;
2429 Blt_Free(linePtr->xErrorToData);
2430 linePtr->xErrorToData = xErrorToData;
2431 }
2432 if (linePtr->yErrorBarCnt > 0) {
2433 Segment2D *errorBars, *segPtr;
2434 int *errorToData, *indexPtr;
2435 int dataIndex;
2436
2437 errorBars = Blt_Malloc(linePtr->yErrorBarCnt * sizeof(Segment2D));
2438 errorToData = Blt_Malloc(linePtr->yErrorBarCnt * sizeof(int));
2439 assert(errorBars);
2440 segPtr = errorBars, indexPtr = errorToData;
2441 for (linkPtr = Blt_ChainFirstLink(linePtr->palette);
2442 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
2443 stylePtr = Blt_ChainGetValue(linkPtr);
2444 stylePtr->yErrorBars = segPtr;
2445 for (i = 0; i < linePtr->yErrorBarCnt; i++) {
2446 dataIndex = linePtr->yErrorToData[i];
2447 if (dataToStyle[dataIndex] == (PenStyle *)stylePtr) {
2448 *segPtr++ = linePtr->yErrorBars[i];
2449 *indexPtr++ = dataIndex;
2450 }
2451 }
2452 stylePtr->yErrorBarCnt = segPtr - stylePtr->yErrorBars;
2453 }
2454 Blt_Free(linePtr->yErrorBars);
2455 linePtr->yErrorBars = errorBars;
2456 Blt_Free(linePtr->yErrorToData);
2457 linePtr->yErrorToData = errorToData;
2458 }
2459}
2460
2461#define CLIP_TOP (1<<0)
2462#define CLIP_BOTTOM (1<<1)
2463#define CLIP_RIGHT (1<<2)
2464#define CLIP_LEFT (1<<3)
2465
2466INLINE static int
2467OutCode(extsPtr, p)
2468 Extents2D *extsPtr;
2469 Point2D *p;
2470{
2471 int code;
2472
2473 code = 0;
2474 if (p->x > extsPtr->right) {
2475 code |= CLIP_RIGHT;
2476 } else if (p->x < extsPtr->left) {
2477 code |= CLIP_LEFT;
2478 }
2479 if (p->y > extsPtr->bottom) {
2480 code |= CLIP_BOTTOM;
2481 } else if (p->y < extsPtr->top) {
2482 code |= CLIP_TOP;
2483 }
2484 return code;
2485}
2486
2487static int
2488ClipSegment(extsPtr, code1, code2, p, q)
2489 Extents2D *extsPtr;
2490 register int code1, code2;
2491 register Point2D *p, *q;
2492{
2493 int inside, outside;
2494
2495 inside = ((code1 | code2) == 0);
2496 outside = ((code1 & code2) != 0);
2497
2498 /*
2499 * In the worst case, we'll clip the line segment against each of
2500 * the four sides of the bounding rectangle.
2501 */
2502 while ((!outside) && (!inside)) {
2503 if (code1 == 0) {
2504 Point2D *tmp;
2505 int code;
2506
2507 /* Swap pointers and out codes */
2508 tmp = p, p = q, q = tmp;
2509 code = code1, code1 = code2, code2 = code;
2510 }
2511 if (code1 & CLIP_LEFT) {
2512 p->y += (q->y - p->y) *
2513 (extsPtr->left - p->x) / (q->x - p->x);
2514 p->x = extsPtr->left;
2515 } else if (code1 & CLIP_RIGHT) {
2516 p->y += (q->y - p->y) *
2517 (extsPtr->right - p->x) / (q->x - p->x);
2518 p->x = extsPtr->right;
2519 } else if (code1 & CLIP_BOTTOM) {
2520 p->x += (q->x - p->x) *
2521 (extsPtr->bottom - p->y) / (q->y - p->y);
2522 p->y = extsPtr->bottom;
2523 } else if (code1 & CLIP_TOP) {
2524 p->x += (q->x - p->x) *
2525 (extsPtr->top - p->y) / (q->y - p->y);
2526 p->y = extsPtr->top;
2527 }
2528 code1 = OutCode(extsPtr, p);
2529
2530 inside = ((code1 | code2) == 0);
2531 outside = ((code1 & code2) != 0);
2532 }
2533 return (!inside);
2534}
2535
2536/*
2537 *----------------------------------------------------------------------
2538 *
2539 * SaveTrace --
2540 *
2541 * Creates a new trace and inserts it into the line's
2542 * list of traces.
2543 *
2544 * Results:
2545 * None.
2546 *
2547 *----------------------------------------------------------------------
2548 */
2549static void
2550SaveTrace(linePtr, start, length, mapPtr)
2551 Line *linePtr;
2552 int start; /* Starting index of the trace in data point
2553 * array. Used to figure out closest point */
2554 int length; /* Number of points forming the trace */
2555 MapInfo *mapPtr;
2556{
2557 Trace *tracePtr;
2558 Point2D *screenPts;
2559 int *indices;
2560 register int i, j;
2561
2562 tracePtr = Blt_Malloc(sizeof(Trace));
2563 assert(tracePtr);
2564 screenPts = Blt_Malloc(sizeof(Point2D) * length);
2565 assert(screenPts);
2566 indices = Blt_Malloc(sizeof(int) * length);
2567 assert(indices);
2568
2569 /* Copy the screen coordinates of the trace into the point array */
2570
2571 if (mapPtr->indices != NULL) {
2572 for (i = 0, j = start; i < length; i++, j++) {
2573 screenPts[i].x = mapPtr->screenPts[j].x;
2574 screenPts[i].y = mapPtr->screenPts[j].y;
2575 indices[i] = mapPtr->indices[j];
2576 }
2577 } else {
2578 for (i = 0, j = start; i < length; i++, j++) {
2579 screenPts[i].x = mapPtr->screenPts[j].x;
2580 screenPts[i].y = mapPtr->screenPts[j].y;
2581 indices[i] = j;
2582 }
2583 }
2584 tracePtr->nScreenPts = length;
2585 tracePtr->screenPts = screenPts;
2586 tracePtr->symbolToData = indices;
2587 tracePtr->start = start;
2588 if (linePtr->traces == NULL) {
2589 linePtr->traces = Blt_ChainCreate();
2590 }
2591 Blt_ChainAppend(linePtr->traces, tracePtr);
2592}
2593
2594/*
2595 *----------------------------------------------------------------------
2596 *
2597 * FreeTraces --
2598 *
2599 * Deletes all the traces for the line.
2600 *
2601 * Results:
2602 * None.
2603 *
2604 *----------------------------------------------------------------------
2605 */
2606static void
2607FreeTraces(linePtr)
2608 Line *linePtr;
2609{
2610 Blt_ChainLink *linkPtr;
2611 Trace *tracePtr;
2612
2613 for (linkPtr = Blt_ChainFirstLink(linePtr->traces); linkPtr != NULL;
2614 linkPtr = Blt_ChainNextLink(linkPtr)) {
2615 tracePtr = Blt_ChainGetValue(linkPtr);
2616 Blt_Free(tracePtr->symbolToData);
2617 Blt_Free(tracePtr->screenPts);
2618 Blt_Free(tracePtr);
2619 }
2620 Blt_ChainDestroy(linePtr->traces);
2621 linePtr->traces = NULL;
2622}
2623
2624/*
2625 *----------------------------------------------------------------------
2626 *
2627 * MapTraces --
2628 *
2629 * Creates an array of line segments of the graph coordinates.
2630 *
2631 * Results:
2632 * None.
2633 *
2634 * Side effects:
2635 * Memory is allocated for the line segment array.
2636 *
2637 *----------------------------------------------------------------------
2638 */
2639static void
2640MapTraces(graphPtr, linePtr, mapPtr)
2641 Graph *graphPtr;
2642 Line *linePtr;
2643 MapInfo *mapPtr;
2644{
2645 int start, count;
2646 int code1, code2;
2647 Point2D *p, *q;
2648 Point2D s;
2649 Extents2D exts;
2650 register int i;
2651 int broken, offscreen;
2652
2653 Blt_GraphExtents(graphPtr, &exts);
2654 count = 1;
2655 code1 = OutCode(&exts, mapPtr->screenPts);
2656 p = mapPtr->screenPts;
2657 q = p + 1;
2658 for (i = 1; i < mapPtr->nScreenPts; i++, p++, q++) {
2659 code2 = OutCode(&exts, q);
2660 if (code2 != 0) {
2661 /* Save the coordinates of the last point, before clipping */
2662 s = *q;
2663 }
2664 broken = BROKEN_TRACE(linePtr->penDir, p->x, q->x);
2665 offscreen = ClipSegment(&exts, code1, code2, p, q);
2666 if (broken || offscreen) {
2667
2668 /*
2669 * The last line segment is either totally clipped by the plotting
2670 * area or the x-direction is wrong, breaking the trace. Either
2671 * way, save information about the last trace (if one exists),
2672 * discarding the current line segment
2673 */
2674
2675 if (count > 1) {
2676 start = i - count;
2677 SaveTrace(linePtr, start, count, mapPtr);
2678 count = 1;
2679 }
2680 } else {
2681 count++; /* Add the point to the trace. */
2682 if (code2 != 0) {
2683
2684 /*
2685 * If the last point is clipped, this means that the trace is
2686 * broken after this point. Restore the original coordinate
2687 * (before clipping) after saving the trace.
2688 */
2689
2690 start = i - (count - 1);
2691 SaveTrace(linePtr, start, count, mapPtr);
2692 mapPtr->screenPts[i] = s;
2693 count = 1;
2694 }
2695 }
2696 code1 = code2;
2697 }
2698 if (count > 1) {
2699 start = i - count;
2700 SaveTrace(linePtr, start, count, mapPtr);
2701 }
2702}
2703
2704/*
2705 *----------------------------------------------------------------------
2706 *
2707 * MapFillArea --
2708 *
2709 * Creates an array of points that represent a polygon that fills
2710 * the area under the element.
2711 *
2712 * Results:
2713 * None.
2714 *
2715 * Side effects:
2716 * Memory is allocated for the polygon point array.
2717 *
2718 *----------------------------------------------------------------------
2719 */
2720static void
2721MapFillArea(graphPtr, linePtr, mapPtr)
2722 Graph *graphPtr;
2723 Line *linePtr;
2724 MapInfo *mapPtr;
2725{
2726 Point2D *origPts, *clipPts;
2727 Extents2D exts;
2728 double maxY;
2729 register int i, n;
2730
2731 if (linePtr->fillPts != NULL) {
2732 Blt_Free(linePtr->fillPts);
2733 linePtr->fillPts = NULL;
2734 linePtr->nFillPts = 0;
2735 }
2736 if (mapPtr->nScreenPts < 3) {
2737 return;
2738 }
2739 n = mapPtr->nScreenPts + 3;
2740 Blt_GraphExtents(graphPtr, &exts);
2741
2742 maxY = (double)graphPtr->bottom;
2743 origPts = Blt_Malloc(sizeof(Point2D) * n);
2744 for (i = 0; i < mapPtr->nScreenPts; i++) {
2745 origPts[i].x = mapPtr->screenPts[i].x + 1;
2746 origPts[i].y = mapPtr->screenPts[i].y;
2747 if (origPts[i].y > maxY) {
2748 maxY = origPts[i].y;
2749 }
2750 }
2751 /* Add edges to make (if necessary) the polygon fill to the bottom
2752 * of plotting window */
2753 origPts[i].x = origPts[i - 1].x;
2754 origPts[i].y = maxY;
2755 i++;
2756 origPts[i].x = origPts[0].x;
2757 origPts[i].y = maxY;
2758 i++;
2759 origPts[i] = origPts[0];
2760
2761 clipPts = Blt_Malloc(sizeof(Point2D) * n * 3);
2762 assert(clipPts);
2763 n = Blt_PolyRectClip(&exts, origPts, n - 1, clipPts);
2764
2765 Blt_Free(origPts);
2766 if (n < 3) {
2767 Blt_Free(clipPts);
2768 } else {
2769 linePtr->fillPts = clipPts;
2770 linePtr->nFillPts = n;
2771 }
2772}
2773
2774static void
2775ResetLine(linePtr)
2776 Line *linePtr;
2777{
2778 FreeTraces(linePtr);
2779 ClearPalette(linePtr->palette);
2780 if (linePtr->symbolPts != NULL) {
2781 Blt_Free(linePtr->symbolPts);
2782 }
2783 if (linePtr->symbolToData != NULL) {
2784 Blt_Free(linePtr->symbolToData);
2785 }
2786 if (linePtr->strips != NULL) {
2787 Blt_Free(linePtr->strips);
2788 }
2789 if (linePtr->stripToData != NULL) {
2790 Blt_Free(linePtr->stripToData);
2791 }
2792 if (linePtr->activePts != NULL) {
2793 Blt_Free(linePtr->activePts);
2794 }
2795 if (linePtr->activeToData != NULL) {
2796 Blt_Free(linePtr->activeToData);
2797 }
2798 if (linePtr->xErrorBars != NULL) {
2799 Blt_Free(linePtr->xErrorBars);
2800 }
2801 if (linePtr->xErrorToData != NULL) {
2802 Blt_Free(linePtr->xErrorToData);
2803 }
2804 if (linePtr->yErrorBars != NULL) {
2805 Blt_Free(linePtr->yErrorBars);
2806 }
2807 if (linePtr->yErrorToData != NULL) {
2808 Blt_Free(linePtr->yErrorToData);
2809 }
2810 linePtr->xErrorBars = linePtr->yErrorBars = linePtr->strips = NULL;
2811 linePtr->symbolPts = linePtr->activePts = NULL;
2812 linePtr->stripToData = linePtr->symbolToData = linePtr->xErrorToData =
2813 linePtr->yErrorToData = linePtr->activeToData = NULL;
2814 linePtr->nActivePts = linePtr->nSymbolPts = linePtr->nStrips =
2815 linePtr->xErrorBarCnt = linePtr->yErrorBarCnt = 0;
2816}
2817
2818/*
2819 *----------------------------------------------------------------------
2820 *
2821 * MapLine --
2822 *
2823 * Calculates the actual window coordinates of the line element.
2824 * The window coordinates are saved in an allocated point array.
2825 *
2826 * Results:
2827 * None.
2828 *
2829 * Side effects:
2830 * Memory is (re)allocated for the point array.
2831 *
2832 *----------------------------------------------------------------------
2833 */
2834static void
2835MapLine(graphPtr, elemPtr)
2836 Graph *graphPtr; /* Graph widget record */
2837 Element *elemPtr; /* Element component record */
2838{
2839 Line *linePtr = (Line *)elemPtr;
2840 MapInfo mapInfo;
2841 int size, nPoints;
2842 PenStyle **dataToStyle;
2843 Blt_ChainLink *linkPtr;
2844 LinePenStyle *stylePtr;
2845
2846 ResetLine(linePtr);
2847 nPoints = NumberOfPoints(linePtr);
2848 if (nPoints < 1) {
2849 return; /* No data points */
2850 }
2851 GetScreenPoints(graphPtr, linePtr, &mapInfo);
2852 MapSymbols(graphPtr, linePtr, &mapInfo);
2853
2854 if ((linePtr->flags & ACTIVE_PENDING) && (linePtr->nActiveIndices > 0)) {
2855 MapActiveSymbols(graphPtr, linePtr);
2856 }
2857 /*
2858 * Map connecting line segments if they are to be displayed.
2859 */
2860 if ((nPoints > 1) && ((graphPtr->classUid == bltStripElementUid) ||
2861 (linePtr->builtinPen.traceWidth > 0))) {
2862 linePtr->smooth = linePtr->reqSmooth;
2863
2864 /*
2865 * Do smoothing if necessary. This can extend the coordinate array,
2866 * so both mapInfo.points and mapInfo.nPoints may change.
2867 */
2868
2869 switch (linePtr->smooth) {
2870 case PEN_SMOOTH_STEP:
2871 GenerateSteps(&mapInfo);
2872 break;
2873
2874 case PEN_SMOOTH_NATURAL:
2875 case PEN_SMOOTH_QUADRATIC:
2876 if (mapInfo.nScreenPts < 3) {
2877 /* Can't interpolate with less than three points. */
2878 linePtr->smooth = PEN_SMOOTH_NONE;
2879 } else {
2880 GenerateSpline(graphPtr, linePtr, &mapInfo);
2881 }
2882 break;
2883
2884 case PEN_SMOOTH_CATROM:
2885 if (mapInfo.nScreenPts < 3) {
2886 /* Can't interpolate with less than three points. */
2887 linePtr->smooth = PEN_SMOOTH_NONE;
2888 } else {
2889 GenerateParametricSpline(graphPtr, linePtr, &mapInfo);
2890 }
2891 break;
2892
2893 default:
2894 break;
2895 }
2896 if (linePtr->rTolerance > 0.0) {
2897 ReducePoints(&mapInfo, linePtr->rTolerance);
2898 }
2899 if ((linePtr->fillTile != NULL) || (linePtr->fillStipple != None)) {
2900 MapFillArea(graphPtr, linePtr, &mapInfo);
2901 }
2902 if (graphPtr->classUid == bltStripElementUid) {
2903 MapStrip(graphPtr, linePtr, &mapInfo);
2904 } else {
2905 MapTraces(graphPtr, linePtr, &mapInfo);
2906 }
2907 }
2908 Blt_Free(mapInfo.screenPts);
2909 Blt_Free(mapInfo.indices);
2910
2911 /* Set the symbol size of all the pen styles. */
2912 for (linkPtr = Blt_ChainFirstLink(linePtr->palette); linkPtr != NULL;
2913 linkPtr = Blt_ChainNextLink(linkPtr)) {
2914 stylePtr = Blt_ChainGetValue(linkPtr);
2915 size = ScaleSymbol(elemPtr, stylePtr->penPtr->symbol.size);
2916 stylePtr->symbolSize = size;
2917 stylePtr->errorBarCapWidth = (stylePtr->penPtr->errorBarCapWidth > 0)
2918 ? stylePtr->penPtr->errorBarCapWidth : (int)(size * 0.6666666);
2919 stylePtr->errorBarCapWidth /= 2;
2920 }
2921 dataToStyle = Blt_StyleMap((Element *)linePtr);
2922 if (((linePtr->yHigh.nValues > 0) && (linePtr->yLow.nValues > 0)) ||
2923 ((linePtr->xHigh.nValues > 0) && (linePtr->xLow.nValues > 0)) ||
2924 (linePtr->xError.nValues > 0) || (linePtr->yError.nValues > 0)) {
2925 Blt_MapErrorBars(graphPtr, (Element *)linePtr, dataToStyle);
2926 }
2927 MergePens(linePtr, dataToStyle);
2928 Blt_Free(dataToStyle);
2929}
2930
2931static double
2932DistanceToLine(x, y, p, q, t)
2933 int x, y; /* Sample X-Y coordinate. */
2934 Point2D *p, *q; /* End points of the line segment. */
2935 Point2D *t; /* (out) Point on line segment. */
2936{
2937 double right, left, top, bottom;
2938
2939 *t = Blt_GetProjection(x, y, p, q);
2940 if (p->x > q->x) {
2941 right = p->x, left = q->x;
2942 } else {
2943 left = p->x, right = q->x;
2944 }
2945 if (p->y > q->y) {
2946 bottom = p->y, top = q->y;
2947 } else {
2948 top = p->y, bottom = q->y;
2949 }
2950 if (t->x > right) {
2951 t->x = right;
2952 } else if (t->x < left) {
2953 t->x = left;
2954 }
2955 if (t->y > bottom) {
2956 t->y = bottom;
2957 } else if (t->y < top) {
2958 t->y = top;
2959 }
2960 return hypot((t->x - x), (t->y - y));
2961}
2962
2963static double
2964DistanceToX(x, y, p, q, t)
2965 int x, y; /* Search X-Y coordinate. */
2966 Point2D *p, *q; /* End points of the line segment. */
2967 Point2D *t; /* (out) Point on line segment. */
2968{
2969 double dx, dy;
2970 double dist;
2971
2972 if (p->x > q->x) {
2973 if ((x > p->x) || (x < q->x)) {
2974 return DBL_MAX; /* X-coordinate outside line segment. */
2975 }
2976 } else {
2977 if ((x > q->x) || (x < p->x)) {
2978 return DBL_MAX; /* X-coordinate outside line segment. */
2979 }
2980 }
2981 dx = p->x - q->x;
2982 dy = p->y - q->y;
2983 t->x = (double)x;
2984 if (FABS(dx) < DBL_EPSILON) {
2985 double d1, d2;
2986 /* Same X-coordinate indicates a vertical line. Pick the
2987 * closest end point. */
2988 d1 = p->y - y;
2989 d2 = q->y - y;
2990 if (FABS(d1) < FABS(d2)) {
2991 t->y = p->y, dist = d1;
2992 } else {
2993 t->y = q->y, dist = d2;
2994 }
2995 } else if (FABS(dy) < DBL_EPSILON) {
2996 /* Horizontal line. */
2997 t->y = p->y, dist = p->y - y;
2998 } else {
2999 double m, b;
3000
3001 m = dy / dx;
3002 b = p->y - (m * p->x);
3003 t->y = (x * m) + b;
3004 dist = y - t->y;
3005 }
3006 return FABS(dist);
3007}
3008
3009static double
3010DistanceToY(x, y, p, q, t)
3011 int x, y; /* Search X-Y coordinate. */
3012 Point2D *p, *q; /* End points of the line segment. */
3013 Point2D *t; /* (out) Point on line segment. */
3014{
3015 double dx, dy;
3016 double dist;
3017
3018 if (p->y > q->y) {
3019 if ((y > p->y) || (y < q->y)) {
3020 return DBL_MAX;
3021 }
3022 } else {
3023 if ((y > q->y) || (y < p->y)) {
3024 return DBL_MAX;
3025 }
3026 }
3027 dx = p->x - q->x;
3028 dy = p->y - q->y;
3029 t->y = y;
3030 if (FABS(dy) < DBL_EPSILON) {
3031 double d1, d2;
3032
3033 /* Save Y-coordinate indicates an horizontal line. Pick the
3034 * closest end point. */
3035 d1 = p->x - x;
3036 d2 = q->x - x;
3037 if (FABS(d1) < FABS(d2)) {
3038 t->x = p->x, dist = d1;
3039 } else {
3040 t->x = q->x, dist = d2;
3041 }
3042 } else if (FABS(dx) < DBL_EPSILON) {
3043 /* Vertical line. */
3044 t->x = p->x, dist = p->x - x;
3045 } else {
3046 double m, b;
3047
3048 m = dy / dx;
3049 b = p->y - (m * p->x);
3050 t->x = (y - b) / m;
3051 dist = x - t->x;
3052 }
3053 return FABS(dist);
3054}
3055
3056/*
3057 *----------------------------------------------------------------------
3058 *
3059 * ClosestTrace --
3060 *
3061 * Find the line segment closest to the given window coordinate
3062 * in the element.
3063 *
3064 * Results:
3065 * If a new minimum distance is found, the information regarding
3066 * it is returned via searchPtr.
3067 *
3068 *----------------------------------------------------------------------
3069 */
3070static int
3071ClosestTrace(graphPtr, linePtr, searchPtr, distProc)
3072 Graph *graphPtr; /* Graph widget record */
3073 Line *linePtr; /* Line element record */
3074 ClosestSearch *searchPtr; /* Info about closest point in element */
3075 DistanceProc *distProc;
3076{
3077 Blt_ChainLink *linkPtr;
3078 Point2D closest, b;
3079 Trace *tracePtr;
3080 double dist, minDist;
3081 register Point2D *pointPtr, *endPtr;
3082 int i;
3083
3084 i = -1; /* Suppress compiler warning. */
3085 minDist = searchPtr->dist;
3086 for (linkPtr = Blt_ChainFirstLink(linePtr->traces); linkPtr != NULL;
3087 linkPtr = Blt_ChainNextLink(linkPtr)) {
3088 tracePtr = Blt_ChainGetValue(linkPtr);
3089 for (pointPtr = tracePtr->screenPts,
3090 endPtr = tracePtr->screenPts + (tracePtr->nScreenPts - 1);
3091 pointPtr < endPtr; pointPtr++) {
3092 dist = (*distProc)(searchPtr->x, searchPtr->y, pointPtr,
3093 pointPtr + 1, &b);
3094 if (dist < minDist) {
3095 closest = b;
3096 i = tracePtr->symbolToData[pointPtr - tracePtr->screenPts];
3097 minDist = dist;
3098 }
3099 }
3100 }
3101 if (minDist < searchPtr->dist) {
3102 searchPtr->dist = minDist;
3103 searchPtr->elemPtr = (Element *)linePtr;
3104 searchPtr->index = i;
3105 searchPtr->point = Blt_InvMap2D(graphPtr, closest.x, closest.y,
3106 &(linePtr->axes));
3107 return TRUE;
3108 }
3109 return FALSE;
3110}
3111
3112/*
3113 *----------------------------------------------------------------------
3114 *
3115 * ClosestStrip --
3116 *
3117 * Find the line segment closest to the given window coordinate
3118 * in the element.
3119 *
3120 * Results:
3121 * If a new minimum distance is found, the information regarding
3122 * it is returned via searchPtr.
3123 *
3124 *----------------------------------------------------------------------
3125 */
3126static int
3127ClosestStrip(graphPtr, linePtr, searchPtr, distProc)
3128 Graph *graphPtr; /* Graph widget record */
3129 Line *linePtr; /* Line element record */
3130 ClosestSearch *searchPtr; /* Info about closest point in element */
3131 DistanceProc *distProc;
3132{
3133 Point2D closest, b;
3134 double dist, minDist;
3135 int count;
3136 int i;
3137 register Segment2D *s;
3138
3139 i = 0;
3140 minDist = searchPtr->dist;
3141 s = linePtr->strips;
3142 for (count = 0; count < linePtr->nStrips; count++, s++) {
3143 dist = (*distProc)(searchPtr->x, searchPtr->y, &(s->p), &(s->q), &b);
3144 if (dist < minDist) {
3145 closest = b;
3146 i = linePtr->stripToData[count];
3147 minDist = dist;
3148 }
3149 }
3150 if (minDist < searchPtr->dist) {
3151 searchPtr->dist = minDist;
3152 searchPtr->elemPtr = (Element *)linePtr;
3153 searchPtr->index = i;
3154 searchPtr->point = Blt_InvMap2D(graphPtr, closest.x, closest.y,
3155 &(linePtr->axes));
3156 return TRUE;
3157 }
3158 return FALSE;
3159}
3160
3161/*
3162 *----------------------------------------------------------------------
3163 *
3164 * ClosestPoint --
3165 *
3166 * Find the element whose data point is closest to the given screen
3167 * coordinate.
3168 *
3169 * Results:
3170 * If a new minimum distance is found, the information regarding
3171 * it is returned via searchPtr.
3172 *
3173 *----------------------------------------------------------------------
3174 */
3175static void
3176ClosestPoint(linePtr, searchPtr)
3177 Line *linePtr; /* Line element that we are looking at */
3178 ClosestSearch *searchPtr; /* Assorted information related to searching
3179 * for the closest point */
3180{
3181 double dist, minDist;
3182 double dx, dy;
3183 int count, i;
3184 register Point2D *pointPtr;
3185
3186 minDist = searchPtr->dist;
3187 i = 0;
3188
3189 /*
3190 * Instead of testing each data point in graph coordinates, look at
3191 * the array of mapped screen coordinates. The advantages are
3192 * 1) only examine points that are visible (unclipped), and
3193 * 2) the computed distance is already in screen coordinates.
3194 */
3195 pointPtr = linePtr->symbolPts;
3196 for (count = 0; count < linePtr->nSymbolPts; count++, pointPtr++) {
3197 dx = (double)(searchPtr->x - pointPtr->x);
3198 dy = (double)(searchPtr->y - pointPtr->y);
3199 if (searchPtr->along == SEARCH_BOTH) {
3200 dist = hypot(dx, dy);
3201 } else if (searchPtr->along == SEARCH_X) {
3202 dist = dx;
3203 } else if (searchPtr->along == SEARCH_Y) {
3204 dist = dy;
3205 } else {
3206 /* This can't happen */
3207 continue;
3208 }
3209 if (dist < minDist) {
3210 i = linePtr->symbolToData[count];
3211 minDist = dist;
3212 }
3213 }
3214 if (minDist < searchPtr->dist) {
3215 searchPtr->elemPtr = (Element *)linePtr;
3216 searchPtr->dist = minDist;
3217 searchPtr->index = i;
3218 searchPtr->point.x = linePtr->x.valueArr[i];
3219 searchPtr->point.y = linePtr->y.valueArr[i];
3220 }
3221}
3222
3223/*
3224 *----------------------------------------------------------------------
3225 *
3226 * GetLineExtents --
3227 *
3228 * Retrieves the range of the line element
3229 *
3230 * Results:
3231 * Returns the number of data points in the element.
3232 *
3233 *----------------------------------------------------------------------
3234 */
3235static void
3236GetLineExtents(elemPtr, extsPtr)
3237 Element *elemPtr;
3238 Extents2D *extsPtr;
3239{
3240 int nPoints;
3241
3242 extsPtr->top = extsPtr->left = DBL_MAX;
3243 extsPtr->bottom = extsPtr->right = -DBL_MAX;
3244
3245 nPoints = NumberOfPoints(elemPtr);
3246 if (nPoints < 1) {
3247 return;
3248 }
3249 extsPtr->right = elemPtr->x.max;
3250 if ((elemPtr->x.min <= 0.0) && (elemPtr->axes.x->logScale)) {
3251 extsPtr->left = Blt_FindElemVectorMinimum(&elemPtr->x, DBL_MIN);
3252 } else {
3253 extsPtr->left = elemPtr->x.min;
3254 }
3255 extsPtr->bottom = elemPtr->y.max;
3256 if ((elemPtr->y.min <= 0.0) && (elemPtr->axes.y->logScale)) {
3257 extsPtr->top = Blt_FindElemVectorMinimum(&elemPtr->y, DBL_MIN);
3258 } else {
3259 extsPtr->top = elemPtr->y.min;
3260 }
3261
3262 /* Correct the data limits for error bars */
3263
3264 if (elemPtr->xError.nValues > 0) {
3265 register int i;
3266 double x;
3267
3268 nPoints = MIN(elemPtr->xError.nValues, nPoints);
3269 for (i = 0; i < nPoints; i++) {
3270 x = elemPtr->x.valueArr[i] + elemPtr->xError.valueArr[i];
3271 if (x > extsPtr->right) {
3272 extsPtr->right = x;
3273 }
3274 x = elemPtr->x.valueArr[i] - elemPtr->xError.valueArr[i];
3275 if (elemPtr->axes.x->logScale) {
3276 if (x < 0.0) {
3277 x = -x; /* Mirror negative values, instead
3278 * of ignoring them. */
3279 }
3280 if ((x > DBL_MIN) && (x < extsPtr->left)) {
3281 extsPtr->left = x;
3282 }
3283 } else if (x < extsPtr->left) {
3284 extsPtr->left = x;
3285 }
3286 }
3287 } else {
3288 if ((elemPtr->xHigh.nValues > 0) &&
3289 (elemPtr->xHigh.max > extsPtr->right)) {
3290 extsPtr->right = elemPtr->xHigh.max;
3291 }
3292 if (elemPtr->xLow.nValues > 0) {
3293 double left;
3294
3295 if ((elemPtr->xLow.min <= 0.0) &&
3296 (elemPtr->axes.x->logScale)) {
3297 left = Blt_FindElemVectorMinimum(&elemPtr->xLow, DBL_MIN);
3298 } else {
3299 left = elemPtr->xLow.min;
3300 }
3301 if (left < extsPtr->left) {
3302 extsPtr->left = left;
3303 }
3304 }
3305 }
3306
3307 if (elemPtr->yError.nValues > 0) {
3308 register int i;
3309 double y;
3310
3311 nPoints = MIN(elemPtr->yError.nValues, nPoints);
3312 for (i = 0; i < nPoints; i++) {
3313 y = elemPtr->y.valueArr[i] + elemPtr->yError.valueArr[i];
3314 if (y > extsPtr->bottom) {
3315 extsPtr->bottom = y;
3316 }
3317 y = elemPtr->y.valueArr[i] - elemPtr->yError.valueArr[i];
3318 if (elemPtr->axes.y->logScale) {
3319 if (y < 0.0) {
3320 y = -y; /* Mirror negative values, instead
3321 * of ignoring them. */
3322 }
3323 if ((y > DBL_MIN) && (y < extsPtr->left)) {
3324 extsPtr->top = y;
3325 }
3326 } else if (y < extsPtr->top) {
3327 extsPtr->top = y;
3328 }
3329 }
3330 } else {
3331 if ((elemPtr->yHigh.nValues > 0) &&
3332 (elemPtr->yHigh.max > extsPtr->bottom)) {
3333 extsPtr->bottom = elemPtr->yHigh.max;
3334 }
3335 if (elemPtr->yLow.nValues > 0) {
3336 double top;
3337
3338 if ((elemPtr->yLow.min <= 0.0) &&
3339 (elemPtr->axes.y->logScale)) {
3340 top = Blt_FindElemVectorMinimum(&elemPtr->yLow, DBL_MIN);
3341 } else {
3342 top = elemPtr->yLow.min;
3343 }
3344 if (top < extsPtr->top) {
3345 extsPtr->top = top;
3346 }
3347 }
3348 }
3349}
3350
3351/*
3352 *----------------------------------------------------------------------
3353 *
3354 * TileChangedProc
3355 *
3356 * Rebuilds the designated GC with the new tile pixmap.
3357 *
3358 * Results:
3359 * None.
3360 *
3361 *----------------------------------------------------------------------
3362 */
3363/*ARGSUSED*/
3364static void
3365TileChangedProc(clientData, tile)
3366 ClientData clientData;
3367 Blt_Tile tile; /* Not used. */
3368{
3369 Line *linePtr = clientData;
3370 Graph *graphPtr;
3371
3372 graphPtr = linePtr->graphPtr;
3373 if (graphPtr->tkwin != NULL) {
3374 graphPtr->flags |= REDRAW_WORLD;
3375 Blt_EventuallyRedrawGraph(graphPtr);
3376 }
3377}
3378
3379/*
3380 *----------------------------------------------------------------------
3381 *
3382 * ConfigureLine --
3383 *
3384 * Sets up the appropriate configuration parameters in the GC.
3385 * It is assumed the parameters have been previously set by
3386 * a call to Tk_ConfigureWidget.
3387 *
3388 * Results:
3389 * The return value is a standard Tcl result. If TCL_ERROR is
3390 * returned, then interp->result contains an error message.
3391 *
3392 * Side effects:
3393 * Configuration information such as line width, line style, color
3394 * etc. get set in a new GC.
3395 *
3396 *----------------------------------------------------------------------
3397 */
3398/*ARGSUSED*/
3399static int
3400ConfigureLine(graphPtr, elemPtr)
3401 Graph *graphPtr;
3402 Element *elemPtr;
3403{
3404 Line *linePtr = (Line *)elemPtr;
3405 unsigned long gcMask;
3406 XGCValues gcValues;
3407 GC newGC;
3408 Blt_ChainLink *linkPtr;
3409
3410 if (ConfigurePen(graphPtr, (Pen *)&(linePtr->builtinPen)) != TCL_OK) {
3411 return TCL_ERROR;
3412 }
3413 /*
3414 * Point to the static normal/active pens if no external pens have
3415 * been selected.
3416 */
3417 if (linePtr->normalPenPtr == NULL) {
3418 linePtr->normalPenPtr = &(linePtr->builtinPen);
3419 }
3420 linkPtr = Blt_ChainFirstLink(linePtr->palette);
3421 if (linkPtr != NULL) {
3422 LinePenStyle *stylePtr;
3423
3424 stylePtr = Blt_ChainGetValue(linkPtr);
3425 stylePtr->penPtr = linePtr->normalPenPtr;
3426 }
3427 if (linePtr->fillTile != NULL) {
3428 Blt_SetTileChangedProc(linePtr->fillTile, TileChangedProc, linePtr);
3429 }
3430 /*
3431 * Set the outline GC for this pen: GCForeground is outline color.
3432 * GCBackground is the fill color (only used for bitmap symbols).
3433 */
3434 gcMask = 0;
3435 if (linePtr->fillFgColor != NULL) {
3436 gcMask |= GCForeground;
3437 gcValues.foreground = linePtr->fillFgColor->pixel;
3438 }
3439 if (linePtr->fillBgColor != NULL) {
3440 gcMask |= GCBackground;
3441 gcValues.background = linePtr->fillBgColor->pixel;
3442 }
3443 if ((linePtr->fillStipple != None) &&
3444 (linePtr->fillStipple != PATTERN_SOLID)) {
3445 gcMask |= (GCStipple | GCFillStyle);
3446 gcValues.stipple = linePtr->fillStipple;
3447 gcValues.fill_style = (linePtr->fillBgColor == NULL)
3448 ? FillStippled : FillOpaqueStippled;
3449 }
3450 newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues);
3451 if (linePtr->fillGC != NULL) {
3452 Tk_FreeGC(graphPtr->display, linePtr->fillGC);
3453 }
3454 linePtr->fillGC = newGC;
3455
3456 if (Blt_ConfigModified(linePtr->configSpecs, "-scalesymbols",
3457 (char *)NULL)) {
3458 linePtr->flags |= (MAP_ITEM | SCALE_SYMBOL);
3459 }
3460 if (Blt_ConfigModified(linePtr->configSpecs, "-pixels", "-trace", "-*data",
3461 "-smooth", "-map*", "-label", "-hide", "-x", "-y", "-areapattern",
3462 (char *)NULL)) {
3463 linePtr->flags |= MAP_ITEM;
3464 }
3465 return TCL_OK;
3466}
3467
3468/*
3469 *----------------------------------------------------------------------
3470 *
3471 * ClosestLine --
3472 *
3473 * Find the closest point or line segment (if interpolated) to
3474 * the given window coordinate in the line element.
3475 *
3476 * Results:
3477 * Returns the distance of the closest point among other
3478 * information.
3479 *
3480 *----------------------------------------------------------------------
3481 */
3482static void
3483ClosestLine(graphPtr, elemPtr, searchPtr)
3484 Graph *graphPtr; /* Graph widget record */
3485 Element *elemPtr; /* Element to examine */
3486 ClosestSearch *searchPtr; /* Info about closest point in element */
3487{
3488 Line *linePtr = (Line *)elemPtr;
3489 int mode;
3490
3491 mode = searchPtr->mode;
3492 if (mode == SEARCH_AUTO) {
3493 LinePen *penPtr = linePtr->normalPenPtr;
3494
3495 mode = SEARCH_POINTS;
3496 if ((NumberOfPoints(linePtr) > 1) && (penPtr->traceWidth > 0)) {
3497 mode = SEARCH_TRACES;
3498 }
3499 }
3500 if (mode == SEARCH_POINTS) {
3501 ClosestPoint(linePtr, searchPtr);
3502 } else {
3503 DistanceProc *distProc;
3504 int found;
3505
3506 if (searchPtr->along == SEARCH_X) {
3507 distProc = DistanceToX;
3508 } else if (searchPtr->along == SEARCH_Y) {
3509 distProc = DistanceToY;
3510 } else {
3511 distProc = DistanceToLine;
3512 }
3513 if (elemPtr->classUid == bltStripElementUid) {
3514 found = ClosestStrip(graphPtr, linePtr, searchPtr, distProc);
3515 } else {
3516 found = ClosestTrace(graphPtr, linePtr, searchPtr, distProc);
3517 }
3518 if ((!found) && (searchPtr->along != SEARCH_BOTH)) {
3519 ClosestPoint(linePtr, searchPtr);
3520 }
3521 }
3522}
3523
3524/*
3525 * XDrawLines() points: XMaxRequestSize(dpy) - 3
3526 * XFillPolygon() points: XMaxRequestSize(dpy) - 4
3527 * XDrawSegments() segments: (XMaxRequestSize(dpy) - 3) / 2
3528 * XDrawRectangles() rectangles: (XMaxRequestSize(dpy) - 3) / 2
3529 * XFillRectangles() rectangles: (XMaxRequestSize(dpy) - 3) / 2
3530 * XDrawArcs() or XFillArcs() arcs: (XMaxRequestSize(dpy) - 3) / 3
3531 */
3532
3533#define MAX_DRAWLINES(d) Blt_MaxRequestSize(d, sizeof(XPoint))
3534#define MAX_DRAWPOLYGON(d) Blt_MaxRequestSize(d, sizeof(XPoint))
3535#define MAX_DRAWSEGMENTS(d) Blt_MaxRequestSize(d, sizeof(XSegment))
3536#define MAX_DRAWRECTANGLES(d) Blt_MaxRequestSize(d, sizeof(XRectangle))
3537#define MAX_DRAWARCS(d) Blt_MaxRequestSize(d, sizeof(XArc))
3538
3539#ifdef WIN32
3540
3541static void
3542DrawCircles(
3543 Display *display,
3544 Drawable drawable,
3545 Line *linePtr,
3546 LinePen *penPtr,
3547 int nSymbolPts,
3548 Point2D *symbolPts,
3549 int radius)
3550{
3551 HBRUSH brush, oldBrush;
3552 HPEN pen, oldPen;
3553 HDC dc;
3554 TkWinDCState state;
3555 register Point2D *pointPtr, *endPtr;
3556
3557 if (drawable == None) {
3558 return; /* Huh? */
3559 }
3560 if ((penPtr->symbol.fillGC == NULL) &&
3561 (penPtr->symbol.outlineWidth == 0)) {
3562 return;
3563 }
3564 dc = TkWinGetDrawableDC(display, drawable, &state);
3565 /* SetROP2(dc, tkpWinRopModes[penPtr->symbol.fillGC->function]); */
3566 if (penPtr->symbol.fillGC != NULL) {
3567 brush = CreateSolidBrush(penPtr->symbol.fillGC->foreground);
3568 } else {
3569 brush = GetStockBrush(NULL_BRUSH);
3570 }
3571 if (penPtr->symbol.outlineWidth > 0) {
3572 pen = Blt_GCToPen(dc, penPtr->symbol.outlineGC);
3573 } else {
3574 pen = GetStockPen(NULL_PEN);
3575 }
3576 oldPen = SelectPen(dc, pen);
3577 oldBrush = SelectBrush(dc, brush);
3578 for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts;
3579 pointPtr < endPtr; pointPtr++) {
3580 Ellipse(dc, (int)pointPtr->x - radius, (int)pointPtr->y - radius,
3581 (int)pointPtr->x + radius + 1, (int)pointPtr->y + radius + 1);
3582 }
3583 DeleteBrush(SelectBrush(dc, oldBrush));
3584 DeletePen(SelectPen(dc, oldPen));
3585 TkWinReleaseDrawableDC(drawable, dc, &state);
3586}
3587
3588#else
3589
3590static void
3591DrawCircles(display, drawable, linePtr, penPtr, nSymbolPts, symbolPts, radius)
3592 Display *display;
3593 Drawable drawable;
3594 Line *linePtr;
3595 LinePen *penPtr;
3596 int nSymbolPts;
3597 Point2D *symbolPts;
3598 int radius;
3599{
3600 register int i;
3601 XArc *arcArr; /* Array of arcs (circle) */
3602 register XArc *arcPtr;
3603 int reqSize, nArcs;
3604 int s;
3605 int count;
3606 register Point2D *pointPtr, *endPtr;
3607
3608 s = radius + radius;
3609 arcArr = Blt_Malloc(nSymbolPts * sizeof(XArc));
3610 arcPtr = arcArr;
3611
3612 if (linePtr->symbolInterval > 0) {
3613 count = 0;
3614 for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts;
3615 pointPtr < endPtr; pointPtr++) {
3616 if (DRAW_SYMBOL(linePtr)) {
3617 arcPtr->x = (short int)pointPtr->x - radius;
3618 arcPtr->y = (short int)pointPtr->y - radius;
3619 arcPtr->width = arcPtr->height = (unsigned short)s;
3620 arcPtr->angle1 = 0;
3621 arcPtr->angle2 = 23040;
3622 arcPtr++, count++;
3623 }
3624 linePtr->symbolCounter++;
3625 }
3626 } else {
3627 count = nSymbolPts;
3628 for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts;
3629 pointPtr < endPtr; pointPtr++) {
3630 arcPtr->x = (short int)pointPtr->x - radius;
3631 arcPtr->y = (short int)pointPtr->y - radius;
3632 arcPtr->width = arcPtr->height = (unsigned short)s;
3633 arcPtr->angle1 = 0;
3634 arcPtr->angle2 = 23040;
3635 arcPtr++;
3636 }
3637 }
3638 reqSize = MAX_DRAWARCS(display);
3639 for (i = 0; i < count; i += reqSize) {
3640 nArcs = ((i + reqSize) > count) ? (count - i) : reqSize;
3641 if (penPtr->symbol.fillGC != NULL) {
3642 XFillArcs(display, drawable, penPtr->symbol.fillGC, arcArr + i,
3643 nArcs);
3644 }
3645 if (penPtr->symbol.outlineWidth > 0) {
3646 XDrawArcs(display, drawable, penPtr->symbol.outlineGC, arcArr + i,
3647 nArcs);
3648 }
3649 }
3650 Blt_Free(arcArr);
3651}
3652
3653#endif
3654
3655static void
3656DrawSquares(display, drawable, linePtr, penPtr, nSymbolPts, symbolPts, r)
3657 Display *display;
3658 Drawable drawable;
3659 Line *linePtr;
3660 LinePen *penPtr;
3661 int nSymbolPts;
3662 register Point2D *symbolPts;
3663 int r;
3664{
3665 XRectangle *rectArr;
3666 register Point2D *pointPtr, *endPtr;
3667 register XRectangle *rectPtr;
3668 int reqSize, nRects;
3669 int s;
3670 register int i;
3671 int count;
3672
3673 s = r + r;
3674 rectArr = Blt_Malloc(nSymbolPts * sizeof(XRectangle));
3675 rectPtr = rectArr;
3676
3677 if (linePtr->symbolInterval > 0) {
3678 count = 0;
3679 for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts;
3680 pointPtr < endPtr; pointPtr++) {
3681 if (DRAW_SYMBOL(linePtr)) {
3682 rectPtr->x = (short int)(pointPtr->x - r);
3683 rectPtr->y = (short int)(pointPtr->y - r);
3684 rectPtr->width = rectPtr->height = (unsigned short)s;
3685 rectPtr++, count++;
3686 }
3687 linePtr->symbolCounter++;
3688 }
3689 } else {
3690 count = nSymbolPts;
3691 for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts;
3692 pointPtr < endPtr; pointPtr++) {
3693 rectPtr->x = (short int)(pointPtr->x - r);
3694 rectPtr->y = (short int)(pointPtr->y - r);
3695 rectPtr->width = rectPtr->height = (unsigned short)s;
3696 rectPtr++;
3697 }
3698 }
3699 reqSize = MAX_DRAWRECTANGLES(display);
3700 for (i = 0; i < count; i += reqSize) {
3701 nRects = ((i + reqSize) > count) ? (count - i) : reqSize;
3702 if (penPtr->symbol.fillGC != NULL) {
3703 XFillRectangles(display, drawable, penPtr->symbol.fillGC,
3704 rectArr + i, nRects);
3705 }
3706 if (penPtr->symbol.outlineWidth > 0) {
3707 XDrawRectangles(display, drawable, penPtr->symbol.outlineGC,
3708 rectArr + i, nRects);
3709 }
3710 }
3711 Blt_Free(rectArr);
3712}
3713
3714/*
3715 * -----------------------------------------------------------------
3716 *
3717 * DrawSymbols --
3718 *
3719 * Draw the symbols centered at the each given x,y coordinate
3720 * in the array of points.
3721 *
3722 * Results:
3723 * None.
3724 *
3725 * Side Effects:
3726 * Draws a symbol at each coordinate given. If active,
3727 * only those coordinates which are currently active are
3728 * drawn.
3729 *
3730 * -----------------------------------------------------------------
3731 */
3732static void
3733DrawSymbols(graphPtr, drawable, linePtr, penPtr, size, nSymbolPts, symbolPts)
3734 Graph *graphPtr; /* Graph widget record */
3735 Drawable drawable; /* Pixmap or window to draw into */
3736 Line *linePtr;
3737 LinePen *penPtr;
3738 int size; /* Size of element */
3739 int nSymbolPts; /* Number of coordinates in array */
3740 Point2D *symbolPts; /* Array of x,y coordinates for line */
3741{
3742 XPoint pattern[13]; /* Template for polygon symbols */
3743 int r1, r2;
3744 register int i, n;
3745 int count;
3746 register Point2D *pointPtr, *endPtr;
3747#define SQRT_PI 1.77245385090552
3748#define S_RATIO 0.886226925452758
3749
3750 if (size < 3) {
3751 if (penPtr->symbol.fillGC != NULL) {
3752 XPoint *points;
3753
3754 points = Blt_Malloc(nSymbolPts * sizeof(XPoint));
3755 count = 0;
3756 for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts;
3757 pointPtr < endPtr; pointPtr++) {
3758 points[count].x = (short int)pointPtr->x;
3759 points[count].y = (short int)pointPtr->y;
3760 count++;
3761 }
3762 XDrawPoints(graphPtr->display, drawable, penPtr->symbol.fillGC,
3763 points, nSymbolPts, CoordModeOrigin);
3764 Blt_Free(points);
3765 }
3766 return;
3767 }
3768 r1 = (int)ceil(size * 0.5);
3769 r2 = (int)ceil(size * S_RATIO * 0.5);
3770
3771 switch (penPtr->symbol.type) {
3772 case SYMBOL_NONE:
3773 break;
3774
3775 case SYMBOL_SQUARE:
3776 DrawSquares(graphPtr->display, drawable, linePtr, penPtr, nSymbolPts,
3777 symbolPts, r2);
3778 break;
3779
3780 case SYMBOL_CIRCLE:
3781 DrawCircles(graphPtr->display, drawable, linePtr, penPtr, nSymbolPts,
3782 symbolPts, r1);
3783 break;
3784
3785 case SYMBOL_SPLUS:
3786 case SYMBOL_SCROSS:
3787 {
3788 XSegment *segArr; /* Array of line segments (splus, scross) */
3789 register XSegment *segPtr;
3790 int reqSize, nSegs, chunk;
3791
3792 if (penPtr->symbol.type == SYMBOL_SCROSS) {
3793 r2 = Round(r2 * M_SQRT1_2);
3794 pattern[3].y = pattern[2].x = pattern[0].x = pattern[0].y = -r2;
3795 pattern[3].x = pattern[2].y = pattern[1].y = pattern[1].x = r2;
3796 } else {
3797 pattern[0].y = pattern[1].y = pattern[2].x = pattern[3].x = 0;
3798 pattern[0].x = pattern[2].y = -r2;
3799 pattern[1].x = pattern[3].y = r2;
3800 }
3801 segArr = Blt_Malloc(nSymbolPts * 2 * sizeof(XSegment));
3802 segPtr = segArr;
3803 if (linePtr->symbolInterval > 0) {
3804 count = 0;
3805 for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts;
3806 pointPtr < endPtr; pointPtr++) {
3807 if (DRAW_SYMBOL(linePtr)) {
3808 segPtr->x1 = pattern[0].x + (short int)pointPtr->x;
3809 segPtr->y1 = pattern[0].y + (short int)pointPtr->y;
3810 segPtr->x2 = pattern[1].x + (short int)pointPtr->x;
3811 segPtr->y2 = pattern[1].y + (short int)pointPtr->y;
3812 segPtr++;
3813 segPtr->x1 = pattern[2].x + (short int)pointPtr->x;
3814 segPtr->y1 = pattern[2].y + (short int)pointPtr->y;
3815 segPtr->x2 = pattern[3].x + (short int)pointPtr->x;
3816 segPtr->y2 = pattern[3].y + (short int)pointPtr->y;
3817 segPtr++;
3818 count++;
3819 }
3820 linePtr->symbolCounter++;
3821 }
3822 } else {
3823 count = nSymbolPts;
3824 for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts;
3825 pointPtr < endPtr; pointPtr++) {
3826 segPtr->x1 = pattern[0].x + (short int)pointPtr->x;
3827 segPtr->y1 = pattern[0].y + (short int)pointPtr->y;
3828 segPtr->x2 = pattern[1].x + (short int)pointPtr->x;
3829 segPtr->y2 = pattern[1].y + (short int)pointPtr->y;
3830 segPtr++;
3831 segPtr->x1 = pattern[2].x + (short int)pointPtr->x;
3832 segPtr->y1 = pattern[2].y + (short int)pointPtr->y;
3833 segPtr->x2 = pattern[3].x + (short int)pointPtr->x;
3834 segPtr->y2 = pattern[3].y + (short int)pointPtr->y;
3835 segPtr++;
3836 }
3837 }
3838 nSegs = count * 2;
3839 /* Always draw skinny symbols regardless of the outline width */
3840 reqSize = MAX_DRAWSEGMENTS(graphPtr->display);
3841 for (i = 0; i < nSegs; i += reqSize) {
3842 chunk = ((i + reqSize) > nSegs) ? (nSegs - i) : reqSize;
3843 XDrawSegments(graphPtr->display, drawable,
3844 penPtr->symbol.outlineGC, segArr + i, chunk);
3845 }
3846 Blt_Free(segArr);
3847 }
3848 break;
3849
3850 case SYMBOL_PLUS:
3851 case SYMBOL_CROSS:
3852 {
3853 XPoint *polygon;
3854 register XPoint *p;
3855 int d; /* Small delta for cross/plus thickness */
3856
3857 d = (r2 / 3);
3858
3859 /*
3860 *
3861 * 2 3 The plus/cross symbol is a closed polygon
3862 * of 12 points. The diagram to the left
3863 * 0,12 1 4 5 represents the positions of the points
3864 * x,y which are computed below. The extra
3865 * 11 10 7 6 (thirteenth) point connects the first and
3866 * last points.
3867 * 9 8
3868 */
3869
3870 pattern[0].x = pattern[11].x = pattern[12].x = -r2;
3871 pattern[2].x = pattern[1].x = pattern[10].x = pattern[9].x = -d;
3872 pattern[3].x = pattern[4].x = pattern[7].x = pattern[8].x = d;
3873 pattern[5].x = pattern[6].x = r2;
3874 pattern[2].y = pattern[3].y = -r2;
3875 pattern[0].y = pattern[1].y = pattern[4].y = pattern[5].y =
3876 pattern[12].y = -d;
3877 pattern[11].y = pattern[10].y = pattern[7].y = pattern[6].y = d;
3878 pattern[9].y = pattern[8].y = r2;
3879
3880 if (penPtr->symbol.type == SYMBOL_CROSS) {
3881 double dx, dy;
3882
3883 /* For the cross symbol, rotate the points by 45 degrees. */
3884 for (n = 0; n < 12; n++) {
3885 dx = (double)pattern[n].x * M_SQRT1_2;
3886 dy = (double)pattern[n].y * M_SQRT1_2;
3887 pattern[n].x = Round(dx - dy);
3888 pattern[n].y = Round(dx + dy);
3889 }
3890 pattern[12] = pattern[0];
3891 }
3892 polygon = Blt_Malloc(nSymbolPts * 13 * sizeof(XPoint));
3893 p = polygon;
3894 if (linePtr->symbolInterval > 0) {
3895 count = 0;
3896 for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts;
3897 pointPtr < endPtr; pointPtr++) {
3898 if (DRAW_SYMBOL(linePtr)) {
3899 for (n = 0; n < 13; n++) {
3900 p->x = pattern[n].x + (short int)pointPtr->x;
3901 p->y = pattern[n].y + (short int)pointPtr->y;
3902 p++;
3903 }
3904 count++;
3905 }
3906 linePtr->symbolCounter++;
3907 }
3908 } else {
3909 count = nSymbolPts;
3910 for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts;
3911 pointPtr < endPtr; pointPtr++) {
3912 for (n = 0; n < 13; n++) {
3913 p->x = pattern[n].x + (short int)pointPtr->x;
3914 p->y = pattern[n].y + (short int)pointPtr->y;
3915 p++;
3916 }
3917 }
3918 }
3919 if (penPtr->symbol.fillGC != NULL) {
3920 for (p = polygon, i = 0; i < count; i++, p += 13) {
3921 XFillPolygon(graphPtr->display, drawable,
3922 penPtr->symbol.fillGC, p, 13, Complex, CoordModeOrigin);
3923 }
3924 }
3925 if (penPtr->symbol.outlineWidth > 0) {
3926 for (p = polygon, i = 0; i < count; i++, p += 13) {
3927 XDrawLines(graphPtr->display, drawable,
3928 penPtr->symbol.outlineGC, p, 13, CoordModeOrigin);
3929 }
3930 }
3931 Blt_Free(polygon);
3932 }
3933 break;
3934
3935 case SYMBOL_DIAMOND:
3936 {
3937 XPoint *polygon;
3938 register XPoint *p;
3939
3940 /*
3941 *
3942 * The plus symbol is a closed polygon
3943 * 1 of 4 points. The diagram to the left
3944 * represents the positions of the points
3945 * 0,4 x,y 2 which are computed below. The extra
3946 * (fifth) point connects the first and
3947 * 3 last points.
3948 *
3949 */
3950 pattern[1].y = pattern[0].x = -r1;
3951 pattern[2].y = pattern[3].x = pattern[0].y = pattern[1].x = 0;
3952 pattern[3].y = pattern[2].x = r1;
3953 pattern[4] = pattern[0];
3954
3955 polygon = Blt_Malloc(nSymbolPts * 5 * sizeof(XPoint));
3956 p = polygon;
3957 if (linePtr->symbolInterval > 0) {
3958 count = 0;
3959 for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts;
3960 pointPtr < endPtr; pointPtr++) {
3961 if (DRAW_SYMBOL(linePtr)) {
3962 for (n = 0; n < 5; n++, p++) {
3963 p->x = pattern[n].x + (short int)pointPtr->x;
3964 p->y = pattern[n].y + (short int)pointPtr->y;
3965 }
3966 count++;
3967 }
3968 linePtr->symbolCounter++;
3969 }
3970 } else {
3971 count = nSymbolPts;
3972 for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts;
3973 pointPtr < endPtr; pointPtr++) {
3974 for (n = 0; n < 5; n++, p++) {
3975 p->x = pattern[n].x + (short int)pointPtr->x;
3976 p->y = pattern[n].y + (short int)pointPtr->y;
3977 }
3978 }
3979 }
3980 if (penPtr->symbol.fillGC != NULL) {
3981 for (p = polygon, i = 0; i < count; i++, p += 5) {
3982 XFillPolygon(graphPtr->display, drawable,
3983 penPtr->symbol.fillGC, p, 5, Convex, CoordModeOrigin);
3984
3985 }
3986 }
3987 if (penPtr->symbol.outlineWidth > 0) {
3988 for (p = polygon, i = 0; i < count; i++, p += 5) {
3989 XDrawLines(graphPtr->display, drawable,
3990 penPtr->symbol.outlineGC, p, 5, CoordModeOrigin);
3991 }
3992 }
3993 Blt_Free(polygon);
3994 }
3995 break;
3996
3997 case SYMBOL_TRIANGLE:
3998 case SYMBOL_ARROW:
3999 {
4000 XPoint *polygon;
4001 register XPoint *p;
4002 double b;
4003 int b2, h1, h2;
4004#define H_RATIO 1.1663402261671607
4005#define B_RATIO 1.3467736870885982
4006#define TAN30 0.57735026918962573
4007#define COS30 0.86602540378443871
4008
4009 b = Round(size * B_RATIO * 0.7);
4010 b2 = Round(b * 0.5);
4011 h2 = Round(TAN30 * b2);
4012 h1 = Round(b2 / COS30);
4013 /*
4014 *
4015 * The triangle symbol is a closed polygon
4016 * 0,3 of 3 points. The diagram to the left
4017 * represents the positions of the points
4018 * x,y which are computed below. The extra
4019 * (fourth) point connects the first and
4020 * 2 1 last points.
4021 *
4022 */
4023
4024 if (penPtr->symbol.type == SYMBOL_ARROW) {
4025 pattern[3].x = pattern[0].x = 0;
4026 pattern[3].y = pattern[0].y = h1;
4027 pattern[1].x = b2;
4028 pattern[2].y = pattern[1].y = -h2;
4029 pattern[2].x = -b2;
4030 } else {
4031 pattern[3].x = pattern[0].x = 0;
4032 pattern[3].y = pattern[0].y = -h1;
4033 pattern[1].x = b2;
4034 pattern[2].y = pattern[1].y = h2;
4035 pattern[2].x = -b2;
4036 }
4037 polygon = Blt_Malloc(nSymbolPts * 4 * sizeof(XPoint));
4038 p = polygon;
4039 if (linePtr->symbolInterval > 0) {
4040 count = 0;
4041 for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts;
4042 pointPtr < endPtr; pointPtr++) {
4043 if (DRAW_SYMBOL(linePtr)) {
4044 for (n = 0; n < 4; n++) {
4045 p->x = pattern[n].x + (short int)pointPtr->x;
4046 p->y = pattern[n].y + (short int)pointPtr->y;
4047 p++;
4048 }
4049 count++;
4050 }
4051 linePtr->symbolCounter++;
4052 }
4053 } else {
4054 count = nSymbolPts;
4055 for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts;
4056 pointPtr < endPtr; pointPtr++) {
4057 for (n = 0; n < 4; n++) {
4058 p->x = pattern[n].x + (short int)pointPtr->x;
4059 p->y = pattern[n].y + (short int)pointPtr->y;
4060 p++;
4061 }
4062 }
4063 }
4064 if (penPtr->symbol.fillGC != NULL) {
4065 for (p = polygon, i = 0; i < count; i++, p += 4) {
4066 XFillPolygon(graphPtr->display, drawable,
4067 penPtr->symbol.fillGC, p, 4, Convex, CoordModeOrigin);
4068 }
4069 }
4070 if (penPtr->symbol.outlineWidth > 0) {
4071 for (p = polygon, i = 0; i < count; i++, p += 4) {
4072 XDrawLines(graphPtr->display, drawable,
4073 penPtr->symbol.outlineGC, p, 4, CoordModeOrigin);
4074 }
4075 }
4076 Blt_Free(polygon);
4077 }
4078 break;
4079 case SYMBOL_BITMAP:
4080 {
4081 Pixmap bitmap, mask;
4082 int width, height, bmWidth, bmHeight;
4083 double scale, sx, sy;
4084 int dx, dy;
4085 register int x, y;
4086
4087 Tk_SizeOfBitmap(graphPtr->display, penPtr->symbol.bitmap,
4088 &width, &height);
4089 mask = None;
4090
4091 /*
4092 * Compute the size of the scaled bitmap. Stretch the
4093 * bitmap to fit a nxn bounding box.
4094 */
4095 sx = (double)size / (double)width;
4096 sy = (double)size / (double)height;
4097 scale = MIN(sx, sy);
4098 bmWidth = (int)(width * scale);
4099 bmHeight = (int)(height * scale);
4100
4101 XSetClipMask(graphPtr->display, penPtr->symbol.outlineGC, None);
4102 if (penPtr->symbol.mask != None) {
4103 mask = Blt_ScaleBitmap(graphPtr->tkwin, penPtr->symbol.mask,
4104 width, height, bmWidth, bmHeight);
4105 XSetClipMask(graphPtr->display, penPtr->symbol.outlineGC,
4106 mask);
4107 }
4108 bitmap = Blt_ScaleBitmap(graphPtr->tkwin, penPtr->symbol.bitmap,
4109 width, height, bmWidth, bmHeight);
4110 if (penPtr->symbol.fillGC == NULL) {
4111 XSetClipMask(graphPtr->display, penPtr->symbol.outlineGC,
4112 bitmap);
4113 }
4114 dx = bmWidth / 2;
4115 dy = bmHeight / 2;
4116 if (linePtr->symbolInterval > 0) {
4117 for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts;
4118 pointPtr < endPtr; pointPtr++) {
4119 if (DRAW_SYMBOL(linePtr)) {
4120 x = (int)pointPtr->x - dx;
4121 y = (int)pointPtr->y - dy;
4122 if ((penPtr->symbol.fillGC == NULL) || (mask != None)) {
4123 XSetClipOrigin(graphPtr->display,
4124 penPtr->symbol.outlineGC, x, y);
4125 }
4126 XCopyPlane(graphPtr->display, bitmap, drawable,
4127 penPtr->symbol.outlineGC, 0, 0, bmWidth, bmHeight,
4128 x, y, 1);
4129 }
4130 linePtr->symbolCounter++;
4131 }
4132 } else {
4133 for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts;
4134 pointPtr < endPtr; pointPtr++) {
4135 x = (int)pointPtr->x - dx;
4136 y = (int)pointPtr->y - dy;
4137 if ((penPtr->symbol.fillGC == NULL) || (mask != None)) {
4138 XSetClipOrigin(graphPtr->display,
4139 penPtr->symbol.outlineGC, x, y);
4140 }
4141 XCopyPlane(graphPtr->display, bitmap, drawable,
4142 penPtr->symbol.outlineGC, 0, 0, bmWidth, bmHeight,
4143 x, y, 1);
4144 }
4145 }
4146 Tk_FreePixmap(graphPtr->display, bitmap);
4147 if (mask != None) {
4148 Tk_FreePixmap(graphPtr->display, mask);
4149 }
4150 }
4151 break;
4152 }
4153}
4154
4155/*
4156 * -----------------------------------------------------------------
4157 *
4158 * DrawSymbol --
4159 *
4160 * Draw the symbol centered at the each given x,y coordinate.
4161 *
4162 * Results:
4163 * None.
4164 *
4165 * Side Effects:
4166 * Draws a symbol at the coordinate given.
4167 *
4168 * -----------------------------------------------------------------
4169 */
4170static void
4171DrawSymbol(graphPtr, drawable, elemPtr, x, y, size)
4172 Graph *graphPtr; /* Graph widget record */
4173 Drawable drawable; /* Pixmap or window to draw into */
4174 Element *elemPtr; /* Line element information */
4175 int x, y; /* Center position of symbol */
4176 int size; /* Size of symbol. */
4177{
4178 Line *linePtr = (Line *)elemPtr;
4179 LinePen *penPtr = linePtr->normalPenPtr;
4180
4181 if (penPtr->traceWidth > 0) {
4182 /*
4183 * Draw an extra line offset by one pixel from the previous to
4184 * give a thicker appearance. This is only for the legend
4185 * entry. This routine is never called for drawing the actual
4186 * line segments.
4187 */
4188 XDrawLine(graphPtr->display, drawable, penPtr->traceGC, x - size,
4189 y, x + size, y);
4190 XDrawLine(graphPtr->display, drawable, penPtr->traceGC, x - size,
4191 y + 1, x + size, y + 1);
4192 }
4193 if (penPtr->symbol.type != SYMBOL_NONE) {
4194 Point2D point;
4195
4196 point.x = x, point.y = y;
4197 DrawSymbols(graphPtr, drawable, linePtr, linePtr->normalPenPtr, size,
4198 1, &point);
4199 }
4200}
4201
4202#ifdef WIN32
4203
4204static void
4205DrawTraces(
4206 Graph *graphPtr,
4207 Drawable drawable, /* Pixmap or window to draw into */
4208 Line *linePtr,
4209 LinePen *penPtr)
4210{
4211 Blt_ChainLink *linkPtr;
4212 HBRUSH brush, oldBrush;
4213 HDC dc;
4214 HPEN pen, oldPen;
4215 POINT *points;
4216 TkWinDCState state;
4217 Trace *tracePtr;
4218 int j;
4219 int nPoints, remaining;
4220 register POINT *p;
4221 register int count;
4222
4223 /*
4224 * Depending if the line is wide (> 1 pixel), arbitrarily break
4225 * the line in sections of 100 points. This bit of weirdness has
4226 * to do with wide geometric pens. The longer the polyline, the
4227 * slower it draws. The trade off is that we lose dash and cap
4228 * uniformity for unbearably slow polyline draws.
4229 */
4230 if (penPtr->traceGC->line_width > 1) {
4231 nPoints = 100;
4232 } else {
4233 nPoints = Blt_MaxRequestSize(graphPtr->display, sizeof(POINT)) - 1;
4234 }
4235 points = Blt_Malloc((nPoints + 1) * sizeof(POINT));
4236
4237 dc = TkWinGetDrawableDC(graphPtr->display, drawable, &state);
4238
4239 pen = Blt_GCToPen(dc, penPtr->traceGC);
4240 oldPen = SelectPen(dc, pen);
4241 brush = CreateSolidBrush(penPtr->traceGC->foreground);
4242 oldBrush = SelectBrush(dc, brush);
4243 SetROP2(dc, tkpWinRopModes[penPtr->traceGC->function]);
4244
4245 for (linkPtr = Blt_ChainFirstLink(linePtr->traces); linkPtr != NULL;
4246 linkPtr = Blt_ChainNextLink(linkPtr)) {
4247 tracePtr = Blt_ChainGetValue(linkPtr);
4248
4249 /*
4250 * If the trace has to be split into separate XDrawLines
4251 * calls, then the end point of the current trace is also the
4252 * starting point of the new split.
4253 */
4254
4255 /* Step 1. Convert and draw the first section of the trace.
4256 * It may contain the entire trace. */
4257
4258 for (p = points, count = 0; count < MIN(nPoints, tracePtr->nScreenPts);
4259 count++, p++) {
4260 p->x = (int)tracePtr->screenPts[count].x;
4261 p->y = (int)tracePtr->screenPts[count].y;
4262 }
4263 Polyline(dc, points, count);
4264
4265 /* Step 2. Next handle any full-size chunks left. */
4266
4267 while ((count + nPoints) < tracePtr->nScreenPts) {
4268 /* Start with the last point of the previous trace. */
4269 points[0].x = points[nPoints - 1].x;
4270 points[0].y = points[nPoints - 1].y;
4271
4272 for (p = points + 1, j = 0; j < nPoints; j++, count++, p++) {
4273 p->x = (int)tracePtr->screenPts[count].x;
4274 p->y = (int)tracePtr->screenPts[count].y;
4275 }
4276 Polyline(dc, points, nPoints + 1);
4277 }
4278
4279 /* Step 3. Convert and draw the remaining points. */
4280
4281 remaining = tracePtr->nScreenPts - count;
4282 if (remaining > 0) {
4283 /* Start with the last point of the previous trace. */
4284 points[0].x = points[nPoints - 1].x;
4285 points[0].y = points[nPoints - 1].y;
4286
4287 for (p = points + 1; count < tracePtr->nScreenPts; count++, p++) {
4288 p->x = (int)tracePtr->screenPts[count].x;
4289 p->y = (int)tracePtr->screenPts[count].y;
4290 }
4291 Polyline(dc, points, remaining + 1);
4292 }
4293 }
4294 Blt_Free(points);
4295 DeletePen(SelectPen(dc, oldPen));
4296 DeleteBrush(SelectBrush(dc, oldBrush));
4297 TkWinReleaseDrawableDC(drawable, dc, &state);
4298}
4299
4300#else
4301
4302static void
4303DrawTraces(graphPtr, drawable, linePtr, penPtr)
4304 Graph *graphPtr;
4305 Drawable drawable; /* Pixmap or window to draw into */
4306 Line *linePtr;
4307 LinePen *penPtr;
4308{
4309 Blt_ChainLink *linkPtr;
4310 Trace *tracePtr;
4311 XPoint *points;
4312 int j;
4313 int nPoints, remaining;
4314 register XPoint *p;
4315 register int count;
4316
4317 nPoints = Blt_MaxRequestSize(graphPtr->display, sizeof(XPoint)) - 1;
4318 points = Blt_Malloc((nPoints + 1) * sizeof(XPoint));
4319
4320 for (linkPtr = Blt_ChainFirstLink(linePtr->traces); linkPtr != NULL;
4321 linkPtr = Blt_ChainNextLink(linkPtr)) {
4322 int n;
4323
4324 tracePtr = Blt_ChainGetValue(linkPtr);
4325
4326 /*
4327 * If the trace has to be split into separate XDrawLines
4328 * calls, then the end point of the current trace is also the
4329 * starting point of the new split.
4330 */
4331 /* Step 1. Convert and draw the first section of the trace.
4332 * It may contain the entire trace. */
4333
4334 n = MIN(nPoints, tracePtr->nScreenPts);
4335 for (p = points, count = 0; count < n; count++, p++) {
4336 p->x = (short int)tracePtr->screenPts[count].x;
4337 p->y = (short int)tracePtr->screenPts[count].y;
4338 }
4339 XDrawLines(graphPtr->display, drawable, penPtr->traceGC, points,
4340 count, CoordModeOrigin);
4341
4342 /* Step 2. Next handle any full-size chunks left. */
4343
4344 while ((count + nPoints) < tracePtr->nScreenPts) {
4345 /* Start with the last point of the previous trace. */
4346 points[0].x = points[nPoints - 1].x;
4347 points[0].y = points[nPoints - 1].y;
4348
4349 for (p = points + 1, j = 0; j < nPoints; j++, count++, p++) {
4350 p->x = (short int)tracePtr->screenPts[count].x;
4351 p->y = (short int)tracePtr->screenPts[count].y;
4352 }
4353 XDrawLines(graphPtr->display, drawable, penPtr->traceGC, points,
4354 nPoints + 1, CoordModeOrigin);
4355 }
4356
4357 /* Step 3. Convert and draw the remaining points. */
4358
4359 remaining = tracePtr->nScreenPts - count;
4360 if (remaining > 0) {
4361 /* Start with the last point of the previous trace. */
4362 points[0].x = points[nPoints - 1].x;
4363 points[0].y = points[nPoints - 1].y;
4364 for (p = points + 1; count < tracePtr->nScreenPts; count++, p++) {
4365 p->x = (short int)tracePtr->screenPts[count].x;
4366 p->y = (short int)tracePtr->screenPts[count].y;
4367 }
4368 XDrawLines(graphPtr->display, drawable, penPtr->traceGC, points,
4369 remaining + 1, CoordModeOrigin);
4370 }
4371 }
4372 Blt_Free(points);
4373}
4374#endif /* WIN32 */
4375
4376static void
4377DrawValues(graphPtr, drawable, linePtr, penPtr, nSymbolPts, symbolPts,
4378 pointToData)
4379 Graph *graphPtr;
4380 Drawable drawable;
4381 Line *linePtr;
4382 LinePen *penPtr;
4383 int nSymbolPts;
4384 Point2D *symbolPts;
4385 int *pointToData;
4386{
4387 Point2D *pointPtr, *endPtr;
4388 int count;
4389 char string[TCL_DOUBLE_SPACE * 2 + 2];
4390 char *fmt;
4391 double x, y;
4392
4393 fmt = penPtr->valueFormat;
4394 if (fmt == NULL) {
4395 fmt = "%g";
4396 }
4397 count = 0;
4398 for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts;
4399 pointPtr < endPtr; pointPtr++) {
4400 x = linePtr->x.valueArr[pointToData[count]];
4401 y = linePtr->y.valueArr[pointToData[count]];
4402 count++;
4403 if (penPtr->valueShow == SHOW_X) {
4404 sprintf(string, fmt, x);
4405 } else if (penPtr->valueShow == SHOW_Y) {
4406 sprintf(string, fmt, y);
4407 } else if (penPtr->valueShow == SHOW_BOTH) {
4408 sprintf(string, fmt, x);
4409 strcat(string, ",");
4410 sprintf(string + strlen(string), fmt, y);
4411 }
4412 Blt_DrawText(graphPtr->tkwin, drawable, string, &(penPtr->valueStyle),
4413 (int)pointPtr->x, (int)pointPtr->y);
4414 }
4415}
4416
4417
4418/*
4419 *----------------------------------------------------------------------
4420 *
4421 * DrawActiveLine --
4422 *
4423 * Draws the connected line(s) representing the element. If the
4424 * line is made up of non-line symbols and the line width
4425 * parameter has been set (linewidth > 0), the element will also
4426 * be drawn as a line (with the linewidth requested). The line
4427 * may consist of separate line segments.
4428 *
4429 * Results:
4430 * None.
4431 *
4432 * Side effects:
4433 * X drawing commands are output.
4434 *
4435 *----------------------------------------------------------------------
4436 */
4437static void
4438DrawActiveLine(graphPtr, drawable, elemPtr)
4439 Graph *graphPtr; /* Graph widget record */
4440 Drawable drawable; /* Pixmap or window to draw into */
4441 Element *elemPtr; /* Element to be drawn */
4442{
4443 Line *linePtr = (Line *)elemPtr;
4444 LinePen *penPtr = linePtr->activePenPtr;
4445 int symbolSize;
4446
4447 if (penPtr == NULL) {
4448 return;
4449 }
4450 symbolSize = ScaleSymbol(elemPtr, linePtr->activePenPtr->symbol.size);
4451
4452 /*
4453 * nActiveIndices
4454 * > 0 Some points are active. Uses activeArr.
4455 * < 0 All points are active.
4456 * == 0 No points are active.
4457 */
4458 if (linePtr->nActiveIndices > 0) {
4459 if (linePtr->flags & ACTIVE_PENDING) {
4460 MapActiveSymbols(graphPtr, linePtr);
4461 }
4462 if (penPtr->symbol.type != SYMBOL_NONE) {
4463 DrawSymbols(graphPtr, drawable, linePtr, penPtr, symbolSize,
4464 linePtr->nActivePts, linePtr->activePts);
4465 }
4466 if (penPtr->valueShow != SHOW_NONE) {
4467 DrawValues(graphPtr, drawable, linePtr, penPtr,
4468 linePtr->nActivePts, linePtr->activePts,
4469 linePtr->activeToData);
4470 }
4471 } else if (linePtr->nActiveIndices < 0) {
4472 if (penPtr->traceWidth > 0) {
4473 if (linePtr->nStrips > 0) {
4474 Blt_Draw2DSegments(graphPtr->display, drawable,
4475 penPtr->traceGC, linePtr->strips, linePtr->nStrips);
4476 } else if (Blt_ChainGetLength(linePtr->traces) > 0) {
4477 DrawTraces(graphPtr, drawable, linePtr, penPtr);
4478 }
4479 }
4480 if (penPtr->symbol.type != SYMBOL_NONE) {
4481 DrawSymbols(graphPtr, drawable, linePtr, penPtr, symbolSize,
4482 linePtr->nSymbolPts, linePtr->symbolPts);
4483 }
4484 if (penPtr->valueShow != SHOW_NONE) {
4485 DrawValues(graphPtr, drawable, linePtr, penPtr,
4486 linePtr->nSymbolPts, linePtr->symbolPts,
4487 linePtr->symbolToData);
4488 }
4489 }
4490}
4491
4492/*
4493 *----------------------------------------------------------------------
4494 *
4495 * DrawNormalLine --
4496 *
4497 * Draws the connected line(s) representing the element. If the
4498 * line is made up of non-line symbols and the line width parameter
4499 * has been set (linewidth > 0), the element will also be drawn as
4500 * a line (with the linewidth requested). The line may consist of
4501 * separate line segments.
4502 *
4503 * Results:
4504 * None.
4505 *
4506 * Side effects:
4507 * X drawing commands are output.
4508 *
4509 *----------------------------------------------------------------------
4510 */
4511static void
4512DrawNormalLine(graphPtr, drawable, elemPtr)
4513 Graph *graphPtr; /* Graph widget record */
4514 Drawable drawable; /* Pixmap or window to draw into */
4515 Element *elemPtr; /* Element to be drawn */
4516{
4517 Line *linePtr = (Line *)elemPtr;
4518 LinePen *penPtr;
4519 Blt_ChainLink *linkPtr;
4520 register LinePenStyle *stylePtr;
4521 unsigned int count;
4522
4523 /* Fill area under the curve */
4524 if (linePtr->fillPts != NULL) {
4525 XPoint *points;
4526 Point2D *endPtr, *pointPtr;
4527
4528 points = Blt_Malloc(sizeof(XPoint) * linePtr->nFillPts);
4529 count = 0;
4530 for(pointPtr = linePtr->fillPts,
4531 endPtr = linePtr->fillPts + linePtr->nFillPts;
4532 pointPtr < endPtr; pointPtr++) {
4533 points[count].x = (short int)pointPtr->x;
4534 points[count].y = (short int)pointPtr->y;
4535 count++;
4536 }
4537 if (linePtr->fillTile != NULL) {
4538 Blt_SetTileOrigin(graphPtr->tkwin, linePtr->fillTile, 0, 0);
4539 Blt_TilePolygon(graphPtr->tkwin, drawable, linePtr->fillTile,
4540 points, linePtr->nFillPts);
4541 } else if (linePtr->fillStipple != None) {
4542 XFillPolygon(graphPtr->display, drawable, linePtr->fillGC,
4543 points, linePtr->nFillPts, Complex, CoordModeOrigin);
4544 }
4545 Blt_Free(points);
4546 }
4547
4548 /* Lines: stripchart segments or graph traces. */
4549
4550 if (linePtr->nStrips > 0) {
4551 for (linkPtr = Blt_ChainFirstLink(linePtr->palette); linkPtr != NULL;
4552 linkPtr = Blt_ChainNextLink(linkPtr)) {
4553 stylePtr = Blt_ChainGetValue(linkPtr);
4554 penPtr = stylePtr->penPtr;
4555 if ((stylePtr->nStrips > 0) && (penPtr->errorBarLineWidth > 0)) {
4556 Blt_Draw2DSegments(graphPtr->display, drawable,
4557 penPtr->traceGC, stylePtr->strips, stylePtr->nStrips);
4558 }
4559 }
4560 } else if ((Blt_ChainGetLength(linePtr->traces) > 0) &&
4561 (linePtr->normalPenPtr->traceWidth > 0)) {
4562 DrawTraces(graphPtr, drawable, linePtr, linePtr->normalPenPtr);
4563 }
4564
4565 if (linePtr->reqMaxSymbols > 0) {
4566 int total;
4567
4568 total = 0;
4569 for (linkPtr = Blt_ChainFirstLink(linePtr->palette); linkPtr != NULL;
4570 linkPtr = Blt_ChainNextLink(linkPtr)) {
4571 stylePtr = Blt_ChainGetValue(linkPtr);
4572 total += stylePtr->nSymbolPts;
4573 }
4574 linePtr->symbolInterval = total / linePtr->reqMaxSymbols;
4575 linePtr->symbolCounter = 0;
4576 }
4577
4578 /* Symbols, error bars, values. */
4579
4580 count = 0;
4581 for (linkPtr = Blt_ChainFirstLink(linePtr->palette); linkPtr != NULL;
4582 linkPtr = Blt_ChainNextLink(linkPtr)) {
4583 stylePtr = Blt_ChainGetValue(linkPtr);
4584 penPtr = stylePtr->penPtr;
4585 if ((stylePtr->xErrorBarCnt > 0) && (penPtr->errorBarShow & SHOW_X)) {
4586 Blt_Draw2DSegments(graphPtr->display, drawable, penPtr->errorBarGC,
4587 stylePtr->xErrorBars, stylePtr->xErrorBarCnt);
4588 }
4589 if ((stylePtr->yErrorBarCnt > 0) && (penPtr->errorBarShow & SHOW_Y)) {
4590 Blt_Draw2DSegments(graphPtr->display, drawable, penPtr->errorBarGC,
4591 stylePtr->yErrorBars, stylePtr->yErrorBarCnt);
4592 }
4593 if ((stylePtr->nSymbolPts > 0) &&
4594 (penPtr->symbol.type != SYMBOL_NONE)) {
4595 DrawSymbols(graphPtr, drawable, linePtr, penPtr,
4596 stylePtr->symbolSize, stylePtr->nSymbolPts,
4597 stylePtr->symbolPts);
4598 }
4599 if (penPtr->valueShow != SHOW_NONE) {
4600 DrawValues(graphPtr, drawable, linePtr, penPtr,
4601 stylePtr->nSymbolPts, stylePtr->symbolPts,
4602 linePtr->symbolToData + count);
4603 }
4604 count += stylePtr->nSymbolPts;
4605 }
4606 linePtr->symbolInterval = 0;
4607}
4608
4609/*
4610 * -----------------------------------------------------------------
4611 *
4612 * GetSymbolPostScriptInfo --
4613 *
4614 * Set up the PostScript environment with the macros and
4615 * attributes needed to draw the symbols of the element.
4616 *
4617 * Results:
4618 * None.
4619 *
4620 * -----------------------------------------------------------------
4621 */
4622static void
4623GetSymbolPostScriptInfo(graphPtr, psToken, penPtr, size)
4624 Graph *graphPtr;
4625 PsToken psToken;
4626 LinePen *penPtr;
4627 int size;
4628{
4629 XColor *outlineColor, *fillColor, *defaultColor;
4630
4631 /* Set line and foreground attributes */
4632 outlineColor = penPtr->symbol.outlineColor;
4633 fillColor = penPtr->symbol.fillColor;
4634 defaultColor = penPtr->traceColor;
4635
4636 if (fillColor == COLOR_DEFAULT) {
4637 fillColor = defaultColor;
4638 }
4639 if (outlineColor == COLOR_DEFAULT) {
4640 outlineColor = defaultColor;
4641 }
4642 if (penPtr->symbol.type == SYMBOL_NONE) {
4643 Blt_LineAttributesToPostScript(psToken, defaultColor,
4644 penPtr->traceWidth + 2, &(penPtr->traceDashes),
4645 CapButt, JoinMiter);
4646 } else {
4647 Blt_LineWidthToPostScript(psToken, penPtr->symbol.outlineWidth);
4648 Blt_LineDashesToPostScript(psToken, (Blt_Dashes *)NULL);
4649 }
4650
4651 /*
4652 * Build a PostScript procedure to draw the symbols. For bitmaps,
4653 * paint both the bitmap and its mask. Otherwise fill and stroke
4654 * the path formed already.
4655 */
4656 Blt_AppendToPostScript(psToken, "\n/DrawSymbolProc {\n", (char *)NULL);
4657 switch (penPtr->symbol.type) {
4658 case SYMBOL_NONE:
4659 break; /* Do nothing */
4660 case SYMBOL_BITMAP:
4661 {
4662 int width, height;
4663 double sx, sy, scale;
4664
4665 /*
4666 * Compute how much to scale the bitmap. Don't let the
4667 * scaled bitmap exceed the bounding square for the
4668 * symbol.
4669 */
4670 Tk_SizeOfBitmap(graphPtr->display, penPtr->symbol.bitmap,
4671 &width, &height);
4672 sx = (double)size / (double)width;
4673 sy = (double)size / (double)height;
4674 scale = MIN(sx, sy);
4675
4676 if ((penPtr->symbol.mask != None) && (fillColor != NULL)) {
4677 Blt_AppendToPostScript(psToken,
4678 "\n % Bitmap mask is \"",
4679 Tk_NameOfBitmap(graphPtr->display, penPtr->symbol.mask),
4680 "\"\n\n ", (char *)NULL);
4681 Blt_BackgroundToPostScript(psToken, fillColor);
4682 Blt_BitmapToPostScript(psToken, graphPtr->display,
4683 penPtr->symbol.mask, scale, scale);
4684 }
4685 Blt_AppendToPostScript(psToken,
4686 "\n % Bitmap symbol is \"",
4687 Tk_NameOfBitmap(graphPtr->display, penPtr->symbol.bitmap),
4688 "\"\n\n ", (char *)NULL);
4689 Blt_ForegroundToPostScript(psToken, outlineColor);
4690 Blt_BitmapToPostScript(psToken, graphPtr->display,
4691 penPtr->symbol.bitmap, scale, scale);
4692 }
4693 break;
4694 default:
4695 if (fillColor != NULL) {
4696 Blt_AppendToPostScript(psToken, " ", (char *)NULL);
4697 Blt_BackgroundToPostScript(psToken, fillColor);
4698 Blt_AppendToPostScript(psToken, " Fill\n", (char *)NULL);
4699 }
4700 if ((outlineColor != NULL) && (penPtr->symbol.outlineWidth > 0)) {
4701 Blt_AppendToPostScript(psToken, " ", (char *)NULL);
4702 Blt_ForegroundToPostScript(psToken, outlineColor);
4703 Blt_AppendToPostScript(psToken, " stroke\n", (char *)NULL);
4704 }
4705 break;
4706 }
4707 Blt_AppendToPostScript(psToken, "} def\n\n", (char *)NULL);
4708}
4709
4710/*
4711 * -----------------------------------------------------------------
4712 *
4713 * SymbolsToPostScript --
4714 *
4715 * Draw a symbol centered at the given x,y window coordinate
4716 * based upon the element symbol type and size.
4717 *
4718 * Results:
4719 * None.
4720 *
4721 * Problems:
4722 * Most notable is the round-off errors generated when
4723 * calculating the centered position of the symbol.
4724 *
4725 * -----------------------------------------------------------------
4726 */
4727static void
4728SymbolsToPostScript(graphPtr, psToken, penPtr, size, nSymbolPts, symbolPts)
4729 Graph *graphPtr;
4730 PsToken psToken;
4731 LinePen *penPtr;
4732 int size;
4733 int nSymbolPts;
4734 Point2D *symbolPts;
4735{
4736 double symbolSize;
4737 register Point2D *pointPtr, *endPtr;
4738 static char *symbolMacros[] =
4739 {
4740 "Li", "Sq", "Ci", "Di", "Pl", "Cr", "Sp", "Sc", "Tr", "Ar", "Bm",
4741 (char *)NULL,
4742 };
4743 GetSymbolPostScriptInfo(graphPtr, psToken, penPtr, size);
4744
4745 symbolSize = (double)size;
4746 switch (penPtr->symbol.type) {
4747 case SYMBOL_SQUARE:
4748 case SYMBOL_CROSS:
4749 case SYMBOL_PLUS:
4750 case SYMBOL_SCROSS:
4751 case SYMBOL_SPLUS:
4752 symbolSize = (double)Round(size * S_RATIO);
4753 break;
4754 case SYMBOL_TRIANGLE:
4755 case SYMBOL_ARROW:
4756 symbolSize = (double)Round(size * 0.7);
4757 break;
4758 case SYMBOL_DIAMOND:
4759 symbolSize = (double)Round(size * M_SQRT1_2);
4760 break;
4761
4762 default:
4763 break;
4764 }
4765 for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts;
4766 pointPtr < endPtr; pointPtr++) {
4767 Blt_FormatToPostScript(psToken, "%g %g %g %s\n", pointPtr->x,
4768 pointPtr->y, symbolSize, symbolMacros[penPtr->symbol.type]);
4769 }
4770}
4771
4772/*
4773 * -----------------------------------------------------------------
4774 *
4775 * SymbolToPostScript --
4776 *
4777 * Draw the symbol centered at the each given x,y coordinate.
4778 *
4779 * Results:
4780 * None.
4781 *
4782 * Side Effects:
4783 * Draws a symbol at the coordinate given.
4784 *
4785 * -----------------------------------------------------------------
4786 */
4787static void
4788SymbolToPostScript(graphPtr, psToken, elemPtr, x, y, size)
4789 Graph *graphPtr; /* Graph widget record */
4790 PsToken psToken;
4791 Element *elemPtr; /* Line element information */
4792 double x, y; /* Center position of symbol */
4793 int size; /* Size of element */
4794{
4795 Line *linePtr = (Line *)elemPtr;
4796 LinePen *penPtr = linePtr->normalPenPtr;
4797
4798 if (penPtr->traceWidth > 0) {
4799 /*
4800 * Draw an extra line offset by one pixel from the previous to
4801 * give a thicker appearance. This is only for the legend
4802 * entry. This routine is never called for drawing the actual
4803 * line segments.
4804 */
4805 Blt_LineAttributesToPostScript(psToken, penPtr->traceColor,
4806 penPtr->traceWidth + 2, &(penPtr->traceDashes), CapButt, JoinMiter);
4807 Blt_FormatToPostScript(psToken, "%g %g %d Li\n", x, y, size + size);
4808 }
4809 if (penPtr->symbol.type != SYMBOL_NONE) {
4810 Point2D point;
4811
4812 point.x = x, point.y = y;
4813 SymbolsToPostScript(graphPtr, psToken, penPtr, size, 1, &point);
4814 }
4815}
4816
4817static void
4818SetLineAttributes(psToken, penPtr)
4819 PsToken psToken;
4820 LinePen *penPtr;
4821{
4822 /* Set the attributes of the line (color, dashes, linewidth) */
4823 Blt_LineAttributesToPostScript(psToken, penPtr->traceColor,
4824 penPtr->traceWidth, &(penPtr->traceDashes), CapButt, JoinMiter);
4825 if ((LineIsDashed(penPtr->traceDashes)) &&
4826 (penPtr->traceOffColor != NULL)) {
4827 Blt_AppendToPostScript(psToken, "/DashesProc {\n gsave\n ",
4828 (char *)NULL);
4829 Blt_BackgroundToPostScript(psToken, penPtr->traceOffColor);
4830 Blt_AppendToPostScript(psToken, " ", (char *)NULL);
4831 Blt_LineDashesToPostScript(psToken, (Blt_Dashes *)NULL);
4832 Blt_AppendToPostScript(psToken, "stroke\n grestore\n} def\n",
4833 (char *)NULL);
4834 } else {
4835 Blt_AppendToPostScript(psToken, "/DashesProc {} def\n", (char *)NULL);
4836 }
4837}
4838
4839static void
4840TracesToPostScript(psToken, linePtr, penPtr)
4841 PsToken psToken;
4842 Line *linePtr;
4843 LinePen *penPtr;
4844{
4845 Blt_ChainLink *linkPtr;
4846 Trace *tracePtr;
4847 register Point2D *pointPtr, *endPtr;
4848 int count;
4849
4850 SetLineAttributes(psToken, penPtr);
4851 for (linkPtr = Blt_ChainFirstLink(linePtr->traces); linkPtr != NULL;
4852 linkPtr = Blt_ChainNextLink(linkPtr)) {
4853 tracePtr = Blt_ChainGetValue(linkPtr);
4854 if (tracePtr->nScreenPts <= 0) {
4855 continue;
4856 }
4857#define PS_MAXPATH 1500 /* Maximum number of components in a PostScript
4858 * (level 1) path. */
4859 pointPtr = tracePtr->screenPts;
4860 Blt_FormatToPostScript(psToken, " newpath %g %g moveto\n",
4861 pointPtr->x,
4862 pointPtr->y);
4863 pointPtr++;
4864 count = 0;
4865 for (endPtr = tracePtr->screenPts + (tracePtr->nScreenPts - 1);
4866 pointPtr < endPtr; pointPtr++) {
4867 Blt_FormatToPostScript(psToken, " %g %g lineto\n",
4868 pointPtr->x,
4869 pointPtr->y);
4870 if ((count % PS_MAXPATH) == 0) {
4871 Blt_FormatToPostScript(psToken,
4872 "DashesProc stroke\n newpath %g %g moveto\n",
4873 pointPtr->x,
4874 pointPtr->y);
4875 }
4876 count++;
4877 }
4878 Blt_FormatToPostScript(psToken, " %g %g lineto\n",
4879 pointPtr->x,
4880 pointPtr->y);
4881 Blt_AppendToPostScript(psToken, "DashesProc stroke\n", (char *)NULL);
4882 }
4883}
4884
4885
4886static void
4887ValuesToPostScript(psToken, linePtr, penPtr, nSymbolPts, symbolPts,
4888 pointToData)
4889 PsToken psToken;
4890 Line *linePtr;
4891 LinePen *penPtr;
4892 int nSymbolPts;
4893 Point2D *symbolPts;
4894 int *pointToData;
4895{
4896 Point2D *pointPtr, *endPtr;
4897 int count;
4898 char string[TCL_DOUBLE_SPACE * 2 + 2];
4899 char *fmt;
4900 double x, y;
4901
4902 fmt = penPtr->valueFormat;
4903 if (fmt == NULL) {
4904 fmt = "%g";
4905 }
4906 count = 0;
4907 for (pointPtr = symbolPts, endPtr = symbolPts + nSymbolPts;
4908 pointPtr < endPtr; pointPtr++) {
4909 x = linePtr->x.valueArr[pointToData[count]];
4910 y = linePtr->y.valueArr[pointToData[count]];
4911 count++;
4912 if (penPtr->valueShow == SHOW_X) {
4913 sprintf(string, fmt, x);
4914 } else if (penPtr->valueShow == SHOW_Y) {
4915 sprintf(string, fmt, y);
4916 } else if (penPtr->valueShow == SHOW_BOTH) {
4917 sprintf(string, fmt, x);
4918 strcat(string, ",");
4919 sprintf(string + strlen(string), fmt, y);
4920 }
4921 Blt_TextToPostScript(psToken, string, &(penPtr->valueStyle),
4922 pointPtr->x, pointPtr->y);
4923 }
4924}
4925
4926
4927/*
4928 *----------------------------------------------------------------------
4929 *
4930 * ActiveLineToPostScript --
4931 *
4932 * Generates PostScript commands to draw as "active" the points
4933 * (symbols) and or line segments (trace) representing the
4934 * element.
4935 *
4936 * Results:
4937 * None.
4938 *
4939 * Side effects:
4940 * PostScript pen width, dashes, and color settings are changed.
4941 *
4942 *----------------------------------------------------------------------
4943 */
4944static void
4945ActiveLineToPostScript(graphPtr, psToken, elemPtr)
4946 Graph *graphPtr;
4947 PsToken psToken;
4948 Element *elemPtr;
4949{
4950 Line *linePtr = (Line *)elemPtr;
4951 LinePen *penPtr = linePtr->activePenPtr;
4952 int symbolSize;
4953
4954 if (penPtr == NULL) {
4955 return;
4956 }
4957 symbolSize = ScaleSymbol(elemPtr, penPtr->symbol.size);
4958 if (linePtr->nActiveIndices > 0) {
4959 if (linePtr->flags & ACTIVE_PENDING) {
4960 MapActiveSymbols(graphPtr, linePtr);
4961 }
4962 if (penPtr->symbol.type != SYMBOL_NONE) {
4963 SymbolsToPostScript(graphPtr, psToken, penPtr, symbolSize,
4964 linePtr->nActivePts, linePtr->activePts);
4965 }
4966 if (penPtr->valueShow != SHOW_NONE) {
4967 ValuesToPostScript(psToken, linePtr, penPtr, linePtr->nActivePts,
4968 linePtr->activePts, linePtr->activeToData);
4969 }
4970 } else if (linePtr->nActiveIndices < 0) {
4971 if (penPtr->traceWidth > 0) {
4972 if (linePtr->nStrips > 0) {
4973 SetLineAttributes(psToken, penPtr);
4974 Blt_2DSegmentsToPostScript(psToken, linePtr->strips,
4975 linePtr->nStrips);
4976 }
4977 if (Blt_ChainGetLength(linePtr->traces) > 0) {
4978 TracesToPostScript(psToken, linePtr, (LinePen *)penPtr);
4979 }
4980 }
4981 if (penPtr->symbol.type != SYMBOL_NONE) {
4982 SymbolsToPostScript(graphPtr, psToken, penPtr, symbolSize,
4983 linePtr->nSymbolPts, linePtr->symbolPts);
4984 }
4985 if (penPtr->valueShow != SHOW_NONE) {
4986 ValuesToPostScript(psToken, linePtr, penPtr, linePtr->nSymbolPts,
4987 linePtr->symbolPts, linePtr->symbolToData);
4988 }
4989 }
4990}
4991
4992/*
4993 *----------------------------------------------------------------------
4994 *
4995 * NormalLineToPostScript --
4996 *
4997 * Similar to the DrawLine procedure, prints PostScript related
4998 * commands to form the connected line(s) representing the element.
4999 *
5000 * Results:
5001 * None.
5002 *
5003 * Side effects:
5004 * PostScript pen width, dashes, and color settings are changed.
5005 *
5006 *----------------------------------------------------------------------
5007 */
5008static void
5009NormalLineToPostScript(graphPtr, psToken, elemPtr)
5010 Graph *graphPtr;
5011 PsToken psToken;
5012 Element *elemPtr;
5013{
5014 Line *linePtr = (Line *)elemPtr;
5015 register LinePenStyle *stylePtr;
5016 Blt_ChainLink *linkPtr;
5017 LinePen *penPtr;
5018 unsigned int count;
5019 XColor *colorPtr;
5020
5021 /* Draw fill area */
5022 if (linePtr->fillPts != NULL) {
5023 /* Create a path to use for both the polygon and its outline. */
5024 Blt_PathToPostScript(psToken, linePtr->fillPts, linePtr->nFillPts);
5025 Blt_AppendToPostScript(psToken, "closepath\n", (char *)NULL);
5026
5027 /* If the background fill color was specified, draw the
5028 * polygon in a solid fashion with that color. */
5029 if (linePtr->fillBgColor != NULL) {
5030 Blt_BackgroundToPostScript(psToken, linePtr->fillBgColor);
5031 Blt_AppendToPostScript(psToken, "Fill\n", (char *)NULL);
5032 }
5033 Blt_ForegroundToPostScript(psToken, linePtr->fillFgColor);
5034 if (linePtr->fillTile != NULL) {
5035 /* TBA: Transparent tiling is the hard part. */
5036 } else if ((linePtr->fillStipple != None) &&
5037 (linePtr->fillStipple != PATTERN_SOLID)) {
5038 /* Draw the stipple in the foreground color. */
5039 Blt_StippleToPostScript(psToken, graphPtr->display,
5040 linePtr->fillStipple);
5041 } else {
5042 Blt_AppendToPostScript(psToken, "Fill\n", (char *)NULL);
5043 }
5044 }
5045 /* Draw lines */
5046 if (linePtr->nStrips > 0) {
5047 for (linkPtr = Blt_ChainFirstLink(linePtr->palette); linkPtr != NULL;
5048 linkPtr = Blt_ChainNextLink(linkPtr)) {
5049 stylePtr = Blt_ChainGetValue(linkPtr);
5050 penPtr = stylePtr->penPtr;
5051 if ((stylePtr->nStrips > 0) && (penPtr->traceWidth > 0)) {
5052 SetLineAttributes(psToken, penPtr);
5053 Blt_2DSegmentsToPostScript(psToken, stylePtr->strips,
5054 stylePtr->nStrips);
5055 }
5056 }
5057 } else if ((Blt_ChainGetLength(linePtr->traces) > 0) &&
5058 (linePtr->normalPenPtr->traceWidth > 0)) {
5059 TracesToPostScript(psToken, linePtr, linePtr->normalPenPtr);
5060 }
5061
5062 /* Draw symbols, error bars, values. */
5063
5064 count = 0;
5065 for (linkPtr = Blt_ChainFirstLink(linePtr->palette); linkPtr != NULL;
5066 linkPtr = Blt_ChainNextLink(linkPtr)) {
5067 stylePtr = Blt_ChainGetValue(linkPtr);
5068 penPtr = stylePtr->penPtr;
5069 colorPtr = penPtr->errorBarColor;
5070 if (colorPtr == COLOR_DEFAULT) {
5071 colorPtr = penPtr->traceColor;
5072 }
5073 if ((stylePtr->xErrorBarCnt > 0) && (penPtr->errorBarShow & SHOW_X)) {
5074 Blt_LineAttributesToPostScript(psToken, colorPtr,
5075 penPtr->errorBarLineWidth, NULL, CapButt, JoinMiter);
5076 Blt_2DSegmentsToPostScript(psToken, stylePtr->xErrorBars,
5077 stylePtr->xErrorBarCnt);
5078 }
5079 if ((stylePtr->yErrorBarCnt > 0) && (penPtr->errorBarShow & SHOW_Y)) {
5080 Blt_LineAttributesToPostScript(psToken, colorPtr,
5081 penPtr->errorBarLineWidth, NULL, CapButt, JoinMiter);
5082 Blt_2DSegmentsToPostScript(psToken, stylePtr->yErrorBars,
5083 stylePtr->yErrorBarCnt);
5084 }
5085 if ((stylePtr->nSymbolPts > 0) &&
5086 (stylePtr->penPtr->symbol.type != SYMBOL_NONE)) {
5087 SymbolsToPostScript(graphPtr, psToken, penPtr,
5088 stylePtr->symbolSize, stylePtr->nSymbolPts,
5089 stylePtr->symbolPts);
5090 }
5091 if (penPtr->valueShow != SHOW_NONE) {
5092 ValuesToPostScript(psToken, linePtr, penPtr,
5093 stylePtr->nSymbolPts, stylePtr->symbolPts,
5094 linePtr->symbolToData + count);
5095 }
5096 count += stylePtr->nSymbolPts;
5097 }
5098}
5099
5100/*
5101 *----------------------------------------------------------------------
5102 *
5103 * DestroyLine --
5104 *
5105 * Release memory and resources allocated for the line element.
5106 *
5107 * Results:
5108 * None.
5109 *
5110 * Side effects:
5111 * Everything associated with the line element is freed up.
5112 *
5113 *----------------------------------------------------------------------
5114 */
5115#define FreeVector(v) \
5116 if ((v).clientId != NULL) { \
5117 Blt_FreeVectorId((v).clientId); \
5118 } else if ((v).valueArr != NULL) { \
5119 Blt_Free((v).valueArr); \
5120 }
5121
5122static void
5123DestroyLine(graphPtr, elemPtr)
5124 Graph *graphPtr;
5125 Element *elemPtr;
5126{
5127 Line *linePtr = (Line *)elemPtr;
5128
5129 if (linePtr->normalPenPtr != &(linePtr->builtinPen)) {
5130 Blt_FreePen(graphPtr, (Pen *)linePtr->normalPenPtr);
5131 }
5132 DestroyPen(graphPtr, (Pen *)&(linePtr->builtinPen));
5133 if (linePtr->activePenPtr != NULL) {
5134 Blt_FreePen(graphPtr, (Pen *)linePtr->activePenPtr);
5135 }
5136
5137 FreeVector(linePtr->w);
5138 FreeVector(linePtr->x);
5139 FreeVector(linePtr->xHigh);
5140 FreeVector(linePtr->xLow);
5141 FreeVector(linePtr->xError);
5142 FreeVector(linePtr->y);
5143 FreeVector(linePtr->yHigh);
5144 FreeVector(linePtr->yLow);
5145 FreeVector(linePtr->yError);
5146
5147 ResetLine(linePtr);
5148 if (linePtr->palette != NULL) {
5149 Blt_FreePalette(graphPtr, linePtr->palette);
5150 Blt_ChainDestroy(linePtr->palette);
5151 }
5152 if (linePtr->tags != NULL) {
5153 Blt_Free(linePtr->tags);
5154 }
5155 if (linePtr->activeIndices != NULL) {
5156 Blt_Free(linePtr->activeIndices);
5157 }
5158 if (linePtr->fillPts != NULL) {
5159 Blt_Free(linePtr->fillPts);
5160 }
5161 if (linePtr->fillTile != NULL) {
5162 Blt_FreeTile(linePtr->fillTile);
5163 }
5164 if ((linePtr->fillStipple != None) &&
5165 (linePtr->fillStipple != PATTERN_SOLID)) {
5166 Tk_FreeBitmap(graphPtr->display, linePtr->fillStipple);
5167 }
5168 if (linePtr->fillGC != NULL) {
5169 Tk_FreeGC(graphPtr->display, linePtr->fillGC);
5170 }
5171}
5172
5173/*
5174 *----------------------------------------------------------------------
5175 *
5176 * Blt_LineElement --
5177 *
5178 * Allocate memory and initialize methods for the new line element.
5179 *
5180 * Results:
5181 * The pointer to the newly allocated element structure is returned.
5182 *
5183 * Side effects:
5184 * Memory is allocated for the line element structure.
5185 *
5186 *----------------------------------------------------------------------
5187 */
5188
5189static ElementProcs lineProcs =
5190{
5191 ClosestLine, /* Finds the closest element/data point */
5192 ConfigureLine, /* Configures the element. */
5193 DestroyLine, /* Destroys the element. */
5194 DrawActiveLine, /* Draws active element */
5195 DrawNormalLine, /* Draws normal element */
5196 DrawSymbol, /* Draws the element symbol. */
5197 GetLineExtents, /* Find the extents of the element's data. */
5198 ActiveLineToPostScript, /* Prints active element. */
5199 NormalLineToPostScript, /* Prints normal element. */
5200 SymbolToPostScript, /* Prints the line's symbol. */
5201 MapLine /* Compute element's screen coordinates. */
5202};
5203
5204Element *
5205Blt_LineElement(graphPtr, name, classUid)
5206 Graph *graphPtr;
5207 char *name;
5208 Blt_Uid classUid;
5209{
5210 register Line *linePtr;
5211
5212 linePtr = Blt_Calloc(1, sizeof(Line));
5213 assert(linePtr);
5214 linePtr->procsPtr = &lineProcs;
5215 if (classUid == bltLineElementUid) {
5216 linePtr->configSpecs = lineElemConfigSpecs;
5217 } else {
5218 linePtr->configSpecs = stripElemConfigSpecs;
5219 }
5220
5221 /* By default an element's name and label are the same. */
5222 linePtr->label = Blt_Strdup(name);
5223 linePtr->name = Blt_Strdup(name);
5224
5225 linePtr->classUid = classUid;
5226 linePtr->flags = SCALE_SYMBOL;
5227 linePtr->graphPtr = graphPtr;
5228 linePtr->labelRelief = TK_RELIEF_FLAT;
5229 linePtr->normalPenPtr = &linePtr->builtinPen;
5230 linePtr->palette = Blt_ChainCreate();
5231 linePtr->penDir = PEN_BOTH_DIRECTIONS;
5232 linePtr->reqSmooth = PEN_SMOOTH_NONE;
5233 InitPen(linePtr->normalPenPtr);
5234 return (Element *)linePtr;
5235}
Note: See TracBrowser for help on using the repository browser.