static GOData * gog_xy_dropbar_plot_axis_get_bounds (GogPlot *plot, GogAxisType axis, GogPlotBoundInfo *bounds) { GogXYDropBarPlot *model = GOG_XY_DROPBAR_PLOT (plot); if ((model->horizontal && axis == GOG_AXIS_Y) || (!model->horizontal && axis == GOG_AXIS_X)) { GSList *ptr; bounds->val.minima = model->x.minima; bounds->val.maxima = model->x.maxima; bounds->is_discrete = model->x.minima > model->x.maxima || !go_finite (model->x.minima) || !go_finite (model->x.maxima); if (bounds->fmt == NULL && model->x.fmt != NULL) bounds->fmt = go_format_ref (model->x.fmt); if (model->x.date_conv) bounds->date_conv = model->x.date_conv; for (ptr = plot->series; ptr != NULL ; ptr = ptr->next) if (gog_series_is_valid (GOG_SERIES (ptr->data))) return GOG_SERIES (ptr->data)->values[0].data; return NULL; } if ((model->horizontal && axis == GOG_AXIS_X) || (!model->horizontal && axis == GOG_AXIS_Y)) { bounds->val.minima = model->y.minima; bounds->val.maxima = model->y.maxima; if (bounds->fmt == NULL && model->y.fmt != NULL) bounds->fmt = go_format_ref (model->y.fmt); if (model->y.date_conv) bounds->date_conv = model->y.date_conv; } return NULL; }
static GOPath * xy_make_path_step (GogChartMap *map, double const *x, double const *y, int n_points, GOLineInterpolation interpolation, gboolean skip_invalid) { GOPath *path; int i, n_valid_points = 0; double xx, yy, last_xx = 0.0, last_yy = 0.0; path = go_path_new (); if (n_points < 1) return path; n_valid_points = 0; for (i = 0; i < n_points; i++) { gog_chart_map_2D_to_view (map, x != NULL ? x[i] : i + 1, y != NULL ? y[i] : i + 1, &xx, &yy); if (go_finite (xx) && go_finite (yy) && fabs (xx) != DBL_MAX && fabs (yy) != DBL_MAX) { n_valid_points++; if (n_valid_points == 1) go_path_move_to (path, xx, yy); else { switch (interpolation) { case GO_LINE_INTERPOLATION_STEP_START: go_path_line_to (path, xx, last_yy); break; case GO_LINE_INTERPOLATION_STEP_END: go_path_line_to (path, last_xx, yy); break; case GO_LINE_INTERPOLATION_STEP_CENTER_X: go_path_line_to (path, (last_xx + xx) / 2.0, last_yy); go_path_line_to (path, (last_xx + xx) / 2.0, yy); break; case GO_LINE_INTERPOLATION_STEP_CENTER_Y: go_path_line_to (path, last_xx, (last_yy + yy) / 2.0); go_path_line_to (path, xx, (last_yy + yy) / 2.0); break; default: g_assert_not_reached (); break; } go_path_line_to (path, xx, yy); } last_xx = xx; last_yy = yy; } else if (!skip_invalid) n_valid_points = 0; } go_path_set_options (path, GO_PATH_OPTIONS_SHARP); return path; }
static void gog_pie_series_update (GogObject *obj) { double *vals = NULL, total; int len = 0; GogPieSeries *series = GOG_PIE_SERIES (obj); unsigned old_num = series->base.num_elements; GogShowNegsMode mode = GOG_PIE_PLOT (series->base.plot)->show_negatives; if (series->base.values[1].data != NULL) { vals = go_data_get_values (series->base.values[1].data); len = go_data_get_vector_size (series->base.values[1].data); } series->base.num_elements = len; for (total = 0. ; len-- > 0 ;) { double val = vals[len]; if (go_finite (val)) { if (val < 0) val = (mode == GOG_SHOW_NEGS_SKIP)? 0.: -val; total += val; } } series->total = total; /* queue plot for redraw */ gog_object_request_update (GOG_OBJECT (series->base.plot)); if (old_num != series->base.num_elements) gog_plot_request_cardinality_update (series->base.plot); if (series_parent_klass->update) series_parent_klass->update (obj); }
static gboolean goc_polyline_prepare_draw (GocItem const *item, cairo_t *cr, gboolean flag) { GocPolyline *polyline = GOC_POLYLINE (item); unsigned i; gboolean scale_line_width = goc_styled_item_get_scale_line_width (GOC_STYLED_ITEM (item)); gboolean needs_restore; cairo_save (cr); needs_restore = TRUE; _goc_item_transform (item, cr, flag); if (polyline->nb_points == 0) return FALSE; if (1 == flag) { goc_group_cairo_transform (item->parent, cr, polyline->points[0].x, polyline->points[0].y); cairo_move_to (cr, 0., 0.); } else { cairo_move_to (cr, polyline->points[0].x, polyline->points[0].y); } if (polyline->use_spline) { GOBezierSpline *spline = (GOBezierSpline *) g_object_get_data (G_OBJECT (polyline), "spline"); cairo_save (cr); if (flag == 0) cairo_translate (cr, polyline->points[0].x, polyline->points[0].y); go_bezier_spline_to_cairo (spline, cr, goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL); cairo_restore (cr); } else { double sign = (flag && goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1: 1; gboolean prev_valid = TRUE; for (i = 1; i < polyline->nb_points; i++) { if (go_finite (polyline->points[i].x)) { if (prev_valid) cairo_line_to (cr, (polyline->points[i].x - polyline->points[0].x * flag) * sign, polyline->points[i].y - polyline->points[0].y * flag); else { cairo_move_to (cr, (polyline->points[i].x - polyline->points[0].x * flag) * sign, polyline->points[i].y - polyline->points[0].y * flag); prev_valid = TRUE; } } else prev_valid = FALSE; } } if (!scale_line_width) { cairo_restore (cr); needs_restore = FALSE; } if (goc_styled_item_set_cairo_line (GOC_STYLED_ITEM (item), cr)) { if (needs_restore) cairo_restore (cr); return TRUE; } if (needs_restore) cairo_restore (cr); return FALSE; }
static GOPath * make_path_linear (GogChartMap *map, double const *x, double const *y, int n_points, gboolean is_polar, gboolean skip_invalid) { GOPath *path; int i, n_valid_points = 0; double xx, yy; double yy_min, yy_max; gboolean is_inverted; path = go_path_new (); if (n_points < 1) return path; gog_axis_map_get_bounds (map->axis_map[1], &yy_min, &yy_max); is_inverted = gog_axis_map_is_inverted (map->axis_map[1]); n_valid_points = 0; for (i = 0; i < n_points; i++) { yy = y != NULL ? y[i] : i + 1; if (is_polar) { if (is_inverted && yy > yy_max) yy = yy_max; else if (!is_inverted && yy < yy_min) yy = yy_min; } gog_chart_map_2D_to_view (map, x != NULL ? x[i] : i + 1, yy, &xx, &yy); if (go_finite (xx) && go_finite (yy) && fabs (xx) != DBL_MAX && fabs (yy) != DBL_MAX) { n_valid_points++; if (n_valid_points == 1) go_path_move_to (path, xx, yy); else go_path_line_to (path, xx, yy); } else if (!skip_invalid) n_valid_points = 0; } return path; }
static int gog_polynom_reg_curve_build_values (GogLinRegCurve *rc, double const *x_vals, double const *y_vals, int n) { double x, y, xx; double xmin, xmax; int i, j, used; gog_reg_curve_get_bounds (&rc->base, &xmin, &xmax); if (rc->x_vals == NULL) rc->x_vals = g_new0 (double*, rc->dims); for (i = 0; i < rc->dims; i++) { g_free (rc->x_vals[i]); rc->x_vals[i] = g_new (double, n); } g_free (rc->y_vals); rc->y_vals = g_new (double, n); for (i = 0, used = 0; i < n; i++) { x = (x_vals)? x_vals[i]: i + 1; y = y_vals[i]; if (!go_finite (x) || !go_finite (y)) { if (rc->base.skip_invalid) continue; used = 0; break; } if (x < xmin || x > xmax) continue; xx = 1.; for (j = 0; j < rc->dims; j++) { xx *= x; rc->x_vals[j][used] = xx; } rc->y_vals[used] = y; used++; } return (used > rc->dims)? used: 0; }
static gboolean get_extremes_2D (double const *x, double const *y, double n_data, double *x_start, double *y_start, double *x_end, double *y_end) { gboolean start_found = FALSE, end_found = FALSE; unsigned int i, j; double xx, yy; for (i = 0, j = n_data - 1; i < n_data; i++, j--) { xx = x != NULL ? x[i] : i + 1; yy = y != NULL ? y[i] : i + 1; if (!start_found && go_finite (xx) && go_finite (yy)) { if (x_start != NULL) *x_start = xx; if (y_start != NULL) *y_start = yy; if (end_found) return TRUE; start_found = TRUE; } xx = x != NULL ? x[j] : j + 1; yy = y != NULL ? y[j] : j + 1; if (!end_found && go_finite (xx) && go_finite (yy)) { if (x_end != NULL) *x_end = xx; if (y_end != NULL) *y_end = yy; if (start_found) return TRUE; end_found = TRUE; } } return FALSE; }
static gboolean find_element (GogView *view, double cx, double cy, double x, double y, unsigned int *index, GogPieSeries **series) { GogPiePlot *pie = GOG_PIE_PLOT (view->model); GSList *ptr; double *vals, scale, len = 0, theta; *series = NULL; *index = 0; for (ptr = pie->base.series ; ptr != NULL ; ptr = ptr->next) if (gog_series_is_valid (GOG_SERIES (*series = ptr->data))) break; if (ptr == NULL) return FALSE; theta = (atan2 (y - cy, x - cx) * 180 / M_PI - pie->initial_angle + 90.) / pie->span / 3.6; if (theta < 0) theta += 1.; vals = go_data_get_values ((*series)->base.values[1].data); scale = 1 / (*series)->total; for (*index = 0 ; *index < (*series)->base.num_elements; (*index)++) { len = vals[*index] * scale; if (len < 0.) len = pie->show_negatives? -len: 0.; if (go_finite (len) && len > 1e-3) { theta -= len; if (theta < 0) break; } } return TRUE; }
static GOPath * polar_make_path_step (GogChartMap *map, double const *x, double const *y, int n_points, GOLineInterpolation interpolation, gboolean skip_invalid) { GogChartMapPolarData *polar_parms; GOPath *path; int i, n_valid_points = 0; double xx, yy; double cx, cy, rx, ry; double rho, rho_min, rho_max, theta, last_rho = 0.0, last_theta = 0.0; gboolean is_inverted; path = go_path_new (); if (n_points < 1) return path; gog_axis_map_get_bounds (map->axis_map[1], &rho_min, &rho_max); is_inverted = gog_axis_map_is_inverted (map->axis_map[1]); polar_parms = gog_chart_map_get_polar_parms (map); cx = polar_parms->cx; cy = polar_parms->cy; rx = polar_parms->rx; ry = polar_parms->ry; n_valid_points = 0; for (i = 0; i < n_points; i++) { rho = y != NULL ? y[i] : i + 1; if (is_inverted && rho > rho_max) rho = rho_max; else if (!is_inverted && rho < rho_min) rho = rho_min; theta = gog_axis_map_to_view (map->axis_map[0], x != NULL ? x[i] : i + 1); rho = gog_axis_map_to_view (map->axis_map[1], rho); xx = cx + rho * rx * cos (theta); yy = cy + rho * ry * sin (theta); if (go_finite (xx) && go_finite (yy) && fabs (xx) != DBL_MAX && fabs (yy) != DBL_MAX) { n_valid_points++; if (n_valid_points == 1) go_path_move_to (path, xx, yy); else switch (interpolation) { case GO_LINE_INTERPOLATION_STEP_START: go_path_arc_to (path, cx, cy, last_rho * rx, last_rho * ry, last_theta, theta); break; case GO_LINE_INTERPOLATION_STEP_END: go_path_arc_to (path, cx, cy, rho * rx, rho * ry, last_theta, theta); break; case GO_LINE_INTERPOLATION_STEP_CENTER_X: go_path_arc_to (path, cx, cy, last_rho * rx, last_rho * ry, last_theta, (last_theta + theta) / 2.0); go_path_arc_to (path, cx, cy, rho * rx, rho * ry, (last_theta + theta) / 2.0, theta); break; case GO_LINE_INTERPOLATION_STEP_CENTER_Y: go_path_arc_to (path, cx, cy, (last_rho + rho) * rx / 2.0, (last_rho + rho) * ry / 2.0, last_theta, theta); go_path_line_to (path, xx, yy); break; default: g_assert_not_reached (); break; } last_theta = theta; last_rho = rho; } else if (!skip_invalid) n_valid_points = 0; } return path; }
static GOPath * make_path_cspline (GogChartMap *map, double const *x, double const *y, int n_points, gboolean is_polar, GOCSplineType type, gboolean skip_invalid, gpointer data) { GOPath *path; int i, n_valid_points = 0; double *uu, *vv, u, v; double p0 = 0., p1 = 0.; /* clamped derivatives */ GOCSpline *spline; path = go_path_new (); if (n_points < 1 || (x && !go_range_vary_uniformly (x, n_points))) return path; uu = g_new (double, n_points); vv = g_new (double, n_points); n_valid_points = 0; for (i = 0; i < n_points; i++) { gog_chart_map_2D_to_view (map, x != NULL ? x[i] : i + 1, y != NULL ? y[i] : i + 1, &u, &v); if (go_finite (u) && go_finite (v) && fabs (u) != DBL_MAX && fabs (v) != DBL_MAX) { uu[n_valid_points] = u; vv[n_valid_points] = v; n_valid_points++; } else { if (skip_invalid || type == GO_CSPLINE_CLAMPED) continue; if (n_valid_points == 2) { go_path_move_to (path, uu[0], vv[0]); go_path_line_to (path, uu[1], vv[1]); } else if (n_valid_points > 2) { int j; /* evaluate the spline */ spline = go_cspline_init (uu, vv, n_valid_points, type, p0, p1); if (spline) { double x0, x1, x2, x3, y0, y1, y2, y3; x0 = uu[0]; y0 = vv[0]; go_path_move_to (path, x0, y0); for (j = 1; j < spline->n; j++) { x3 = uu[j]; y3 = vv[j]; u = x3 - x0; x1 = (2. * x0 + x3) / 3.; x2 = (x0 + 2. * x3) / 3.; y1 = y0 + spline->c[j-1] / 3. * u; y2 = y0 + (2. * spline->c[j-1] + spline->b[j-1] * u) / 3. * u; go_path_curve_to (path, x1, y1, x2, y2, x3, y3); x0 = x3; y0 = y3; } go_cspline_destroy (spline); } } n_valid_points = 0; } } if (n_valid_points == 2) { go_path_move_to (path, uu[0], vv[0]); go_path_line_to (path, uu[1], vv[1]); } else if (n_valid_points > 2) { if (type == GO_CSPLINE_CLAMPED && data != NULL) { p0 = gog_chart_map_2D_derivative_to_view (map, ((double*) data)[0], uu[0], vv[0]); p1 = gog_chart_map_2D_derivative_to_view (map, ((double*) data)[1], uu[n_valid_points - 1], vv[n_valid_points - 1]); } spline = go_cspline_init (uu, vv, n_valid_points, type, p0, p1); if (spline) { double x0, x1, x2, x3, y0, y1, y2, y3; x0 = uu[0]; y0 = vv[0]; go_path_move_to (path, x0, y0); for (i = 1; i < spline->n; i++) { x3 = uu[i]; y3 = vv[i]; u = x3 - x0; x1 = (2. * x0 + x3) / 3.; x2 = (x0 + 2. * x3) / 3.; y1 = y0 + spline->c[i-1] / 3. * u; y2 = y0 + (2. * spline->c[i-1] + spline->b[i-1] * u) / 3. * u; go_path_curve_to (path, x1, y1, x2, y2, x3, y3); x0 = x3; y0 = y3; } go_cspline_destroy (spline); } } g_free (uu); g_free (vv); return path; }
static GOPath * make_path_spline (GogChartMap *map, double const *x, double const *y, int n_points, gboolean is_polar, gboolean closed, gboolean skip_invalid) { GOPath *path; int i, n_valid_points = 0; double *uu, *vv, *tt; double u, v; double yy, yy_min, yy_max; gboolean is_inverted; GOBezierSpline *spline; path = go_path_new (); if (n_points < 1) return path; gog_axis_map_get_bounds (map->axis_map[1], &yy_min, &yy_max); is_inverted = gog_axis_map_is_inverted (map->axis_map[1]); uu = g_new (double, n_points); vv = g_new (double, n_points); tt = g_new (double, n_points); n_valid_points = 0; for (i = 0; i < n_points; i++) { yy = y != NULL ? y[i] : i + 1; if (is_polar) { if (is_inverted && yy > yy_max) yy = yy_max; else if (!is_inverted && yy < yy_min) yy = yy_min; } gog_chart_map_2D_to_view (map, x != NULL ? x[i] : i + 1, yy, &u, &v); if (go_finite (u) && go_finite (v) && fabs (u) != DBL_MAX && fabs (v) != DBL_MAX) { uu[n_valid_points] = u; vv[n_valid_points] = v; tt[n_valid_points] = n_valid_points; n_valid_points++; } else { if (closed || skip_invalid) continue; if (n_valid_points == 2) { go_path_move_to (path, uu[0], vv[0]); go_path_line_to (path, uu[1], vv[1]); } else if (n_valid_points > 2) { /* evaluate the spline */ spline = go_bezier_spline_init (uu, vv, n_valid_points, closed); path = go_bezier_spline_to_path (spline); go_bezier_spline_destroy (spline); } n_valid_points = 0; } } if (n_valid_points == 2) { go_path_move_to (path, uu[0], vv[0]); go_path_line_to (path, uu[1], vv[1]); } else if (n_valid_points > 2) { /* evaluate the spline */ spline = go_bezier_spline_init (uu, vv, n_valid_points, closed); path = go_bezier_spline_to_path (spline); go_bezier_spline_destroy (spline); } g_free (uu); g_free (vv); g_free (tt); return path; }
static void gog_xy_dropbar_plot_update (GogObject *obj) { GogXYDropBarPlot *model = GOG_XY_DROPBAR_PLOT (obj); GogSeries const *series = NULL; double x_min, x_max, y_min, y_max, tmp_min, tmp_max; GSList *ptr; unsigned xaxis, yaxis; if (model->horizontal) { xaxis = 1; yaxis = 0; } else { xaxis = 0; yaxis = 1; } x_min = y_min = DBL_MAX; x_max = y_max = -DBL_MAX; gog_xy_dropbar_plot_clear_formats (model); for (ptr = model->base.series ; ptr != NULL ; ptr = ptr->next) { series = ptr->data; if (!gog_series_is_valid (GOG_SERIES (series))) continue; go_data_get_bounds (series->values[1].data, &tmp_min, &tmp_max); if (y_min > tmp_min) y_min = tmp_min; if (y_max < tmp_max) y_max = tmp_max; if (model->y.fmt == NULL) { model->y.fmt = go_data_preferred_fmt (series->values[1].data); model->y.date_conv = go_data_date_conv (series->values[1].data); } go_data_get_bounds (series->values[2].data, &tmp_min, &tmp_max); if (y_min > tmp_min) y_min = tmp_min; if (y_max < tmp_max) y_max = tmp_max; if (series->values[0].data != NULL) { go_data_get_bounds (series->values[0].data, &tmp_min, &tmp_max); if (!go_finite (tmp_min) || !go_finite (tmp_max) || tmp_min > tmp_max) { tmp_min = 0; tmp_max = go_data_get_vector_size (series->values[1].data); } else if (model->x.fmt == NULL) { model->x.fmt = go_data_preferred_fmt (series->values[0].data); model->x.date_conv = go_data_date_conv (series->values[0].data); } } else { tmp_min = 0; tmp_max = go_data_get_vector_size (series->values[1].data); } if (x_min > tmp_min) x_min = tmp_min; if (x_max < tmp_max) x_max = tmp_max; } /* make room for bar width, this is approximate since real width is larger */ tmp_max = (x_max - x_min) * model->width / 200.; x_min -= tmp_max; x_max += tmp_max; if (model->x.minima != x_min || model->x.maxima != x_max) { model->x.minima = x_min; model->x.maxima = x_max; gog_axis_bound_changed (model->base.axis[xaxis], GOG_OBJECT (model)); } if (model->y.minima != y_min || model->y.maxima != y_max) { model->y.minima = y_min; model->y.maxima = y_max; gog_axis_bound_changed (model->base.axis[yaxis], GOG_OBJECT (model)); } gog_object_emit_changed (GOG_OBJECT (obj), FALSE); if (gog_xy_dropbar_parent_klass->update) gog_xy_dropbar_parent_klass->update (obj); }
static void gog_pie_view_render (GogView *view, GogViewAllocation const *bbox) { GogPiePlot const *model = GOG_PIE_PLOT (view->model); GogPieSeries const *series = NULL; double separated_cx, separated_cy, cx, cy, r, theta, len, *vals, scale; double default_sep; unsigned elem, k; GOPath *path; GogTheme *theme = gog_object_get_theme (GOG_OBJECT (model)); GOStyle *style, *white_style = NULL, *elt_style = NULL; GSList *ptr; unsigned num_series = 0; unsigned index; double center_radius; double center_size = 0.0; double r_ext, r_int, r_tot; double outline_width_max; gboolean has_hole; double separation_max, separation; GogPieSeriesElement *gpse; GList const *overrides; GogShowNegsMode mode = model->show_negatives; gboolean negative; /* compute number of valid series */ for (ptr = model->base.series ; ptr != NULL ; ptr = ptr->next) { series = ptr->data; if (!gog_series_is_valid (GOG_SERIES (ptr->data))) continue; num_series++; } if (num_series <= 0) return; separation_max = .0; outline_width_max = .0; if ((style = go_styled_object_get_style (GO_STYLED_OBJECT (series)))) outline_width_max = gog_renderer_line_size (view->renderer, style->line.width); if (mode == GOG_SHOW_NEGS_WHITE) { white_style = go_style_dup (style); white_style->fill.type = GO_STYLE_FILL_PATTERN; go_pattern_set_solid (&white_style->fill.pattern, GO_COLOR_WHITE); } for (overrides = gog_series_get_overrides (GOG_SERIES (series)); overrides != NULL; overrides = overrides->next) { separation = GOG_PIE_SERIES_ELEMENT (overrides->data)->separation; if (separation_max < separation) separation_max = separation; style = go_styled_object_get_style (GO_STYLED_OBJECT (overrides->data)); if (outline_width_max < style->line.width) outline_width_max = style->line.width; } if (separation_max < -model->default_separation) separation_max = -model->default_separation; if (GOG_IS_RING_PLOT (model)) center_size = GOG_RING_PLOT(model)->center_size; else if (num_series > 1) num_series = 1; /* calculate things when span < 100. */ if (model->span < 100.) { double xmin, xmax, ymin, ymax, ratio; double begin, cur, end; if (num_series == 1) { begin = (model->initial_angle + series->initial_angle) * M_PI / 180. - M_PI / 2.; end = begin + model->span * M_PI / 50.; } else { /* WARNING: this code has not been checked */ ptr = model->base.series; while (!gog_series_is_valid (GOG_SERIES (ptr->data))) ptr = ptr->next; series = ptr->data; begin = end = series->initial_angle; for (ptr = ptr->next; ptr != NULL; ptr = ptr->next) { if (!gog_series_is_valid (GOG_SERIES (ptr->data))) continue; series = ptr->data; cur = series->initial_angle; if (cur < begin) begin = cur; if (cur > end) end = cur; } begin = (model->initial_angle + begin) * M_PI / 180. - M_PI / 2.; end = ((model->initial_angle + end) / 180. + model->span / 50.) * M_PI - M_PI / 2.; } cur = ceil (begin / M_PI * 2 - 1e-10) * M_PI / 2; xmin = xmax = cos (begin); ymin = ymax = sin (begin); while (cur < end) { cx = cos (cur); cy = sin (cur); if (cx > xmax) xmax = cx; if (cx < xmin) xmin = cx; if (cy > ymax) ymax = cy; if (cy < ymin) ymin = cy; cur += M_PI / 2; } cx = cos (end); cy = sin (end); if (cx > xmax) xmax = cx; if (cx < xmin) xmin = cx; if (cy > ymax) ymax = cy; if (cy < ymin) ymin = cy; /* we ensure that the center will be visible */ if (xmin > 0.) xmin = 0.; if (xmax < 0.) xmax = 0.; if (ymin > 0.) ymin = 0.; if (ymax < 0.) ymax = 0.; ratio = (ymax - ymin) / (xmax - xmin); if (view->allocation.h > view->allocation.w * ratio) { r_tot = view->allocation.w * MAX (xmax, -xmin) / (xmax - xmin); cx = view->allocation.x - view->allocation.w * xmin / (xmax - xmin); cy = view->allocation.y + (view->allocation.h + view->allocation.w * ratio) / 2. - view->allocation.w * ratio * ymax / (ymax - ymin); } else { r_tot = view->allocation.h * MAX (ymax, -ymin) / (ymax - ymin); cx = view->allocation.x + (view->allocation.w - view->allocation.h / ratio) / 2. - view->allocation.h / ratio * xmin / (xmax - xmin); cy = view->allocation.y - view->allocation.h * ymin / (ymax - ymin); } r_tot /= 1. + model->default_separation + separation_max; } else { /* centre things */ cx = view->allocation.x + view->allocation.w/2.; cy = view->allocation.y + view->allocation.h/2.; r_tot = view->allocation.h; if (r_tot > view->allocation.w) r_tot = view->allocation.w; r_tot /= 2. * (1. + model->default_separation + separation_max); } path = go_path_new (); default_sep = r_tot * model->default_separation; center_radius = r_tot * center_size; r = r_tot * (1. - center_size); elem = model->base.index_num; index = 1; for (ptr = model->base.series ; ptr != NULL ; ptr = ptr->next) { series = ptr->data; if (!gog_series_is_valid (GOG_SERIES (series))) continue; if (index > num_series) /* people snuck extra series into a pie */ break; if (num_series == index) r -= outline_width_max / 2.0; has_hole = center_radius > 0. || index > 1; r_int = center_radius + r * ((double)index - 1.0) / (double)num_series; r_ext = center_radius + r * (double)index / (double)num_series; theta = (model->initial_angle + series->initial_angle) * M_PI / 180. - M_PI / 2.; scale = 2 * M_PI / 100 * model->span / series->total; vals = go_data_get_values (series->base.values[1].data); style = GOG_STYLED_OBJECT (series)->style; if (model->base.vary_style_by_element || mode == GOG_SHOW_NEGS_WHITE) style = go_style_dup (style); gog_renderer_push_style (view->renderer, style); overrides = gog_series_get_overrides (GOG_SERIES (series)); for (k = 0 ; k < series->base.num_elements; k++) { len = vals[k] * scale; negative = len < 0; if (negative) { if (mode == GOG_SHOW_NEGS_SKIP) { if ((overrides != NULL) && (GOG_SERIES_ELEMENT (overrides->data)->index == k)) overrides = overrides->next; continue; } len = -len; } if (!go_finite (len) || len < 1e-3) { if ((overrides != NULL) && (GOG_SERIES_ELEMENT (overrides->data)->index == k)) overrides = overrides->next; continue; } gpse = NULL; if ((overrides != NULL) && (GOG_SERIES_ELEMENT (overrides->data)->index == k)) { gpse = GOG_PIE_SERIES_ELEMENT (overrides->data); overrides = overrides->next; if (negative && mode == GOG_SHOW_NEGS_WHITE) { elt_style = go_style_dup (go_styled_object_get_style ( GO_STYLED_OBJECT (gpse))); elt_style->fill.type = GO_STYLE_FILL_PATTERN; go_pattern_set_solid (&elt_style->fill.pattern, GO_COLOR_WHITE); gog_renderer_push_style (view->renderer, elt_style); } else gog_renderer_push_style (view->renderer, go_styled_object_get_style ( GO_STYLED_OBJECT (gpse))); } else { if (negative && mode == GOG_SHOW_NEGS_WHITE) gog_renderer_push_style (view->renderer, white_style); else if (model->base.vary_style_by_element) gog_theme_fillin_style (theme, style, GOG_OBJECT (series), model->base.index_num + k, GO_STYLE_FILL); } /* only separate the outer ring */ separated_cx = cx; separated_cy = cy; if (num_series == index && (default_sep > 0. || gpse != NULL)) { separation = default_sep; if (gpse != NULL) separation += gpse->separation * r_tot; separated_cx += separation * cos (theta + len/2.); separated_cy += separation * sin (theta + len/2.); } theta += len; go_path_ring_wedge (path, separated_cx, separated_cy, r_ext, r_ext, has_hole ? r_int : 0.0, has_hole ? r_int : 0.0, theta - len, theta); gog_renderer_draw_shape (view->renderer, path); go_path_clear (path); if (gpse != NULL || (negative && mode == GOG_SHOW_NEGS_WHITE)) { gog_renderer_pop_style (view->renderer); if (elt_style) { g_object_unref (elt_style); elt_style = NULL; } } } gog_renderer_pop_style (view->renderer); if (model->base.vary_style_by_element || mode == GOG_SHOW_NEGS_WHITE) g_object_unref (style); if (white_style) g_object_unref (white_style); index ++; } go_path_free (path); }
static int gog_pie_view_get_data_at_point (GogPlotView *view, double x, double y, GogSeries **series) { GogPiePlot const *model = GOG_PIE_PLOT (view->base.model); GogPieSeries const *pseries = NULL; double r_tot, r_cur, r_int, r_ext, cx, cy, r, th, th0, theta, scale, *vals; double separated_cx, separated_cy; unsigned int index, elem, k; double center_radius; double center_size = 0.0; unsigned num_series = 0; double default_sep, len; double separation_max = 0., separation; GSList *ptr; double outline_width_max = 0.; gboolean has_hole; GogPieSeriesElement *gpse; GList const *overrides; GogShowNegsMode mode = model->show_negatives; gboolean negative; GOStyle *style; *series = NULL; /* compute number of valid series */ for (ptr = model->base.series ; ptr != NULL ; ptr = ptr->next) { if (!gog_series_is_valid (GOG_SERIES (ptr->data))) continue; pseries = ptr->data; if ((style = go_styled_object_get_style (GO_STYLED_OBJECT (pseries)))) outline_width_max = MAX (outline_width_max, gog_renderer_line_size (view->base.renderer, style->line.width)); for (overrides = gog_series_get_overrides (GOG_SERIES (pseries)); overrides != NULL; overrides = overrides->next) { separation = GOG_PIE_SERIES_ELEMENT (overrides->data)->separation; if (separation_max < separation) separation_max = separation; style = go_styled_object_get_style (GO_STYLED_OBJECT (overrides->data)); if (outline_width_max < style->line.width) outline_width_max = style->line.width; } num_series++; } if (separation_max < -model->default_separation) separation_max = -model->default_separation; if (num_series <= 0) return -1; if (GOG_IS_RING_PLOT (model)) center_size = GOG_RING_PLOT(model)->center_size; else if (num_series > 1) num_series = 1; /* calculate things when span < 100. */ if (model->span < 100.) { double xmin, xmax, ymin, ymax, ratio; double begin, cur, end; if (num_series == 1) { pseries = model->base.series->data; begin = (model->initial_angle + pseries->initial_angle) * M_PI / 180. - M_PI / 2.; end = begin + model->span * M_PI / 50.; } else { /* WARNING: this code has not been checked */ ptr = model->base.series; while (!gog_series_is_valid (GOG_SERIES (ptr->data))) ptr = ptr->next; pseries = ptr->data; begin = end = pseries->initial_angle; for (ptr = ptr->next; ptr != NULL; ptr = ptr->next) { if (!gog_series_is_valid (GOG_SERIES (ptr->data))) continue; pseries = ptr->data; cur = pseries->initial_angle; if (cur < begin) begin = cur; if (cur > end) end = cur; } begin = (model->initial_angle + begin) * M_PI / 180. - M_PI / 2.; end = ((model->initial_angle + end) / 180. + model->span / 50.) * M_PI - M_PI / 2.; } cur = ceil (begin / M_PI * 2 - 1e-10) * M_PI / 2; xmin = xmax = cos (begin); ymin = ymax = sin (begin); while (cur < end) { cx = cos (cur); cy = sin (cur); if (cx > xmax) xmax = cx; if (cx < xmin) xmin = cx; if (cy > ymax) ymax = cy; if (cy < ymin) ymin = cy; cur += M_PI / 2; } cx = cos (end); cy = sin (end); if (cx > xmax) xmax = cx; if (cx < xmin) xmin = cx; if (cy > ymax) ymax = cy; if (cy < ymin) ymin = cy; /* we ensure that the center will be visible */ if (xmin > 0.) xmin = 0.; if (xmax < 0.) xmax = 0.; if (ymin > 0.) ymin = 0.; if (ymax < 0.) ymax = 0.; ratio = (ymax - ymin) / (xmax - xmin); if (view->base.allocation.h > view->base.allocation.w * ratio) { r_tot = view->base.allocation.w * MAX (xmax, -xmin) / (xmax - xmin); cx = view->base.allocation.x - view->base.allocation.w * xmin / (xmax - xmin); cy = view->base.allocation.y + (view->base.allocation.h + view->base.allocation.w * ratio) / 2. - view->base.allocation.w * ratio * ymax / (ymax - ymin); } else { r_tot = view->base.allocation.h * MAX (ymax, -ymin) / (ymax - ymin); cx = view->base.allocation.x + (view->base.allocation.w - view->base.allocation.h / ratio) / 2. - view->base.allocation.h / ratio * xmin / (xmax - xmin); cy = view->base.allocation.y - view->base.allocation.h * ymin / (ymax - ymin); } r_tot /= 1. + model->default_separation + separation_max; } else { /* centre things */ cx = view->base.allocation.x + view->base.allocation.w/2.; cy = view->base.allocation.y + view->base.allocation.h/2.; r_tot = view->base.allocation.h; if (r_tot > view->base.allocation.w) r_tot = view->base.allocation.w; r_tot /= 2. * (1. + model->default_separation + separation_max); } r = hypot (x - cx, y - cy); default_sep = r_tot * model->default_separation; center_radius = r_tot * center_size; r_cur = r_tot * (1. - center_size); if (r < center_radius) return -1; elem = model->base.index_num; index = 1; th0 = (model->initial_angle + pseries->initial_angle) * M_PI / 180. - M_PI / 2.; th = atan2 (y - cy, x - cx); if (th < th0) th += 2 * M_PI; for (ptr = model->base.series ; ptr != NULL ; ptr = ptr->next) { pseries = ptr->data; if (!gog_series_is_valid (GOG_SERIES (pseries))) continue; if (index > num_series) /* people snuck extra series into a pie */ break; if (num_series == index) r_cur -= outline_width_max / 2.0; has_hole = center_radius > 0. || index > 1; r_int = (has_hole)? (center_radius + r_cur * ((double) index - 1.0) / (double) num_series): 0.; r_ext = center_radius + r_cur * (double) index / (double) num_series; theta = th0; scale = 2 * M_PI / 100 * model->span / pseries->total; vals = go_data_get_values (pseries->base.values[1].data); overrides = gog_series_get_overrides (GOG_SERIES (pseries)); for (k = 0 ; k < pseries->base.num_elements; k++) { len = vals[k] * scale; negative = len < 0; if (negative) { if (mode == GOG_SHOW_NEGS_SKIP) { if ((overrides != NULL) && (GOG_SERIES_ELEMENT (overrides->data)->index == k)) overrides = overrides->next; continue; } len = -len; } if (!go_finite (len) || len < 1e-3) { if ((overrides != NULL) && (GOG_SERIES_ELEMENT (overrides->data)->index == k)) overrides = overrides->next; continue; } gpse = NULL; if ((overrides != NULL) && (GOG_SERIES_ELEMENT (overrides->data)->index == k)) { gpse = GOG_PIE_SERIES_ELEMENT (overrides->data); overrides = overrides->next; } /* only separate the outer ring */ separated_cx = cx; separated_cy = cy; if (num_series == index && (default_sep > 0. || gpse != NULL)) { separation = default_sep; if (gpse != NULL) separation += gpse->separation * r_tot; separated_cx += separation * cos (theta + len/2.); separated_cy += separation * sin (theta + len/2.); r = hypot (x - separated_cx, y - separated_cy); th = atan2 (y - separated_cy, x - separated_cx); if (th < th0) th += 2 * M_PI; } theta += len; if (r > r_int && r <= r_ext && th > theta - len && th <= theta) { *series = GOG_SERIES (pseries); return k; } if (gpse) { r = hypot (x - cx, y - cy); th = atan2 (y - cy, x - cx); if (th < th0) th += 2 * M_PI; } } index ++; } return -1; }