1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2009, 2011 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "output/charts/piechart.h"
23 #include "output/cairo-chart.h"
25 #include "gl/minmax.h"
27 /* Draw a single slice of the pie */
29 draw_segment(cairo_t *cr,
32 double start_angle, double segment_angle,
33 const struct xrchart_colour *colour)
35 cairo_move_to (cr, x0, y0);
36 cairo_arc (cr, x0, y0, radius, start_angle, start_angle + segment_angle);
37 cairo_line_to (cr, x0, y0);
39 cairo_set_source_rgb (cr,
41 colour->green / 255.0,
42 colour->blue / 255.0);
43 cairo_fill_preserve (cr);
49 xrchart_draw_piechart (const struct chart_item *chart_item, cairo_t *cr,
50 struct xrchart_geometry *geom)
52 const struct piechart *pie = to_piechart (chart_item);
53 double total_magnitude;
54 double left_label, right_label;
55 double centre_x, centre_y;
60 centre_x = (geom->axis[SCALE_ABSCISSA].data_max + geom->axis[SCALE_ORDINATE].data_min) / 2.0 ;
61 centre_y = (geom->axis[SCALE_ORDINATE].data_max + geom->axis[SCALE_ORDINATE].data_min) / 2.0 ;
63 left_label = geom->axis[SCALE_ORDINATE].data_min + (geom->axis[SCALE_ABSCISSA].data_max - geom->axis[SCALE_ORDINATE].data_min)/10.0;
64 right_label = geom->axis[SCALE_ABSCISSA].data_max - (geom->axis[SCALE_ABSCISSA].data_max - geom->axis[SCALE_ORDINATE].data_min)/10.0;
66 radius = MIN (5.0 / 12.0 * (geom->axis[SCALE_ORDINATE].data_max - geom->axis[SCALE_ORDINATE].data_min),
67 1.0 / 4.0 * (geom->axis[SCALE_ABSCISSA].data_max - geom->axis[SCALE_ORDINATE].data_min));
69 radius = MIN (5.0 / 12.0 * (geom->axis[SCALE_ORDINATE].data_max - geom->axis[SCALE_ORDINATE].data_min),
70 1.0 / 4.0 * (geom->axis[SCALE_ABSCISSA].data_max - geom->axis[SCALE_ORDINATE].data_min));
72 xrchart_write_title (cr, geom, "%s", chart_item_get_title (chart_item));
74 total_magnitude = 0.0;
75 for (i = 0; i < pie->n_slices; i++)
76 total_magnitude += pie->slices[i].magnitude;
79 /* Draw the segments */
81 for (i = 0; i < pie->n_slices ; ++i )
83 const double segment_angle =
84 pie->slices[i].magnitude / total_magnitude * 2 * M_PI ;
86 /* Fill the segment */
88 centre_x, centre_y, radius,
90 &data_colour[i % XRCHART_N_COLOURS]);
92 angle += segment_angle;
96 /* Now add the labels.
97 Don't put this in the loop above; the labels must
98 be put in last, otherwise the segment fill could
102 for (i = 0; i < pie->n_slices ; ++i )
104 const double segment_angle =
105 pie->slices[i].magnitude / total_magnitude * 2 * M_PI ;
107 const double label_x = centre_x +
108 radius * cos (angle + segment_angle/2.0);
110 const double label_y = centre_y +
111 radius * sin (angle + segment_angle/2.0);
113 if ( label_x < centre_x )
115 cairo_move_to (cr, label_x, label_y);
116 cairo_line_to (cr, left_label, label_y);
118 cairo_move_to (cr, left_label, label_y + 5);
119 xrchart_label (cr, 'l', 'x', geom->font_size,
120 ds_cstr (&pie->slices[i].label));
124 cairo_move_to (cr, label_x, label_y);
125 cairo_line_to (cr, right_label, label_y);
127 cairo_move_to (cr, right_label, label_y + 5);
128 xrchart_label (cr, 'r', 'x', geom->font_size,
129 ds_cstr (&pie->slices[i].label));
132 angle += segment_angle;
135 /* Draw an outline to the pie */
136 cairo_arc (cr, centre_x, centre_y, radius, 0, 2 * M_PI);