ruby-gdchart 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }