Beispiel #1
0
static GOStyle *
sop_default_style (void)
{
	GOStyle *res = go_style_new ();
	res->interesting_fields = GO_STYLE_OUTLINE | GO_STYLE_FILL;
	res->line.width = 0; /* hairline */
	res->line.color = GO_COLOR_BLACK;
	res->line.dash_type = GO_LINE_SOLID; /* anything but 0 */
	res->line.join = CAIRO_LINE_JOIN_ROUND;
	res->fill.type = GO_STYLE_FILL_PATTERN;
	go_pattern_set_solid (&res->fill.pattern, GO_COLOR_WHITE);
	return res;
}
Beispiel #2
0
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);
}