ruby-gdchart 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +81 -0
- data/README +47 -0
- data/examples/bar_example.rb +23 -0
- data/examples/line_example.rb +27 -0
- data/examples/pie_example.rb +19 -0
- data/ext/extconf.rb +35 -0
- data/ext/gdchart.c +1123 -0
- data/ext/gdchart0.11.5dev/Makefile +145 -0
- data/ext/gdchart0.11.5dev/README.txt +87 -0
- data/ext/gdchart0.11.5dev/array_alloc.c +183 -0
- data/ext/gdchart0.11.5dev/array_alloc.h +41 -0
- data/ext/gdchart0.11.5dev/ft_samp.c +89 -0
- data/ext/gdchart0.11.5dev/ft_samp.sav +89 -0
- data/ext/gdchart0.11.5dev/gdc.c +310 -0
- data/ext/gdchart0.11.5dev/gdc.h +158 -0
- data/ext/gdchart0.11.5dev/gdc_pie.c +691 -0
- data/ext/gdchart0.11.5dev/gdc_pie_samp.c +77 -0
- data/ext/gdchart0.11.5dev/gdc_samp1.c +47 -0
- data/ext/gdchart0.11.5dev/gdc_samp2.c +88 -0
- data/ext/gdchart0.11.5dev/gdchart.c +2193 -0
- data/ext/gdchart0.11.5dev/gdchart.h +248 -0
- data/ext/gdchart0.11.5dev/gdcpie.h +85 -0
- data/ext/gdchart0.11.5dev/price_conv.c +93 -0
- metadata +67 -0
@@ -0,0 +1,158 @@
|
|
1
|
+
/* GDCHART 0.10.0dev GDC.H 2 Nov 2000 */
|
2
|
+
/* Copyright Bruce Verderaime 1998-2004 */
|
3
|
+
|
4
|
+
/*
|
5
|
+
General header common to chart (xy[z]) and pie
|
6
|
+
*/
|
7
|
+
|
8
|
+
#ifndef _GDC_H
|
9
|
+
#define _GDC_H
|
10
|
+
|
11
|
+
#ifndef _USE_MATH_DEFINES
|
12
|
+
#define _USE_MATH_DEFINES
|
13
|
+
#endif
|
14
|
+
#ifndef _XOPEN_SOURCE
|
15
|
+
#define _XOPEN_SOURCE
|
16
|
+
#endif
|
17
|
+
#include <math.h>
|
18
|
+
/* uncle */
|
19
|
+
#ifndef M_PI
|
20
|
+
#define M_PI 3.14159265358979323846
|
21
|
+
#define M_PI_2 1.57079632679489661923
|
22
|
+
#endif
|
23
|
+
|
24
|
+
#include <limits.h>
|
25
|
+
#include <float.h>
|
26
|
+
#ifdef GDC_INCL
|
27
|
+
#include "gd.h"
|
28
|
+
#include "gdfonts.h"
|
29
|
+
#include "gdfontt.h"
|
30
|
+
#include "gdfontmb.h"
|
31
|
+
#include "gdfontg.h"
|
32
|
+
#include "gdfontl.h"
|
33
|
+
#include "array_alloc.h"
|
34
|
+
#endif
|
35
|
+
|
36
|
+
/* --- backward compatibility --- */
|
37
|
+
/* may be removed at a later date */
|
38
|
+
#define GDC_generate_gif GDC_generate_img
|
39
|
+
#define pie_gif GDC_out_pie
|
40
|
+
/* ------------------------------ */
|
41
|
+
|
42
|
+
#ifndef TRUE
|
43
|
+
#define TRUE 1
|
44
|
+
#define FALSE 0
|
45
|
+
#endif
|
46
|
+
|
47
|
+
#define GDC_NOVALUE -FLT_MAX
|
48
|
+
#define GDC_NULL GDC_NOVALUE
|
49
|
+
|
50
|
+
#define ABS( x ) ( (x)<0.0? -(x): (x) )
|
51
|
+
#define MAX( x, y ) ( (x)>(y)?(x):(y) )
|
52
|
+
#define MIN( x, y ) ( (x)<(y)?(x):(y) )
|
53
|
+
#define TO_RAD(o) ( (o)/360.0*(2.0*M_PI) )
|
54
|
+
|
55
|
+
#define GDC_NOCOLOR 0x1000000L
|
56
|
+
#define GDC_DFLTCOLOR 0x2000000L
|
57
|
+
#define PVRED 0x00FF0000
|
58
|
+
#define PVGRN 0x0000FF00
|
59
|
+
#define PVBLU 0x000000FF
|
60
|
+
#define l2gdcal( c ) ((c)&PVRED)>>16 , ((c)&PVGRN)>>8 , ((c)&0x000000FF)
|
61
|
+
#define l2gdshd( c ) (((c)&PVRED)>>16)/2 , (((c)&PVGRN)>>8)/2 , (((c)&0x000000FF))/2
|
62
|
+
static int _gdccfoo1;
|
63
|
+
static unsigned long _gdccfoo2;
|
64
|
+
#define _gdcntrst(bg) ( ((bg)&0x800000?0x000000:0xFF0000)| \
|
65
|
+
((bg)&0x008000?0x000000:0x00FF00)| \
|
66
|
+
((bg)&0x000080?0x000000:0x0000FF) )
|
67
|
+
#define _clrallocate( im, rawclr, bgc ) \
|
68
|
+
( (_gdccfoo2=rawclr==GDC_DFLTCOLOR? _gdcntrst(bgc): rawclr), \
|
69
|
+
(_gdccfoo1=gdImageColorExact(im,l2gdcal(_gdccfoo2))) != -1? \
|
70
|
+
_gdccfoo1: \
|
71
|
+
gdImageColorsTotal(im) == gdMaxColors? \
|
72
|
+
gdImageColorClosest(im,l2gdcal(_gdccfoo2)): \
|
73
|
+
gdImageColorAllocate(im,l2gdcal(_gdccfoo2)) )
|
74
|
+
#define _clrshdallocate( im, rawclr, bgc ) \
|
75
|
+
( (_gdccfoo2=rawclr==GDC_DFLTCOLOR? _gdcntrst(bgc): rawclr), \
|
76
|
+
(_gdccfoo1=gdImageColorExact(im,l2gdshd(_gdccfoo2))) != -1? \
|
77
|
+
_gdccfoo1: \
|
78
|
+
gdImageColorsTotal(im) == gdMaxColors? \
|
79
|
+
gdImageColorClosest(im,l2gdshd(_gdccfoo2)): \
|
80
|
+
gdImageColorAllocate(im,l2gdshd(_gdccfoo2)) )
|
81
|
+
|
82
|
+
typedef enum {
|
83
|
+
GDC_GIF = 0,
|
84
|
+
#ifdef HAVE_JPEG
|
85
|
+
GDC_JPEG = 1,
|
86
|
+
#endif
|
87
|
+
GDC_PNG = 2,
|
88
|
+
GDC_WBMP = 3 /* as of gd1.8.3 WBMP is black and white only. */
|
89
|
+
} GDC_image_type_t;
|
90
|
+
|
91
|
+
/* ordered by size */
|
92
|
+
enum GDC_font_size { GDC_pad = 0,
|
93
|
+
GDC_TINY = 1,
|
94
|
+
GDC_SMALL = 2,
|
95
|
+
GDC_MEDBOLD = 3,
|
96
|
+
GDC_LARGE = 4,
|
97
|
+
GDC_GIANT = 5,
|
98
|
+
GDC_numfonts= 6 }; /* GDC[PIE]_fontc depends on this */
|
99
|
+
|
100
|
+
typedef enum {
|
101
|
+
GDC_DESTROY_IMAGE = 0, /* default */
|
102
|
+
GDC_EXPOSE_IMAGE = 1, /* user must call GDC_destroy_image() */
|
103
|
+
GDC_REUSE_IMAGE = 2 /* i.e., paint on top of */
|
104
|
+
} GDC_HOLD_IMAGE_T; /* EXPOSE & REUSE */
|
105
|
+
|
106
|
+
#ifdef GDC_INCL
|
107
|
+
struct GDC_FONT_T {
|
108
|
+
gdFontPtr f;
|
109
|
+
char h;
|
110
|
+
char w;
|
111
|
+
};
|
112
|
+
|
113
|
+
typedef enum { GDC_JUSTIFY_RIGHT,
|
114
|
+
GDC_JUSTIFY_CENTER,
|
115
|
+
GDC_JUSTIFY_LEFT } GDC_justify_t;
|
116
|
+
|
117
|
+
|
118
|
+
struct fnt_sz_t {
|
119
|
+
int w;
|
120
|
+
int h;
|
121
|
+
} GDCfnt_sz( char* str, enum GDC_font_size gdfontsz, char* ttfont, double ttfptsz, double angle, char **status );
|
122
|
+
|
123
|
+
int GDCImageStringNL( gdImagePtr, struct GDC_FONT_T*, char*, double, double, int, int, char*, int, GDC_justify_t, char** );
|
124
|
+
void load_font_conversions();
|
125
|
+
short cnt_nl( char*, int* );
|
126
|
+
#endif
|
127
|
+
|
128
|
+
#ifdef GDC_LIB
|
129
|
+
#define EXTERND extern
|
130
|
+
#define DEFAULTO(val)
|
131
|
+
extern struct GDC_FONT_T GDC_fontc[];
|
132
|
+
#else
|
133
|
+
#define EXTERND
|
134
|
+
#define DEFAULTO(val) = val
|
135
|
+
#endif
|
136
|
+
|
137
|
+
/**** COMMON OPTIONS ********************************/
|
138
|
+
#ifndef _GDC_COMMON_OPTIONS
|
139
|
+
#define _GDC_COMMON_OPTIONS
|
140
|
+
EXTERND GDC_image_type_t GDC_image_type DEFAULTO( GDC_PNG );
|
141
|
+
EXTERND int GDC_jpeg_quality DEFAULTO( -1 ); /* 0-95 */
|
142
|
+
EXTERND char GDC_generate_img DEFAULTO( TRUE );
|
143
|
+
|
144
|
+
EXTERND GDC_HOLD_IMAGE_T GDC_hold_img DEFAULTO( GDC_DESTROY_IMAGE );
|
145
|
+
EXTERND void *GDC_image DEFAULTO( (void*)NULL ); /* in/out */
|
146
|
+
#endif
|
147
|
+
/****************************************************/
|
148
|
+
|
149
|
+
|
150
|
+
void GDC_destroy_image( void* );
|
151
|
+
void out_err( int IMGWIDTH,
|
152
|
+
int IMGHEIGHT,
|
153
|
+
FILE*,
|
154
|
+
unsigned long BGColor,
|
155
|
+
unsigned long LineColor,
|
156
|
+
char *str );
|
157
|
+
|
158
|
+
#endif /*!_GDC_H*/
|
@@ -0,0 +1,691 @@
|
|
1
|
+
/* GDCHART 0.11.3dev GDC_PIE.C 11 Mar 2003 */
|
2
|
+
/* Copyright Bruce Verderaime 1998-2004 */
|
3
|
+
|
4
|
+
/* ELLIPSE (angled/perspective view) */
|
5
|
+
/* TODO */
|
6
|
+
/* view on/off/%/deg option should be tied to 3d_angle? */
|
7
|
+
/* limited in two directions only - by X axis, or Y axis */
|
8
|
+
/* ELIPSEY [scaling] only one that make sense? */
|
9
|
+
/* connections between face&background (effects Y axis only?) */
|
10
|
+
/* sizing still doesn't work - DONE */
|
11
|
+
/* label distances need to be variable about the ellipse/3d_angle */
|
12
|
+
/* #define ELLIPSEX 1.00 */
|
13
|
+
/* #define ELLIPSEY 0.30 */
|
14
|
+
|
15
|
+
#define GDC_INCL
|
16
|
+
#define GDC_LIB
|
17
|
+
#include "gdc.h" /* gdc.h before system includes to pick up features */
|
18
|
+
|
19
|
+
#include <stdio.h>
|
20
|
+
|
21
|
+
#include "gdcpie.h"
|
22
|
+
|
23
|
+
/* rem circle: x = rcos(@), y = rsin(@) */
|
24
|
+
|
25
|
+
extern struct GDC_FONT_T GDC_fontc[];
|
26
|
+
|
27
|
+
#define SET_RECT( gdp, x1, x2, y1, y2 ) gdp[0].x = gdp[3].x = x1, \
|
28
|
+
gdp[0].y = gdp[1].y = y1, \
|
29
|
+
gdp[1].x = gdp[2].x = x2, \
|
30
|
+
gdp[2].y = gdp[3].y = y2
|
31
|
+
|
32
|
+
#define PX( x ) ( cx + (int)( ((float)rad*ellipsex)*sin(pscl*(double)(x)) ) ) /* expects a val */
|
33
|
+
#define PY( x ) ( cy - (int)( ((float)rad*ellipsey)*cos(pscl*(double)(x)) ) ) /* expects a val */
|
34
|
+
|
35
|
+
#define CX( i,d ) ( cx + \
|
36
|
+
(d? xdepth_3D: 0) + \
|
37
|
+
(int)( (double)(GDCPIE_explode?GDCPIE_explode[(i)]:0) * sin((double)(slice_angle[0][i])) ) )
|
38
|
+
#define CY( i,d ) ( cy - \
|
39
|
+
(d? ydepth_3D: 0) - \
|
40
|
+
(int)( (double)(GDCPIE_explode?GDCPIE_explode[(i)]:0) * cos((double)(slice_angle[0][i])) ) )
|
41
|
+
/* expect slice number: i (index into slice_angle array) *\
|
42
|
+
* and position on slice: f (0: slice middle, *
|
43
|
+
* 1: leading (clockwise), *
|
44
|
+
* 2: trailing edge) *
|
45
|
+
* and 3D depth: d (0: do depth, *
|
46
|
+
* 1: no depth adjustment) *
|
47
|
+
\* adjusts for explosion */
|
48
|
+
#define IX( i,f,d ) ( CX(i,d) + (int)( (double)rad*ellipsex * sin((double)(slice_angle[f][i])) ) )
|
49
|
+
#define IY( i,f,d ) ( CY(i,d) - (int)( (double)rad*ellipsey * cos((double)(slice_angle[f][i])) ) )
|
50
|
+
/* same as above except o is angle */
|
51
|
+
#define OX( i,o,d ) ( CX(i,d) + (int)( (double)rad*ellipsex * sin((double)(o)) ) )
|
52
|
+
#define OY( i,o,d ) ( CY(i,d) - (int)( (double)rad*ellipsey * cos((double)(o)) ) )
|
53
|
+
|
54
|
+
#define TO_INT_DEG(o) (int)rint( (double)((o)/(2.0*M_PI)*360.0) )
|
55
|
+
#define TO_INT_DEG_FLOOR(o) (int)floor( (double)((o)/(2.0*M_PI)*360.0) )
|
56
|
+
#define TO_INT_DEG_CEIL(o) (int)ceil( (double)((o)/(2.0*M_PI)*360.0) )
|
57
|
+
#define TO_RAD(o) ( (o)/360.0*(2.0*M_PI) )
|
58
|
+
/* assume !> 4*PI */
|
59
|
+
#define MOD_2PI(o) ( (o)>=(2.0*M_PI)? ((o)-(2.0*M_PI)): (((o)<0)? ((o)+(2.0*M_PI)): (o)) )
|
60
|
+
#define MOD_360(o) ( (o)>=360? (o)-360: (o) ) /* assume !> 720 */
|
61
|
+
|
62
|
+
struct tmp_slice_t { int i; /* original index */
|
63
|
+
char hidden; /* 'behind' top [3D] pie */
|
64
|
+
float angle; /* radian */
|
65
|
+
float slice; }; /* radian */
|
66
|
+
static float pie_3D_rad; /* user requested 3D angle in radians */
|
67
|
+
|
68
|
+
/* degrees (radians) between angle a, and depth angle */
|
69
|
+
/* 1&2, so comparisons can be done. */
|
70
|
+
#define RAD_DIST1( a ) ( (dist_foo1=ABS(((a>-.00001&&a<.00001)?0.00001:a)-pie_3D_rad)), ((dist_foo1>M_PI)? ABS(dist_foo1-2.0*M_PI): dist_foo1) )
|
71
|
+
#define RAD_DIST2( a ) ( (dist_foo2=ABS(((a>-.00001&&a<.00001)?0.00001:a)-pie_3D_rad)), ((dist_foo2>M_PI)? ABS(dist_foo2-2.0*M_PI): dist_foo2) )
|
72
|
+
static float dist_foo1, dist_foo2;
|
73
|
+
|
74
|
+
/* ------------------------------------------------------- *\
|
75
|
+
* oof! cleaner way???
|
76
|
+
* order by angle opposite (180) of depth angle
|
77
|
+
* comparing across 0-360 line
|
78
|
+
\* ------------------------------------------------------- */
|
79
|
+
static int
|
80
|
+
ocmpr( struct tmp_slice_t *a,
|
81
|
+
struct tmp_slice_t *b )
|
82
|
+
{
|
83
|
+
if( RAD_DIST1(a->angle) < RAD_DIST2(b->angle) )
|
84
|
+
return 1;
|
85
|
+
if( RAD_DIST1(a->angle) > RAD_DIST2(b->angle) )
|
86
|
+
return -1;
|
87
|
+
|
88
|
+
/* a tie (will happen between each slice) */
|
89
|
+
/* are we within pie_3D_rad */
|
90
|
+
if( (a->angle < pie_3D_rad) && (pie_3D_rad < a->slice) ||
|
91
|
+
(a->slice < pie_3D_rad) && (pie_3D_rad < a->angle) )
|
92
|
+
return 1;
|
93
|
+
if( (b->slice < pie_3D_rad) && (pie_3D_rad < b->angle) ||
|
94
|
+
(b->angle < pie_3D_rad) && (pie_3D_rad < b->slice) )
|
95
|
+
return -1;
|
96
|
+
|
97
|
+
/* let slice angle decide */
|
98
|
+
if( RAD_DIST1(a->slice) < RAD_DIST2(b->slice) )
|
99
|
+
return 1;
|
100
|
+
if( RAD_DIST1(a->slice) > RAD_DIST2(b->slice) )
|
101
|
+
return -1;
|
102
|
+
|
103
|
+
return 0;
|
104
|
+
}
|
105
|
+
|
106
|
+
/* ======================================================= *\
|
107
|
+
* PIE
|
108
|
+
*
|
109
|
+
* Notes:
|
110
|
+
* always drawn from 12:00 position clockwise
|
111
|
+
* 'missing' slices don't get labels
|
112
|
+
* sum(val[0], ... val[num_points-1]) is assumed to be 100%
|
113
|
+
\* ======================================================= */
|
114
|
+
void
|
115
|
+
GDC_out_pie( short IMGWIDTH,
|
116
|
+
short IMGHEIGHT,
|
117
|
+
FILE *img_fptr, /* open file pointer */
|
118
|
+
GDCPIE_TYPE type,
|
119
|
+
int num_points,
|
120
|
+
char *lbl[], /* data labels */
|
121
|
+
float val[] ) /* data */
|
122
|
+
{
|
123
|
+
int i;
|
124
|
+
|
125
|
+
gdImagePtr im;
|
126
|
+
int BGColor,
|
127
|
+
LineColor,
|
128
|
+
PlotColor,
|
129
|
+
EdgeColor,
|
130
|
+
EdgeColorShd;
|
131
|
+
CREATE_ARRAY1( SliceColor, int, num_points ); /* int SliceColor[num_points] */
|
132
|
+
CREATE_ARRAY1( SliceColorShd, int, num_points ); /* int SliceColorShd[num_points] */
|
133
|
+
|
134
|
+
float rad = 0.0; /* radius */
|
135
|
+
float ellipsex = 1.0;
|
136
|
+
float ellipsey = 1.0 - (float)GDCPIE_perspective/100.0;
|
137
|
+
float tot_val = 0.0;
|
138
|
+
float pscl;
|
139
|
+
int cx, /* affects PX() */
|
140
|
+
cy; /* affects PY() */
|
141
|
+
/* ~ 1% for a size of 100 pixs */
|
142
|
+
/* label sizes will more dictate this */
|
143
|
+
float min_grphable = ( GDCPIE_other_threshold < 0?
|
144
|
+
100.0/(float)MIN(IMGWIDTH,IMGHEIGHT):
|
145
|
+
(float)GDCPIE_other_threshold )/100.0;
|
146
|
+
short num_slices1 = 0,
|
147
|
+
num_slices2 = 0;
|
148
|
+
char any_too_small = FALSE;
|
149
|
+
CREATE_ARRAY1( others, char, num_points ); /* char others[num_points] */
|
150
|
+
CREATE_ARRAY2( slice_angle, float, 3, num_points ); /* float slice_angle[3][num_points] */
|
151
|
+
/* must be used with others[] */
|
152
|
+
char threeD = ( type == GDC_3DPIE );
|
153
|
+
|
154
|
+
int xdepth_3D = 0, /* affects PX() */
|
155
|
+
ydepth_3D = 0; /* affects PY() */
|
156
|
+
int do3Dx = 0, /* reserved for macro use */
|
157
|
+
do3Dy = 0;
|
158
|
+
|
159
|
+
CREATE_ARRAY2( pct_lbl, char, num_points, 16 ); /* sizeof or strlen (GDCPIE_percent_fmt)? */
|
160
|
+
CREATE_ARRAY1( pct_ftsz, struct fnt_sz_t, num_points ); /* struct fnt_sz_t lbl_ftsz[num_points] */
|
161
|
+
CREATE_ARRAY1( lbl_ftsz, struct fnt_sz_t, num_points ); /* struct fnt_sz_t lbl_ftsz[num_points] */
|
162
|
+
|
163
|
+
|
164
|
+
#ifdef HAVE_LIBFREETYPE
|
165
|
+
char *gdcpie_title_font = GDCPIE_title_font;
|
166
|
+
char *gdcpie_label_font = GDCPIE_label_font;
|
167
|
+
double gdcpie_title_ptsize = GDCPIE_title_ptsize;
|
168
|
+
double gdcpie_label_ptsize = GDCPIE_label_ptsize;
|
169
|
+
#else
|
170
|
+
char *gdcpie_title_font = NULL;
|
171
|
+
char *gdcpie_label_font = NULL;
|
172
|
+
double gdcpie_title_ptsize = 0.0;
|
173
|
+
double gdcpie_label_ptsize = 0.0;
|
174
|
+
#endif
|
175
|
+
|
176
|
+
/* GDCPIE_3d_angle = MOD_360(90-GDCPIE_3d_angle+360); */
|
177
|
+
pie_3D_rad = TO_RAD( GDCPIE_3d_angle );
|
178
|
+
|
179
|
+
xdepth_3D = threeD? (int)( cos((double)MOD_2PI(M_PI_2-pie_3D_rad+2.0*M_PI)) * GDCPIE_3d_depth ): 0;
|
180
|
+
ydepth_3D = threeD? (int)( sin((double)MOD_2PI(M_PI_2-pie_3D_rad+2.0*M_PI)) * GDCPIE_3d_depth ): 0;
|
181
|
+
/* xdepth_3D = threeD? (int)( cos(pie_3D_rad) * GDCPIE_3d_depth ): 0; */
|
182
|
+
/* ydepth_3D = threeD? (int)( sin(pie_3D_rad) * GDCPIE_3d_depth ): 0; */
|
183
|
+
|
184
|
+
load_font_conversions();
|
185
|
+
|
186
|
+
/* ----- get total value ----- */
|
187
|
+
for( i=0; i<num_points; ++i )
|
188
|
+
tot_val += val[i];
|
189
|
+
|
190
|
+
/* ----- pie sizing ----- */
|
191
|
+
/* ----- make width room for labels, depth, etc.: ----- */
|
192
|
+
/* ----- determine pie's radius ----- */
|
193
|
+
{
|
194
|
+
int title_hgt = GDCPIE_title? 1 /* title? horizontal text line */
|
195
|
+
+ GDCfnt_sz( GDCPIE_title,
|
196
|
+
GDCPIE_title_size,
|
197
|
+
gdcpie_title_font, gdcpie_title_ptsize, 0.0, NULL ).h
|
198
|
+
|
199
|
+
+ 2:
|
200
|
+
0;
|
201
|
+
float last = 0.0;
|
202
|
+
float label_explode_limit = 0.0;
|
203
|
+
int cheight,
|
204
|
+
cwidth;
|
205
|
+
|
206
|
+
/* maximum: no labels, explosions */
|
207
|
+
/* gotta start somewhere */
|
208
|
+
rad = (float)MIN( (IMGWIDTH/2)/ellipsex-(1+ABS(xdepth_3D)), (IMGHEIGHT/2)/ellipsey-(1+ABS(ydepth_3D))-title_hgt );
|
209
|
+
|
210
|
+
/* ok fix center, i.e., no floating re labels, explosion, etc. */
|
211
|
+
cx = IMGWIDTH/2 /* - xdepth_3D */ ;
|
212
|
+
cy = (IMGHEIGHT-title_hgt)/2 + title_hgt /* + ydepth_3D */ ;
|
213
|
+
|
214
|
+
cheight = (IMGHEIGHT- title_hgt)/2 /* - ydepth_3D */ ;
|
215
|
+
cwidth = cx;
|
216
|
+
|
217
|
+
/* walk around pie. determine spacing to edge */
|
218
|
+
for( i=0; i<num_points; ++i )
|
219
|
+
{
|
220
|
+
float this_pct = val[i]/tot_val; /* should never be > 100% */
|
221
|
+
float this = this_pct*(2.0*M_PI); /* pie-portion */
|
222
|
+
if( (this_pct > min_grphable) || /* too small */
|
223
|
+
(!GDCPIE_missing || !GDCPIE_missing[i]) ) /* still want angles */
|
224
|
+
{
|
225
|
+
int this_explode = GDCPIE_explode? GDCPIE_explode[i]: 0;
|
226
|
+
double this_sin;
|
227
|
+
double this_cos;
|
228
|
+
slice_angle[0][i] = this/2.0+last; /* mid-point on full pie */
|
229
|
+
slice_angle[1][i] = last; /* 1st on full pie */
|
230
|
+
slice_angle[2][i] = this+last; /* 2nd on full pie */
|
231
|
+
this_sin = ellipsex*sin( (double)slice_angle[0][i] );
|
232
|
+
this_cos = ellipsey*cos( (double)slice_angle[0][i] );
|
233
|
+
|
234
|
+
if( !GDCPIE_missing || !(GDCPIE_missing[i]) )
|
235
|
+
{
|
236
|
+
short lbl_wdth = 0,
|
237
|
+
lbl_hgt = 0;
|
238
|
+
float this_y_explode_limit,
|
239
|
+
this_x_explode_limit;
|
240
|
+
|
241
|
+
/* start slice label height, width */
|
242
|
+
/* accounting for PCT placement, font */
|
243
|
+
pct_ftsz[i].h = 0;
|
244
|
+
pct_ftsz[i].w = 0;
|
245
|
+
if( GDCPIE_percent_fmt &&
|
246
|
+
GDCPIE_percent_labels != GDCPIE_PCT_NONE )
|
247
|
+
{
|
248
|
+
sprintf( pct_lbl[i], GDCPIE_percent_fmt, this_pct * 100.0 );
|
249
|
+
pct_ftsz[i] = GDCfnt_sz( pct_lbl[i],
|
250
|
+
GDCPIE_label_size,
|
251
|
+
gdcpie_label_font, gdcpie_label_ptsize, 0.0, NULL );
|
252
|
+
lbl_wdth = pct_ftsz[i].w;
|
253
|
+
lbl_hgt = pct_ftsz[i].h;
|
254
|
+
}
|
255
|
+
|
256
|
+
if( lbl && lbl[i] )
|
257
|
+
{
|
258
|
+
lbl_ftsz[i] = GDCfnt_sz( lbl[i],
|
259
|
+
GDCPIE_label_size,
|
260
|
+
gdcpie_label_font, gdcpie_label_ptsize, 0.0, NULL );
|
261
|
+
|
262
|
+
if( GDCPIE_percent_labels == GDCPIE_PCT_ABOVE ||
|
263
|
+
GDCPIE_percent_labels == GDCPIE_PCT_BELOW )
|
264
|
+
{
|
265
|
+
lbl_wdth = MAX( pct_ftsz[i].w, lbl_ftsz[i].w );
|
266
|
+
lbl_hgt = pct_ftsz[i].h + lbl_ftsz[i].h + 1;
|
267
|
+
}
|
268
|
+
else
|
269
|
+
if( GDCPIE_percent_labels == GDCPIE_PCT_RIGHT ||
|
270
|
+
GDCPIE_percent_labels == GDCPIE_PCT_LEFT )
|
271
|
+
{
|
272
|
+
lbl_wdth = pct_ftsz[i].w + lbl_ftsz[i].w + 1;
|
273
|
+
lbl_hgt = MAX( pct_ftsz[i].h, lbl_ftsz[i].h );
|
274
|
+
}
|
275
|
+
else /* GDCPIE_PCT_NONE */
|
276
|
+
{
|
277
|
+
lbl_wdth = lbl_ftsz[i].w;
|
278
|
+
lbl_hgt = lbl_ftsz[i].h;
|
279
|
+
}
|
280
|
+
}
|
281
|
+
else
|
282
|
+
lbl_wdth = lbl_hgt = 0;
|
283
|
+
/* end label height, width */
|
284
|
+
|
285
|
+
/* diamiter limited by this point's: explosion, label */
|
286
|
+
/* (radius to box @ slice_angle) - (explode) - (projected label size) */
|
287
|
+
/* radius constraint due to labels */
|
288
|
+
this_y_explode_limit = (float)this_cos==0.0? FLT_MAX:
|
289
|
+
( (float)( (double)cheight/ABS(this_cos) ) -
|
290
|
+
(float)( this_explode + (lbl&&lbl[i]? GDCPIE_label_dist: 0) ) -
|
291
|
+
(float)( lbl_hgt/2 ) / (float)ABS(this_cos) );
|
292
|
+
this_x_explode_limit = (float)this_sin==0.0? FLT_MAX:
|
293
|
+
( (float)( (double)cwidth/ABS(this_sin) ) -
|
294
|
+
(float)( this_explode + (lbl&&lbl[i]? GDCPIE_label_dist: 0) ) -
|
295
|
+
(float)( lbl_wdth ) / (float)ABS(this_sin) );
|
296
|
+
|
297
|
+
rad = MIN( rad, this_y_explode_limit );
|
298
|
+
rad = MIN( rad, this_x_explode_limit );
|
299
|
+
|
300
|
+
/* ok at this radius (which is most likely larger than final) */
|
301
|
+
/* adjust for inter-label spacing */
|
302
|
+
/* if( lbl[i] && *lbl[i] ) */
|
303
|
+
/* { */
|
304
|
+
/* char which_edge = slice_angle[0][i] > M_PI? +1: -1; // which semi */
|
305
|
+
/* last_label_yedge = cheight - (int)( (rad + // top or bottom of label */
|
306
|
+
/* (float)(this_explode + */
|
307
|
+
/* (float)GDCPIE_label_dist)) * (float)this_cos ) + */
|
308
|
+
/* ( (GDC_fontc[GDCPIE_label_size].h+1)/2 + */
|
309
|
+
/* GDC_label_spacing )*which_edge; */
|
310
|
+
/* } */
|
311
|
+
|
312
|
+
/* radius constriant due to exploded depth */
|
313
|
+
/* at each edge of the slice, and the middle */
|
314
|
+
/* this is really stupid */
|
315
|
+
/* this section uses a different algorithm then above, but does the same thing */
|
316
|
+
/* could be combined, but each is ugly enough! */
|
317
|
+
/* PROTECT /0 */
|
318
|
+
if( threeD )
|
319
|
+
{
|
320
|
+
short j;
|
321
|
+
int this_y_explode_pos;
|
322
|
+
int this_x_explode_pos;
|
323
|
+
|
324
|
+
/* first N E S W (actually no need for N) */
|
325
|
+
if( (slice_angle[1][i] < M_PI_2 && M_PI_2 < slice_angle[2][i]) && /* E */
|
326
|
+
(this_x_explode_pos=OX(i,M_PI_2,1)) > cx+cwidth )
|
327
|
+
rad -= (float)ABS( (double)(1+this_x_explode_pos-(cx+cwidth))/sin(M_PI_2) );
|
328
|
+
if( (slice_angle[1][i] < 3.0*M_PI_2 && 3.0*M_PI_2 < slice_angle[2][i]) && /* W */
|
329
|
+
(this_x_explode_pos=OX(i,3.0*M_PI_2,1)) < cx-cwidth )
|
330
|
+
rad -= (float)ABS( (double)(this_x_explode_pos-(cx+cwidth))/sin(3.0*M_PI_2) );
|
331
|
+
if( (slice_angle[1][i] < M_PI && M_PI < slice_angle[2][i]) && /* S */
|
332
|
+
(this_y_explode_pos=OY(i,M_PI,1)) > cy+cheight )
|
333
|
+
rad -= (float)ABS( (double)(1+this_y_explode_pos-(cy+cheight))/cos(M_PI) );
|
334
|
+
|
335
|
+
for( j=0; j<3; ++j )
|
336
|
+
{
|
337
|
+
this_y_explode_pos = IY(i,j,1);
|
338
|
+
if( this_y_explode_pos < cy-cheight )
|
339
|
+
rad -= (float)ABS( (double)((cy-cheight)-this_y_explode_pos)/cos((double)slice_angle[j][i]) );
|
340
|
+
if( this_y_explode_pos > cy+cheight )
|
341
|
+
rad -= (float)ABS( (double)(1+this_y_explode_pos-(cy+cheight))/cos((double)slice_angle[j][i]) );
|
342
|
+
|
343
|
+
this_x_explode_pos = IX(i,j,1);
|
344
|
+
if( this_x_explode_pos < cx-cwidth )
|
345
|
+
rad -= (float)ABS( (double)((cx-cwidth)-this_x_explode_pos)/sin((double)slice_angle[j][i]) );
|
346
|
+
if( this_x_explode_pos > cx+cwidth )
|
347
|
+
rad -= (float)ABS( (double)(1+this_x_explode_pos-(cx+cwidth))/sin((double)slice_angle[j][i]) );
|
348
|
+
}
|
349
|
+
}
|
350
|
+
}
|
351
|
+
others[i] = FALSE;
|
352
|
+
}
|
353
|
+
else
|
354
|
+
{
|
355
|
+
others[i] = TRUE;
|
356
|
+
slice_angle[0][i] = -FLT_MAX;
|
357
|
+
}
|
358
|
+
last += this;
|
359
|
+
}
|
360
|
+
}
|
361
|
+
|
362
|
+
/* ----- go ahead and start the image ----- */
|
363
|
+
im = gdImageCreate( IMGWIDTH, IMGHEIGHT );
|
364
|
+
|
365
|
+
/* --- allocate the requested colors --- */
|
366
|
+
BGColor = clrallocate( im, GDCPIE_BGColor );
|
367
|
+
LineColor = clrallocate( im, GDCPIE_LineColor );
|
368
|
+
PlotColor = clrallocate( im, GDCPIE_PlotColor );
|
369
|
+
if( GDCPIE_EdgeColor != GDC_NOCOLOR )
|
370
|
+
{
|
371
|
+
EdgeColor = clrallocate( im, GDCPIE_EdgeColor );
|
372
|
+
if( threeD )
|
373
|
+
EdgeColorShd = clrshdallocate( im, GDCPIE_EdgeColor );
|
374
|
+
}
|
375
|
+
|
376
|
+
/* --- set color for each slice --- */
|
377
|
+
for( i=0; i<num_points; ++i )
|
378
|
+
if( GDCPIE_Color )
|
379
|
+
{
|
380
|
+
unsigned long slc_clr = GDCPIE_Color[i];
|
381
|
+
|
382
|
+
SliceColor[i] = clrallocate( im, slc_clr );
|
383
|
+
if( threeD )
|
384
|
+
SliceColorShd[i] = clrshdallocate( im, slc_clr );
|
385
|
+
}
|
386
|
+
else
|
387
|
+
{
|
388
|
+
SliceColor[i] = PlotColor;
|
389
|
+
if( threeD )
|
390
|
+
SliceColorShd[i] = clrshdallocate( im, GDCPIE_PlotColor );
|
391
|
+
}
|
392
|
+
|
393
|
+
pscl = (2.0*M_PI)/tot_val;
|
394
|
+
|
395
|
+
/* ----- calc: smallest a slice can be ----- */
|
396
|
+
/* 1/2 circum / num slices per side. */
|
397
|
+
/* determined by number of labels that'll fit (height) */
|
398
|
+
/* scale to user values */
|
399
|
+
/* ( M_PI / (IMGHEIGHT / (SFONTHGT+1)) ) */
|
400
|
+
/* min_grphable = tot_val / */
|
401
|
+
/* ( 2.0 * (float)IMGHEIGHT / (float)(SFONTHGT+1+TFONTHGT+2) ); */
|
402
|
+
|
403
|
+
|
404
|
+
if( threeD )
|
405
|
+
{
|
406
|
+
/* draw background shaded pie */
|
407
|
+
{
|
408
|
+
float rad1 = rad * 3.0/4.0;
|
409
|
+
for( i=0; i<num_points; ++i )
|
410
|
+
if( !(others[i]) &&
|
411
|
+
(!GDCPIE_missing || !GDCPIE_missing[i]) )
|
412
|
+
{
|
413
|
+
int edge_color = GDCPIE_EdgeColor == GDC_NOCOLOR? SliceColorShd[i]:
|
414
|
+
EdgeColorShd;
|
415
|
+
|
416
|
+
gdImageLine( im, CX(i,1), CY(i,1), IX(i,1,1), IY(i,1,1), edge_color );
|
417
|
+
gdImageLine( im, CX(i,1), CY(i,1), IX(i,2,1), IY(i,2,1), edge_color );
|
418
|
+
gdImageArc( im, CX(i,1), CY(i,1),
|
419
|
+
(int)(rad*ellipsex*2.0), (int)(rad*ellipsey*2.0),
|
420
|
+
TO_INT_DEG_FLOOR(slice_angle[1][i])+270,
|
421
|
+
TO_INT_DEG_CEIL(slice_angle[2][i])+270,
|
422
|
+
edge_color );
|
423
|
+
|
424
|
+
/* gdImageFilledArc( im, CX(i,1), CY(i,1), */
|
425
|
+
/* rad*ellipsex*2, rad*ellipsey*2, */
|
426
|
+
/* TO_INT_DEG_FLOOR(slice_angle[1][i])+270, */
|
427
|
+
/* TO_INT_DEG_CEIL(slice_angle[2][i])+270, */
|
428
|
+
/* SliceColorShd[i], */
|
429
|
+
/* gdPie ); */
|
430
|
+
/* attempt to fill, if slice is wide enough */
|
431
|
+
if( (ABS(IX(i,1,1)-IX(i,2,1)) + ABS(IY(i,1,1)-IY(i,2,1))) > 2 )
|
432
|
+
{
|
433
|
+
float rad = rad1; /* local override */
|
434
|
+
gdImageFillToBorder( im, IX(i,0,1), IY(i,0,1), edge_color, SliceColorShd[i] );
|
435
|
+
}
|
436
|
+
}
|
437
|
+
}
|
438
|
+
/* fill in connection to foreground pie */
|
439
|
+
/* this is where we earn our keep */
|
440
|
+
{
|
441
|
+
int t,
|
442
|
+
num_slice_angles = 0;
|
443
|
+
CREATE_ARRAY1( tmp_slice, struct tmp_slice_t, 4*num_points+4 ); /* should only need 2*num_points+2 */
|
444
|
+
|
445
|
+
for( i=0; i<num_points; ++i )
|
446
|
+
if( !GDCPIE_missing || !GDCPIE_missing[i] )
|
447
|
+
{
|
448
|
+
if( RAD_DIST1(slice_angle[1][i]) < RAD_DIST2(slice_angle[0][i]) )
|
449
|
+
tmp_slice[num_slice_angles].hidden = FALSE;
|
450
|
+
else
|
451
|
+
tmp_slice[num_slice_angles].hidden = TRUE;
|
452
|
+
tmp_slice[num_slice_angles].i = i;
|
453
|
+
tmp_slice[num_slice_angles].slice = slice_angle[0][i];
|
454
|
+
tmp_slice[num_slice_angles++].angle = slice_angle[1][i];
|
455
|
+
if( RAD_DIST1(slice_angle[2][i]) < RAD_DIST2(slice_angle[0][i]) )
|
456
|
+
tmp_slice[num_slice_angles].hidden = FALSE;
|
457
|
+
else
|
458
|
+
tmp_slice[num_slice_angles].hidden = TRUE;
|
459
|
+
tmp_slice[num_slice_angles].i = i;
|
460
|
+
tmp_slice[num_slice_angles].slice = slice_angle[0][i];
|
461
|
+
tmp_slice[num_slice_angles++].angle = slice_angle[2][i];
|
462
|
+
/* identify which 2 slices (i) have a tangent parallel to depth angle */
|
463
|
+
if( slice_angle[1][i]<MOD_2PI(pie_3D_rad+M_PI_2) && slice_angle[2][i]>MOD_2PI(pie_3D_rad+M_PI_2) )
|
464
|
+
{
|
465
|
+
tmp_slice[num_slice_angles].i = i;
|
466
|
+
tmp_slice[num_slice_angles].hidden = FALSE;
|
467
|
+
tmp_slice[num_slice_angles].slice = slice_angle[0][i];
|
468
|
+
tmp_slice[num_slice_angles++].angle = MOD_2PI( pie_3D_rad+M_PI_2 );
|
469
|
+
}
|
470
|
+
if( slice_angle[1][i]<MOD_2PI(pie_3D_rad+3.0*M_PI_2) && slice_angle[2][i]>MOD_2PI(pie_3D_rad+3.0*M_PI_2) )
|
471
|
+
{
|
472
|
+
tmp_slice[num_slice_angles].i = i;
|
473
|
+
tmp_slice[num_slice_angles].hidden = FALSE;
|
474
|
+
tmp_slice[num_slice_angles].slice = slice_angle[0][i];
|
475
|
+
tmp_slice[num_slice_angles++].angle = MOD_2PI( pie_3D_rad+3.0*M_PI_2 );
|
476
|
+
}
|
477
|
+
}
|
478
|
+
|
479
|
+
qsort( tmp_slice, num_slice_angles, sizeof(struct tmp_slice_t), ocmpr );
|
480
|
+
for( t=0; t<num_slice_angles; ++t )
|
481
|
+
{
|
482
|
+
gdPoint gdp[4];
|
483
|
+
|
484
|
+
i = tmp_slice[t].i;
|
485
|
+
|
486
|
+
gdp[0].x = CX(i,0); gdp[0].y = CY(i,0);
|
487
|
+
gdp[1].x = CX(i,1); gdp[1].y = CY(i,1);
|
488
|
+
gdp[2].x = OX(i,tmp_slice[t].angle,1); gdp[2].y = OY(i,tmp_slice[t].angle,1);
|
489
|
+
gdp[3].x = OX(i,tmp_slice[t].angle,0); gdp[3].y = OY(i,tmp_slice[t].angle,0);
|
490
|
+
|
491
|
+
if( !(tmp_slice[t].hidden) )
|
492
|
+
gdImageFilledPolygon( im, gdp, 4, SliceColorShd[i] );
|
493
|
+
else
|
494
|
+
{
|
495
|
+
rad -= 2.0; /* no peeking */
|
496
|
+
gdp[0].x = OX(i,slice_angle[0][i],0); gdp[0].y = OY(i,slice_angle[0][i],0);
|
497
|
+
gdp[1].x = OX(i,slice_angle[0][i],1); gdp[1].y = OY(i,slice_angle[0][i],1);
|
498
|
+
rad += 2.0;
|
499
|
+
gdp[2].x = OX(i,slice_angle[1][i],1); gdp[2].y = OY(i,slice_angle[1][i],1);
|
500
|
+
gdp[3].x = OX(i,slice_angle[1][i],0); gdp[3].y = OY(i,slice_angle[1][i],0);
|
501
|
+
gdImageFilledPolygon( im, gdp, 4, SliceColorShd[i] );
|
502
|
+
gdp[2].x = OX(i,slice_angle[2][i],1); gdp[2].y = OY(i,slice_angle[2][i],1);
|
503
|
+
gdp[3].x = OX(i,slice_angle[2][i],0); gdp[3].y = OY(i,slice_angle[2][i],0);
|
504
|
+
gdImageFilledPolygon( im, gdp, 4, SliceColorShd[i] );
|
505
|
+
}
|
506
|
+
|
507
|
+
|
508
|
+
if( GDCPIE_EdgeColor != GDC_NOCOLOR )
|
509
|
+
{
|
510
|
+
gdImageLine( im, CX(i,0), CY(i,0), CX(i,1), CY(i,1), EdgeColorShd );
|
511
|
+
gdImageLine( im, OX(i,tmp_slice[t].angle,0), OY(i,tmp_slice[t].angle,0),
|
512
|
+
OX(i,tmp_slice[t].angle,1), OY(i,tmp_slice[t].angle,1),
|
513
|
+
EdgeColorShd );
|
514
|
+
}
|
515
|
+
}
|
516
|
+
FREE_ARRAY1( tmp_slice );
|
517
|
+
}
|
518
|
+
}
|
519
|
+
|
520
|
+
|
521
|
+
/* ----- pie face ----- */
|
522
|
+
{
|
523
|
+
/* float last = 0.0; */
|
524
|
+
float rad1 = rad * 3.0/4.0;
|
525
|
+
for( i=0; i<num_points; ++i )
|
526
|
+
if( !others[i] &&
|
527
|
+
(!GDCPIE_missing || !GDCPIE_missing[i]) )
|
528
|
+
{
|
529
|
+
int edge_color = GDCPIE_EdgeColor == GDC_NOCOLOR? SliceColor[i]:
|
530
|
+
EdgeColorShd;
|
531
|
+
/* last += val[i]; */
|
532
|
+
/* EXPLODE_CX_CY( slice_angle[0][i], i ); */
|
533
|
+
gdImageLine( im, CX(i,0), CY(i,0), IX(i,1,0), IY(i,1,0), edge_color );
|
534
|
+
gdImageLine( im, CX(i,0), CY(i,0), IX(i,2,0), IY(i,2,0), edge_color );
|
535
|
+
gdImageArc( im, CX(i,0), CY(i,0),
|
536
|
+
(int)(rad*ellipsex*2.0), (int)(rad*ellipsey*2.0),
|
537
|
+
(TO_INT_DEG_FLOOR(slice_angle[1][i])+270)%360,
|
538
|
+
(TO_INT_DEG_CEIL(slice_angle[2][i])+270)%360,
|
539
|
+
edge_color );
|
540
|
+
/* antialiasing here */
|
541
|
+
/* likely only on the face? */
|
542
|
+
/* bugs in gd2.0.0 */
|
543
|
+
/* arc doesn't honor deg>360 */
|
544
|
+
/* arcs from gdImageFilledArc() don't match with gdImageArc() */
|
545
|
+
/* angles are off */
|
546
|
+
/* doesn't always fill completely */
|
547
|
+
/* gdImageFilledArc( im, CX(i,0), CY(i,0), */
|
548
|
+
/* (int)(rad*ellipsex*2.0), (int)(rad*ellipsey*2.0), */
|
549
|
+
/* (TO_INT_DEG_FLOOR(slice_angle[1][i])+270)%360, */
|
550
|
+
/* (TO_INT_DEG_CEIL(slice_angle[2][i])+270)%360, */
|
551
|
+
/* SliceColor[i], */
|
552
|
+
/* gdPie ); */
|
553
|
+
/* attempt to fill, if slice is wide enough */
|
554
|
+
{
|
555
|
+
float rad = rad1; /* local override */
|
556
|
+
if( (ABS(IX(i,1,1)-IX(i,2,1)) + ABS(IY(i,1,1)-IY(i,2,1))) > 2 )
|
557
|
+
{
|
558
|
+
gdImageFillToBorder( im, IX(i,0,0), IY(i,0,0), edge_color, SliceColor[i] );
|
559
|
+
}
|
560
|
+
/* catch missed pixels on narrow slices */
|
561
|
+
gdImageLine( im, CX(i,0), CY(i,0), IX(i,0,0), IY(i,0,0), SliceColor[i] );
|
562
|
+
}
|
563
|
+
}
|
564
|
+
}
|
565
|
+
|
566
|
+
if( GDCPIE_title )
|
567
|
+
{
|
568
|
+
struct fnt_sz_t tftsz = GDCfnt_sz( GDCPIE_title,
|
569
|
+
GDCPIE_title_size,
|
570
|
+
gdcpie_title_font, gdcpie_title_ptsize, 0.0, NULL );
|
571
|
+
GDCImageStringNL( im,
|
572
|
+
&GDC_fontc[GDCPIE_title_size],
|
573
|
+
gdcpie_title_font, gdcpie_title_ptsize,
|
574
|
+
0.0,
|
575
|
+
IMGWIDTH/2 - tftsz.w/2,
|
576
|
+
1,
|
577
|
+
GDCPIE_title,
|
578
|
+
LineColor,
|
579
|
+
GDC_JUSTIFY_CENTER,
|
580
|
+
NULL );
|
581
|
+
}
|
582
|
+
|
583
|
+
/* labels */
|
584
|
+
if( lbl )
|
585
|
+
{
|
586
|
+
float liner = rad;
|
587
|
+
|
588
|
+
rad += GDCPIE_label_dist;
|
589
|
+
for( i=0; i<num_points; ++i )
|
590
|
+
{
|
591
|
+
if( !others[i] &&
|
592
|
+
(!GDCPIE_missing || !GDCPIE_missing[i]) )
|
593
|
+
{
|
594
|
+
int lblx, pctx,
|
595
|
+
lbly, pcty,
|
596
|
+
linex, liney;
|
597
|
+
|
598
|
+
lbly = (liney = IY(i,0,0))-lbl_ftsz[i].h / 2;
|
599
|
+
lblx = pctx = linex = IX(i,0,0);
|
600
|
+
|
601
|
+
if( slice_angle[0][i] > M_PI ) /* which semicircle */
|
602
|
+
{
|
603
|
+
lblx -= lbl_ftsz[i].w;
|
604
|
+
pctx = lblx;
|
605
|
+
++linex;
|
606
|
+
}
|
607
|
+
else
|
608
|
+
--linex;
|
609
|
+
|
610
|
+
switch( GDCPIE_percent_labels )
|
611
|
+
{
|
612
|
+
case GDCPIE_PCT_LEFT: if( slice_angle[0][i] > M_PI )
|
613
|
+
pctx -= lbl_ftsz[i].w-1;
|
614
|
+
else
|
615
|
+
lblx += pct_ftsz[i].w+1;
|
616
|
+
pcty = IY(i,0,0) - ( 1+pct_ftsz[i].h ) / 2;
|
617
|
+
break;
|
618
|
+
case GDCPIE_PCT_RIGHT: if( slice_angle[0][i] > M_PI )
|
619
|
+
lblx -= pct_ftsz[i].w-1;
|
620
|
+
else
|
621
|
+
pctx += lbl_ftsz[i].w+1;
|
622
|
+
pcty = IY(i,0,0) - ( 1+pct_ftsz[i].h ) / 2;
|
623
|
+
break;
|
624
|
+
case GDCPIE_PCT_ABOVE: lbly += (1+pct_ftsz[i].h) / 2;
|
625
|
+
pcty = lbly - pct_ftsz[i].h;
|
626
|
+
break;
|
627
|
+
case GDCPIE_PCT_BELOW: lbly -= (1+pct_ftsz[i].h) / 2;
|
628
|
+
pcty = lbly + lbl_ftsz[i].h;
|
629
|
+
break;
|
630
|
+
case GDCPIE_PCT_NONE:
|
631
|
+
default:;
|
632
|
+
}
|
633
|
+
|
634
|
+
if( GDCPIE_percent_labels != GDCPIE_PCT_NONE )
|
635
|
+
GDCImageStringNL( im,
|
636
|
+
&GDC_fontc[GDCPIE_label_size],
|
637
|
+
gdcpie_label_font, gdcpie_label_ptsize,
|
638
|
+
0.0,
|
639
|
+
slice_angle[0][i] <= M_PI? pctx:
|
640
|
+
pctx+lbl_ftsz[i].w-pct_ftsz[i].w,
|
641
|
+
pcty,
|
642
|
+
pct_lbl[i],
|
643
|
+
LineColor,
|
644
|
+
GDC_JUSTIFY_CENTER,
|
645
|
+
NULL );
|
646
|
+
if( lbl[i] )
|
647
|
+
GDCImageStringNL( im,
|
648
|
+
&GDC_fontc[GDCPIE_label_size],
|
649
|
+
gdcpie_label_font, gdcpie_label_ptsize,
|
650
|
+
0.0,
|
651
|
+
lblx,
|
652
|
+
lbly,
|
653
|
+
lbl[i],
|
654
|
+
LineColor,
|
655
|
+
slice_angle[0][i] <= M_PI? GDC_JUSTIFY_LEFT:
|
656
|
+
GDC_JUSTIFY_RIGHT,
|
657
|
+
NULL );
|
658
|
+
if( GDCPIE_label_line )
|
659
|
+
{
|
660
|
+
float rad = liner;
|
661
|
+
gdImageLine( im, linex, liney, IX(i,0,0), IY(i,0,0), LineColor );
|
662
|
+
}
|
663
|
+
}
|
664
|
+
}
|
665
|
+
rad -= GDCPIE_label_dist;
|
666
|
+
}
|
667
|
+
|
668
|
+
fflush( img_fptr );
|
669
|
+
switch( GDC_image_type )
|
670
|
+
{
|
671
|
+
#ifdef HAVE_JPEG
|
672
|
+
case GDC_JPEG: gdImageJpeg( im, img_fptr, GDC_jpeg_quality ); break;
|
673
|
+
#endif
|
674
|
+
case GDC_WBMP: gdImageWBMP( im, PlotColor, img_fptr ); break;
|
675
|
+
case GDC_GIF: gdImageGif( im, img_fptr); break;
|
676
|
+
case GDC_PNG:
|
677
|
+
default: gdImagePng( im, img_fptr );
|
678
|
+
}
|
679
|
+
|
680
|
+
FREE_ARRAY1( lbl_ftsz );
|
681
|
+
FREE_ARRAY1( pct_ftsz );
|
682
|
+
FREE_ARRAY2( pct_lbl );
|
683
|
+
|
684
|
+
FREE_ARRAY2( slice_angle );
|
685
|
+
FREE_ARRAY1( others );
|
686
|
+
|
687
|
+
FREE_ARRAY1( SliceColorShd );
|
688
|
+
FREE_ARRAY1( SliceColor );
|
689
|
+
gdImageDestroy(im);
|
690
|
+
return;
|
691
|
+
}
|