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