[goffice] Fixed area plots issues.
- From: Jean Bréfort <jbrefort src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [goffice] Fixed area plots issues.
- Date: Mon, 5 Aug 2013 11:52:43 +0000 (UTC)
commit 06c6cac61f5b4332d94deda3847c6c1d8285f853
Author: Jean Brefort <jean brefort normalesup org>
Date: Mon Aug 5 13:51:20 2013 +0200
Fixed area plots issues.
ChangeLog | 18 ++
NEWS | 3 +-
docs/reference/goffice-0.10-sections.txt | 61 ++++++-
goffice/graph/gog-chart-map.c | 5 +-
goffice/math/go-matrix.c | 1 +
goffice/utils/go-path.c | 187 +++++++++++++++++-
goffice/utils/go-path.h | 9 +
plugins/plot_barcol/gog-line.c | 331 +++++++++++++++++++++++++++---
plugins/plot_xy/gog-xy.c | 4 +-
9 files changed, 576 insertions(+), 43 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index eb10100..702bcc8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2013-08-05 Jean Brefort <jean brefort normalesup org>
+
+ * docs/reference/goffice-0.10-sections.txt: make gtk-doc happy.
+ * goffice/graph/gog-chart-map.c (xy_make_path_step): remove an unneeded
+ lineto instruction.
+ * goffice/math/go-matrix.c: make gtk-doc happy.
+ * goffice/utils/go-path.c (go_path_add_points),
+ (go_path_interpret_full), (go_path_copy),
+ (go_path_copy_restricted), (go_path_append): two new functions and sanitize
+ a few others.
+ * goffice/utils/go-path.h: new functions.
+ * plugins/plot_barcol/gog-line.c (gog_line_view_get_data_at_point),
+ (gog_line_view_render):, (gog_line_view_class_init): implement
+ get_data_at_point for area and line plots and fix rendring of stacked area
+ plots. [#627277][#689661][#705034]
+ * plugins/plot_xy/gog-xy.c (gog_xy_view_get_data_at_point): minor
+ optimization.
+
2013-08-02 Jean Brefort <jean brefort normalesup org>
* plugins/plot_xy/gog-bubble-prefs.ui: fix area vs diameter selection.
diff --git a/NEWS b/NEWS
index d933fcc..4834355 100644
--- a/NEWS
+++ b/NEWS
@@ -8,7 +8,8 @@ Jean:
* Fixed text and path items positions. [see #704391]
* Don't crash when a pixbuf has an invalid size. [#704560][#705005]
* Fix area vs diameter selection in bubble plots. [#705312]
-
+ * Implement get_data_at_point for area and line plots. [#627277][#689661]
+ * Fix rendring of stacked area plots. [#705034]
Morten:
* Add prescaling to go_linear_regression_leverage. [#703381]
diff --git a/docs/reference/goffice-0.10-sections.txt b/docs/reference/goffice-0.10-sections.txt
index d799f7a..7dc78d2 100644
--- a/docs/reference/goffice-0.10-sections.txt
+++ b/docs/reference/goffice-0.10-sections.txt
@@ -1622,10 +1622,12 @@ go_path_arc_to
go_path_clear
go_path_close
go_path_copy
+go_path_copy_restricted
go_path_curve_to
go_path_free
go_path_get_options
go_path_interpret
+go_path_interpret_full
go_path_line_to
go_path_move_to
go_path_new
@@ -1857,8 +1859,6 @@ go_plugin_service_simple_get_type
<SECTION>
<FILE>go-quad</FILE>
<TITLE>GOQuad</TITLE>
-GOQuad
-GOQuadl
go_quad_add
go_quad_addl
go_quad_div
@@ -1883,6 +1883,63 @@ go_quad_sub
go_quad_subl
go_quad_value
go_quad_valuel
+<SUBSECTION Private>
+GOQuad
+GOQuadl
+</SECTION>
+
+<SECTION>
+<FILE>go-quad-matrix</FILE>
+<TITLE>GOQuadMatrix</TITLE>
+go_quad_matrix_back_solve
+go_quad_matrix_back_solvel
+go_quad_matrix_copy
+go_quad_matrix_copyl
+go_quad_matrix_determinant
+go_quad_matrix_determinantl
+go_quad_matrix_dump
+go_quad_matrix_dumpl
+go_quad_matrix_dup
+go_quad_matrix_dupl
+go_quad_matrix_eigen_range
+go_quad_matrix_eigen_rangel
+go_quad_matrix_free
+go_quad_matrix_freel
+go_quad_matrix_fwd_solve
+go_quad_matrix_fwd_solvel
+go_quad_matrix_inverse
+go_quad_matrix_inversel
+go_quad_matrix_multiply
+go_quad_matrix_multiplyl
+go_quad_matrix_new
+go_quad_matrix_newl
+go_quad_matrix_pseudo_inverse
+go_quad_matrix_pseudo_inversel
+go_quad_matrix_transpose
+go_quad_matrix_transposel
+<SUBSECTION Private>
+GOQuadMatrix
+GOQuadMatrixl
+</SECTION>
+
+<SECTION>
+<FILE>go-quad-qr</FILE>
+<TITLE>GOQuadQR</TITLE>
+go_quad_qr_determinant
+go_quad_qr_determinantl
+go_quad_qr_free
+go_quad_qr_freel
+go_quad_qr_mark_degenerate
+go_quad_qr_mark_degeneratel
+go_quad_qr_multiply_qt
+go_quad_qr_multiply_qtl
+go_quad_qr_new
+go_quad_qr_newl
+go_quad_qr_r
+go_quad_qr_rl
+<SUBSECTION Private>
+GOQuadQR
+GOQuadQRl
</SECTION>
<SECTION>
diff --git a/goffice/graph/gog-chart-map.c b/goffice/graph/gog-chart-map.c
index d0a9949..a006b23 100644
--- a/goffice/graph/gog-chart-map.c
+++ b/goffice/graph/gog-chart-map.c
@@ -466,7 +466,7 @@ xy_make_path_step (GogChartMap *map, double const *x, double const *y, int n_poi
if (n_valid_points == 1)
go_path_move_to (path, xx, yy);
- else
+ else {
switch (interpolation) {
case GO_LINE_INTERPOLATION_STEP_START:
go_path_line_to (path, xx, last_yy);
@@ -486,7 +486,8 @@ xy_make_path_step (GogChartMap *map, double const *x, double const *y, int n_poi
g_assert_not_reached ();
break;
}
- go_path_line_to (path, xx, yy);
+ go_path_line_to (path, xx, yy);
+ }
last_xx = xx;
last_yy = yy;
} else if (!skip_invalid)
diff --git a/goffice/math/go-matrix.c b/goffice/math/go-matrix.c
index 3c3b16d..aa46a0b 100644
--- a/goffice/math/go-matrix.c
+++ b/goffice/math/go-matrix.c
@@ -612,6 +612,7 @@ SUFFIX(go_quad_matrix_dump) (const QMATRIX *A, const char *fmt)
*
* R is a matrix of size n-times-n. (To get the m-times-n version
* of R, simply add m-n null rows.)
+ * Returns: (transfer full): a new #GOQuadQR.
**/
/**
diff --git a/goffice/utils/go-path.c b/goffice/utils/go-path.c
index 20e2bf8..6c89e02 100644
--- a/goffice/utils/go-path.c
+++ b/goffice/utils/go-path.c
@@ -346,11 +346,12 @@ static void
go_path_add_points (GOPath *path, GOPathAction action,
GOPathPoint *points, int n_points)
{
- GOPathDataBuffer *buffer = path->data_buffer_tail;
+ GOPathDataBuffer *buffer;
int i;
g_return_if_fail (GO_IS_PATH (path));
+ buffer = path->data_buffer_tail;
if (buffer->n_actions + 1 > GO_PATH_DEFAULT_BUFFER_SIZE
|| buffer->n_points + n_points > GO_PATH_DEFAULT_BUFFER_SIZE)
buffer = go_path_add_data_buffer (path);
@@ -657,6 +658,153 @@ go_path_interpret (GOPath const *path,
}
}
+/**
+ * go_path_interpret_full:
+ * @path: #GOPath
+ * @start: index of the first action to interpret
+ * @end: index of the last action to interpret
+ * @direction: #GOPathDirection
+ * @move_to: (scope call): the callback for move to.
+ * @line_to: (scope call): the callback for drawing a line.
+ * @curve_to: (scope call): the callback for drawing a bezier cubic spline.
+ * @close_path: (scope call): the callback for closing the path.
+ * @closure: data to pass as first argument to the callbacks.
+ *
+ * This function can be used to draw a portion path or for other purposes.
+ * Only actions between start and end will be executed. If start or end is
+ * negative, it is not taken into account.
+ * Since: 0.10.5
+ **/
+void
+go_path_interpret_full (GOPath const *path,
+ gssize start,
+ gssize end,
+ GOPathDirection direction,
+ GOPathMoveToFunc move_to,
+ GOPathLineToFunc line_to,
+ GOPathCurveToFunc curve_to,
+ GOPathClosePathFunc close_path,
+ void *closure)
+{
+ GOPathDataBuffer *buffer;
+ GOPathAction action, next_action;
+ GOPathPoint *points;
+ GOPathPoint *prev_control_points = NULL;
+ gboolean forward = (direction == GO_PATH_DIRECTION_FORWARD);
+ int index;
+ gssize cur;
+
+ if (path == NULL || start >= end)
+ return;
+
+ if (forward) {
+ cur = 0;
+ for (buffer = path->data_buffer_head; buffer != NULL; buffer = buffer->next) {
+ int i;
+ points = buffer->points;
+
+ for (i = 0; i != buffer->n_actions; i++) {
+
+ action = buffer->actions[i];
+
+ if (end > 0 && cur > end)
+ return;
+ else if (cur == start)
+ switch (action) {
+ case GO_PATH_ACTION_MOVE_TO:
+ case GO_PATH_ACTION_LINE_TO:
+ move_to (closure, &points[0]);
+ break;
+ case GO_PATH_ACTION_CURVE_TO:
+ move_to (closure, &points[2]);
+ break;
+ case GO_PATH_ACTION_CLOSE_PATH:
+ default:
+ break;
+ }
+ else if (cur > start)
+ switch (action) {
+ case GO_PATH_ACTION_MOVE_TO:
+ move_to (closure, &points[0]);
+ break;
+ case GO_PATH_ACTION_LINE_TO:
+ line_to (closure, &points[0]);
+ break;
+ case GO_PATH_ACTION_CURVE_TO:
+ curve_to (closure, &points[0], &points[1], &points[2]);
+ break;
+ case GO_PATH_ACTION_CLOSE_PATH:
+ default:
+ close_path (closure);
+ break;
+ }
+ points += action_n_args[action];
+ cur++;
+ }
+ }
+ return;
+ }
+
+ next_action = GO_PATH_ACTION_MOVE_TO;
+ cur = 0;
+ for (buffer = path->data_buffer_head; buffer != NULL; buffer = buffer->next)
+ cur += buffer->n_actions;
+
+ for (buffer = path->data_buffer_tail; buffer != NULL; buffer = buffer->previous) {
+ int i;
+
+ points = buffer->points + buffer->n_points;
+
+ for (i = buffer->n_actions - 1; i != -1; i--) {
+ cur--;
+ action = next_action;
+ next_action = buffer->actions[i];
+
+ points -= action_n_args[next_action];
+
+ index = next_action == GO_PATH_ACTION_CURVE_TO ? 2 : 0;
+
+ if (end > 0 && cur > end)
+ continue;
+ else if (cur == end)
+ switch (action) {
+ case GO_PATH_ACTION_MOVE_TO:
+ case GO_PATH_ACTION_LINE_TO:
+ case GO_PATH_ACTION_CURVE_TO:
+ (*move_to) (closure, &points[index]);
+ break;
+ case GO_PATH_ACTION_CLOSE_PATH:
+ default:
+ break;
+ }
+ else {
+ switch (action) {
+ case GO_PATH_ACTION_MOVE_TO:
+ (*move_to) (closure, &points[index]);
+ break;
+ case GO_PATH_ACTION_LINE_TO:
+ (*line_to) (closure, &points[index]);
+ break;
+ case GO_PATH_ACTION_CURVE_TO:
+ (*curve_to) (closure,
+ &prev_control_points[1],
+ &prev_control_points[0],
+ &points[index]);
+ break;
+ case GO_PATH_ACTION_CLOSE_PATH:
+ default:
+ (*close_path) (closure);
+ break;
+ }
+ if (cur < start)
+ return;
+ }
+
+ prev_control_points = &points[0];
+ }
+ }
+}
+
static void
go_path_cairo_move_to (cairo_t *cr, GOPathPoint const *point)
{
@@ -729,7 +877,11 @@ go_path_append_close (GOPath *path)
GOPath *go_path_copy (GOPath const *path)
{
- GOPath *new_path = go_path_new ();
+ GOPath *new_path;
+
+ if (path == NULL)
+ return NULL;
+ new_path = go_path_new ();
new_path->options = path->options;
go_path_interpret (path, GO_PATH_DIRECTION_FORWARD,
(GOPathMoveToFunc) go_path_append_move_to,
@@ -739,6 +891,33 @@ GOPath *go_path_copy (GOPath const *path)
return new_path;
}
+
+/**
+ * go_path_copy_restricted:
+ * @path: #GOPath
+ * @start: the first action to copy
+ * @end: the second action to copy
+ *
+ * Copies actions between start and end will be copied inside a new #GOPath.
+ * Returns: a new #GOPath. If start or end is
+ * negative, it is not taken into account.
+ * Since: 0.10.5
+ **/
+
+GOPath *go_path_copy_restricted (GOPath const *path, gssize start, gssize end)
+{
+ GOPath *new_path;
+ if (path == NULL)
+ return NULL;
+ new_path = go_path_new ();
+ new_path->options = path->options;
+ go_path_interpret_full (path, start, end, GO_PATH_DIRECTION_FORWARD,
+ (GOPathMoveToFunc) go_path_append_move_to,
+ (GOPathLineToFunc) go_path_append_line_to,
+ (GOPathCurveToFunc) go_path_append_curve_to,
+ (GOPathClosePathFunc) go_path_append_close, new_path);
+ return new_path;
+}
/**
* go_path_append:
* @path1: #GOPath
@@ -749,6 +928,10 @@ GOPath *go_path_copy (GOPath const *path)
*/
GOPath *go_path_append (GOPath *path1, GOPath const *path2)
{
+ if (path2 == NULL)
+ return path1;
+ if (path1 == NULL)
+ return go_path_copy (path2);
go_path_interpret (path2, GO_PATH_DIRECTION_FORWARD,
(GOPathMoveToFunc) go_path_append_move_to,
(GOPathLineToFunc) go_path_append_line_to,
diff --git a/goffice/utils/go-path.h b/goffice/utils/go-path.h
index fe0f5f1..36b955b 100644
--- a/goffice/utils/go-path.h
+++ b/goffice/utils/go-path.h
@@ -105,12 +105,21 @@ void go_path_interpret (GOPath const *path,
GOPathCurveToFunc curve_to,
GOPathClosePathFunc close_path,
void *closure);
+void go_path_interpret_full (GOPath const *path,
+ gssize start, gssize end,
+ GOPathDirection direction,
+ GOPathMoveToFunc move_to,
+ GOPathLineToFunc line_to,
+ GOPathCurveToFunc curve_to,
+ GOPathClosePathFunc close_path,
+ void *closure);
void go_path_to_cairo (GOPath const *path,
GOPathDirection direction,
cairo_t *cr);
GOPath *go_path_copy (GOPath const *path);
+GOPath *go_path_copy_restricted (GOPath const *path, gssize start, gssize end);
GOPath *go_path_append (GOPath *path1, GOPath const *path2);
GOPath *go_path_scale (GOPath *path, double scale_x, double scale_y);
char *go_path_to_svg (GOPath *path);
diff --git a/plugins/plot_barcol/gog-line.c b/plugins/plot_barcol/gog-line.c
index d2252ad..e7ed577 100644
--- a/plugins/plot_barcol/gog-line.c
+++ b/plugins/plot_barcol/gog-line.c
@@ -693,12 +693,214 @@ typedef struct {
typedef GogPlotView GogLineView;
typedef GogPlotViewClass GogLineViewClass;
+static int
+gog_line_view_get_data_at_point (GogPlotView *view, double x, double y, GogSeries **series)
+{
+ GogPlot1_5d const *model = GOG_PLOT1_5D (((GogView *) view)->model);
+ GogPlot1_5dType const type = model->type;
+ GogChart *chart = GOG_CHART (view->base.model->parent);
+ GogChartMap *chart_map;
+ GogAxisMap *x_map, *y_map;
+ int i = -1, j, dist, max_dist = 0, line_dist = 0;
+ GOStyle *style;
+ GogViewAllocation const *area;
+ double xc, yc, value, y_zero;
+ GSList *ptr;
+ GogSeriesElement *gse;
+ GList *overrides; /* not const because we call g_list_* which have no const equivalent */
+ gssize num_series = model->num_series, num_elements = model->num_elements, *lengths;
+ double **vals, **yvals, *xvals, sum, abs_sum;
+ GogSeries **pseries;
+ gboolean is_null;
+ GOLineInterpolation *interpolations;
+
+ if (g_slist_length (model->base.series) < 1)
+ return -1;
+ area = gog_chart_view_get_plot_area (view->base.parent);
+ chart_map = gog_chart_map_new (chart, area,
+ GOG_PLOT (model)->axis[GOG_AXIS_X],
+ GOG_PLOT (model)->axis[GOG_AXIS_Y],
+ NULL, FALSE);
+ if (!gog_chart_map_is_valid (chart_map)) {
+ gog_chart_map_free (chart_map);
+ return -1;
+ }
+
+ x_map = gog_chart_map_get_axis_map (chart_map, 0);
+ y_map = gog_chart_map_get_axis_map (chart_map, 1);
+ y_zero = gog_axis_map_get_baseline (y_map);
+
+ vals = g_alloca (num_series * sizeof (double *));
+ yvals = g_alloca (num_series * sizeof (double *));
+ lengths = g_alloca (num_series * sizeof (gssize));
+ pseries = g_alloca (num_series * sizeof (GogSeries *));
+ interpolations = g_alloca (num_series * sizeof (GOLineInterpolation));
+ xvals = g_new (double, num_elements);
+ j = 0;
+ for (ptr = model->base.series ; ptr != NULL ; ptr = ptr->next) {
+ pseries[j] = ptr->data;
+
+ if (!gog_series_is_valid (pseries[j])) {
+ vals[j] = NULL;
+ lengths[j] = 0;
+ continue;
+ }
+
+ vals[j] = go_data_get_values (pseries[j]->values[1].data);
+ yvals[j] = g_new (double, num_elements);
+ lengths[j] = go_data_get_vector_size (pseries[j]->values[1].data);
+ interpolations[j] = pseries[j]->interpolation;
+ if (interpolations[j] == GO_LINE_INTERPOLATION_CLOSED_SPLINE)
+ interpolations[j] = GO_LINE_INTERPOLATION_SPLINE;
+ j++;
+ }
+ for (i = 0; i < num_elements; i++) {
+ xvals[i] = gog_axis_map_to_view (x_map, i + 1);
+ sum = abs_sum = 0.0;
+ if (type == GOG_1_5D_AS_PERCENTAGE) {
+ for (j = 0; j < num_series; j++)
+ if (vals[j] && i < lengths[j] && gog_axis_map_finite (y_map, vals[j][i]))
+ abs_sum += fabs (vals[j][i]);
+ is_null = (go_sub_epsilon (abs_sum) <= 0.);
+ } else
+ is_null = TRUE;
+
+ for (j = 0; j < num_series; j++) {
+ if (i >= lengths[j])
+ continue;
+
+ if (vals[j] && gog_axis_map_finite (y_map, vals[j][i])) {
+ value = vals[j][i];
+ sum += value;
+ } else
+ value = go_nan;
+
+ switch (type) {
+ case GOG_1_5D_NORMAL:
+ yvals[j][i] = gog_axis_map_finite (y_map, value)?
+ value: go_nan;
+ break;
+
+ case GOG_1_5D_STACKED:
+ yvals[j][i] = gog_axis_map_finite (y_map, sum)?
+ sum: go_nan;
+ break;
+
+ case GOG_1_5D_AS_PERCENTAGE:
+ if (!go_finite (value))
+ yvals[j][i] = go_nan;
+ else if (is_null)
+ yvals[j][i] = y_zero;
+ else
+ yvals[j][i] = gog_axis_map_finite (y_map, sum)?
+ sum / abs_sum:
+ go_nan;
+ break;
+ }
+ }
+ }
+ if (GOG_IS_PLOT_AREA (model)) {
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ GOPath *path;
+ int start, end, step;
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1 , 1);
+ cr = cairo_create (surface);
+ i = -1;
+ if (type == GOG_1_5D_NORMAL) {
+ start = num_series - 1;
+ end = -1;
+ step = -1;
+ } else {
+ start = 0;
+ end = num_series;
+ step = 1;
+ }
+ for (j = start; j != end; j += step) {
+ if (lengths[j] <= 0)
+ continue;
+ path = gog_chart_map_make_path (chart_map, NULL, yvals[j], lengths[j],
+ interpolations[j], FALSE,
+ &GOG_AREA_SERIES (pseries[j])->clamped_derivs);
+
+ go_path_line_to (path, gog_axis_map_to_view (x_map, lengths[j]), y_zero);
+ go_path_line_to (path, gog_axis_map_to_view (x_map, 1), y_zero);
+ go_path_close (path);
+ go_path_to_cairo (path, GO_PATH_DIRECTION_FORWARD, cr);
+ go_path_free (path);
+ if (cairo_in_fill (cr, x, y)) {
+ *series = pseries[j];
+ i = gog_axis_map_from_view (x_map, x) - 1;
+ break;
+ }
+ cairo_new_path (cr);
+ }
+ cairo_surface_destroy (surface);
+ cairo_destroy (cr);
+ } else { /* GogLinePlot */
+ for (j = num_series -1; j >= 0; j--) {
+ if (lengths[j] == 0)
+ continue;
+ style = go_styled_object_get_style (GO_STYLED_OBJECT (pseries[j]));
+ if (go_style_is_line_visible (style))
+ line_dist = ceil (style->line.width / 2);
+ if (go_style_is_marker_visible (style))
+ max_dist = (go_marker_get_size (style->marker.mark) + 1) / 2;
+ else if (go_style_is_line_visible (style))
+ max_dist = line_dist;
+ else
+ max_dist = 0;
+ overrides = g_list_last ((GList *) gog_series_get_overrides (GOG_SERIES
(pseries[j])));
+ for (i = lengths[j] - 1; i >= 0; i--) {
+ xc = xvals[i];
+ yc = gog_axis_map_to_view (y_map, yvals[j][i]);
+ if (!go_finite (xc) || !go_finite (yc))
+ continue;
+ xc = fabs (xc - x);
+ yc = fabs (yc - y);
+ dist = MAX (xc, yc);
+ gse = NULL;
+ while (overrides &&
+ GOG_SERIES_ELEMENT (overrides->data)->index > (unsigned) i)
+ overrides = g_list_previous (overrides);
+ if (overrides &&
+ GOG_SERIES_ELEMENT (overrides->data)->index == (unsigned) i) {
+ gse = GOG_SERIES_ELEMENT (overrides->data);
+ overrides = g_list_previous (overrides);
+ style = go_styled_object_get_style (GO_STYLED_OBJECT (gse));
+ if (go_style_is_marker_visible (style)) {
+ if (dist <= (go_marker_get_size (style->marker.mark) + 1) /
2) {
+ *series = pseries[j];
+ break;
+ }
+ } else if (dist <= line_dist) {
+ *series = pseries[j];
+ break;
+ }
+ }
+ if (gse == NULL && dist <= max_dist) {
+ *series = pseries[j];
+ break;
+ }
+ }
+ if (i >= 0)
+ break;
+ }
+ for (j = 0; j < num_series; j++)
+ g_free (yvals[j]);
+ }
+
+ gog_chart_map_free (chart_map);
+ return i;
+}
+
static void
gog_line_view_render (GogView *view, GogViewAllocation const *bbox)
{
GogPlot1_5d const *model = GOG_PLOT1_5D (view->model);
GogPlot1_5dType const type = model->type;
- GogSeries1_5d const *series;
+ GogSeries1_5d const **series;
GogSeries const *base_series;
GogChart *chart = GOG_CHART (view->model->parent);
GogChartMap *chart_map;
@@ -713,7 +915,6 @@ gog_line_view_render (GogView *view, GogViewAllocation const *bbox)
ErrorBarData **error_data;
GOStyle **styles;
unsigned *lengths;
- GOPath *path, *last_path = NULL;
GOPath **drop_paths;
Point **points = NULL;
GogErrorBar **errors;
@@ -764,6 +965,7 @@ gog_line_view_render (GogView *view, GogViewAllocation const *bbox)
error_data = g_alloca (num_series * sizeof (ErrorBarData *));
lengths = g_alloca (num_series * sizeof (unsigned));
styles = g_alloca (num_series * sizeof (GOStyle *));
+ series = g_alloca (num_series * sizeof (GogSeries *));
interpolations = g_alloca (num_series * sizeof (GOLineInterpolation));
if (!is_area_plot)
points = g_alloca (num_series * sizeof (Point *));
@@ -773,8 +975,8 @@ gog_line_view_render (GogView *view, GogViewAllocation const *bbox)
i = 0;
for (ptr = model->base.series ; ptr != NULL ; ptr = ptr->next) {
- series = ptr->data;
- base_series = GOG_SERIES (series);
+ series[i] = ptr->data;
+ base_series = GOG_SERIES (ptr->data);
if (!gog_series_is_valid (base_series)) {
vals[i] = NULL;
@@ -785,7 +987,7 @@ gog_line_view_render (GogView *view, GogViewAllocation const *bbox)
vals[i] = go_data_get_values (base_series->values[1].data);
yvals[i] = g_new (double, num_elements);
lengths[i] = go_data_get_vector_size (base_series->values[1].data);
- styles[i] = GOG_STYLED_OBJECT (series)->style;
+ styles[i] = GOG_STYLED_OBJECT (base_series)->style;
interpolations[i] = base_series->interpolation;
if (interpolations[i] == GO_LINE_INTERPOLATION_CLOSED_SPLINE)
interpolations[i] = GO_LINE_INTERPOLATION_SPLINE;
@@ -793,12 +995,12 @@ gog_line_view_render (GogView *view, GogViewAllocation const *bbox)
if (!is_area_plot)
points[i] = g_malloc (sizeof (Point) * (lengths[i]));
- errors[i] = series->errors;
- if (gog_error_bar_is_visible (series->errors))
- error_data[i] = g_malloc (sizeof (ErrorBarData) * lengths[i]);
+ errors[i] = series[i]->errors;
+ if (gog_error_bar_is_visible (series[i]->errors))
+ error_data[i] = g_malloc (sizeof (ErrorBarData) * num_elements);
else
error_data[i] = NULL;
- if (series->has_drop_lines) {
+ if (series[i]->has_drop_lines) {
if (!role)
role = gog_object_find_role_by_name (
GOG_OBJECT (series), "Drop lines");
@@ -821,10 +1023,10 @@ gog_line_view_render (GogView *view, GogViewAllocation const *bbox)
is_null = TRUE;
for (i = 0; i < num_series; i++) {
- if (j >= lengths[i])
+ if (type == GOG_1_5D_NORMAL && j >= lengths[i])
continue;
- if (vals[i] && gog_axis_map_finite (y_map, vals[i][j])) {
+ if (vals[i] && gog_axis_map_finite (y_map, (j < lengths[i])? vals[i][j]: go_nan)) {
value = vals[i][j];
if (gog_error_bar_is_visible (errors[i])) {
gog_error_bar_get_bounds (errors[i], j, &minus, &plus);
@@ -925,38 +1127,100 @@ gog_line_view_render (GogView *view, GogViewAllocation const *bbox)
gog_renderer_push_clip_rectangle (view->renderer, view->allocation.x, view->allocation.y,
view->allocation.w, view->allocation.h);
- for (i = 0; i < num_series; i++) {
- if (lengths[i] == 0)
- continue;
- path = gog_chart_map_make_path (chart_map, NULL, yvals[i], lengths[i],
- interpolations[i], type != GOG_1_5D_NORMAL && !is_area_plot,
- &GOG_AREA_SERIES (series)->clamped_derivs);
+ if (is_area_plot && type != GOG_1_5D_NORMAL) {
+ GOPath **paths = g_alloca (num_series * sizeof (GOPath *)), *close_path, *seg;
+ unsigned step;
+ unsigned k, m;
+ for (i = 0; i < num_series; i++) {
+ if (lengths[i] == 0)
+ continue;
+ paths[i] = gog_chart_map_make_path (chart_map, NULL, yvals[i], lengths[i],
+ interpolations[i], type != GOG_1_5D_NORMAL &&
!is_area_plot,
+ &GOG_AREA_SERIES (series[i])->clamped_derivs);
+ close_path = NULL;
+ gog_renderer_push_style (view->renderer, styles[i]);
+ j = i;
+ k = 0;
+ while (j > 0) {
+ j--;
+ if (lengths[j] == 0)
+ continue;
+ if (lengths[j] == lengths[i]) {
+ k = lengths[i];
+ close_path = paths[j];
+ } else
+ j++;
+ break;
+ }
+ while (j > 0 && k < lengths[i] - 1) {
+ j--;
+ if (lengths[j] > k + 1) {
+ m = MIN (lengths[i], lengths[j]) - 1;
+ switch (interpolations[j]) {
+ case GO_LINE_INTERPOLATION_STEP_START:
+ case GO_LINE_INTERPOLATION_STEP_END:
+ step = 2;
+ break;
+ case GO_LINE_INTERPOLATION_STEP_CENTER_X:
+ case GO_LINE_INTERPOLATION_STEP_CENTER_Y:
+ step = 3;
+ break;
+ default:
+ step = 1;
+ break;
+ }
+ seg = go_path_copy_restricted (paths[j], k * step, m * step);
+ k = m;
+ close_path = go_path_append (close_path, seg);
+ go_path_free (seg);
+ }
+ }
+ k++;
+ if (k < lengths[i]) {
+ if (close_path == NULL)
+ close_path = go_path_new ();
+ go_path_move_to (close_path, gog_axis_map_to_view (x_map, k), y_zero);
+ go_path_line_to (close_path, gog_axis_map_to_view (x_map, lengths[i]),
y_zero);
+ }
+ gog_renderer_fill_serie (view->renderer, paths[i], close_path);
+ gog_renderer_stroke_serie (view->renderer, close_path);
+ if (close_path != paths[j])
+ go_path_free (close_path);
+ gog_renderer_stroke_serie (view->renderer, paths[i]);
+ gog_renderer_pop_style (view->renderer);
+ }
+ for (i = 0; i < num_series; i++) {
+ if (lengths[i] == 0)
+ continue;
+ go_path_free (paths[i]);
+ }
+ } else {
+ GOPath *path;
+ for (i = 0; i < num_series; i++) {
+ if (lengths[i] == 0)
+ continue;
+ path = gog_chart_map_make_path (chart_map, NULL, yvals[i], lengths[i],
+ interpolations[i], type != GOG_1_5D_NORMAL &&
!is_area_plot,
+ &GOG_AREA_SERIES (series[i])->clamped_derivs);
- gog_renderer_push_style (view->renderer, styles[i]);
+ gog_renderer_push_style (view->renderer, styles[i]);
- if (!is_area_plot) {
- gog_renderer_stroke_serie (view->renderer, path);
- go_path_free (path);
- } else {
- if (type == GOG_1_5D_NORMAL || last_path == NULL) {
+ if (!is_area_plot) {
+ gog_renderer_stroke_serie (view->renderer, path);
+ go_path_free (path);
+ } else {
GOPath *close_path = go_path_new ();
go_path_move_to (close_path, gog_axis_map_to_view (x_map, 1), y_zero);
go_path_line_to (close_path, gog_axis_map_to_view (x_map, lengths[i]),
y_zero);
gog_renderer_fill_serie (view->renderer, path, close_path);
gog_renderer_stroke_serie (view->renderer, close_path);
go_path_free (close_path);
- } else {
- gog_renderer_fill_serie (view->renderer, path, last_path);
- go_path_free (last_path);
+ gog_renderer_stroke_serie (view->renderer, path);
+ go_path_free (path);
}
- gog_renderer_stroke_serie (view->renderer, path);
- last_path = path;
+ gog_renderer_pop_style (view->renderer);
}
-
- gog_renderer_pop_style (view->renderer);
- }
- if (last_path)
- go_path_free (last_path);
+}
/*Now draw drop lines */
for (i = 0; i < num_series; i++)
@@ -1057,6 +1321,7 @@ gog_line_view_class_init (GogViewClass *view_klass)
line_view_parent_klass = (GogViewClass*) g_type_class_peek_parent (view_klass);
view_klass->render = gog_line_view_render;
view_klass->size_allocate = gog_line_view_size_allocate;
+ ((GogPlotViewClass *) view_klass)->get_data_at_point = gog_line_view_get_data_at_point;
}
GSF_DYNAMIC_CLASS (GogLineView, gog_line_view,
diff --git a/plugins/plot_xy/gog-xy.c b/plugins/plot_xy/gog-xy.c
index 7fbf915..a4a9062 100644
--- a/plugins/plot_xy/gog-xy.c
+++ b/plugins/plot_xy/gog-xy.c
@@ -897,7 +897,6 @@ static int
gog_xy_view_get_data_at_point (GogPlotView *view, double x, double y, GogSeries **series)
{
Gog2DPlot const *model = GOG_2D_PLOT (view->base.model);
- unsigned num_series;
GogChart *chart = GOG_CHART (view->base.model->parent);
GogChartMap *chart_map;
GogAxisMap *x_map, *y_map;
@@ -912,8 +911,7 @@ gog_xy_view_get_data_at_point (GogPlotView *view, double x, double y, GogSeries
GogSeriesElement *gse;
GList *overrides; /* not const because we call g_list_* which have no const equivalent */
- for (num_series = 0, ptr = model->base.series ; ptr != NULL ; ptr = ptr->next, num_series++);
- if (num_series < 1)
+ if (g_slist_length (model->base.series) < 1)
return -1;
area = gog_chart_view_get_plot_area (view->base.parent);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]