X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Foutput%2Fcharts%2Fpiechart.c;h=935c6eb0fed9784024c54e571e53936e07c09c7b;hb=204a1ee35aebcc2cf955017070c1a3638cdaee22;hp=d7db80e921a6f573991ed0be14e1eaf583e8527d;hpb=005ac6d163e0e535a06e9bfb223f2f75f9320c9a;p=pspp diff --git a/src/output/charts/piechart.c b/src/output/charts/piechart.c index d7db80e921..935c6eb0fe 100644 --- a/src/output/charts/piechart.c +++ b/src/output/charts/piechart.c @@ -17,78 +17,101 @@ #include -#include +#include + #include +#include +#include #include #include - -#include -#include - -#include -#include #include +#include +#include +#include +#include #include "minmax.h" +struct piechart + { + struct chart chart; + char *title; + struct slice *slices; + int n_slices; + }; -/* Pie charts of course need to know Pi :) */ -#ifndef M_PI -#define M_PI ( 22.0 / 7.0 ) -#endif - - +static const struct chart_class piechart_class; /* Draw a single slice of the pie */ static void -draw_segment(struct chart *ch, +draw_segment(cairo_t *, double centre_x, double centre_y, double radius, double start_angle, double segment_angle, - const char *colour) ; + const struct chart_colour *) ; -/* Draw a piechart */ -void -piechart_plot(const char *title, const struct slice *slices, int n_slices) +/* Creates and returns a chart that will render a piechart with + the given TITLE and the N_SLICES described in SLICES. */ +struct chart * +piechart_create (const char *title, const struct slice *slices, int n_slices) { + struct piechart *pie; int i; - double total_magnetude=0; - - struct chart *ch; - double left_label; - double right_label; + pie = xmalloc (sizeof *pie); + chart_init (&pie->chart, &piechart_class); + pie->title = xstrdup (title); + pie->slices = xnmalloc (n_slices, sizeof *pie->slices); + for (i = 0; i < n_slices; i++) + { + const struct slice *src = &slices[i]; + struct slice *dst = &pie->slices[i]; - double centre_x; - double centre_y; + ds_init_string (&dst->label, &src->label); + dst->magnitude = src->magnitude; + } + pie->n_slices = n_slices; + return &pie->chart; +} +static void +piechart_draw (const struct chart *chart, cairo_t *cr, + struct chart_geometry *geom) +{ + const struct piechart *pie = UP_CAST (chart, struct piechart, chart); + double total_magnitude; + double left_label, right_label; + double centre_x, centre_y; double radius; + double angle; + int i; - ch = chart_create (); - if (ch == NULL) - return; + centre_x = (geom->data_right + geom->data_left) / 2.0 ; + centre_y = (geom->data_top + geom->data_bottom) / 2.0 ; - left_label = ch->data_left + (ch->data_right - ch->data_left)/10.0; - right_label = ch->data_right - (ch->data_right - ch->data_left)/10.0; - centre_x = (ch->data_right + ch->data_left ) / 2.0; - centre_y = (ch->data_top + ch->data_bottom ) / 2.0; - radius = MIN (5.0 / 12.0 * (ch->data_top - ch->data_bottom), - 1.0 / 4.0 * (ch->data_right - ch->data_left)); + left_label = geom->data_left + (geom->data_right - geom->data_left)/10.0; + right_label = geom->data_right - (geom->data_right - geom->data_left)/10.0; - chart_write_title(ch, "%s", title); + radius = MIN (5.0 / 12.0 * (geom->data_top - geom->data_bottom), + 1.0 / 4.0 * (geom->data_right - geom->data_left)); - for (i = 0 ; i < n_slices ; ++i ) - total_magnetude += slices[i].magnetude; + radius = MIN (5.0 / 12.0 * (geom->data_top - geom->data_bottom), + 1.0 / 4.0 * (geom->data_right - geom->data_left)); - for (i = 0 ; i < n_slices ; ++i ) - { - static double angle=0.0; + chart_write_title (cr, geom, "%s", pie->title); + total_magnitude = 0.0; + for (i = 0; i < pie->n_slices; i++) + total_magnitude += pie->slices[i].magnitude; + + angle = 0.0; + for (i = 0; i < pie->n_slices ; ++i ) + { const double segment_angle = - slices[i].magnetude / total_magnetude * 2 * M_PI ; + pie->slices[i].magnitude / total_magnitude * 2 * M_PI ; const double label_x = centre_x - radius * sin(angle + segment_angle/2.0); @@ -97,120 +120,78 @@ piechart_plot(const char *title, const struct slice *slices, int n_slices) radius * cos(angle + segment_angle/2.0); /* Fill the segment */ - draw_segment(ch, - centre_x, centre_y, radius, - angle, segment_angle, - data_colour[i % N_CHART_COLOURS]); + draw_segment (cr, + centre_x, centre_y, radius, + angle, segment_angle, + &data_colour[i % N_CHART_COLOURS]); /* Now add the labels */ if ( label_x < centre_x ) { - pl_line_r(ch->lp, label_x, label_y, - left_label, label_y ); - pl_moverel_r(ch->lp,0,5); - pl_alabel_r (ch->lp, 0, 0, ds_cstr (&slices[i].label)); + cairo_move_to (cr, label_x, label_y); + cairo_line_to (cr, left_label, label_y); + cairo_stroke (cr); + cairo_move_to (cr, left_label, label_y + 5); + chart_label (cr, 'l', 'x', geom->font_size, + ds_cstr (&pie->slices[i].label)); } else { - pl_line_r(ch->lp, - label_x, label_y, - right_label, label_y - ); - pl_moverel_r(ch->lp,0,5); - pl_alabel_r (ch->lp, 'r', 0, ds_cstr (&slices[i].label)); + cairo_move_to (cr, label_x, label_y); + cairo_line_to (cr, right_label, label_y); + cairo_stroke (cr); + cairo_move_to (cr, right_label, label_y + 5); + chart_label (cr, 'r', 'x', geom->font_size, + ds_cstr (&pie->slices[i].label)); } angle += segment_angle; - } /* Draw an outline to the pie */ - pl_filltype_r(ch->lp,0); - pl_fcircle_r (ch->lp, centre_x, centre_y, radius); - - chart_submit(ch); + cairo_arc (cr, centre_x, centre_y, radius, 0, 2 * M_PI); + cairo_stroke (cr); } +/* Draw a single slice of the pie */ static void -fill_segment(struct chart *ch, - double x0, double y0, - double radius, - double start_angle, double segment_angle) ; - - -/* Fill a segment with the current fill colour */ -static void -fill_segment(struct chart *ch, +draw_segment(cairo_t *cr, double x0, double y0, double radius, - double start_angle, double segment_angle) + double start_angle, double segment_angle, + const struct chart_colour *colour) { - - const double start_x = x0 - radius * sin(start_angle); - const double start_y = y0 + radius * cos(start_angle); - - const double stop_x = - x0 - radius * sin(start_angle + segment_angle); - - const double stop_y = - y0 + radius * cos(start_angle + segment_angle); - - assert(segment_angle <= 2 * M_PI); - assert(segment_angle >= 0); - - if ( segment_angle > M_PI ) - { - /* Then we must draw it in two halves */ - fill_segment(ch, x0, y0, radius, start_angle, segment_angle / 2.0 ); - fill_segment(ch, x0, y0, radius, start_angle + segment_angle / 2.0, - segment_angle / 2.0 ); - } - else - { - pl_move_r(ch->lp, x0, y0); - - pl_cont_r(ch->lp, stop_x, stop_y); - pl_cont_r(ch->lp, start_x, start_y); - - pl_arc_r(ch->lp, - x0, y0, - stop_x, stop_y, - start_x, start_y - ); - - pl_endpath_r(ch->lp); - } + cairo_move_to (cr, x0, y0); + cairo_arc (cr, x0, y0, radius, start_angle, start_angle + segment_angle); + cairo_line_to (cr, x0, y0); + cairo_save (cr); + cairo_set_source_rgb (cr, + colour->red / 255.0, + colour->green / 255.0, + colour->blue / 255.0); + cairo_fill_preserve (cr); + cairo_restore (cr); + cairo_stroke (cr); } - - -/* Draw a single slice of the pie */ static void -draw_segment(struct chart *ch, - double x0, double y0, - double radius, - double start_angle, double segment_angle, - const char *colour) +piechart_destroy (struct chart *chart) { - const double start_x = x0 - radius * sin(start_angle); - const double start_y = y0 + radius * cos(start_angle); - - pl_savestate_r(ch->lp); - - pl_savestate_r(ch->lp); - pl_colorname_r(ch->lp, colour); - - pl_pentype_r(ch->lp,1); - pl_filltype_r(ch->lp,1); - - fill_segment(ch, x0, y0, radius, start_angle, segment_angle); - pl_restorestate_r(ch->lp); - - /* Draw line dividing segments */ - pl_pentype_r(ch->lp, 1); - pl_fline_r(ch->lp, x0, y0, start_x, start_y); - + struct piechart *pie = UP_CAST (chart, struct piechart, chart); + int i; - pl_restorestate_r(ch->lp); + free (pie->title); + for (i = 0; i < pie->n_slices; i++) + { + struct slice *slice = &pie->slices[i]; + ds_destroy (&slice->label); + } + free (pie->slices); + free (pie); } +static const struct chart_class piechart_class = + { + piechart_draw, + piechart_destroy + };