[anjuta] foocanvas: Implement cubic B-curve to smoothen lines
- From: Naba Kumar <naba src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [anjuta] foocanvas: Implement cubic B-curve to smoothen lines
- Date: Sat, 8 May 2010 11:38:08 +0000 (UTC)
commit 9b0083753b12275717c28daf62fd9c3538daf5ff
Author: Naba Kumar <naba gnome org>
Date: Sat May 8 13:34:33 2010 +0300
foocanvas: Implement cubic B-curve to smoothen lines
libfoocanvas/foo-canvas-line.c | 91 +++++++++++++++++++++++++++++++++++++++-
libfoocanvas/foo-canvas-line.h | 1 +
2 files changed, 90 insertions(+), 2 deletions(-)
---
diff --git a/libfoocanvas/foo-canvas-line.c b/libfoocanvas/foo-canvas-line.c
index 570ead1..5a1600e 100644
--- a/libfoocanvas/foo-canvas-line.c
+++ b/libfoocanvas/foo-canvas-line.c
@@ -254,6 +254,7 @@ foo_canvas_line_init (FooCanvasLine *line)
line->shape_b = 0.0;
line->shape_c = 0.0;
line->spline_steps = DEFAULT_SPLINE_STEPS;
+ line->line_smoothed = FALSE;
}
static void
@@ -661,6 +662,7 @@ foo_canvas_line_set_property (GObject *object,
/* Since the line's points have changed, we need to re-generate arrowheads in
* addition to recalculating the bounds.
*/
+ line->line_smoothed = FALSE;
foo_canvas_item_request_update (item);
break;
@@ -744,11 +746,15 @@ foo_canvas_line_set_property (GObject *object,
break;
case PROP_SMOOTH:
- /* FIXME */
+ line->smooth = g_value_get_boolean (value);
+ line->line_smoothed = FALSE;
+ foo_canvas_item_request_update (item);
break;
case PROP_SPLINE_STEPS:
- /* FIXME */
+ line->spline_steps = g_value_get_int (value);
+ line->line_smoothed = FALSE;
+ foo_canvas_item_request_update (item);
break;
case PROP_ARROW_SHAPE_A:
@@ -1010,6 +1016,84 @@ item_to_canvas (FooCanvas *canvas, double *item_coords, GdkPoint *canvas_coords,
}
}
+/**
+ * Implements a cubic B-curve. 4 consecutive points are taken at a time to
+ * build the curve segments. Any remaining points at the end that don't form
+ * a curve are just joined as line segments.
+ *
+ * The process modifies the line points of the canvas item. So after this, the
+ * points are no longer what user originally supplied. The curve is computed
+ * once before a draw and reused, until influencial properties are modified
+ * (points, smooth, spline_steps properties of the canvas item). So, make sure
+ * when these properties are modified, line->line_smoothed is reset to FALSE
+ * so that next draw would recalculate it.
+ *
+ * Algorithm: see http://en.wikipedia.org/wiki/Bezier_curve
+ */
+static void
+foo_canvas_line_smooth (FooCanvasLine *line)
+{
+ gint curr_point = 0;
+ gint num_points = 0;
+ gdouble *line_points;
+
+ if (line->line_smoothed)
+ return;
+
+ if (!line->smooth || line->num_points <= 2)
+ {
+ line->line_smoothed = TRUE;
+ return;
+ }
+
+ line_points = g_new (gdouble, 2 * ((line->num_points - 1) * line->spline_steps));
+ while (curr_point < (line->num_points - 3))
+ {
+ gint step;
+ gdouble p0_x, p0_y, p1_x, p1_y, p2_x, p2_y, p3_x, p3_y;
+ p0_x = line->coords[2 * curr_point];
+ p0_y = line->coords[2 * curr_point + 1];
+ p1_x = line->coords[2 * (curr_point + 1)];
+ p1_y = line->coords[2 * (curr_point + 1) + 1];
+ p2_x = line->coords[2 * (curr_point + 2)];
+ p2_y = line->coords[2 * (curr_point + 2) + 1];
+ p3_x = line->coords[2 * (curr_point + 3)];
+ p3_y = line->coords[2 * (curr_point + 3) + 1];
+ for (step = 0; step < line->spline_steps; step++)
+ {
+ gdouble q0_x, q0_y, q1_x, q1_y, q2_x, q2_y;
+ gdouble r0_x, r0_y, r1_x, r1_y;
+
+ q0_x = p0_x + (p1_x - p0_x) * step / line->spline_steps;
+ q0_y = p0_y + (p1_y - p0_y) * step / line->spline_steps;
+ q1_x = p1_x + (p2_x - p1_x) * step / line->spline_steps;
+ q1_y = p1_y + (p2_y - p1_y) * step / line->spline_steps;
+ q2_x = p2_x + (p3_x - p2_x) * step / line->spline_steps;
+ q2_y = p2_y + (p3_y - p2_y) * step / line->spline_steps;
+
+ r0_x = q0_x + (q1_x - q0_x) * step / line->spline_steps;
+ r0_y = q0_y + (q1_y - q0_y) * step / line->spline_steps;
+ r1_x = q1_x + (q2_x - q1_x) * step / line->spline_steps;
+ r1_y = q1_y + (q2_y - q1_y) * step / line->spline_steps;
+
+ line_points[2 * num_points] = r0_x + (r1_x - r0_x) * step / line->spline_steps;
+ line_points[2 * num_points + 1] = r0_y + (r1_y - r0_y) * step / line->spline_steps;
+ num_points++;
+ }
+ curr_point += 3;
+ }
+ for (; curr_point < line->num_points; curr_point++)
+ {
+ line_points[2 * num_points] = line->coords[2 * curr_point];
+ line_points[2 * num_points + 1] = line->coords[2 * curr_point + 1];
+ num_points++;
+ }
+ line->line_smoothed = TRUE;
+ g_free (line->coords);
+ line->coords = line_points;
+ line->num_points = num_points;
+}
+
static void
foo_canvas_line_draw (FooCanvasItem *item, GdkDrawable *drawable,
GdkEventExpose *event)
@@ -1025,6 +1109,9 @@ foo_canvas_line_draw (FooCanvasItem *item, GdkDrawable *drawable,
if (line->num_points == 0)
return;
+ /* Smooth the line, if not yet done */
+ foo_canvas_line_smooth (FOO_CANVAS_LINE (line));
+
/* Build array of canvas pixel coordinates */
if (line->num_points <= NUM_STATIC_POINTS)
diff --git a/libfoocanvas/foo-canvas-line.h b/libfoocanvas/foo-canvas-line.h
index 42dfd74..f77c065 100644
--- a/libfoocanvas/foo-canvas-line.h
+++ b/libfoocanvas/foo-canvas-line.h
@@ -134,6 +134,7 @@ struct _FooCanvasLine {
guint first_arrow : 1; /* Draw first arrowhead? */
guint last_arrow : 1; /* Draw last arrowhead? */
guint smooth : 1; /* Smooth line (with parabolic splines)? */
+ gboolean line_smoothed : 1; /* If smooth == TRUE, has the line been smoothened */
};
struct _FooCanvasLineClass {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]