1 /***********************************************************************/
2 /* Open Visualization Data Explorer */
3 /* (C) Copyright IBM Corp. 1989,1999 */
4 /* ALL RIGHTS RESERVED */
5 /* This code licensed under the */
6 /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */
7 /***********************************************************************/
8
9 #include <dxconfig.h>
10 #include "../base/defines.h"
11
12
13
14 /*
15 * The graph is drawn within the framework of the top of a bar graph
16 * with a line along each edge (with length of the value difference
17 * with that neighbor) and accross the top. Thus there are two points
18 * for each bar, at either end of the top of its bar.
19 *
20 * The range of the entire graph is 0.0 at one edge and 1.0 at the
21 * other. (Of course the 0-1 can be remapped to anything in the
22 * application). Since the values at 0.0 and 1.0 are drawn and the
23 * edges are treated as the center of the bars for 0 and 1 in a bar
24 * graph, the first and last "bars" are half the width of the rest.
25 * 1.0 - 0
26 * The following is a crude example of a range of six bars across -
27 * the graph. 0.0 | | | | | | | 1.0 1
28 * 0 1 2 3 4 5 -
29 * 0=(0.0-0.1), 1=(0.1-0.3), 2=(0.3-0.5), 2
30 * 3=(0.5-0.7), 4=(0.7-0.9), 5=(0.9-1.0) -
31 * 3
32 * The bar width is [(bar_count - 1) / width] (except the 2 half bars) -
33 * 4
34 * index = (int)(level * (float)(bar_count - 1)) -
35 * To go from index to level at the bar's center: 5
36 * level = (float)index / (float)(bar_count - 1) -
37 * 0.0 - 6
38 * The graph is adaptively created, following the bar edges only in
39 * cases where the level or its neighbor is used by more than 1 control
40 * point. The reason for this is that a "connect-the-centers" line
41 * graph scheme creates a smoother graph, but an "outline-the-edges" bar
42 * graph scheme is needed to show discontinuities (as occurs between
43 * redundant control points at a given level: called overload in the code).
44 *
45 * Bar_count - 1 is called last_level_index in the ControlLine record.
46 */
47
48
49 #include <math.h>
50 #include "ControlField.h"
51
52
53 /*
54 * Declare templates for locally defined and used subroutines
55 */
56 static void InitializeLine( ControlLine* line, int num_levels );
57
58
59 /* Subroutine: CreateControlLine
60 * Purpose: Create and initialize a ControlLine structure (leave setting up
61 * GC for expose time)
62 */
CreateControlLine(ControlField * field,int load_limit,Pixel color)63 ControlLine* CreateControlLine( ControlField* field,
64 int load_limit, Pixel color )
65 {
66 ControlLine* line;
67
68 line = (ControlLine *)XtMalloc(sizeof(struct ControlLineRec));
69 line->points = NULL;
70 line->values = NULL;
71 line->load = NULL;
72 line->load_limit = load_limit;
73 line->num_points = 0;
74 line->num_levels = 0;
75 line->field = field;
76 line->gc = NULL;
77 line->erase_gc = NULL;
78 line->color = color;
79 InitializeLine(line, field->num_levels);
80 SetLineCoords(line);
81 return line;
82 }
83
84
85 /* Subroutine: InitializeLine
86 * Purpose: Set the fixed parameters of the drawn line for the current
87 * dimensions. Malloc the space for values, points & loads
88 */
InitializeLine(ControlLine * line,int num_levels)89 static void InitializeLine( ControlLine* line, int num_levels )
90 {
91 if( num_levels > line->num_levels )
92 {
93 if( line->values )
94 XtFree((char*)line->values);
95 if( line->points )
96 XtFree((char*)line->points);
97 if( line->load )
98 XtFree((char*)line->load);
99 line->values = (double *)XtCalloc(num_levels, sizeof(double));
100 line->points = (XPoint *)XtMalloc(2 * num_levels * sizeof(XPoint));
101 /* Need extra load to fake next which tests FALSE for last level */
102 line->load = (short *)XtCalloc(num_levels + 1, sizeof(short));
103 line->load[num_levels] = 0;
104 }
105 line->num_points = 2 * num_levels;
106 line->num_levels = num_levels;
107 line->last_level_index = num_levels - 1;
108 }
109
110
111 /* Subroutine: SetLineCoords
112 * Purpose: Set the proper coordinates to draw the line as per the control
113 * points
114 * Note: Load limit is a measure to compare against the number of control
115 * point ranges which apply at a given level. The test switches
116 * between simple graph (centered) and bar graph (two edges)
117 */
SetLineCoords(ControlLine * line)118 void SetLineCoords( ControlLine* line )
119 {
120 LineCoord* coord;
121 int i;
122 Boolean prior_overload, current_overload, next_overload;
123 register XPoint* line_point = line->points;
124
125 coord = line->field->coords;
126
127 /*
128 * RGB field.
129 */
130 if(line->field->num_lines == 3)
131 {
132 if( line->field->vertical )
133 {
134 double value_range = (double)(line->field->width - 1);
135 short margin = line->field->left_margin;
136
137 prior_overload = FALSE;
138 current_overload = (line->load[0] > line->load_limit);
139 for( i=0; i<line->last_level_index; i++ )
140 {
141 register short val_coord;
142
143 val_coord =
144 (int)((line->values[i] * value_range) + 0.5) + margin;
145 line_point->x = val_coord;
146 if( prior_overload || current_overload )
147 line_point->y = coord[i].low;
148 else
149 line_point->y = coord[i].mid;
150 ++line_point;
151 next_overload = (line->load[i+1] > line->load_limit);
152 if( current_overload || next_overload )
153 {
154 line_point->x = val_coord;
155 line_point->y = coord[i].high;
156 ++line_point;
157 }
158 prior_overload = current_overload;
159 current_overload = next_overload;
160 }
161 }
162 else
163 {
164 double value_range = (double)(line->field->height - 1);
165 short margin = line->field->top_margin;
166
167 prior_overload = FALSE;
168 current_overload = (line->load[0] > line->load_limit);
169 for( i=0; i<line->last_level_index; i++ )
170 {
171 register short val_coord;
172
173 val_coord =
174 (int)(((1.0 - line->values[i]) * value_range) + 0.5) + margin;
175 line_point->y = val_coord;
176 if( prior_overload || current_overload )
177 line_point->x = coord[i].low;
178 else
179 line_point->x = coord[i].mid;
180 ++line_point;
181 next_overload = (line->load[i+1] > line->load_limit);
182 if( current_overload || next_overload )
183 {
184 line_point->y = val_coord;
185 line_point->x = coord[i].high;
186 ++line_point;
187 }
188 prior_overload = current_overload;
189 current_overload = next_overload;
190 }
191 }
192 }
193 else
194 {
195 if(line->field->num_maps > 0)
196 {
197 for( i=0; i < line->field->map[0]->num_points; i++)
198 {
199 if(i==0)
200 {
201 line_point->x = line->field->map[0]->points[i].x;
202 line_point->y = line->field->height +
203 line->field->top_margin - 1;
204 line_point++;
205 }
206 line_point->x = line->field->map[0]->points[i].x;
207 line_point->y = line->field->map[0]->points[i].y;
208 line_point++;
209 if(i==(line->field->map[0]->num_points - 1))
210 {
211 line_point->x = line->field->map[0]->points[i].x;
212 line_point->y = line->field->top_margin;
213 line_point++;
214 }
215 }
216 }
217 }
218 line->num_points = line_point - line->points;
219 }
220
221
222 /* Subroutine: DrawLine
223 * Purpose: Draw the line on the screen and record a toggle in case it is
224 * an Xor operation
225 */
DrawLine(ControlLine * line,GC gc)226 void DrawLine( ControlLine* line, GC gc )
227 {
228 if(gc == NULL) return;
229 if (!line->field->w) return ;
230 if (!XtIsRealized((Widget)(line->field->w))) return ;
231 XDrawLines(XtDisplay(line->field->w), XtWindow(line->field->w),
232 gc, line->points, line->num_points,
233 CoordModeOrigin);
234 XSync(XtDisplay(line->field->w), FALSE);
235 }
236