Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
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);
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
0
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;
}
Ejemplo n.º 6
0
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;
}
Ejemplo n.º 7
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;
}
Ejemplo n.º 8
0
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;
}
Ejemplo n.º 9
0
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;
}
Ejemplo n.º 10
0
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;
}
Ejemplo n.º 11
0
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;
}
Ejemplo n.º 12
0
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);
}
Ejemplo n.º 13
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);
}
Ejemplo n.º 14
0
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;
}