ruby-gdchart 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,77 @@
1
+ /* GDCHART 0.10.0dev PIE SAMPLE 2 Nov 2000 */
2
+ /* Copyright Bruce Verderaime 1998-2004 */
3
+
4
+ /* creates a file "pie.png". Can be stdout for CGI use. */
5
+ /* vi: :set tabstop=4 */
6
+
7
+ #include <stdio.h>
8
+ #include <math.h>
9
+
10
+ #include "gdc.h"
11
+ #include "gdcpie.h"
12
+
13
+ main( int argc, char *argv[] )
14
+ {
15
+ /* labels */
16
+ char *lbl[] = { "CPQ\n(DEC)",
17
+ "HP",
18
+ "SCO",
19
+ "IBM",
20
+ "SGI",
21
+ "SUN\nSPARC",
22
+ "other" };
23
+ /* values to chart */
24
+ float p[] = { 12.5,
25
+ 20.1,
26
+ 2.0,
27
+ 22.0,
28
+ 5.0,
29
+ 18.0,
30
+ 13.0 };
31
+
32
+ FILE *fp = fopen( "pie.png", "wb" );
33
+
34
+ /* set which slices to explode, and by how much */
35
+ int expl[] = { 0, 0, 0, 0, 0, 20, 0 };
36
+
37
+ /* set missing slices */
38
+ unsigned char missing[] = { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE };
39
+
40
+ /* colors */
41
+ unsigned long clr[] = { 0xFF4040L, 0x80FF80L, 0x8080FFL, 0xFF80FFL, 0xFFFF80L, 0x80FFFFL, 0x0080FFL };
42
+
43
+ /* set options */
44
+ /* a lot of options are set here for illustration */
45
+ /* none need be - see gdcpie.h for defaults */
46
+ /* GDCPIE_title = "Sample\nPIE"; */
47
+ GDCPIE_label_line = TRUE;
48
+ GDCPIE_label_dist = 15; /* dist. labels to slice edge */
49
+ /* can be negative */
50
+ GDCPIE_LineColor = 0x000000L;
51
+ GDCPIE_label_size = GDC_SMALL;
52
+ GDCPIE_3d_depth = 25;
53
+ GDCPIE_3d_angle = 180; /* 0 - 359 */
54
+ GDCPIE_perspective = 70; /* 0 - 99 */
55
+ GDCPIE_explode = expl; /* default: NULL - no explosion */
56
+ GDCPIE_Color = clr;
57
+ GDCPIE_BGColor = 0xFFFFFFL;
58
+ /* GDCPIE_EdgeColor = 0x000000L; default is GDCPIE_NOCOLOR */
59
+ /* for no edging */
60
+ GDCPIE_missing = missing; /* default: NULL - none missing */
61
+
62
+ /* add percentage to slice label */
63
+ /* below the slice label */
64
+ GDCPIE_percent_labels = GDCPIE_PCT_BELOW;
65
+ GDC_image_type = GDC_PNG;
66
+ /* call the lib */
67
+ GDC_out_pie( 300, /* width */
68
+ 200, /* height */
69
+ fp, /* open file pointer */
70
+ GDC_3DPIE, /* or GDC_2DPIE */
71
+ 7, /* number of slices */
72
+ NULL, /* can be NULL */
73
+ p ); /* data array */
74
+
75
+ fclose( fp );
76
+ exit( 0 );
77
+ }
@@ -0,0 +1,47 @@
1
+ /* GDCHART 0.10.0dev 1st CHART SAMPLE 2 Nov 2000 */
2
+ /* Copyright Bruce Verderaime 1998-2004 */
3
+
4
+ /* writes gif file to stdout */
5
+
6
+ /* sample gdchart usage */
7
+ /* this will produce a 3D BAR chart */
8
+ /* this is suitable for use as a CGI */
9
+
10
+ /* for CGI use un-comment the "Content-Type" line */
11
+
12
+ #include <stdio.h>
13
+
14
+ #include "gdc.h"
15
+ #include "gdchart.h"
16
+
17
+ main()
18
+ {
19
+ /* ----- set some data ----- */
20
+ /* float a[6] = { 0.5, 0.09, 0.6, 0.85, 0.0, 0.90 }, */
21
+ /* b[6] = { 1.9, 1.3, 0.6, 0.75, 0.1, 2.0 }; */
22
+ float a[2][6] = { { 0.5, 0.09, 0.6, 0.85, 0.0, 0.90 },
23
+ { 1.9, 1.3, 0.6, 0.75, 0.1, 2.0 } };
24
+
25
+ /* ----- X labels ----- */
26
+ char *t[6] = { "Chicago", "New York", "L.A.", "Atlanta", "Paris, MD\n(USA) ", "London" };
27
+ /* ----- data set colors (RGB) ----- */
28
+ unsigned long sc[2] = { 0xFF8080, 0x8080FF };
29
+
30
+ GDC_BGColor = 0xFFFFFFL; /* backgound color (white) */
31
+ GDC_LineColor = 0x000000L; /* line color (black) */
32
+ GDC_SetColor = &(sc[0]); /* assign set colors */
33
+
34
+ /* printf( "Content-Type: image/gif\n\n" ); tell browser type */
35
+ GDC_image_type = GDC_GIF;
36
+ /* ----- call the lib ----- */
37
+ GDC_out_graph( 250, 200, /* short width, height */
38
+ stdout, /* FILE* open FILE pointer */
39
+ GDC_3DBAR, /* GDC_CHART_T chart type */
40
+ 6, /* int number of points per data set */
41
+ t, /* char*[] array of X labels */
42
+ 2, /* int number of data sets */
43
+ (float*)a, NULL ); /* float[] data set 1 */
44
+ /* b ); ... data set n */
45
+
46
+ exit(0);
47
+ }
@@ -0,0 +1,88 @@
1
+ /* GDCHART 0.10.0dev 2nd CHART SAMPLE 2 Nov 2000 */
2
+ /* Copyright Bruce Verderaime 1998-2004 */
3
+
4
+ /*
5
+ ** vi note :set tabstop=4 **
6
+
7
+ a more complicated example
8
+ High Low Close Combo (Volume) with annotation
9
+
10
+ produces a file: g2.png
11
+
12
+ Until a README is ready, see gdchart.h for options
13
+ All options are defaulted, no need to set any
14
+ */
15
+
16
+ #include <stdio.h>
17
+
18
+ #include "gdc.h"
19
+ #include "gdchart.h"
20
+
21
+
22
+ main()
23
+ {
24
+ /* set some sample data points */
25
+ float h[12] = { 17.8, 17.1, 17.3, GDC_NOVALUE, 17.2, 17.1,
26
+ 17.3, 17.3, 17.3, 17.1, 17.5, 17.4 };
27
+
28
+ float c[12] = { 17.0, 16.8, 16.9, GDC_NOVALUE, 16.9, 16.8,
29
+ 17.2, 16.8, 17.0, 16.9, 16.4, 16.1 };
30
+
31
+ float l[12] = { 16.8, 16.8, 16.7, GDC_NOVALUE, 16.5, 16.0,
32
+ 16.1, 16.8, 16.5, 16.9, 16.2, 16.0 };
33
+
34
+ float v[12] = { 150.0, 100.0, 340.0, GDC_NOVALUE, 999.0, 390.0,
35
+ 420.0, 150.0, 100.0, 340.0, 1590.0, 700.0 };
36
+ char *t[12] = { "May", "Jun", "Jul", "Aug", "Sep", "Oct",
37
+ "Nov", "Dec", "Jan", "Feb", "Mar", "Apr" };
38
+
39
+ /* set color RGB as ulong array */
40
+ /* unsigned long setcolor[3] = { 0xC0C0FF, 0xFF4040, 0xFFFFFF }; */
41
+
42
+ GDC_ANNOTATION_T anno;
43
+
44
+ /* need an open FILE pointer - can be stdout */
45
+ FILE *outpng1 = fopen( "g2.png", "wb" ); /* rem: test open() fail */
46
+
47
+ anno.color = 0x00FF00;
48
+ strncpy( anno.note, "Did Not\nTrade", MAX_NOTE_LEN ); /* don't exceed MAX_NOTE_LEN */
49
+ anno.point = 3; /* first is 0 */
50
+ GDC_annotation_font_size = GDC_TINY;
51
+ GDC_annotation = &anno; /* set annote option */
52
+
53
+ GDC_HLC_style = GDC_HLC_I_CAP | GDC_HLC_CLOSE_CONNECTED;
54
+ GDC_HLC_cap_width = 45;
55
+
56
+ GDC_bar_width = 75; /* % */
57
+
58
+ /* GDC_BGImage = "W.gif"; */
59
+
60
+ GDC_title = "Widget Corp.";
61
+ GDC_ytitle = "Price ($)";
62
+ GDC_ytitle2 = "Volume (K)";
63
+ GDC_ytitle_size = GDC_SMALL;
64
+ GDC_VolColor = 0x4040FFL; /* aka combo */
65
+ GDC_3d_depth = 4.0; /* % entire image */
66
+
67
+ /* GDC_SetColor = setcolor; /* see README */
68
+ GDC_PlotColor = 0xFFFFFF;
69
+ GDC_grid = FALSE;
70
+
71
+ /* GDC_xtitle="fy.1998"; */
72
+
73
+ /* fprintf( stdout, "Content-Type: image/png\n\n" ); /* rem: for web use */
74
+ /* finally: make the call */
75
+ out_graph( 200, 175, /* overall width, height */
76
+ outpng1, /* open FILE pointer */
77
+ GDC_COMBO_HLC_AREA, /* chart type */
78
+ 12, /* number of points */
79
+ t, /* X axis label array */
80
+ 1, /* number of sets (see README) */
81
+ h, /* set 1 (high) */
82
+ l, /* low */
83
+ c, /* close */
84
+ v ); /* combo/volume */
85
+
86
+ fclose( outpng1 );
87
+ exit(0);
88
+ }
@@ -0,0 +1,2193 @@
1
+ /* GDCHART 0.11.3dev GDCHART.C 11 Mar 2003 */
2
+ /* Copyright Bruce Verderaime 1998-2004 */
3
+
4
+ /* vi:set tabstop=4 */
5
+
6
+ #define GDC_INCL
7
+ #define GDC_LIB
8
+ #include "gdc.h" /* gdc.h before system includes to pick up features */
9
+
10
+ #include <stdio.h>
11
+ #include <stdlib.h>
12
+ #include <math.h>
13
+ #include <string.h>
14
+ #include <stdarg.h>
15
+ #include <errno.h>
16
+
17
+ #include "gdchart.h"
18
+
19
+ #define HIGHSET 0
20
+ #define LOWSET 1
21
+ #define CLOSESET 2
22
+
23
+ /* scaled translation onto graph */
24
+ #define PX( x ) (int)( xorig + (setno*xdepth_3D) + (x)*xscl )
25
+ #define PY( y ) (int)( yorig - (setno*ydepth_3D) + (y)*yscl )
26
+ #define PV( y ) (int)( vyorig - (setno*ydepth_3D) + (y)*vyscl )
27
+
28
+ #define SET_RECT( gdp, x1, x2, y1, y2 ) gdp[0].x = gdp[3].x = x1, \
29
+ gdp[0].y = gdp[1].y = y1, \
30
+ gdp[1].x = gdp[2].x = x2, \
31
+ gdp[2].y = gdp[3].y = y2
32
+
33
+
34
+ #define SET_3D_POLY( gdp, x1, x2, y1, y2, xoff, yoff ) \
35
+ gdp[0].x = x1, gdp[0].y = y1, \
36
+ gdp[1].x = x1+(xoff), gdp[1].y = y1-yoff, \
37
+ gdp[2].x = x2+(xoff), gdp[2].y = y2-yoff, \
38
+ gdp[3].x = x2, gdp[3].y = y2
39
+ /* ------------------------------------------------------------------------- */
40
+ /* vals in pixels */
41
+ /* ref is front plane */
42
+ /* allows for intersecting 3D lines */
43
+ /* (also used for single 3D lines >:-Q */
44
+ struct YS { int y1; int y2; float slope; int lnclr; int shclr; };
45
+ static int qcmpr( const void *a, const void *b )
46
+ { if( ((struct YS*)a)->y2 < ((struct YS*)b)->y2 ) return 1;
47
+ if( ((struct YS*)a)->y2 > ((struct YS*)b)->y2 ) return -1;
48
+ return 0; }
49
+ void
50
+ draw_3d_line( gdImagePtr im,
51
+ int y0,
52
+ int x1,
53
+ int x2,
54
+ int y1[],
55
+ int y2[],
56
+ int xdepth,
57
+ int ydepth,
58
+ int num_sets,
59
+ int clr[],
60
+ int clrshd[] )
61
+ {
62
+ #define F(x,i) (int)( (float)((x)-x1)*slope[i]+(float)y1[i] )
63
+ float depth_slope = xdepth==0? FLT_MAX: (float)ydepth/(float)xdepth;
64
+ CREATE_ARRAY1( slope, float, num_sets ); /* float slope[num_sets] */
65
+ CREATE_ARRAY1( lnclr, int, num_sets ); /* int slope[num_sets] */
66
+ CREATE_ARRAY1( shclr, int, num_sets ); /* int slope[num_sets] */
67
+ CREATE_ARRAY1( ypts, struct YS, num_sets ); /* struct YS slope[num_sets] */
68
+ int i;
69
+ int x;
70
+ gdPoint poly[4];
71
+
72
+ for( i=0; i<num_sets; ++i )
73
+ {
74
+ /* lnclr[i] = clr[i]; */
75
+ /* shclr[i] = clrshd[i]; */
76
+ slope[i] = x2==x1? FLT_MAX: (float)(y2[i]-y1[i])/(float)(x2-x1);
77
+ }
78
+
79
+ for( x=x1+1; x<=x2; ++x )
80
+ {
81
+ for( i=0; i<num_sets; ++i ) /* load set of points */
82
+ {
83
+ ypts[i].y1 = F(x-1,i);
84
+ ypts[i].y2 = F(x,i);
85
+ ypts[i].lnclr = clr[i];
86
+ ypts[i].shclr = clrshd[i];
87
+ ypts[i].slope = slope[i];
88
+ } /* sorted "lowest" first */
89
+ qsort( ypts, num_sets, sizeof(struct YS), qcmpr );
90
+ /* put out in that order */
91
+ for( i=0; i<num_sets; ++i )
92
+ { /* top */
93
+ SET_3D_POLY( poly, x-1, x, ypts[i].y1, ypts[i].y2, xdepth, ydepth );
94
+ gdImageFilledPolygon( im, poly, 4, /* depth_slope ever < 0 ? */
95
+ -ypts[i].slope>depth_slope? ypts[i].shclr: ypts[i].lnclr );
96
+ if( x == x1+1 ) /* edging */
97
+ gdImageLine( im,
98
+ x-1, ypts[i].y2,
99
+ x-1+xdepth, ypts[i].y2-ydepth,
100
+ -ypts[i].slope<=depth_slope? ypts[i].shclr: ypts[i].lnclr );
101
+ }
102
+ }
103
+ FREE_ARRAY1( slope );
104
+ FREE_ARRAY1( lnclr );
105
+ FREE_ARRAY1( shclr );
106
+ FREE_ARRAY1( ypts );
107
+ }
108
+
109
+ /* ------------------------------------------------------------------------- */
110
+ /* vals in pixels */
111
+ /* ref is front plane */
112
+ void
113
+ draw_3d_area( gdImagePtr im,
114
+ int x1,
115
+ int x2,
116
+ int y0, /* drawn from 0 */
117
+ int y1,
118
+ int y2,
119
+ int xdepth,
120
+ int ydepth,
121
+ int clr,
122
+ int clrshd )
123
+ {
124
+
125
+ gdPoint poly[4];
126
+ int y_intercept = 0; /* if xdepth || ydepth */
127
+
128
+ if( xdepth || ydepth )
129
+ {
130
+ float line_slope = x2==x1? FLT_MAX: (float)-(y2-y1) / (float)(x2-x1);
131
+ float depth_slope = xdepth==0? FLT_MAX: (float)ydepth/(float)xdepth;
132
+
133
+ y_intercept = (y1 > y0 && y2 < y0) || /* line crosses y0 */
134
+ (y1 < y0 && y2 > y0)?
135
+ (int)((1.0/ABS(line_slope))*(float)(ABS(y1-y0)))+x1:
136
+ 0; /* never */
137
+
138
+ /* edging along y0 depth */
139
+ gdImageLine( im, x1+xdepth, y0-ydepth, x2+xdepth, y0-ydepth, clrshd );
140
+
141
+ SET_3D_POLY( poly, x1, x2, y1, y2, xdepth, ydepth ); /* top */
142
+ gdImageFilledPolygon( im, poly, 4, line_slope>depth_slope? clrshd: clr );
143
+
144
+ SET_3D_POLY( poly, x1, x2, y0, y0, xdepth, ydepth+1 ); /* along y axis */
145
+ gdImageFilledPolygon( im, poly, 4, clr );
146
+
147
+ SET_3D_POLY( poly, x2, x2, y0, y2, xdepth, ydepth ); /* side */
148
+ gdImageFilledPolygon( im, poly, 4, clrshd );
149
+
150
+ if( y_intercept )
151
+ gdImageLine( im, y_intercept, y0,
152
+ y_intercept+xdepth, y0-ydepth, clrshd ); /* edging */
153
+ gdImageLine( im, x1, y0, x1+xdepth, y0-ydepth, clrshd ); /* edging */
154
+ gdImageLine( im, x2, y0, x2+xdepth, y0-ydepth, clrshd ); /* edging */
155
+
156
+ /* SET_3D_POLY( poly, x2, x2, y0, y2, xdepth, ydepth ); // side */
157
+ /* gdImageFilledPolygon( im, poly, 4, clrshd ); */
158
+
159
+ gdImageLine( im, x1, y1, x1+xdepth, y1-ydepth, clrshd ); /* edging */
160
+ gdImageLine( im, x2, y2, x2+xdepth, y2-ydepth, clrshd ); /* edging */
161
+ }
162
+
163
+ if( y1 == y2 ) /* bar rect */
164
+ SET_RECT( poly, x1, x2, y0, y1 ); /* front */
165
+ else
166
+ {
167
+ poly[0].x = x1; poly[0].y = y0;
168
+ poly[1].x = x2; poly[1].y = y0;
169
+ poly[2].x = x2; poly[2].y = y2;
170
+ poly[3].x = x1; poly[3].y = y1;
171
+ }
172
+ gdImageFilledPolygon( im, poly, 4, clr );
173
+
174
+ gdImageLine( im, x1, y0, x2, y0, clrshd ); /* edging along y0 */
175
+
176
+ if( (xdepth || ydepth) && /* front edging only on 3D */
177
+ (y1<y0 || y2<y0) ) /* and only above y0 */
178
+ {
179
+ if( y1 > y0 && y2 < y0 ) /* line crosses from below y0 */
180
+ gdImageLine( im, y_intercept, y0, x2, y2, clrshd );
181
+ else
182
+ if( y1 < y0 && y2 > y0 ) /* line crosses from above y0 */
183
+ gdImageLine( im, x1, y1, y_intercept, y0, clrshd );
184
+ else /* completely above */
185
+ gdImageLine( im, x1, y1, x2, y2, clrshd );
186
+ }
187
+ }
188
+
189
+ /* ------------------------------------------------------------------------- */
190
+ /* vals in pixels */
191
+ /* ref is front plane */
192
+ void
193
+ draw_3d_bar( gdImagePtr im,
194
+ int x1,
195
+ int x2,
196
+ int y0,
197
+ int yhigh,
198
+ int xdepth,
199
+ int ydepth,
200
+ int clr,
201
+ int clrshd )
202
+ {
203
+ #define SET_3D_BAR( gdp, x1, x2, y1, y2, xoff, yoff ) \
204
+ gdp[0].x = x1, gdp[0].y = y1, \
205
+ gdp[1].x = x1+(xoff), gdp[1].y = y1-yoff, \
206
+ gdp[2].x = x2+(xoff), gdp[2].y = y2-yoff, \
207
+ gdp[3].x = x2, gdp[3].y = y2
208
+
209
+ gdPoint poly[4];
210
+ int usd = MIN( y0, yhigh ); /* up-side-down bars */
211
+
212
+
213
+ if( xdepth || ydepth )
214
+ {
215
+ if( y0 != yhigh ) /* 0 height? */
216
+ {
217
+ SET_3D_BAR( poly, x2, x2, y0, yhigh, xdepth, ydepth ); /* side */
218
+ gdImageFilledPolygon( im, poly, 4, clrshd );
219
+ }
220
+
221
+ SET_3D_BAR( poly, x1, x2, usd, usd, xdepth, ydepth ); /* top */
222
+ gdImageFilledPolygon( im, poly, 4, clr );
223
+ }
224
+
225
+ SET_RECT( poly, x1, x2, y0, yhigh ); /* front */
226
+ gdImageFilledPolygon( im, poly, 4, clr );
227
+
228
+ if( xdepth || ydepth )
229
+ gdImageLine( im, x1, usd, x2, usd, clrshd );
230
+ }
231
+
232
+ /* ------------------------------------------------------------------------- */
233
+ struct BS { float y1; float y2; int clr; int shclr; };
234
+ static int barcmpr( const void *a, const void *b )
235
+ { if( ((struct BS*)a)->y2 < ((struct BS*)b)->y2 ) return -1;
236
+ if( ((struct BS*)a)->y2 > ((struct BS*)b)->y2 ) return 1;
237
+ return 0; }
238
+
239
+ /* ------------------------------------------------------------------------- */
240
+ /* simple two-point linear interpolation */
241
+ /* attempts between first, then nearest */
242
+ void
243
+ do_interpolations( int num_points,
244
+ int interp_point,
245
+ float vals[] )
246
+ {
247
+ int i, j;
248
+ float v1 = GDC_NOVALUE,
249
+ v2 = GDC_NOVALUE;
250
+ int p1 = -1,
251
+ p2 = -1;
252
+
253
+ /* find backwards */
254
+ for( i=interp_point-1; i>=0 && p1==-1; --i )
255
+ if( vals[i] != GDC_NOVALUE && vals[i] != GDC_INTERP_VALUE )
256
+ {
257
+ v1 = vals[i];
258
+ p1 = i;
259
+ }
260
+ /* find forwards */
261
+ for( j=interp_point+1; j<num_points && p2==-1; ++j )
262
+ if( vals[j] != GDC_NOVALUE && vals[j] != GDC_INTERP_VALUE )
263
+ {
264
+ v2 = vals[j];
265
+ p2 = j;
266
+ }
267
+ /* no forward sample, find backwards */
268
+ for( ; i>=0 && p2==-1; --i )
269
+ if( vals[i] != GDC_NOVALUE && vals[i] != GDC_INTERP_VALUE )
270
+ {
271
+ v2 = vals[i];
272
+ p2 = i;
273
+ }
274
+ /* no backwards sample, find forwards */
275
+ for( ; j<num_points && p1==-1; ++j )
276
+ if( vals[j] != GDC_NOVALUE && vals[j] != GDC_INTERP_VALUE )
277
+ {
278
+ v1 = vals[j];
279
+ p1 = j;
280
+ }
281
+ if( p1==-1 || p2==-1 || /* need both */
282
+ p1 == p2 ) /* idiot */
283
+ {
284
+ vals[interp_point] = GDC_NOVALUE;
285
+ return;
286
+ }
287
+
288
+ /* Point-slope formula */
289
+ vals[interp_point] = ((v2-v1)/(float)(p2-p1)) * (float)(interp_point-p1) + v1;
290
+ return;
291
+ }
292
+
293
+ /* ========================================================================= */
294
+ /* little error checking 0: ok, */
295
+ /* -ret: error no graph output */
296
+ /* ret: error graph out */
297
+ /* watch out for # params and array sizes==num_points */
298
+ /* ------------------------------------------------------------------------- */
299
+ /* original var arg interface */
300
+ int
301
+ out_graph( short IMGWIDTH, /* no check for a image that's too small to fit */
302
+ short IMGHEIGHT, /* needed info (labels, etc), could core dump */
303
+ FILE *img_fptr, /* open file pointer (img out) */
304
+ GDC_CHART_T type,
305
+ int num_points, /* points along x axis (even iterval) */
306
+ /* all arrays dependant on this */
307
+ char *xlbl[], /* array of xlabels */
308
+ int num_sets,
309
+ ... )
310
+ {
311
+ char do_hlc = ( type == GDC_HILOCLOSE ||
312
+ type == GDC_3DHILOCLOSE ||
313
+ type == GDC_3DCOMBO_HLC_BAR ||
314
+ type == GDC_3DCOMBO_HLC_AREA ||
315
+ type == GDC_COMBO_HLC_BAR ||
316
+ type == GDC_COMBO_HLC_AREA );
317
+
318
+ char do_fb = ( type == GDC_FLOATINGBAR ||
319
+ type == GDC_3DFLOATINGBAR );
320
+
321
+ char do_vol = ( type == GDC_COMBO_HLC_BAR ||
322
+ type == GDC_COMBO_HLC_AREA ||
323
+ type == GDC_COMBO_LINE_BAR ||
324
+ type == GDC_COMBO_LINE_AREA ||
325
+ type == GDC_COMBO_LINE_LINE ||
326
+ type == GDC_3DCOMBO_HLC_BAR ||
327
+ type == GDC_3DCOMBO_HLC_AREA||
328
+ type == GDC_3DCOMBO_LINE_BAR||
329
+ type == GDC_3DCOMBO_LINE_AREA ||
330
+ type == GDC_3DCOMBO_LINE_LINE );
331
+
332
+ int num_arrays = num_sets * (do_hlc? 3:
333
+ do_fb? 2: 1);
334
+
335
+ CREATE_ARRAY1( data, float, num_arrays*num_points ); /* float data[num_arrays*num_points] */
336
+ float *combo_data = (float*)NULL;
337
+
338
+ va_list ap;
339
+ int i,
340
+ rtn;
341
+
342
+ va_start( ap, num_sets );
343
+ for( i=0; i<num_arrays; ++i )
344
+ memcpy( data+i*num_points, va_arg(ap, float*), num_points*sizeof(float) );
345
+ if( do_vol )
346
+ combo_data = va_arg(ap, float*);
347
+ va_end(ap);
348
+
349
+ rtn = GDC_out_graph( IMGWIDTH,
350
+ IMGHEIGHT,
351
+ img_fptr,
352
+ type,
353
+ num_points,
354
+ xlbl,
355
+ num_sets,
356
+ data,
357
+ combo_data );
358
+ FREE_ARRAY1( data );
359
+
360
+ return rtn;
361
+ }
362
+
363
+ /* ------------------------------------------------------------------------- */
364
+ /* multi array interface */
365
+ int
366
+ GDC_out_graph( short IMGWIDTH, /* no check for a img that's too small to fit */
367
+ short IMGHEIGHT, /* needed info (labels, etc), could core dump */
368
+ FILE *img_fptr, /* open file pointer (img out) */
369
+ GDC_CHART_T type,
370
+ int num_points, /* points along x axis (even iterval) */
371
+ /* all arrays dependant on this */
372
+ char *xlbl[], /* array of xlabels */
373
+ int num_sets,
374
+ float *data, /* (float*) cast on multi-dim array (num_sets > 1) */
375
+ float *combo_data ) /* only used on COMBO chart types */
376
+ {
377
+ int i, j, k;
378
+
379
+ int graphwidth;
380
+ int grapheight;
381
+ gdImagePtr im;
382
+ gdImagePtr bg_img = NULL;
383
+
384
+ float xorig, yorig, vyorig;
385
+ float yscl = 0.0;
386
+ float vyscl = 0.0;
387
+ float xscl = 0.0;
388
+ float vhighest = -FLT_MAX;
389
+ float vlowest = FLT_MAX;
390
+ float highest = -FLT_MAX;
391
+ float lowest = FLT_MAX;
392
+ gdPoint volpoly[4];
393
+
394
+ char do_vol = ( type == GDC_COMBO_HLC_BAR || /* aka: combo */
395
+ type == GDC_COMBO_HLC_AREA ||
396
+ type == GDC_COMBO_LINE_BAR ||
397
+ type == GDC_COMBO_LINE_AREA ||
398
+ type == GDC_COMBO_LINE_LINE ||
399
+ type == GDC_3DCOMBO_HLC_BAR ||
400
+ type == GDC_3DCOMBO_HLC_AREA||
401
+ type == GDC_3DCOMBO_LINE_BAR||
402
+ type == GDC_3DCOMBO_LINE_AREA ||
403
+ type == GDC_3DCOMBO_LINE_LINE );
404
+ char threeD = ( type == GDC_3DAREA ||
405
+ type == GDC_3DLINE ||
406
+ type == GDC_3DBAR ||
407
+ type == GDC_3DFLOATINGBAR ||
408
+ type == GDC_3DHILOCLOSE ||
409
+ type == GDC_3DCOMBO_HLC_BAR ||
410
+ type == GDC_3DCOMBO_HLC_AREA||
411
+ type == GDC_3DCOMBO_LINE_BAR||
412
+ type == GDC_3DCOMBO_LINE_AREA ||
413
+ type == GDC_3DCOMBO_LINE_LINE );
414
+ char num_groups = num_sets; /* set before num_sets gets adjusted */
415
+ char set_depth = ( GDC_stack_type == GDC_STACK_DEPTH )? num_groups:
416
+ 1;
417
+ char do_bar = ( type == GDC_3DBAR || /* offset X objects to leave */
418
+ type == GDC_BAR || /* room at X(0) and X(n) */
419
+ type == GDC_3DFLOATINGBAR || /* i.e., not up against Y axes */
420
+ type == GDC_FLOATINGBAR);
421
+ char do_ylbl_fractions = /* %f format not given, or */
422
+ ( !GDC_ylabel_fmt || /* format doesn't have a %,g,e,E,f or F */
423
+ strlen(GDC_ylabel_fmt) == strcspn(GDC_ylabel_fmt,"%geEfF") );
424
+ float ylbl_interval = 0.0;
425
+ int xlbl_hgt = 0;
426
+ int xdepth_3Dtotal = 0;
427
+ int ydepth_3Dtotal = 0;
428
+ int xdepth_3D = 0; /* affects PX() */
429
+ int ydepth_3D = 0; /* affects PY() and PV() */
430
+ int hlf_barwdth = 0; /* half bar widths */
431
+ int hlf_hlccapwdth = 0; /* half cap widths for HLC_I_CAP and DIAMOND */
432
+ int annote_len = 0,
433
+ annote_hgt = 0;
434
+
435
+ /* args */
436
+ int setno = 0; /* affects PX() and PY() */
437
+ CREATE_ARRAY1( uvals, float *, type == GDC_HILOCLOSE ||
438
+ type == GDC_3DHILOCLOSE ||
439
+ type == GDC_3DCOMBO_HLC_BAR ||
440
+ type == GDC_3DCOMBO_HLC_AREA ||
441
+ type == GDC_COMBO_HLC_BAR ||
442
+ type == GDC_COMBO_HLC_AREA? num_sets *= 3: /* 1 more last set is vol */
443
+ type == GDC_FLOATINGBAR ||
444
+ type == GDC_3DFLOATINGBAR? num_sets *= 2:
445
+ type == GDC_COMBO_LINE_BAR ||
446
+ type == GDC_3DCOMBO_LINE_BAR ||
447
+ type == GDC_3DCOMBO_LINE_AREA||
448
+ type == GDC_3DCOMBO_LINE_LINE||
449
+ type == GDC_COMBO_LINE_AREA ||
450
+ type == GDC_COMBO_LINE_LINE? num_sets: /* 1 more last set is vol */
451
+ num_sets );
452
+ CREATE_ARRAY1( ExtVolColor, int, num_points ); /* int ExtVolColor[num_points], */
453
+ CREATE_ARRAY2( ExtColor, int, num_sets, num_points ); /* ExtColor[num_sets][num_points], */
454
+ CREATE_ARRAY2( ExtColorShd, int, threeD?num_sets:1, /* ExtColorShd[num_sets][num_points]; */
455
+ threeD?num_points:1 ); /* shade colors only with 3D */
456
+ float *uvol;
457
+
458
+ int BGColor,
459
+ LineColor,
460
+ PlotColor,
461
+ GridColor,
462
+ VolColor,
463
+ ThumbDColor,
464
+ ThumbLblColor,
465
+ ThumbUColor,
466
+ /* ArrowDColor, */
467
+ /* ArrowUColor, */
468
+ AnnoteColor;
469
+ #ifdef HAVE_LIBFREETYPE
470
+ char *gdc_title_font = GDC_title_font; /* for convienience */
471
+ char *gdc_ytitle_font = GDC_ytitle_font; /* in func calls */
472
+ char *gdc_xtitle_font = GDC_xtitle_font;
473
+ /* char *gdc_yaxis_font = GDC_yaxis_font; */
474
+ char *gdc_xaxis_font = GDC_xaxis_font;
475
+ double gdc_title_ptsize = GDC_title_ptsize;
476
+ double gdc_ytitle_ptsize = GDC_ytitle_ptsize;
477
+ double gdc_xtitle_ptsize = GDC_xtitle_ptsize;
478
+ /* double gdc_yaxis_ptsize = GDC_yaxis_ptsize; */
479
+ double gdc_xaxis_ptsize = GDC_xaxis_ptsize;
480
+ double gdc_xaxis_rad = TO_RAD( GDC_xaxis_angle );
481
+ char *gdc_annotation_font = GDC_annotation_font;
482
+ double gdc_annotation_ptsize = GDC_annotation_ptsize;
483
+
484
+ #else
485
+ char *gdc_title_font = NULL;
486
+ char *gdc_ytitle_font = NULL;
487
+ char *gdc_xtitle_font = NULL;
488
+ /* char *gdc_yaxis_font = NULL; */
489
+ char *gdc_xaxis_font = NULL;
490
+ double gdc_title_ptsize = 0.0;
491
+ double gdc_ytitle_ptsize = 0.0;
492
+ double gdc_xtitle_ptsize = 0.0;
493
+ /* double gdc_yaxis_ptsize = 0.0; */
494
+ double gdc_xaxis_ptsize = 0.0;
495
+ double gdc_xaxis_rad = GDC_xaxis_angle==90.0? M_PI/2.0: 0.0;
496
+ char *gdc_annotation_font = NULL;
497
+ double gdc_annotation_ptsize=0.0;
498
+ #endif
499
+ double sin_xangle = 1.0, /* calc only when&if needed */
500
+ cos_xangle = 0.0;
501
+
502
+ /* idiot checks */
503
+ if( IMGWIDTH<=0 || IMGHEIGHT<=0 || (!img_fptr && GDC_generate_img) )
504
+ {
505
+ FREE_ARRAY1( uvals );
506
+ FREE_ARRAY1( ExtVolColor );
507
+ FREE_ARRAY2( ExtColor );
508
+ FREE_ARRAY2( ExtColorShd );
509
+ return -1;
510
+ }
511
+ if( num_points <= 0 )
512
+ {
513
+ out_err( IMGWIDTH, IMGHEIGHT, img_fptr, GDC_BGColor, GDC_LineColor, "No Data Available" );
514
+ FREE_ARRAY1( uvals );
515
+ FREE_ARRAY1( ExtVolColor );
516
+ FREE_ARRAY2( ExtColor );
517
+ FREE_ARRAY2( ExtColorShd );
518
+ return 1;
519
+ }
520
+
521
+ load_font_conversions();
522
+ if( GDC_thumbnail )
523
+ {
524
+ GDC_grid = FALSE;
525
+ GDC_xaxis = FALSE;
526
+ GDC_yaxis = FALSE;
527
+ }
528
+
529
+ /* ----- get args ----- */
530
+ for( i=0; i<num_sets; ++i )
531
+ uvals[i] = data+i*num_points;
532
+ if( do_vol )
533
+ if( !combo_data )
534
+ {
535
+ out_err( IMGWIDTH, IMGHEIGHT, img_fptr, GDC_BGColor, GDC_LineColor, "No Combo Data Available" );
536
+ FREE_ARRAY1( uvals );
537
+ FREE_ARRAY1( ExtVolColor );
538
+ FREE_ARRAY2( ExtColor );
539
+ FREE_ARRAY2( ExtColorShd );
540
+ return -2;
541
+ }
542
+ else
543
+ uvol = combo_data;
544
+
545
+ /* ----- calculate interpretations first ----- */
546
+ if( GDC_interpolations )
547
+ {
548
+ for( i=0; i<num_sets; ++i )
549
+ for( j=0; j<num_points; ++j )
550
+ if( uvals[i][j] == GDC_INTERP_VALUE )
551
+ {
552
+ do_interpolations( num_points, j, uvals[i] );
553
+ }
554
+ if( do_vol )
555
+ for( j=0; j<num_points; ++j )
556
+ if( uvol[j] == GDC_INTERP_VALUE )
557
+ {
558
+ do_interpolations( num_points, j, uvol );
559
+ }
560
+ }
561
+
562
+ /* ----- highest & lowest values ----- */
563
+ if( GDC_stack_type == GDC_STACK_SUM ) /* need to walk sideways */
564
+ for( j=0; j<num_points; ++j )
565
+ {
566
+ float set_sum = 0.0;
567
+ for( i=0; i<num_sets; ++i )
568
+ if( uvals[i][j] != GDC_NOVALUE )
569
+ {
570
+ set_sum += uvals[i][j];
571
+ highest = MAX( highest, set_sum );
572
+ lowest = MIN( lowest, set_sum );
573
+ }
574
+ }
575
+ else
576
+ if( GDC_stack_type == GDC_STACK_LAYER ) /* need to walk sideways */
577
+ for( j=0; j<num_points; ++j )
578
+ {
579
+ float neg_set_sum = 0.0,
580
+ pos_set_sum = 0.0;
581
+ for( i=0; i<num_sets; ++i )
582
+ if( uvals[i][j] != GDC_NOVALUE )
583
+ if( uvals[i][j] < 0.0 )
584
+ neg_set_sum += uvals[i][j];
585
+ else
586
+ pos_set_sum += uvals[i][j];
587
+ lowest = MIN( lowest, MIN(neg_set_sum,pos_set_sum) );
588
+ highest = MAX( highest, MAX(neg_set_sum,pos_set_sum) );
589
+ }
590
+ else
591
+ for( i=0; i<num_sets; ++i )
592
+ for( j=0; j<num_points; ++j )
593
+ if( uvals[i][j] != GDC_NOVALUE )
594
+ {
595
+ highest = MAX( uvals[i][j], highest );
596
+ lowest = MIN( uvals[i][j], lowest );
597
+ }
598
+ if( GDC_scatter )
599
+ for( i=0; i<GDC_num_scatter_pts; ++i )
600
+ {
601
+ highest = MAX( (GDC_scatter+i)->val, highest );
602
+ lowest = MIN( (GDC_scatter+i)->val, lowest );
603
+ }
604
+ if( do_vol ) /* for now only one combo set allowed */
605
+ {
606
+ /* vhighest = 1.0; */
607
+ /* vlowest = 0.0; */
608
+ for( j=0; j<num_points; ++j )
609
+ if( uvol[j] != GDC_NOVALUE )
610
+ {
611
+ vhighest = MAX( uvol[j], vhighest );
612
+ vlowest = MIN( uvol[j], vlowest );
613
+ }
614
+ if( vhighest == -FLT_MAX ) /* no values */
615
+ vhighest = 1.0; /* for scaling, need a range */
616
+ if( vlowest == FLT_MAX )
617
+ vlowest = 0.0;
618
+ if( type == GDC_COMBO_LINE_BAR ||
619
+ type == GDC_COMBO_HLC_BAR ||
620
+ type == GDC_COMBO_LINE_AREA ||
621
+ type == GDC_COMBO_HLC_AREA ||
622
+ type == GDC_3DCOMBO_LINE_BAR ||
623
+ type == GDC_3DCOMBO_LINE_AREA ||
624
+ type == GDC_3DCOMBO_HLC_BAR ||
625
+ type == GDC_3DCOMBO_HLC_AREA )
626
+ if( vhighest < 0.0 )
627
+ vhighest = 0.0;
628
+ else
629
+ if( vlowest > 0.0 )
630
+ vlowest = 0.0; /* bar, area should always start at 0 */
631
+ }
632
+
633
+ if( lowest == FLT_MAX )
634
+ lowest = 0.0;
635
+ if( highest == -FLT_MAX )
636
+ highest = 1.0; /* need a range */
637
+ if( type == GDC_AREA || /* bars and area should always start at 0 */
638
+ type == GDC_BAR ||
639
+ type == GDC_3DBAR ||
640
+ type == GDC_3DAREA )
641
+ if( highest < 0.0 )
642
+ highest = 0.0;
643
+ else
644
+ if( lowest > 0.0 ) /* negs should be drawn from 0 */
645
+ lowest = 0.0;
646
+
647
+ if( GDC_requested_ymin != GDC_NOVALUE && GDC_requested_ymin < lowest )
648
+ lowest = GDC_requested_ymin;
649
+ if( GDC_requested_ymax != GDC_NOVALUE && GDC_requested_ymax > highest )
650
+ highest = GDC_requested_ymax;
651
+
652
+ /* ----- graph height and width within the img height width ----- */
653
+ /* grapheight/height is the actual size of the scalable graph */
654
+ {
655
+ int title_hgt = GDC_title? 2 /* title? horizontal text line(s) */
656
+ + GDCfnt_sz(GDC_title,GDC_title_size,gdc_title_font,gdc_title_ptsize,0.0,NULL).h
657
+ + 2:
658
+ 2;
659
+ int xlabel_hgt = 0;
660
+ int xtitle_hgt = GDC_xtitle? 1+GDCfnt_sz(GDC_xtitle,GDC_xtitle_size,gdc_xtitle_font,gdc_xtitle_ptsize,0.0,NULL).h+1: 0;
661
+ int ytitle_hgt = GDC_ytitle? 1+GDCfnt_sz(GDC_ytitle,GDC_ytitle_size,gdc_ytitle_font,gdc_ytitle_ptsize,M_PI/2.0,NULL).h+1: 0;
662
+ int vtitle_hgt = do_vol&&GDC_ytitle2? 1+GDCfnt_sz(GDC_ytitle2,GDC_ytitle_size,gdc_ytitle_font,gdc_ytitle_ptsize,M_PI/2.0,NULL).h+1: 0;
663
+ int ylabel_wth = 0;
664
+ int vlabel_wth = 0;
665
+
666
+ int xtics = GDC_ticks && (GDC_grid||GDC_xaxis)? 1+2: 0;
667
+ int ytics = GDC_ticks && (GDC_grid||GDC_yaxis)? 1+3: 0;
668
+ int vtics = GDC_ticks && (GDC_yaxis&&do_vol)? 3+1: 0;
669
+
670
+
671
+ #define HYP_DEPTH ( (double)((IMGWIDTH+IMGHEIGHT)/2) * ((double)GDC_3d_depth)/100.0 )
672
+ #define RAD_DEPTH ( (double)GDC_3d_angle*2*M_PI/360 )
673
+ xdepth_3D = threeD? (int)( cos(RAD_DEPTH) * HYP_DEPTH ): 0;
674
+ ydepth_3D = threeD? (int)( sin(RAD_DEPTH) * HYP_DEPTH ): 0;
675
+ xdepth_3Dtotal = xdepth_3D*set_depth;
676
+ ydepth_3Dtotal = ydepth_3D*set_depth;
677
+ annote_hgt = GDC_annotation && *(GDC_annotation->note)?
678
+ 1 + /* space to note */
679
+ (1+GDCfnt_sz( GDC_annotation->note,GDC_annotation_font_size,
680
+ gdc_annotation_font,gdc_annotation_ptsize,0.0,NULL ).h) +
681
+ 1 + /* space under note */
682
+ 2: 0; /* space to chart */
683
+ annote_len = GDC_annotation && *(GDC_annotation->note)?
684
+ GDCfnt_sz( GDC_annotation->note,GDC_annotation_font_size,
685
+ gdc_annotation_font,gdc_annotation_ptsize,0.0,NULL ).w:
686
+ 0;
687
+
688
+ /* find length of "longest" (Y) xaxis label */
689
+ /* find the average "width" (X) xaxis label */
690
+ /* avg method fails when 2 or 3 very wide are consecutive, with the rest being thin */
691
+ /* this is most evident with horizontal (0deg) xlabels */
692
+ /* assume in this case they are quite uniform, e.g., dates */
693
+ /* find affects on graphwidth/xorig of wildly overhanging angled labels */
694
+ if( GDC_xaxis && xlbl )
695
+ {
696
+ int biggest = -INT_MAX,
697
+ widest = -INT_MAX;
698
+ #ifdef HAVE_LIBFREETYPE
699
+ if( gdc_xaxis_rad!=M_PI/2.0 && gdc_xaxis_font && gdc_xaxis_ptsize )
700
+ {
701
+ sin_xangle = sin( gdc_xaxis_rad ),
702
+ cos_xangle = cos( gdc_xaxis_rad );
703
+ }
704
+ #endif
705
+
706
+ for( i=0; i<num_points; ++i )
707
+ {
708
+ int len = 0,
709
+ wdth = 0;
710
+ if( !GDC_xlabel_ctl ||
711
+ (GDC_xlabel_ctl && GDC_xlabel_ctl[i]) )
712
+ {
713
+ char *sts;
714
+ struct fnt_sz_t lftsz = GDCfnt_sz( xlbl[i], GDC_xaxisfont_size,
715
+ gdc_xaxis_font, gdc_xaxis_ptsize, gdc_xaxis_rad,
716
+ &sts );
717
+
718
+ if( gdc_xaxis_rad == M_PI/2.0 || /* no need to do the floating point math */
719
+ (sts && *sts) ) /* FT fail status, used default gdfont */
720
+ {
721
+ #ifdef DEBUG
722
+ fprintf( stderr, "TTF/FT failure: %s\n", sts );
723
+ #endif
724
+ len = lftsz.w;
725
+ wdth = lftsz.h;
726
+ }
727
+ else
728
+ if( gdc_xaxis_rad == 0.0 ) /* protect /0 */
729
+ { /* reverse when horiz. */
730
+ len = lftsz.h;
731
+ wdth = lftsz.w;
732
+ }
733
+ else /* length & width due to the angle */
734
+ {
735
+ len = (int)( (double)lftsz.w * sin_xangle + (double)lftsz.h * cos_xangle );
736
+ wdth = (int)( (double)lftsz.h / sin_xangle );
737
+ }
738
+ }
739
+ biggest = MAX( len, biggest ); /* last seg */
740
+ widest = MAX( wdth, widest ); /* last seg */
741
+ }
742
+ xlbl_hgt = 1+ widest +1;
743
+ xlabel_hgt = 1+ biggest +1;
744
+ }
745
+
746
+ grapheight = IMGHEIGHT - ( xtics +
747
+ xtitle_hgt +
748
+ xlabel_hgt +
749
+ title_hgt +
750
+ annote_hgt +
751
+ ydepth_3Dtotal +
752
+ 2 );
753
+ if( GDC_hard_size && GDC_hard_grapheight ) /* user wants to use his */
754
+ grapheight = GDC_hard_grapheight;
755
+ GDC_hard_grapheight = grapheight;
756
+ /* before width can be known... */
757
+ /* ----- y labels intervals ----- */
758
+ {
759
+ float tmp_highest;
760
+ /* possible y gridline points */
761
+ #define NUM_YPOINTS (sizeof(ypoints_2f) / sizeof(float))
762
+ float ypoints_2f[] = { 1.0/64.0, 1.0/32.0, 1.0/16.0, 1.0/8.0, 1.0/4.0, 1.0/2.0,
763
+ 1.0, 2.0, 3.0, 5.0, 10.0, 25.0,
764
+ 50.0, 100.0, 250.0, 500.0, 1000.0, 2500, 5000.0,
765
+ 10000.0, 25000.0, 50000.0, 100000.0,500000.0,1000000, 5000000,
766
+ 10000000, 50000000 },
767
+ ypoints_dec[NUM_YPOINTS] = /* "pretty" points for dec (non-fraction) */
768
+ { 0.005, 0.01, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5,
769
+ 1.0, 2.0, 3.0, 5.0, 10.0, 25.0,
770
+ 50.0, 100.0, 250.0, 500.0, 1000.0, 2500, 5000.0,
771
+ 10000.0, 25000.0, 50000.0, 100000.0,500000.0,1000000, 5000000 },
772
+ *ypoints = do_ylbl_fractions? ypoints_2f: ypoints_dec;
773
+ int max_num_ylbls;
774
+ int longest_ylblen = 0;
775
+ /* maximum y lables that'll fit... */
776
+ max_num_ylbls = grapheight / (3+GDC_fontc[GDC_yaxisfont_size==GDC_TINY? GDC_yaxisfont_size+1:
777
+ GDC_yaxisfont_size].h);
778
+ if( max_num_ylbls < 3 )
779
+ {
780
+ /* gdImageDestroy(im); haven't yet created it */
781
+ out_err( IMGWIDTH, IMGHEIGHT,
782
+ img_fptr,
783
+ GDC_BGColor, GDC_LineColor,
784
+ "Insificient Height" );
785
+ FREE_ARRAY1( uvals );
786
+ FREE_ARRAY1( ExtVolColor );
787
+ FREE_ARRAY2( ExtColor );
788
+ FREE_ARRAY2( ExtColorShd );
789
+ return 2;
790
+ }
791
+
792
+ { /* one "space" interval above + below */
793
+ float ylbl_density_space_intvl = ((float)max_num_ylbls-(1.0+1.0)) * (float)GDC_ylabel_density/100.0;
794
+ for( i=1; i<NUM_YPOINTS; ++i )
795
+ /* if( ypoints[i] > ylbl_interval ) */
796
+ /* break; */
797
+ if( (highest-lowest)/ypoints[i] < ylbl_density_space_intvl )
798
+ break;
799
+ /* gotta go through the above loop to catch the 'tweeners :-| */
800
+ }
801
+
802
+ ylbl_interval = GDC_requested_yinterval != GDC_NOVALUE &&
803
+ GDC_requested_yinterval > ypoints[i-1]? GDC_requested_yinterval:
804
+ ypoints[i-1];
805
+
806
+ /* perform floating point remainders */
807
+ /* gonculate largest interval-point < lowest */
808
+ if( lowest != 0.0 &&
809
+ lowest != GDC_requested_ymin )
810
+ {
811
+ if( lowest < 0.0 )
812
+ lowest -= ylbl_interval;
813
+ /* lowest = (lowest-ypoints[0]) - */
814
+ /* ( ( ((lowest-ypoints[0])/ylbl_interval)*ylbl_interval ) - */
815
+ /* ( (float)((int)((lowest-ypoints[0])/ylbl_interval))*ylbl_interval ) ); */
816
+ lowest = ylbl_interval * (float)(int)((lowest-ypoints[0])/ylbl_interval);
817
+ }
818
+ /* find smallest interval-point > highest */
819
+ tmp_highest = lowest;
820
+ do /* while( (tmp_highest += ylbl_interval) <= highest ) */
821
+ {
822
+ int nmrtr, dmntr, whole;
823
+ char *price_to_str( float, int*, int*, int*, char* );
824
+ int lbl_len;
825
+ char foo[32];
826
+
827
+ if( GDC_yaxis )
828
+ { /* XPG2 compatibility */
829
+ sprintf( foo, do_ylbl_fractions? "%.0f": GDC_ylabel_fmt, tmp_highest );
830
+ lbl_len = ylbl_interval<1.0? strlen( price_to_str(tmp_highest,
831
+ &nmrtr,
832
+ &dmntr,
833
+ &whole,
834
+ do_ylbl_fractions? NULL: GDC_ylabel_fmt) ):
835
+ strlen( foo );
836
+ longest_ylblen = MAX( longest_ylblen, lbl_len );
837
+ }
838
+ } while( (tmp_highest += ylbl_interval) <= highest );
839
+ ylabel_wth = longest_ylblen * GDC_fontc[GDC_yaxisfont_size].w;
840
+ highest = GDC_requested_ymax==GDC_NOVALUE? tmp_highest:
841
+ MAX( GDC_requested_ymax, highest );
842
+
843
+ if( do_vol )
844
+ {
845
+ float num_yintrvls = (highest-lowest) / ylbl_interval;
846
+ /* no skyscrapers */
847
+ if( vhighest != 0.0 )
848
+ vhighest += (vhighest-vlowest) / (num_yintrvls*2.0);
849
+ if( vlowest != 0.0 )
850
+ vlowest -= (vhighest-vlowest) / (num_yintrvls*2.0);
851
+
852
+ if( GDC_yaxis2 )
853
+ {
854
+ char svlongest[32];
855
+ int lbl_len_low = sprintf( svlongest, GDC_ylabel2_fmt? GDC_ylabel2_fmt: "%.0f", vlowest );
856
+ int lbl_len_high = sprintf( svlongest, GDC_ylabel2_fmt? GDC_ylabel2_fmt: "%.0f", vhighest );
857
+ vlabel_wth = 1
858
+ + MAX( lbl_len_low,lbl_len_high ) * GDC_fontc[GDC_yaxisfont_size].w;
859
+ }
860
+ }
861
+ }
862
+
863
+ graphwidth = IMGWIDTH - ( ( (GDC_hard_size && GDC_hard_xorig)? GDC_hard_xorig:
864
+ ( ytitle_hgt +
865
+ ylabel_wth +
866
+ ytics ) )
867
+ + vtics
868
+ + vtitle_hgt
869
+ + vlabel_wth
870
+ + xdepth_3Dtotal );
871
+ if( GDC_hard_size && GDC_hard_graphwidth ) /* user wants to use his */
872
+ graphwidth = GDC_hard_graphwidth;
873
+ GDC_hard_graphwidth = graphwidth;
874
+
875
+ /* ----- scale to img size ----- */
876
+ /* offset to 0 at lower left (where it should be) */
877
+ xscl = (float)(graphwidth-xdepth_3Dtotal) / (float)(num_points + (do_bar?2:0));
878
+ yscl = -((float)grapheight) / (float)(highest-lowest);
879
+ if( do_vol )
880
+ {
881
+ float hilow_diff = vhighest-vlowest==0.0? 1.0: vhighest-vlowest;
882
+
883
+ vyscl = -((float)grapheight) / hilow_diff;
884
+ vyorig = (float)grapheight
885
+ + ABS(vyscl) * MIN(vlowest,vhighest)
886
+ + ydepth_3Dtotal
887
+ + title_hgt
888
+ + annote_hgt;
889
+ }
890
+ xorig = (float)( IMGWIDTH - ( graphwidth +
891
+ vtitle_hgt +
892
+ vtics +
893
+ vlabel_wth ) );
894
+ if( GDC_hard_size && GDC_hard_xorig )
895
+ xorig = GDC_hard_xorig;
896
+ GDC_hard_xorig = xorig;
897
+ /* yorig = (float)grapheight + ABS(yscl * lowest) + ydepth_3Dtotal + title_hgt; */
898
+ yorig = (float)grapheight
899
+ + ABS(yscl) * MIN(lowest,highest)
900
+ + ydepth_3Dtotal
901
+ + title_hgt
902
+ + annote_hgt;
903
+ /*???? if( GDC_hard_size && GDC_hard_yorig ) /* vyorig too? */
904
+ /*???? yorig = GDC_hard_yorig; FRED - check email */
905
+ GDC_hard_yorig = yorig;
906
+
907
+ hlf_barwdth = (int)( (float)(PX(2)-PX(1)) * (((float)GDC_bar_width/100.0)/2.0) ); /* used only for bars */
908
+ hlf_hlccapwdth = (int)( (float)(PX(2)-PX(1)) * (((float)GDC_HLC_cap_width/100.0)/2.0) );
909
+ }
910
+ /* scaled, sized, ready */
911
+
912
+
913
+ /* ----- OK start the graphic ----- */
914
+ if( (GDC_hold_img & GDC_REUSE_IMAGE) &&
915
+ GDC_image != (void*)NULL )
916
+ im = GDC_image;
917
+ else
918
+ im = gdImageCreate( IMGWIDTH, IMGHEIGHT );
919
+
920
+
921
+ BGColor = gdImageColorAllocate( im, l2gdcal(GDC_BGColor) );
922
+ LineColor = clrallocate( im, GDC_LineColor );
923
+ PlotColor = clrallocate( im, GDC_PlotColor );
924
+ GridColor = clrallocate( im, GDC_GridColor );
925
+ if( do_vol )
926
+ {
927
+ VolColor = clrallocate( im, GDC_VolColor );
928
+ for( i=0; i<num_points; ++i )
929
+ if( GDC_ExtVolColor )
930
+ ExtVolColor[i] = clrallocate( im, GDC_ExtVolColor[i] );
931
+ else
932
+ ExtVolColor[i] = VolColor;
933
+ }
934
+ /* ArrowDColor = gdImageColorAllocate( im, 0xFF, 0, 0 ); */
935
+ /* ArrowUColor = gdImageColorAllocate( im, 0, 0xFF, 0 ); */
936
+ if( GDC_annotation )
937
+ AnnoteColor = clrallocate( im, GDC_annotation->color );
938
+
939
+ /* attempt to import optional background image */
940
+ if( GDC_BGImage )
941
+ {
942
+ FILE *in = fopen(GDC_BGImage, "rb");
943
+ if( !in )
944
+ {
945
+ ; /* Cant load background image, drop it */
946
+ }
947
+ else
948
+ {
949
+ /* assume GIF */
950
+ /* should determine type by file extension, option, ... */
951
+ if( bg_img = gdImageCreateFromGif(in) ) /* = */
952
+ {
953
+ int bgxpos = gdImageSX(bg_img)<IMGWIDTH? IMGWIDTH/2 - gdImageSX(bg_img)/2: 0,
954
+ bgypos = gdImageSY(bg_img)<IMGHEIGHT? IMGHEIGHT/2 - gdImageSY(bg_img)/2: 0;
955
+
956
+
957
+ if( gdImageSX(bg_img) > IMGWIDTH || /* resize only if too big */
958
+ gdImageSY(bg_img) > IMGHEIGHT ) /* [and center] */
959
+ {
960
+ gdImageCopyResized( im, bg_img, /* dst, src */
961
+ bgxpos, bgypos, /* dstX, dstY */
962
+ 0, 0, /* srcX, srcY */
963
+ IMGWIDTH, IMGHEIGHT, /* dstW, dstH */
964
+ IMGWIDTH, IMGHEIGHT ); /* srcW, srcH */
965
+ }
966
+ else /* just center */
967
+ gdImageCopy( im, bg_img, /* dst, src */
968
+ bgxpos, bgypos, /* dstX, dstY */
969
+ 0, 0, /* srcX, srcY */
970
+ IMGWIDTH, IMGHEIGHT ); /* W, H */
971
+ }
972
+ fclose(in);
973
+ }
974
+ }
975
+
976
+ for( j=0; j<num_sets; ++j )
977
+ for( i=0; i<num_points; ++i )
978
+ if( GDC_ExtColor )
979
+ {
980
+ unsigned long ext_clr = *(GDC_ExtColor+num_points*j+i);
981
+
982
+ ExtColor[j][i] = clrallocate( im, ext_clr );
983
+ if( threeD )
984
+ ExtColorShd[j][i] = clrshdallocate( im, ext_clr );
985
+ }
986
+ else if( GDC_SetColor )
987
+ {
988
+ int set_clr = GDC_SetColor[j];
989
+ ExtColor[j][i] = clrallocate( im, set_clr );
990
+ if( threeD )
991
+ ExtColorShd[j][i] = clrshdallocate( im, set_clr );
992
+ }
993
+ else
994
+ {
995
+ ExtColor[j][i] = PlotColor;
996
+ if( threeD )
997
+ ExtColorShd[j][i] = clrshdallocate( im, GDC_PlotColor );
998
+ }
999
+
1000
+
1001
+ if( GDC_transparent_bg )
1002
+ gdImageColorTransparent( im, BGColor );
1003
+
1004
+ if( GDC_title )
1005
+ {
1006
+ struct fnt_sz_t tftsz = GDCfnt_sz( GDC_title, GDC_title_size, gdc_title_font, gdc_title_ptsize, 0.0, NULL );
1007
+ int titlecolor = clrallocate( im, GDC_TitleColor );
1008
+
1009
+ GDCImageStringNL( im,
1010
+ &GDC_fontc[GDC_title_size],
1011
+ gdc_title_font, gdc_title_ptsize,
1012
+ 0.0,
1013
+ IMGWIDTH/2 - tftsz.w/2,
1014
+ 1,
1015
+ GDC_title,
1016
+ titlecolor,
1017
+ GDC_JUSTIFY_CENTER,
1018
+ NULL );
1019
+ }
1020
+ if( GDC_xtitle )
1021
+ {
1022
+ struct fnt_sz_t xtftsz = GDCfnt_sz( GDC_xtitle, GDC_xtitle_size, gdc_xtitle_font, gdc_xtitle_ptsize, 0.0, NULL );
1023
+ int titlecolor = GDC_XTitleColor==GDC_DFLTCOLOR? PlotColor:
1024
+ clrallocate( im, GDC_XTitleColor );
1025
+ GDCImageStringNL( im,
1026
+ &GDC_fontc[GDC_xtitle_size],
1027
+ gdc_xtitle_font, gdc_xtitle_ptsize,
1028
+ 0.0,
1029
+ IMGWIDTH/2 - xtftsz.w/2,
1030
+ IMGHEIGHT-1-xtftsz.h-1,
1031
+ GDC_xtitle,
1032
+ titlecolor,
1033
+ GDC_JUSTIFY_CENTER,
1034
+ NULL );
1035
+ }
1036
+
1037
+
1038
+ /* ----- start drawing ----- */
1039
+ /* ----- backmost first - border, grid & labels ----- */
1040
+ /* if no grid, on 3D, border needs to handle it */
1041
+ if( !GDC_grid && threeD &&
1042
+ ((GDC_border == GDC_BORDER_ALL) || (GDC_border & GDC_BORDER_X) || (GDC_border & GDC_BORDER_Y)) )
1043
+ {
1044
+ int x1, x2,
1045
+ y1, y2;
1046
+
1047
+ x1 = PX(0);
1048
+ y1 = PY(lowest);
1049
+
1050
+ setno = set_depth;
1051
+ x2 = PX(0);
1052
+ y2 = PY(lowest);
1053
+
1054
+ gdImageLine( im, x1, y1, x2, y2, LineColor ); /* depth at origin */
1055
+ if( (GDC_border == GDC_BORDER_ALL) || (GDC_border & GDC_BORDER_X) )
1056
+ gdImageLine( im, x2, y2, PX(num_points-1+(do_bar?2:0)), y2, LineColor );
1057
+ if( (GDC_border == GDC_BORDER_ALL) || (GDC_border & GDC_BORDER_Y) )
1058
+ gdImageLine( im, x2, PY(highest), x2, y2, LineColor );
1059
+ setno = 0;
1060
+ }
1061
+ if( GDC_grid || GDC_ticks || GDC_yaxis )
1062
+ { /* grid lines & y label(s) */
1063
+ float tmp_y = lowest;
1064
+ int labelcolor = GDC_YLabelColor==GDC_DFLTCOLOR?
1065
+ LineColor: clrallocate( im, GDC_YLabelColor );
1066
+ int label2color = GDC_YLabel2Color==GDC_DFLTCOLOR?
1067
+ VolColor: clrallocate( im, GDC_YLabel2Color );
1068
+
1069
+ /* step from lowest to highest puting in labels and grid at interval points */
1070
+ /* since now "odd" intervals may be requested, try to step starting at 0, */
1071
+ /* if lowest < 0 < highest */
1072
+ for( i=-1; i<=1; i+=2 ) /* -1, 1 */
1073
+ {
1074
+ if( i == -1 ) if( lowest >= 0.0 ) /* all pos plotting */
1075
+ continue;
1076
+ else
1077
+ tmp_y = MIN( 0, highest ); /* step down to lowest */
1078
+
1079
+ if( i == 1 ) if( highest <= 0.0 ) /* all neg plotting */
1080
+ continue;
1081
+ else
1082
+ tmp_y = MAX( 0, lowest ); /* step up to highest */
1083
+
1084
+
1085
+ /* if( !(highest > 0 && lowest < 0) ) // doesn't straddle 0 */
1086
+ /* { */
1087
+ /* if( i == -1 ) // only do once: normal */
1088
+ /* continue; */
1089
+ /* } */
1090
+ /* else */
1091
+ /* tmp_y = 0; */
1092
+
1093
+ do /* while( (tmp_y (+-)= ylbl_interval) < [highest,lowest] ) */
1094
+ {
1095
+ int n, d, w;
1096
+ char *price_to_str( float, int*, int*, int*, char* );
1097
+ char nmrtr[3+1], dmntr[3+1], whole[8];
1098
+ char all_whole = ylbl_interval<1.0? FALSE: TRUE;
1099
+
1100
+ char *ylbl_str = price_to_str( tmp_y,&n,&d,&w,
1101
+ do_ylbl_fractions? NULL: GDC_ylabel_fmt );
1102
+ if( do_ylbl_fractions )
1103
+ {
1104
+ sprintf( nmrtr, "%d", n );
1105
+ sprintf( dmntr, "%d", d );
1106
+ sprintf( whole, "%d", w );
1107
+ }
1108
+
1109
+ if( GDC_grid || GDC_ticks )
1110
+ {
1111
+ int x1, x2, y1, y2;
1112
+ /* int gridline_clr = tmp_y == 0.0? LineColor: GridColor; */
1113
+ /* tics */
1114
+ x1 = PX(0); y1 = PY(tmp_y);
1115
+ if( GDC_ticks )
1116
+ gdImageLine( im, x1-2, y1, x1, y1, GridColor );
1117
+ if( GDC_grid )
1118
+ {
1119
+ setno = set_depth;
1120
+ x2 = PX(0); y2 = PY(tmp_y); /* w/ new setno */
1121
+ gdImageLine( im, x1, y1, x2, y2, GridColor ); /* depth for 3Ds */
1122
+ gdImageLine( im, x2, y2, PX(num_points-1+(do_bar?2:0)), y2, GridColor );
1123
+ setno = 0; /* set back to foremost */
1124
+ }
1125
+ }
1126
+ if( GDC_yaxis )
1127
+ if( do_ylbl_fractions )
1128
+ {
1129
+ if( w || (!w && !n && !d) )
1130
+ {
1131
+ gdImageString( im,
1132
+ GDC_fontc[GDC_yaxisfont_size].f,
1133
+ PX(0)-2-strlen(whole)*GDC_fontc[GDC_yaxisfont_size].w
1134
+ - ( (!all_whole)?
1135
+ (strlen(nmrtr)*GDC_fontc[GDC_yaxisfont_size-1].w +
1136
+ GDC_fontc[GDC_yaxisfont_size].w +
1137
+ strlen(nmrtr)*GDC_fontc[GDC_yaxisfont_size-1].w) :
1138
+ 1 ),
1139
+ PY(tmp_y)-GDC_fontc[GDC_yaxisfont_size].h/2,
1140
+ (unsigned char*)whole,
1141
+ labelcolor );
1142
+ }
1143
+ if( n )
1144
+ {
1145
+ gdImageString( im,
1146
+ GDC_fontc[GDC_yaxisfont_size-1].f,
1147
+ PX(0)-2-strlen(nmrtr)*GDC_fontc[GDC_yaxisfont_size-1].w
1148
+ -GDC_fontc[GDC_yaxisfont_size].w
1149
+ -strlen(nmrtr)*GDC_fontc[GDC_yaxisfont_size-1].w + 1,
1150
+ PY(tmp_y)-GDC_fontc[GDC_yaxisfont_size].h/2 + 1,
1151
+ (unsigned char*)nmrtr,
1152
+ labelcolor );
1153
+ gdImageString( im,
1154
+ GDC_fontc[GDC_yaxisfont_size].f,
1155
+ PX(0)-2-GDC_fontc[GDC_yaxisfont_size].w
1156
+ -strlen(nmrtr)*GDC_fontc[GDC_yaxisfont_size-1].w,
1157
+ PY(tmp_y)-GDC_fontc[GDC_yaxisfont_size].h/2,
1158
+ (unsigned char*)"/",
1159
+ labelcolor );
1160
+ gdImageString( im,
1161
+ GDC_fontc[GDC_yaxisfont_size-1].f,
1162
+ PX(0)-2-strlen(nmrtr)*GDC_fontc[GDC_yaxisfont_size-1].w - 2,
1163
+ PY(tmp_y)-GDC_fontc[GDC_yaxisfont_size].h/2 + 3,
1164
+ (unsigned char*)dmntr,
1165
+ labelcolor );
1166
+ }
1167
+ }
1168
+ else
1169
+ gdImageString( im,
1170
+ GDC_fontc[GDC_yaxisfont_size].f,
1171
+ PX(0)-2-strlen(ylbl_str)*GDC_fontc[GDC_yaxisfont_size].w,
1172
+ PY(tmp_y)-GDC_fontc[GDC_yaxisfont_size].h/2,
1173
+ (unsigned char*)ylbl_str,
1174
+ labelcolor );
1175
+
1176
+
1177
+ if( do_vol && GDC_yaxis2 )
1178
+ {
1179
+ char vylbl[16];
1180
+ /* opposite of PV(y) */
1181
+ sprintf( vylbl,
1182
+ GDC_ylabel2_fmt? GDC_ylabel2_fmt: "%.0f",
1183
+ ((float)(PY(tmp_y)+(setno*ydepth_3D)-vyorig))/vyscl );
1184
+
1185
+ setno = set_depth;
1186
+ if( GDC_ticks )
1187
+ gdImageLine( im, PX(num_points-1+(do_bar?2:0)), PY(tmp_y),
1188
+ PX(num_points-1+(do_bar?2:0))+3, PY(tmp_y), GridColor );
1189
+ if( atof(vylbl) == 0.0 ) /* rounding can cause -0 */
1190
+ strcpy( vylbl, "0" );
1191
+ gdImageString( im,
1192
+ GDC_fontc[GDC_yaxisfont_size].f,
1193
+ PX(num_points-1+(do_bar?2:0))+6,
1194
+ PY(tmp_y)-GDC_fontc[GDC_yaxisfont_size].h/2,
1195
+ (unsigned char*)vylbl,
1196
+ label2color );
1197
+ setno = 0;
1198
+ }
1199
+ }
1200
+ while( ((i>0) && ((tmp_y += ylbl_interval) < highest)) ||
1201
+ ((i<0) && ((tmp_y -= ylbl_interval) > lowest)) );
1202
+ }
1203
+
1204
+ /* catch last (bottom) grid line - specific to an "off" requested interval */
1205
+ if( GDC_grid && threeD )
1206
+ {
1207
+ setno = set_depth;
1208
+ gdImageLine( im, PX(0), PY(lowest), PX(num_points-1+(do_bar?2:0)), PY(lowest), GridColor );
1209
+ setno = 0; /* set back to foremost */
1210
+ }
1211
+
1212
+ /* vy axis title */
1213
+ if( do_vol && GDC_ytitle2 )
1214
+ {
1215
+ struct fnt_sz_t ytftsz = GDCfnt_sz( GDC_ytitle2, GDC_ytitle_size, gdc_ytitle_font, gdc_ytitle_ptsize, 0.0, NULL );
1216
+ int titlecolor = GDC_YTitle2Color==GDC_DFLTCOLOR? VolColor:
1217
+ clrallocate( im, GDC_YTitle2Color );
1218
+ GDCImageStringNL( im,
1219
+ &GDC_fontc[GDC_ytitle_size],
1220
+ gdc_ytitle_font, gdc_ytitle_ptsize,
1221
+ M_PI/2.0,
1222
+ IMGWIDTH-(1+ytftsz.h),
1223
+ yorig/2+ytftsz.w/2,
1224
+ GDC_ytitle2,
1225
+ titlecolor,
1226
+ GDC_JUSTIFY_CENTER,
1227
+ NULL );
1228
+ }
1229
+
1230
+ /* y axis title */
1231
+ if( GDC_yaxis && GDC_ytitle )
1232
+ {
1233
+ struct fnt_sz_t ytftsz = GDCfnt_sz( GDC_ytitle, GDC_ytitle_size, gdc_ytitle_font, gdc_ytitle_ptsize, 0.0, NULL );
1234
+ int titlecolor = GDC_YTitleColor==GDC_DFLTCOLOR? PlotColor:
1235
+ clrallocate( im, GDC_YTitleColor );
1236
+ GDCImageStringNL( im,
1237
+ &GDC_fontc[GDC_ytitle_size],
1238
+ gdc_ytitle_font, gdc_ytitle_ptsize,
1239
+ M_PI/2.0,
1240
+ 1,
1241
+ yorig/2+ytftsz.w/2,
1242
+ GDC_ytitle,
1243
+ titlecolor,
1244
+ GDC_JUSTIFY_CENTER,
1245
+ NULL );
1246
+ }
1247
+ }
1248
+
1249
+ /* interviening set grids */
1250
+ /* 0 < setno < num_sets non-inclusive, they've already been covered */
1251
+ if( GDC_grid && threeD )
1252
+ {
1253
+ for( setno=set_depth - 1;
1254
+ setno > 0;
1255
+ --setno )
1256
+ {
1257
+ gdImageLine( im, PX(0), PY(lowest), PX(0), PY(highest), GridColor );
1258
+ gdImageLine( im, PX(0), PY(lowest), PX(num_points-1+(do_bar?2:0)), PY(lowest), GridColor );
1259
+ }
1260
+ setno = 0;
1261
+ }
1262
+
1263
+ if( ( GDC_grid || GDC_0Shelf ) && /* line color grid at 0 */
1264
+ ( (lowest < 0.0 && highest > 0.0) ||
1265
+ ( (lowest == 0.0 || highest == 0.0) && !(GDC_border&GDC_BORDER_X) ) ) )
1266
+ {
1267
+ int x1, x2, y1, y2;
1268
+ /* tics */
1269
+ x1 = PX(0); y1 = PY(0);
1270
+ if( GDC_ticks )
1271
+ gdImageLine( im, x1-2, y1, x1, y1, LineColor );
1272
+ setno = set_depth;
1273
+ x2 = PX(0); y2 = PY(0); /* w/ new setno */
1274
+ gdImageLine( im, x1, y1, x2, y2, LineColor ); /* depth for 3Ds */
1275
+ gdImageLine( im, x2, y2, PX(num_points-1+(do_bar?2:0)), y2, LineColor );
1276
+ setno = 0; /* set back to foremost */
1277
+ }
1278
+
1279
+ /* x ticks and xlables */
1280
+ if( GDC_grid || GDC_xaxis )
1281
+ {
1282
+ int num_xlbls = graphwidth / /* maximum x lables that'll fit */
1283
+ ( (GDC_xlabel_spacing==SHRT_MAX?0:GDC_xlabel_spacing) + xlbl_hgt );
1284
+ int labelcolor = GDC_XLabelColor==GDC_DFLTCOLOR? LineColor:
1285
+ clrallocate( im, GDC_XLabelColor );
1286
+ for( i=0; i<num_points+(do_bar?2:0); ++i )
1287
+ {
1288
+ int xi = do_bar? i-1: i;
1289
+ int x1, x2, y1, y2, yh; /* ticks & grids */
1290
+ #define DO_TICK(x,y) if( GDC_ticks ) \
1291
+ gdImageLine( im, x, y, x, y+2, GridColor ); \
1292
+ else
1293
+ #define DO_GRID(x1,y1,x2,y2) if( GDC_grid ) \
1294
+ { \
1295
+ gdImageLine( im, x1, y1, x2, y2, GridColor ); /* depth */ \
1296
+ gdImageLine( im, x2, y2, x2, yh, GridColor ); \
1297
+ } \
1298
+ else
1299
+
1300
+ x1 = PX(i); y1 = PY(lowest);
1301
+ setno = set_depth;
1302
+ x2 = PX(i); y2 = PY(lowest); yh = PY(highest);
1303
+ setno = 0; /* reset to foremost */
1304
+
1305
+ if( i == 0 ) /* catch 3D Y back corner */
1306
+ DO_GRID(x1,y1,x2,y2);
1307
+
1308
+ /* labeled points */
1309
+ if( (!GDC_xlabel_ctl && ( (i%(1+num_points/num_xlbls) == 0) || /* # x labels are regulated */
1310
+ num_xlbls >= num_points ||
1311
+ GDC_xlabel_spacing == SHRT_MAX ))
1312
+ ||
1313
+ (GDC_xlabel_ctl && xi>=0 && *(GDC_xlabel_ctl+xi)) )
1314
+ {
1315
+ DO_TICK(x1,y1); /* labeled points tick & grid */
1316
+ DO_GRID(x1,y1,x2,y2);
1317
+
1318
+ if( !do_bar || (i>0 && xi<num_points) )
1319
+ if( GDC_xaxis && xlbl && xlbl[xi] && *(xlbl[xi]) )
1320
+ {
1321
+ char *sts;
1322
+ struct fnt_sz_t lftsz = GDCfnt_sz( xlbl[xi], GDC_xaxisfont_size,
1323
+ gdc_xaxis_font, gdc_xaxis_ptsize,
1324
+ gdc_xaxis_rad,
1325
+ &sts );
1326
+ if( gdc_xaxis_rad == M_PI/2.0 ||
1327
+ (sts && *sts) ) /* FT fail status, used default gdfont */
1328
+ {
1329
+ #ifdef DEBUG
1330
+ fprintf( stderr, "TTF/FT failure: %s\n", sts );
1331
+ #endif
1332
+ GDCImageStringNL( im,
1333
+ &GDC_fontc[GDC_xaxisfont_size],
1334
+ gdc_xaxis_font, gdc_xaxis_ptsize,
1335
+ M_PI/2.0,
1336
+ PX(i)-1 - (lftsz.h/2),
1337
+ PY(lowest) + 2 + 1 + lftsz.w,
1338
+ xlbl[xi],
1339
+ labelcolor,
1340
+ GDC_JUSTIFY_RIGHT,
1341
+ NULL );
1342
+ }
1343
+ else
1344
+ if( gdc_xaxis_rad == 0.0 )
1345
+ GDCImageStringNL( im,
1346
+ &GDC_fontc[GDC_xaxisfont_size],
1347
+ gdc_xaxis_font, gdc_xaxis_ptsize,
1348
+ 0.0,
1349
+ PX(i)-1 - (lftsz.w/2),
1350
+ PY(lowest) + 2 + 1,
1351
+ xlbl[xi],
1352
+ labelcolor,
1353
+ GDC_JUSTIFY_CENTER,
1354
+ NULL );
1355
+ else
1356
+ GDCImageStringNL( im,
1357
+ &GDC_fontc[GDC_xaxisfont_size],
1358
+ gdc_xaxis_font, gdc_xaxis_ptsize,
1359
+ gdc_xaxis_rad,
1360
+ PX(i)-1 - (int)((double)lftsz.w*cos_xangle
1361
+ + (double)lftsz.h*gdc_xaxis_rad/(M_PI/2.0)/2.0),
1362
+ PY(lowest) + 2 + 1 + (int)((double)lftsz.w*sin_xangle),
1363
+ xlbl[xi],
1364
+ labelcolor,
1365
+ GDC_JUSTIFY_RIGHT,
1366
+ NULL );
1367
+ }
1368
+ }
1369
+ /* every point, on-point */
1370
+ if( i>0 )
1371
+ {
1372
+ if( GDC_grid == GDC_TICK_POINTS ) /* --- GRID --- */
1373
+ DO_GRID( x1, y1, x2, y2 );
1374
+ else if( GDC_grid > GDC_TICK_NONE )
1375
+ {
1376
+ int k;
1377
+ int xt;
1378
+ int prevx = PX(i-1);
1379
+ int intrv_dist = (x1-prevx)/(GDC_grid+1);
1380
+ DO_GRID( x1, y1, x2, y2 );
1381
+ for( k=0, xt=prevx + intrv_dist;
1382
+ k<GDC_grid && xt<x1;
1383
+ ++k, xt += intrv_dist )
1384
+ DO_GRID( xt, y1, xt+xdepth_3Dtotal, y2 );
1385
+ }
1386
+
1387
+ if( GDC_ticks == GDC_TICK_POINTS ) /* --- TICKS --- */
1388
+ DO_TICK(x1,y1);
1389
+ else if( GDC_ticks > GDC_TICK_NONE )
1390
+ {
1391
+ int k;
1392
+ int xt;
1393
+ int prevx=PX(i-1);
1394
+ int intrv_dist = (x1-prevx)/(GDC_ticks+1);
1395
+ DO_TICK( x1, y1 );
1396
+ for( k=0, xt=prevx + intrv_dist;
1397
+ k<GDC_ticks && xt<x1;
1398
+ ++k, xt += intrv_dist )
1399
+ DO_TICK( xt, y1 );
1400
+ }
1401
+ }
1402
+ }
1403
+ }
1404
+
1405
+ /* ----- secondard data plotting (volume) ----- */
1406
+ /* so that grid lines appear under vol */
1407
+ if( do_vol )
1408
+ {
1409
+ setno = set_depth;
1410
+ if( type == GDC_COMBO_HLC_BAR ||
1411
+ type == GDC_COMBO_LINE_BAR ||
1412
+ type == GDC_3DCOMBO_LINE_BAR ||
1413
+ type == GDC_3DCOMBO_HLC_BAR )
1414
+ {
1415
+ if( uvol[0] != GDC_NOVALUE )
1416
+ draw_3d_bar( im, PX(0), PX(0)+hlf_barwdth,
1417
+ PV(0), PV(uvol[0]),
1418
+ 0, 0,
1419
+ ExtVolColor[0],
1420
+ ExtVolColor[0] );
1421
+ for( i=1; i<num_points-1; ++i )
1422
+ if( uvol[i] != GDC_NOVALUE )
1423
+ draw_3d_bar( im, PX(i)-hlf_barwdth, PX(i)+hlf_barwdth,
1424
+ PV(0), PV(uvol[i]),
1425
+ 0, 0,
1426
+ ExtVolColor[i],
1427
+ ExtVolColor[i] );
1428
+ if( uvol[i] != GDC_NOVALUE )
1429
+ draw_3d_bar( im, PX(i)-hlf_barwdth, PX(i),
1430
+ PV(0), PV(uvol[i]),
1431
+ 0, 0,
1432
+ ExtVolColor[i],
1433
+ ExtVolColor[i] );
1434
+ }
1435
+ else
1436
+ if( type == GDC_COMBO_HLC_AREA ||
1437
+ type == GDC_COMBO_LINE_AREA ||
1438
+ type == GDC_3DCOMBO_LINE_AREA||
1439
+ type == GDC_3DCOMBO_HLC_AREA )
1440
+ {
1441
+ for( i=1; i<num_points; ++i )
1442
+ if( uvol[i-1] != GDC_NOVALUE && uvol[i] != GDC_NOVALUE )
1443
+ draw_3d_area( im, PX(i-1), PX(i),
1444
+ PV(0), PV(uvol[i-1]), PV(uvol[i]),
1445
+ 0, 0,
1446
+ ExtVolColor[i],
1447
+ ExtVolColor[i] );
1448
+ }
1449
+ else
1450
+ if( type == GDC_COMBO_LINE_LINE ||
1451
+ type == GDC_3DCOMBO_LINE_LINE )
1452
+ {
1453
+ for( i=1; i<num_points; ++i )
1454
+ if( uvol[i-1] != GDC_NOVALUE && uvol[i] != GDC_NOVALUE )
1455
+ gdImageLine( im, PX(i-1), PV(uvol[i-1]),
1456
+ PX(i), PV(uvol[i]),
1457
+ ExtVolColor[i] );
1458
+ }
1459
+ setno = 0;
1460
+ } /* volume polys done */
1461
+
1462
+ if( GDC_annotation && threeD ) /* back half of annotation line */
1463
+ {
1464
+ int x1 = PX(GDC_annotation->point+(do_bar?1:0)),
1465
+ y1 = PY(lowest);
1466
+ setno = set_depth;
1467
+ gdImageLine( im, x1, y1, PX(GDC_annotation->point+(do_bar?1:0)), PY(lowest), AnnoteColor );
1468
+ gdImageLine( im, PX(GDC_annotation->point+(do_bar?1:0)), PY(lowest),
1469
+ PX(GDC_annotation->point+(do_bar?1:0)), PY(highest)-2, AnnoteColor );
1470
+ setno = 0;
1471
+ }
1472
+
1473
+ /* ---------- start plotting the data ---------- */
1474
+ switch( type )
1475
+ {
1476
+ case GDC_3DBAR: /* depth, width, y interval need to allow for whitespace between bars */
1477
+ case GDC_BAR:
1478
+ /* --------- */
1479
+ switch( GDC_stack_type )
1480
+ {
1481
+ case GDC_STACK_DEPTH:
1482
+ for( setno=num_sets-1; setno>=0; --setno ) /* back sets first PX, PY depth */
1483
+ for( i=0; i<num_points; ++i )
1484
+ if( uvals[setno][i] != GDC_NOVALUE )
1485
+ draw_3d_bar( im, PX(i+(do_bar?1:0))-hlf_barwdth, PX(i+(do_bar?1:0))+hlf_barwdth,
1486
+ PY(0), PY(uvals[setno][i]),
1487
+ xdepth_3D, ydepth_3D,
1488
+ ExtColor[setno][i],
1489
+ threeD? ExtColorShd[setno][i]: ExtColor[setno][i] );
1490
+ setno = 0;
1491
+ break;
1492
+
1493
+ case GDC_STACK_LAYER:
1494
+ {
1495
+ int j = 0;
1496
+ CREATE_ARRAY1( barset, struct BS, num_sets );
1497
+
1498
+ /* float lasty[ num_points ]; */
1499
+ /* for( i=0; i<num_points; ++i ) */
1500
+ /* if( uvals[j][i] != GDC_NOVALUE ) */
1501
+ /* { */
1502
+ /* lasty[i] = uvals[j][i]; */
1503
+ /* draw_3d_bar( im, PX(i+(do_bar?1:0))-hlf_barwdth, PX(i+(do_bar?1:0))+hlf_barwdth, */
1504
+ /* PY(0), PY(uvals[j][i]), */
1505
+ /* xdepth_3D, ydepth_3D, */
1506
+ /* ExtColor[j][i], */
1507
+ /* threeD? ExtColorShd[j][i]: ExtColor[j][i] ); */
1508
+ /* } */
1509
+ for( i=0; i<num_points; ++i )
1510
+ {
1511
+ float lasty_pos = 0.0;
1512
+ float lasty_neg = 0.0;
1513
+ int k;
1514
+
1515
+ for( j=0, k=0; j<num_sets; ++j )
1516
+ {
1517
+ if( uvals[j][i] != GDC_NOVALUE )
1518
+ {
1519
+ if( uvals[j][i] < 0.0 )
1520
+ {
1521
+ barset[k].y1 = lasty_neg;
1522
+ barset[k].y2 = uvals[j][i] + lasty_neg;
1523
+ lasty_neg = barset[k].y2;
1524
+ }
1525
+ else
1526
+ {
1527
+ barset[k].y1 = lasty_pos;
1528
+ barset[k].y2 = uvals[j][i] + lasty_pos;
1529
+ lasty_pos = barset[k].y2;
1530
+ }
1531
+ barset[k].clr = ExtColor[j][i];
1532
+ barset[k].shclr = threeD? ExtColorShd[j][i]: ExtColor[j][i];
1533
+ ++k;
1534
+ }
1535
+ }
1536
+ qsort( barset, k, sizeof(struct BS), barcmpr );
1537
+
1538
+ for( j=0; j<k; ++j )
1539
+ {
1540
+ draw_3d_bar( im,
1541
+ PX(i+(do_bar?1:0))-hlf_barwdth, PX(i+(do_bar?1:0))+hlf_barwdth,
1542
+ PY(barset[j].y1), PY(barset[j].y2),
1543
+ xdepth_3D, ydepth_3D,
1544
+ barset[j].clr,
1545
+ barset[j].shclr );
1546
+ }
1547
+ }
1548
+ FREE_ARRAY1( barset );
1549
+ }
1550
+ break;
1551
+
1552
+ case GDC_STACK_BESIDE:
1553
+ { /* h/.5, h/1, h/1.5, h/2, ... */
1554
+ int new_barwdth = (int)( (float)hlf_barwdth / ((float)num_sets/2.0) );
1555
+ for( i=0; i<num_points; ++i )
1556
+ for( j=0; j<num_sets; ++j )
1557
+ if( uvals[j][i] != GDC_NOVALUE )
1558
+ draw_3d_bar( im, PX(i+(do_bar?1:0))-hlf_barwdth+new_barwdth*j+1,
1559
+ PX(i+(do_bar?1:0))-hlf_barwdth+new_barwdth*(j+1),
1560
+ PY(0), PY(uvals[j][i]),
1561
+ xdepth_3D, ydepth_3D,
1562
+ ExtColor[j][i],
1563
+ threeD? ExtColorShd[j][i]: ExtColor[j][i] );
1564
+ }
1565
+ break;
1566
+ }
1567
+ break;
1568
+
1569
+ case GDC_3DFLOATINGBAR:
1570
+ case GDC_FLOATINGBAR:
1571
+ /* --------- */
1572
+ switch( GDC_stack_type )
1573
+ {
1574
+ case GDC_STACK_DEPTH:
1575
+ for( setno=num_groups-1; setno>=0; --setno ) /* back sets first PX, PY depth */
1576
+ for( i=0; i<num_points; ++i )
1577
+ if( uvals[0+setno*2][i] != GDC_NOVALUE &&
1578
+ uvals[1+setno*2][i] != GDC_NOVALUE &&
1579
+ uvals[1+setno*2][i] > uvals[0+setno*2][i] )
1580
+ draw_3d_bar( im, PX(i+(do_bar?1:0))-hlf_barwdth, PX(i+(do_bar?1:0))+hlf_barwdth,
1581
+ PY(uvals[0+setno*2][i]), PY(uvals[1+setno*2][i]),
1582
+ xdepth_3D, ydepth_3D,
1583
+ ExtColor[setno][i],
1584
+ threeD? ExtColorShd[setno][i]: ExtColor[setno][i] );
1585
+ setno = 0;
1586
+ break;
1587
+
1588
+ case GDC_STACK_BESIDE:
1589
+ { /* h/.5, h/1, h/1.5, h/2, ... */
1590
+ int new_barwdth = (int)( (float)hlf_barwdth / ((float)num_groups/2.0) );
1591
+ for( i=0; i<num_points; ++i )
1592
+ for( j=0; j<num_groups; ++j )
1593
+ if( uvals[0+j*2][i] != GDC_NOVALUE &&
1594
+ uvals[1+j*2][i] != GDC_NOVALUE &&
1595
+ uvals[1+j*2][i] > uvals[0+j*2][i] )
1596
+ draw_3d_bar( im, PX(i+(do_bar?1:0))-hlf_barwdth+new_barwdth*j+1,
1597
+ PX(i+(do_bar?1:0))-hlf_barwdth+new_barwdth*(j+1),
1598
+ PY(uvals[0+j*2][i]), PY(uvals[1+j*2][i]),
1599
+ xdepth_3D, ydepth_3D,
1600
+ ExtColor[j][i],
1601
+ threeD? ExtColorShd[j][i]: ExtColor[j][i] );
1602
+ }
1603
+ break;
1604
+ }
1605
+ break;
1606
+
1607
+ case GDC_LINE:
1608
+ case GDC_COMBO_LINE_BAR:
1609
+ case GDC_COMBO_LINE_AREA:
1610
+ case GDC_COMBO_LINE_LINE:
1611
+ for( j=num_sets-1; j>=0; --j )
1612
+ for( i=1; i<num_points; ++i )
1613
+ if( uvals[j][i-1] != GDC_NOVALUE && uvals[j][i] != GDC_NOVALUE )
1614
+ {
1615
+ gdImageLine( im, PX(i-1), PY(uvals[j][i-1]), PX(i), PY(uvals[j][i]), ExtColor[j][i] );
1616
+ gdImageLine( im, PX(i-1), PY(uvals[j][i-1])+1, PX(i), PY(uvals[j][i])+1, ExtColor[j][i] );
1617
+ }
1618
+ else
1619
+ {
1620
+ if( uvals[j][i-1] != GDC_NOVALUE )
1621
+ gdImageSetPixel( im, PX(i-1), PY(uvals[j][i-1]), ExtColor[j][i] );
1622
+ if( uvals[j][i] != GDC_NOVALUE )
1623
+ gdImageSetPixel( im, PX(i), PY(uvals[j][i]), ExtColor[j][i] );
1624
+ }
1625
+ break;
1626
+
1627
+ case GDC_3DLINE:
1628
+ case GDC_3DCOMBO_LINE_BAR:
1629
+ case GDC_3DCOMBO_LINE_AREA:
1630
+ case GDC_3DCOMBO_LINE_LINE:
1631
+ {
1632
+ CREATE_ARRAY1( y1, int, num_sets );
1633
+ CREATE_ARRAY1( y2, int, num_sets );
1634
+ CREATE_ARRAY1( clr, int, num_sets );
1635
+ CREATE_ARRAY1( clrshd, int, num_sets );
1636
+
1637
+ for( i=1; i<num_points; ++i )
1638
+ {
1639
+ if( GDC_stack_type == GDC_STACK_DEPTH )
1640
+ {
1641
+ for( j=num_sets-1; j>=0; --j )
1642
+ if( uvals[j][i-1] != GDC_NOVALUE &&
1643
+ uvals[j][i] != GDC_NOVALUE )
1644
+ {
1645
+ setno = j;
1646
+ y1[j] = PY(uvals[j][i-1]);
1647
+ y2[j] = PY(uvals[j][i]);
1648
+
1649
+ draw_3d_line( im,
1650
+ PY(0),
1651
+ PX(i-1), PX(i),
1652
+ &(y1[j]), &(y2[j]),
1653
+ xdepth_3D, ydepth_3D,
1654
+ 1,
1655
+ &(ExtColor[j][i]),
1656
+ &(ExtColorShd[j][i]) );
1657
+ setno = 0;
1658
+ }
1659
+ }
1660
+ else
1661
+ if( GDC_stack_type == GDC_STACK_BESIDE ||
1662
+ GDC_stack_type == GDC_STACK_SUM ) /* all same plane */
1663
+ {
1664
+ int set;
1665
+ float usey1 = 0.0,
1666
+ usey2 = 0.0;
1667
+ for( j=0,set=0; j<num_sets; ++j )
1668
+ if( uvals[j][i-1] != GDC_NOVALUE &&
1669
+ uvals[j][i] != GDC_NOVALUE )
1670
+ {
1671
+ if( GDC_stack_type == GDC_STACK_SUM )
1672
+ {
1673
+ usey1 += uvals[j][i-1];
1674
+ usey2 += uvals[j][i];
1675
+ }
1676
+ else
1677
+ {
1678
+ usey1 = uvals[j][i-1];
1679
+ usey2 = uvals[j][i];
1680
+ }
1681
+ y1[set] = PY(usey1);
1682
+ y2[set] = PY(usey2);
1683
+ clr[set] = ExtColor[j][i];
1684
+ clrshd[set] = ExtColorShd[j][i]; /* fred */
1685
+ ++set;
1686
+ }
1687
+ draw_3d_line( im,
1688
+ PY(0),
1689
+ PX(i-1), PX(i),
1690
+ y1, y2,
1691
+ xdepth_3D, ydepth_3D,
1692
+ set,
1693
+ clr,
1694
+ clrshd );
1695
+ }
1696
+ }
1697
+ FREE_ARRAY1( clr );
1698
+ FREE_ARRAY1( clrshd );
1699
+ FREE_ARRAY1( y1 );
1700
+ FREE_ARRAY1( y2 );
1701
+ }
1702
+ break;
1703
+
1704
+ case GDC_AREA:
1705
+ case GDC_3DAREA:
1706
+ switch( GDC_stack_type )
1707
+ {
1708
+ case GDC_STACK_SUM:
1709
+ {
1710
+ CREATE_ARRAY1( lasty, float, num_points );
1711
+ int j = 0;
1712
+ for( i=1; i<num_points; ++i )
1713
+ if( uvals[j][i] != GDC_NOVALUE )
1714
+ {
1715
+ lasty[i] = uvals[j][i];
1716
+ if( uvals[j][i-1] != GDC_NOVALUE )
1717
+ draw_3d_area( im, PX(i-1), PX(i),
1718
+ PY(0), PY(uvals[j][i-1]), PY(uvals[j][i]),
1719
+ xdepth_3D, ydepth_3D,
1720
+ ExtColor[j][i],
1721
+ threeD? ExtColorShd[j][i]: ExtColor[j][i] );
1722
+ }
1723
+ for( j=1; j<num_sets; ++j )
1724
+ for( i=1; i<num_points; ++i )
1725
+ if( uvals[j][i] != GDC_NOVALUE && uvals[j][i-1] != GDC_NOVALUE )
1726
+ {
1727
+ draw_3d_area( im, PX(i-1), PX(i),
1728
+ PY(lasty[i]), PY(lasty[i-1]+uvals[j][i-1]), PY(lasty[i]+uvals[j][i]),
1729
+ xdepth_3D, ydepth_3D,
1730
+ ExtColor[j][i],
1731
+ threeD? ExtColorShd[j][i]: ExtColor[j][i] );
1732
+ lasty[i] += uvals[j][i];
1733
+ }
1734
+ FREE_ARRAY1( lasty );
1735
+ }
1736
+ break;
1737
+
1738
+ case GDC_STACK_BESIDE: /* behind w/o depth */
1739
+ for( j=num_sets-1; j>=0; --j ) /* back sets 1st (setno = 0) */
1740
+ for( i=1; i<num_points; ++i )
1741
+ if( uvals[j][i-1] != GDC_NOVALUE && uvals[j][i] != GDC_NOVALUE )
1742
+ draw_3d_area( im, PX(i-1), PX(i),
1743
+ PY(0), PY(uvals[j][i-1]), PY(uvals[j][i]),
1744
+ xdepth_3D, ydepth_3D,
1745
+ ExtColor[j][i],
1746
+ threeD? ExtColorShd[j][i]: ExtColor[j][i] );
1747
+ break;
1748
+
1749
+ case GDC_STACK_DEPTH:
1750
+ default:
1751
+ for( setno=num_sets-1; setno>=0; --setno ) /* back sets first PX, PY depth */
1752
+ for( i=1; i<num_points; ++i )
1753
+ if( uvals[setno][i-1] != GDC_NOVALUE && uvals[setno][i] != GDC_NOVALUE )
1754
+ draw_3d_area( im, PX(i-1), PX(i),
1755
+ PY(0), PY(uvals[setno][i-1]), PY(uvals[setno][i]),
1756
+ xdepth_3D, ydepth_3D,
1757
+ ExtColor[setno][i],
1758
+ threeD? ExtColorShd[setno][i]: ExtColor[setno][i] );
1759
+ setno = 0;
1760
+ }
1761
+ break;
1762
+
1763
+ case GDC_3DHILOCLOSE:
1764
+ case GDC_3DCOMBO_HLC_BAR:
1765
+ case GDC_3DCOMBO_HLC_AREA:
1766
+ {
1767
+ gdPoint poly[4];
1768
+ for( j=num_groups-1; j>=0; --j )
1769
+ {
1770
+ for( i=1; i<num_points+1; ++i )
1771
+ if( uvals[CLOSESET+j*3][i-1] != GDC_NOVALUE )
1772
+ {
1773
+ if( (GDC_HLC_style & GDC_HLC_I_CAP) && /* bottom half of 'I' */
1774
+ uvals[LOWSET+j*3][i-1] != GDC_NOVALUE )
1775
+ {
1776
+ SET_3D_POLY( poly, PX(i-1)-hlf_hlccapwdth, PX(i-1)+hlf_hlccapwdth,
1777
+ PY(uvals[LOWSET+j*3][i-1]), PY(uvals[LOWSET+j*3][i-1]),
1778
+ xdepth_3D, ydepth_3D );
1779
+ gdImageFilledPolygon( im, poly, 4, ExtColor[LOWSET+j*3][i-1] );
1780
+ gdImagePolygon( im, poly, 4, ExtColorShd[LOWSET+j*3][i-1] );
1781
+ }
1782
+ /* all HLC have vert line */
1783
+ if( uvals[LOWSET+j*3][i-1] != GDC_NOVALUE )
1784
+ { /* bottom 'half' */
1785
+ SET_3D_POLY( poly, PX(i-1), PX(i-1),
1786
+ PY(uvals[LOWSET+j*3][i-1]), PY(uvals[CLOSESET+j*3][i-1]),
1787
+ xdepth_3D, ydepth_3D );
1788
+ gdImageFilledPolygon( im, poly, 4, ExtColor[LOWSET+j*3][i-1] );
1789
+ gdImagePolygon( im, poly, 4, ExtColorShd[LOWSET+j*3][i-1] );
1790
+ }
1791
+ if( uvals[HIGHSET+j*3][i-1] != GDC_NOVALUE )
1792
+ { /* top 'half' */
1793
+ SET_3D_POLY( poly, PX(i-1), PX(i-1),
1794
+ PY(uvals[CLOSESET+j*3][i-1]), PY(uvals[HIGHSET+j*3][i-1]),
1795
+ xdepth_3D, ydepth_3D );
1796
+ gdImageFilledPolygon( im, poly, 4, ExtColor[HIGHSET+j*3][i-1] );
1797
+ gdImagePolygon( im, poly, 4, ExtColorShd[HIGHSET+j*3][i-1] );
1798
+ }
1799
+ /* line at close */
1800
+ gdImageLine( im, PX(i-1), PY(uvals[CLOSESET+j*3][i-1]),
1801
+ PX(i-1)+xdepth_3D, PY(uvals[CLOSESET+j*3][i-1])-ydepth_3D,
1802
+ ExtColorShd[CLOSESET+j*3][i-1] );
1803
+ /* top half 'I' */
1804
+ if( !( (GDC_HLC_style & GDC_HLC_DIAMOND) &&
1805
+ (PY(uvals[HIGHSET+j*3][i-1]) > PY(uvals[CLOSESET+j*3][i-1])-hlf_hlccapwdth) ) &&
1806
+ uvals[HIGHSET+j*3][i-1] != GDC_NOVALUE )
1807
+ if( GDC_HLC_style & GDC_HLC_I_CAP )
1808
+ {
1809
+ SET_3D_POLY( poly, PX(i-1)-hlf_hlccapwdth, PX(i-1)+hlf_hlccapwdth,
1810
+ PY(uvals[HIGHSET+j*3][i-1]), PY(uvals[HIGHSET+j*3][i-1]),
1811
+ xdepth_3D, ydepth_3D );
1812
+ gdImageFilledPolygon( im, poly, 4, ExtColor[HIGHSET+j*3][i-1] );
1813
+ gdImagePolygon( im, poly, 4, ExtColorShd[HIGHSET+j*3][i-1] );
1814
+ }
1815
+
1816
+ if( i < num_points &&
1817
+ uvals[CLOSESET+j*3][i] != GDC_NOVALUE )
1818
+ {
1819
+ if( GDC_HLC_style & GDC_HLC_CLOSE_CONNECTED ) /* line from prev close */
1820
+ {
1821
+ SET_3D_POLY( poly, PX(i-1), PX(i),
1822
+ PY(uvals[CLOSESET+j*3][i-1]), PY(uvals[CLOSESET+j*3][i-1]),
1823
+ xdepth_3D, ydepth_3D );
1824
+ gdImageFilledPolygon( im, poly, 4, ExtColor[CLOSESET+j*3][i] );
1825
+ gdImagePolygon( im, poly, 4, ExtColorShd[CLOSESET+j*3][i] );
1826
+ }
1827
+ else /* CLOSE_CONNECTED and CONNECTING are mutually exclusive */
1828
+ if( GDC_HLC_style & GDC_HLC_CONNECTING ) /* thin connecting line */
1829
+ {
1830
+ int y1 = PY(uvals[CLOSESET+j*3][i-1]),
1831
+ y2 = PY(uvals[CLOSESET+j*3][i]);
1832
+ draw_3d_line( im,
1833
+ PY(0),
1834
+ PX(i-1), PX(i),
1835
+ &y1, &y2, /* rem only 1 set */
1836
+ xdepth_3D, ydepth_3D,
1837
+ 1,
1838
+ &(ExtColor[CLOSESET+j*3][i]),
1839
+ &(ExtColorShd[CLOSESET+j*3][i]) );
1840
+ /* edge font of it */
1841
+ gdImageLine( im, PX(i-1), PY(uvals[CLOSESET+j*3][i-1]),
1842
+ PX(i), PY(uvals[CLOSESET+j*3][i]),
1843
+ ExtColorShd[CLOSESET+j*3][i] );
1844
+ }
1845
+ /* top half 'I' again */
1846
+ if( PY(uvals[CLOSESET+j*3][i-1]) <= PY(uvals[CLOSESET+j*3][i]) &&
1847
+ uvals[HIGHSET+j*3][i-1] != GDC_NOVALUE )
1848
+ if( GDC_HLC_style & GDC_HLC_I_CAP )
1849
+ {
1850
+ SET_3D_POLY( poly, PX(i-1)-hlf_hlccapwdth, PX(i-1)+hlf_hlccapwdth,
1851
+ PY(uvals[HIGHSET+j*3][i-1]), PY(uvals[HIGHSET+j*3][i-1]),
1852
+ xdepth_3D, ydepth_3D );
1853
+ gdImageFilledPolygon( im, poly, 4, ExtColor[HIGHSET+j*3][i-1] );
1854
+ gdImagePolygon( im, poly, 4, ExtColorShd[HIGHSET+j*3][i-1] );
1855
+ }
1856
+ }
1857
+ if( GDC_HLC_style & GDC_HLC_DIAMOND )
1858
+ { /* front */
1859
+ poly[0].x = PX(i-1)-hlf_hlccapwdth;
1860
+ poly[0].y = PY(uvals[CLOSESET+j*3][i-1]);
1861
+ poly[1].x = PX(i-1);
1862
+ poly[1].y = PY(uvals[CLOSESET+j*3][i-1])+hlf_hlccapwdth;
1863
+ poly[2].x = PX(i-1)+hlf_hlccapwdth;
1864
+ poly[2].y = PY(uvals[CLOSESET+j*3][i-1]);
1865
+ poly[3].x = PX(i-1);
1866
+ poly[3].y = PY(uvals[CLOSESET+j*3][i-1])-hlf_hlccapwdth;
1867
+ gdImageFilledPolygon( im, poly, 4, ExtColor[CLOSESET+j*3][i-1] );
1868
+ gdImagePolygon( im, poly, 4, ExtColorShd[CLOSESET+j*3][i-1] );
1869
+ /* bottom side */
1870
+ SET_3D_POLY( poly, PX(i-1), PX(i-1)+hlf_hlccapwdth,
1871
+ PY(uvals[CLOSESET+j*3][i-1])+hlf_hlccapwdth,
1872
+ PY(uvals[CLOSESET+j*3][i-1]),
1873
+ xdepth_3D, ydepth_3D );
1874
+ gdImageFilledPolygon( im, poly, 4, ExtColorShd[CLOSESET+j*3][i-1] );
1875
+ /* gdImagePolygon( im, poly, 4, ExtColor[CLOSESET+j*3][i-1] ); */
1876
+ /* top side */
1877
+ SET_3D_POLY( poly, PX(i-1), PX(i-1)+hlf_hlccapwdth,
1878
+ PY(uvals[CLOSESET+j*3][i-1])-hlf_hlccapwdth,
1879
+ PY(uvals[CLOSESET+j*3][i-1]),
1880
+ xdepth_3D, ydepth_3D );
1881
+ gdImageFilledPolygon( im, poly, 4, ExtColor[CLOSESET+j*3][i-1] );
1882
+ gdImagePolygon( im, poly, 4, ExtColorShd[CLOSESET+j*3][i-1] );
1883
+ }
1884
+ }
1885
+ }
1886
+ }
1887
+ break;
1888
+
1889
+ case GDC_HILOCLOSE:
1890
+ case GDC_COMBO_HLC_BAR:
1891
+ case GDC_COMBO_HLC_AREA:
1892
+ for( j=num_groups-1; j>=0; --j )
1893
+ {
1894
+ for( i=0; i<num_points; ++i )
1895
+ if( uvals[CLOSESET+j*3][i] != GDC_NOVALUE )
1896
+ { /* all HLC have vert line */
1897
+ if( uvals[LOWSET+j*3][i] != GDC_NOVALUE )
1898
+ gdImageLine( im, PX(i), PY(uvals[CLOSESET+j*3][i]),
1899
+ PX(i), PY(uvals[LOWSET+j*3][i]),
1900
+ ExtColor[LOWSET+(j*3)][i] );
1901
+ if( uvals[HIGHSET+j*3][i] != GDC_NOVALUE )
1902
+ gdImageLine( im, PX(i), PY(uvals[HIGHSET+j*3][i]),
1903
+ PX(i), PY(uvals[CLOSESET+j*3][i]),
1904
+ ExtColor[HIGHSET+j*3][i] );
1905
+
1906
+ if( GDC_HLC_style & GDC_HLC_I_CAP )
1907
+ {
1908
+ if( uvals[LOWSET+j*3][i] != GDC_NOVALUE )
1909
+ gdImageLine( im, PX(i)-hlf_hlccapwdth, PY(uvals[LOWSET+j*3][i]),
1910
+ PX(i)+hlf_hlccapwdth, PY(uvals[LOWSET+j*3][i]),
1911
+ ExtColor[LOWSET+j*3][i] );
1912
+ if( uvals[HIGHSET+j*3][i] != GDC_NOVALUE )
1913
+ gdImageLine( im, PX(i)-hlf_hlccapwdth, PY(uvals[HIGHSET+j*3][i]),
1914
+ PX(i)+hlf_hlccapwdth, PY(uvals[HIGHSET+j*3][i]),
1915
+ ExtColor[HIGHSET+j*3][i] );
1916
+ }
1917
+ if( GDC_HLC_style & GDC_HLC_DIAMOND )
1918
+ {
1919
+ gdPoint cd[4];
1920
+
1921
+ cd[0].x = PX(i)-hlf_hlccapwdth; cd[0].y = PY(uvals[CLOSESET+j*3][i]);
1922
+ cd[1].x = PX(i); cd[1].y = PY(uvals[CLOSESET+j*3][i])+hlf_hlccapwdth;
1923
+ cd[2].x = PX(i)+hlf_hlccapwdth; cd[2].y = PY(uvals[CLOSESET+j*3][i]);
1924
+ cd[3].x = PX(i); cd[3].y = PY(uvals[CLOSESET+j*3][i])-hlf_hlccapwdth;
1925
+ gdImageFilledPolygon( im, cd, 4, ExtColor[CLOSESET+j*3][i] );
1926
+ }
1927
+ }
1928
+ for( i=1; i<num_points; ++i )
1929
+ if( uvals[CLOSESET+j*3][i-1] != GDC_NOVALUE && uvals[CLOSESET+j*3][i] != GDC_NOVALUE )
1930
+ {
1931
+ if( GDC_HLC_style & GDC_HLC_CLOSE_CONNECTED ) /* line from prev close */
1932
+ gdImageLine( im, PX(i-1), PY(uvals[CLOSESET+j*3][i-1]),
1933
+ PX(i), PY(uvals[CLOSESET+j*3][i-1]),
1934
+ ExtColor[CLOSESET+j*3][i] );
1935
+ else /* CLOSE_CONNECTED and CONNECTING are mutually exclusive */
1936
+ if( GDC_HLC_style & GDC_HLC_CONNECTING ) /* thin connecting line */
1937
+ gdImageLine( im, PX(i-1), PY(uvals[CLOSESET+j*3][i-1]),
1938
+ PX(i), PY(uvals[CLOSESET+j*3][i]),
1939
+ ExtColor[CLOSESET+j*3][i] );
1940
+ }
1941
+ }
1942
+ break;
1943
+ }
1944
+ setno = 0;
1945
+
1946
+ /* ---------- scatter points over all other plots ---------- */
1947
+ /* scatters, by their very nature, don't lend themselves to standard array of points */
1948
+ /* also, this affords the opportunity to include scatter points onto any type of chart */
1949
+ /* drawing of the scatter point should be an exposed function, so the user can */
1950
+ /* use it to draw a legend, and/or add their own */
1951
+ if( GDC_scatter )
1952
+ {
1953
+ CREATE_ARRAY1( scatter_clr, int, GDC_num_scatter_pts );
1954
+ gdPoint ct[3];
1955
+
1956
+ for( i=0; i<GDC_num_scatter_pts; ++i )
1957
+ {
1958
+ int hlf_scatterwdth = (int)( (float)(PX(2)-PX(1))
1959
+ * (((float)((GDC_scatter+i)->width)/100.0)/2.0) );
1960
+ int scat_x = PX( (GDC_scatter+i)->point + (do_bar?1:0) ),
1961
+ scat_y = PY( (GDC_scatter+i)->val );
1962
+
1963
+ if( (GDC_scatter+i)->point >= num_points || /* invalid point */
1964
+ (GDC_scatter+i)->point < 0 )
1965
+ continue;
1966
+ scatter_clr[i] = clrallocate( im, (GDC_scatter+i)->color );
1967
+
1968
+ switch( (GDC_scatter+i)->ind )
1969
+ {
1970
+ case GDC_SCATTER_CIRCLE:
1971
+ {
1972
+ long uniq_clr = get_uniq_color( im );
1973
+ int s = 0,
1974
+ e = 360,
1975
+ fo = 0;
1976
+
1977
+ if( !do_bar )
1978
+ if( (GDC_scatter+i)->point == 0 )
1979
+ { s = 270; e = 270+180; fo = 1; }
1980
+ else
1981
+ if( (GDC_scatter+i)->point == num_points-1 )
1982
+ { s = 90; e = 90+180; fo = -1; }
1983
+ if( uniq_clr != -1L ) /* the safe way */
1984
+ {
1985
+ int uc = gdImageColorAllocate( im, l2gdcal(uniq_clr) );
1986
+ gdImageArc( im, scat_x, scat_y,
1987
+ hlf_scatterwdth*2, hlf_scatterwdth*2,
1988
+ s, e,
1989
+ uc );
1990
+ if( fo ) /* close off semi-circle case */
1991
+ gdImageLine( im, scat_x, scat_y+hlf_scatterwdth,
1992
+ scat_x, scat_y-hlf_scatterwdth,
1993
+ uc );
1994
+ gdImageFillToBorder( im, scat_x+fo, scat_y, uc, scatter_clr[i] );
1995
+ gdImageArc( im, scat_x, scat_y,
1996
+ hlf_scatterwdth*2, hlf_scatterwdth*2,
1997
+ s, e,
1998
+ scatter_clr[i] );
1999
+ if( fo )
2000
+ gdImageLine( im, scat_x, scat_y+hlf_scatterwdth,
2001
+ scat_x, scat_y-hlf_scatterwdth,
2002
+ scatter_clr[i] );
2003
+ gdImageColorDeallocate( im, uc );
2004
+ }
2005
+ else /* chance it */
2006
+ {
2007
+ gdImageArc( im, scat_x, scat_y,
2008
+ hlf_scatterwdth*2, hlf_scatterwdth*2,
2009
+ s, e,
2010
+ scatter_clr[i] );
2011
+ if( fo )
2012
+ gdImageLine( im, scat_x, scat_y+hlf_scatterwdth,
2013
+ scat_x, scat_y-hlf_scatterwdth,
2014
+ scatter_clr[i] );
2015
+ gdImageFillToBorder( im, scat_x+fo, scat_y,
2016
+ scatter_clr[i], scatter_clr[i] );
2017
+ }
2018
+ }
2019
+ break;
2020
+ case GDC_SCATTER_TRIANGLE_UP:
2021
+ ct[0].x = scat_x;
2022
+ ct[0].y = scat_y;
2023
+ ct[1].x = scat_x - hlf_scatterwdth;
2024
+ ct[1].y = scat_y + hlf_scatterwdth;;
2025
+ ct[2].x = scat_x + hlf_scatterwdth;
2026
+ ct[2].y = scat_y + hlf_scatterwdth;
2027
+ if( !do_bar )
2028
+ if( (GDC_scatter+i)->point == 0 )
2029
+ ct[1].x = scat_x;
2030
+ else
2031
+ if( (GDC_scatter+i)->point == num_points-1 )
2032
+ ct[2].x = scat_x;
2033
+ gdImageFilledPolygon( im, ct, 3, scatter_clr[i] );
2034
+ break;
2035
+ case GDC_SCATTER_TRIANGLE_DOWN:
2036
+ ct[0].x = scat_x;
2037
+ ct[0].y = scat_y;
2038
+ ct[1].x = scat_x - hlf_scatterwdth;
2039
+ ct[1].y = scat_y - hlf_scatterwdth;;
2040
+ ct[2].x = scat_x + hlf_scatterwdth;
2041
+ ct[2].y = scat_y - hlf_scatterwdth;
2042
+ if( !do_bar )
2043
+ if( (GDC_scatter+i)->point == 0 )
2044
+ ct[1].x = scat_x;
2045
+ else
2046
+ if( (GDC_scatter+i)->point == num_points-1 )
2047
+ ct[2].x = scat_x;
2048
+ gdImageFilledPolygon( im, ct, 3, scatter_clr[i] );
2049
+ break;
2050
+ }
2051
+ }
2052
+ FREE_ARRAY1( scatter_clr );
2053
+ }
2054
+
2055
+ /* box it off */
2056
+ /* after plotting so the outline covers any plot lines */
2057
+ {
2058
+ if( GDC_border == GDC_BORDER_ALL || (GDC_border & GDC_BORDER_X) )
2059
+ gdImageLine( im, PX(0), PY(lowest), PX(num_points-1+(do_bar?2:0)), PY(lowest), LineColor );
2060
+
2061
+ if( GDC_border == GDC_BORDER_ALL || (GDC_border & GDC_BORDER_TOP) )
2062
+ {
2063
+ setno = set_depth;
2064
+ gdImageLine( im, PX(0), PY(highest), PX(num_points-1+(do_bar?2:0)), PY(highest), LineColor );
2065
+ setno = 0;
2066
+ }
2067
+ }
2068
+ if( GDC_border )
2069
+ {
2070
+ int x1, y1, x2, y2;
2071
+
2072
+ x1 = PX(0);
2073
+ y1 = PY(highest);
2074
+ x2 = PX(num_points-1+(do_bar?2:0));
2075
+ y2 = PY(lowest);
2076
+ if( GDC_border == GDC_BORDER_ALL || (GDC_border & GDC_BORDER_Y) )
2077
+ gdImageLine( im, x1, PY(lowest), x1, y1, LineColor );
2078
+
2079
+ setno = set_depth;
2080
+ if( GDC_border == GDC_BORDER_ALL || (GDC_border & GDC_BORDER_Y) || (GDC_border & GDC_BORDER_TOP) )
2081
+ gdImageLine( im, x1, y1, PX(0), PY(highest), LineColor );
2082
+ /* if( !GDC_grid || do_vol || GDC_thumbnail ) // grid leaves right side Y open */
2083
+ {
2084
+ if( GDC_border == GDC_BORDER_ALL || (GDC_border & GDC_BORDER_X) || (GDC_border & GDC_BORDER_Y2) )
2085
+ gdImageLine( im, x2, y2, PX(num_points-1+(do_bar?2:0)), PY(lowest), LineColor );
2086
+ if( GDC_border == GDC_BORDER_ALL || (GDC_border & GDC_BORDER_Y2) )
2087
+ gdImageLine( im, PX(num_points-1+(do_bar?2:0)), PY(lowest),
2088
+ PX(num_points-1+(do_bar?2:0)), PY(highest), LineColor );
2089
+ }
2090
+ setno = 0;
2091
+ }
2092
+
2093
+ if( GDC_0Shelf && threeD && /* front of 0 shelf */
2094
+ ( (lowest < 0.0 && highest > 0.0) ||
2095
+ ( (lowest == 0.0 || highest == 0.0) && !(GDC_border&GDC_BORDER_X) ) ) )
2096
+ {
2097
+ int x2 = PX( num_points-1+(do_bar?2:0) ),
2098
+ y2 = PY( 0 );
2099
+
2100
+ gdImageLine( im, PX(0), PY(0), x2, y2, LineColor ); /* front line */
2101
+ setno = set_depth;
2102
+ /* depth for 3Ds */
2103
+ gdImageLine( im, x2, y2, PX(num_points-1+(do_bar?2:0)), PY(0), LineColor );
2104
+ setno = 0; /* set back to foremost */
2105
+ }
2106
+
2107
+ if( GDC_annotation ) /* front half of annotation line */
2108
+ {
2109
+ int x1 = PX(GDC_annotation->point+(do_bar?1:0)),
2110
+ y1 = PY(highest);
2111
+ int x2;
2112
+ /* front line */
2113
+ gdImageLine( im, x1, PY(lowest)+1, x1, y1, AnnoteColor );
2114
+ if( threeD )
2115
+ { /* on back plane */
2116
+ setno = set_depth;
2117
+ x2 = PX(GDC_annotation->point+(do_bar?1:0));
2118
+ /* prspective line */
2119
+ gdImageLine( im, x1, y1, x2, PY(highest), AnnoteColor );
2120
+ }
2121
+ else /* for 3D done with back line */
2122
+ {
2123
+ x2 = PX(GDC_annotation->point+(do_bar?1:0));
2124
+ gdImageLine( im, x1, y1, x1, y1-2, AnnoteColor );
2125
+ }
2126
+ /* line-to and note */
2127
+ if( *(GDC_annotation->note) ) /* any note? */
2128
+ {
2129
+ if( GDC_annotation->point >= (num_points/2) ) /* note to the left */
2130
+ {
2131
+ gdImageLine( im, x2, PY(highest)-2,
2132
+ x2-annote_hgt/2, PY(highest)-2-annote_hgt/2,
2133
+ AnnoteColor );
2134
+ GDCImageStringNL( im,
2135
+ &GDC_fontc[GDC_annotation_font_size],
2136
+ gdc_annotation_font, gdc_annotation_ptsize,
2137
+ 0.0,
2138
+ x2-annote_hgt/2-1-annote_len - 1,
2139
+ PY(highest)-annote_hgt+1,
2140
+ GDC_annotation->note,
2141
+ AnnoteColor,
2142
+ GDC_JUSTIFY_RIGHT,
2143
+ NULL );
2144
+ }
2145
+ else /* note to right */
2146
+ {
2147
+ gdImageLine( im, x2, PY(highest)-2,
2148
+ x2+annote_hgt/2, PY(highest)-2-annote_hgt/2,
2149
+ AnnoteColor );
2150
+ GDCImageStringNL( im,
2151
+ &GDC_fontc[GDC_annotation_font_size],
2152
+ gdc_annotation_font, gdc_annotation_ptsize,
2153
+ 0.0,
2154
+ x2+annote_hgt/2+1 + 1,
2155
+ PY(highest)-annote_hgt+1,
2156
+ GDC_annotation->note,
2157
+ AnnoteColor,
2158
+ GDC_JUSTIFY_LEFT,
2159
+ NULL );
2160
+ }
2161
+ }
2162
+ setno = 0;
2163
+ }
2164
+
2165
+
2166
+ /* usually GDC_generate_img is used in conjunction with hard or hold options */
2167
+ if( GDC_generate_img )
2168
+ {
2169
+ fflush(img_fptr); /* clear anything buffered */
2170
+ switch( GDC_image_type )
2171
+ {
2172
+ #ifdef HAVE_JPEG
2173
+ case GDC_JPEG: gdImageJpeg( im, img_fptr, GDC_jpeg_quality ); break;
2174
+ #endif
2175
+ case GDC_WBMP: gdImageWBMP( im, PlotColor, img_fptr ); break;
2176
+ case GDC_GIF: gdImageGif( im, img_fptr); break;
2177
+ case GDC_PNG:
2178
+ default: gdImagePng( im, img_fptr );
2179
+ }
2180
+ }
2181
+
2182
+ if( bg_img )
2183
+ gdImageDestroy(bg_img);
2184
+ if( GDC_hold_img & GDC_EXPOSE_IMAGE )
2185
+ GDC_image = (void*)im;
2186
+ else
2187
+ gdImageDestroy(im);
2188
+ FREE_ARRAY1( uvals );
2189
+ FREE_ARRAY1( ExtVolColor );
2190
+ FREE_ARRAY2( ExtColor );
2191
+ FREE_ARRAY2( ExtColorShd );
2192
+ return 0;
2193
+ }