Re: Canvas smooth lines?



On Thu, 25 Mar 1999, Federico Mena Quintero wrote:

> >  Hi, I'm wondering if it is OK to touch the head branch of gnome-libs
> >  to implement the smooth canvas lines (in gnome_canvas_line_point)?
> >  I assume that the smooth_steps would cover the whole polyline (or would
> >  it be only one segment)?
> 
> If you want to do this, please do it as closely as possible as Tk does
> it.  Basically it creates parabolic splines for each group of three
> points.
> 
> If you implement this, would you mind if I take a look at the patch
> before putting it on cvs?

Oops, here's the patch.

	Tuomas

? gnome-data/postscript.convert
? libgnorba/GnomeObject.h
? libgnorba/GnomeObject-common.c
? libgnorba/GnomeObject-stubs.c
? libgnorba/GnomeObject-skels.c
? libgnorba/Table.h
? libgnorba/Table-common.c
? libgnorba/Table-stubs.c
? libgnorba/Table-skels.c
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gnome-libs/ChangeLog,v
retrieving revision 1.390
diff -u -r1.390 ChangeLog
--- ChangeLog	1999/03/26 00:16:34	1.390
+++ ChangeLog	1999/03/27 13:02:35
@@ -1,3 +1,8 @@
+1999-03-27  Tuomas J. Lukka  <lukka@iki.fi>
+
+	*  implemented canvas splines
+
+
 1999-03-25  Federico Mena Quintero  <federico@nuclecu.unam.mx>
 
 	* configure.in: Bumped version number to 1.0.5.
Index: libgnomeui/gnome-canvas-line.c
===================================================================
RCS file: /cvs/gnome/gnome-libs/libgnomeui/gnome-canvas-line.c,v
retrieving revision 1.37
diff -u -r1.37 gnome-canvas-line.c
--- gnome-canvas-line.c	1999/01/18 17:50:16	1.37
+++ gnome-canvas-line.c	1999/03/27 13:02:36
@@ -181,6 +181,9 @@
 	if (line->coords)
 		g_free (line->coords);
 
+	if (line->orig_coords && line->orig_coords != line->coords) 
+		g_free (line->orig_coords);
+
 	if (line->first_coords)
 		g_free (line->first_coords);
 
@@ -336,6 +339,101 @@
 	gnome_canvas_group_child_bounds (GNOME_CANVAS_GROUP (item->parent), item);
 }
 
+static void
+bezierpoints ( double cx[4], double cy[4], int n,
+				 double *res )
+{
+	int i;
+	for(i=0; i<n; i++) {
+		double r = i/(double)n;
+		double r2 = r*r;
+		double r3 = r2*r;
+		double f = 1-r;
+		double f2 = f*f;
+		double f3 = f2*f;
+		res[0] = f3*cx[0] + 3*f2*r*cx[1] + 3*f*r2*cx[2] + r3*cx[3];
+		res[1] = f3*cy[0] + 3*f2*r*cy[1] + 3*f*r2*cy[2] + r3*cy[3];
+		res += 2;
+	}
+}
+
+static void
+reconfigure_smoothing (GnomeCanvasLine *line)
+{
+	int i;
+	double cx[4];
+	double cy[4];
+
+	if(!line->smooth || line->orig_num_points <= 2) {
+		line->num_points = line->orig_num_points;
+		line->coords = line->orig_coords;
+		return;
+	}
+	if (line->orig_num_points == 0) {
+		line->num_points = 0;
+		line->coords = NULL;
+		return;
+	}
+
+	/* Handle smoothed lines by generating an expanded set ot points */
+
+	/* We have spline_steps segments inside each original
+	 * line segment, plus the end point 
+	 */
+	line->num_points = line->spline_steps * (line->orig_num_points - 2) + 1;
+	line->coords = g_malloc(2 * sizeof(*(line->coords)) * line->num_points);
+
+	/* Still need special case of closed lines */
+
+	for(i = 1; i < line->orig_num_points-1; i++) {
+		int ind = i*2;
+		/* Calculate control points */
+		if(i == 1) { 
+			cx[0] = line->orig_coords[ind-2];
+			cy[0] = line->orig_coords[ind-1];
+			cx[1] = 1/3.0 * line->orig_coords[ind-2] +
+				2/3.0 * line->orig_coords[ind];
+			cy[1] = 1/3.0 * line->orig_coords[ind-1] +
+				2/3.0 * line->orig_coords[ind+1];
+		} else {
+			/* Default case: use the previous point */
+			cx[0] = 1/2.0 * line->orig_coords[ind-2] +
+				1/2.0 * line->orig_coords[ind];
+			cy[0] = 1/2.0 * line->orig_coords[ind-1] +
+				1/2.0 * line->orig_coords[ind+1];
+			cx[1] = 1/6.0 * line->orig_coords[ind-2] +
+				5/6.0 * line->orig_coords[ind];
+			cy[1] = 1/6.0 * line->orig_coords[ind-1] +
+				5/6.0 * line->orig_coords[ind+1];
+		}
+		if(i == line->orig_num_points-2) {
+			cx[2] = 2/3.0 * line->orig_coords[ind] +
+				1/3.0 * line->orig_coords[ind+2];
+			cy[2] = 2/3.0 * line->orig_coords[ind+1] +
+				1/3.0 * line->orig_coords[ind+3];
+			cx[3] = line->orig_coords[ind+2];
+			cy[3] = line->orig_coords[ind+3];
+		} else {
+			/* Default case: use the next point */
+			cx[2] = 5/6.0 * line->orig_coords[ind] +
+				1/6.0 * line->orig_coords[ind+2];
+			cy[2] = 5/6.0 * line->orig_coords[ind+1] +
+				1/6.0 * line->orig_coords[ind+3];
+			cx[3] = 1/2.0 * line->orig_coords[ind] +
+				1/2.0 * line->orig_coords[ind+2];
+			cy[3] = 1/2.0 * line->orig_coords[ind+1] +
+				1/2.0 * line->orig_coords[ind+3];
+		}
+		bezierpoints(cx, cy, 
+			line->spline_steps, 
+			line->coords + 2 * (i-1) * line->spline_steps
+		);
+	}
+	line->coords[2*(i-1)*line->spline_steps] = line->orig_coords[i*2];
+	line->coords[2*(i-1)*line->spline_steps+1] = line->orig_coords[i*2+1];
+
+}
+
 /* Recalculates the arrow polygons for the line */
 static void
 reconfigure_arrows (GnomeCanvasLine *line)
@@ -563,6 +661,7 @@
 static void
 gnome_canvas_line_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
 {
+	int smoothed;
 	GnomeCanvasItem *item;
 	GnomeCanvasLine *line;
 	GnomeCanvasPoints *points;
@@ -576,17 +675,25 @@
 	case ARG_POINTS:
 		points = GTK_VALUE_POINTER (*arg);
 
+		/* Discard both the smoothed and original coordinates */
+		smoothed = (line->coords != line->orig_coords);
 		if (line->coords) {
 			g_free (line->coords);
 			line->coords = NULL;
 		}
+		line->num_points = 0;
 
+		if (line->orig_coords && smoothed) {
+			g_free (line->orig_coords);
+			line->orig_coords = NULL;
+		}
+
 		if (!points)
-			line->num_points = 0;
+			line->orig_num_points = 0;
 		else {
-			line->num_points = points->num_points;
-			line->coords = g_new (double, 2 * line->num_points);
-			memcpy (line->coords, points->coords, 2 * line->num_points * sizeof (double));
+			line->orig_num_points = points->num_points;
+			line->orig_coords = g_new (double, 2 * line->orig_num_points);
+			memcpy (line->orig_coords, points->coords, 2 * line->orig_num_points * sizeof (double));
 		}
 
 		/* Drop the arrowhead polygons if they exist -- they will be regenerated */
@@ -720,13 +827,25 @@
 		break;
 
 	case ARG_SMOOTH:
-		/* FIXME */
+		line->smooth = GTK_VALUE_BOOL (*arg);
+#ifdef OLD_XFORM
+		reconfigure_smoothing (line);
+#else
+		gnome_canvas_item_request_update (item);
+#endif
 		break;
 
 	case ARG_SPLINE_STEPS:
-		/* FIXME */
+		line->smooth = GTK_VALUE_UINT (*arg);
+#ifdef OLD_XFORM
+		reconfigure_smoothing (line);
+#else
+		gnome_canvas_item_request_update (item);
+#endif
 		break;
 
+
+
 	case ARG_ARROW_SHAPE_A:
 		line->shape_a = fabs (GTK_VALUE_DOUBLE (*arg));
 #ifdef OLD_XFORM
@@ -770,9 +889,9 @@
 
 	switch (arg_id) {
 	case ARG_POINTS:
-		if (line->num_points != 0) {
-			points = gnome_canvas_points_new (line->num_points);
-			memcpy (points->coords, line->coords, 2 * line->num_points * sizeof (double));
+		if (line->orig_num_points != 0) {
+			points = gnome_canvas_points_new (line->orig_num_points);
+			memcpy (points->coords, line->orig_coords, 2 * line->orig_num_points * sizeof (double));
 			GTK_VALUE_POINTER (*arg) = points;
 		} else
 			GTK_VALUE_POINTER (*arg) = NULL;
@@ -909,6 +1028,7 @@
 	if (parent_class->update)
 		(* parent_class->update) (item, affine, clip_path, flags);
 
+	reconfigure_smoothing (line);
 	reconfigure_arrows (line);
 
 	if (item->canvas->aa) {
@@ -1130,15 +1250,9 @@
 	*actual_item = item;
 
 	best = 1.0e36;
-
-	/* Handle smoothed lines by generating an expanded set ot points */
 
-	if (line->smooth && (line->num_points > 2)) {
-		/* FIXME */
-	} else {
-		num_points = line->num_points;
-		line_points = line->coords;
-	}
+	num_points = line->num_points;
+	line_points = line->coords;
 
 	/* Compute a polygon for each edge of the line and test the point against it.  The effective
 	 * width of the line is adjusted so that it will be at least one pixel thick (so that zero
Index: libgnomeui/gnome-canvas-line.h
===================================================================
RCS file: /cvs/gnome/gnome-libs/libgnomeui/gnome-canvas-line.h,v
retrieving revision 1.10
diff -u -r1.10 gnome-canvas-line.h
--- gnome-canvas-line.h	1999/01/01 07:51:39	1.10
+++ gnome-canvas-line.h	1999/03/27 13:02:36
@@ -78,7 +78,11 @@
 				 * refer to the necks of the arrowheads rather than their tips.  The
 				 * actual endpoints are stored in the first_arrow and last_arrow
 				 * arrays, if they exist.
+				 * Smoothed coordinates are placed in this array
+				 * although this may refer to the same memory as orig_coords
 				 */
+	int orig_num_points;	/* Original number of points */
+	double * orig_coords;   /* Original coordinates before smoothing */
 
 	double width;		/* Width of the line */
 
Index: test-gnome/canvas-primitives.c
===================================================================
RCS file: /cvs/gnome/gnome-libs/test-gnome/canvas-primitives.c,v
retrieving revision 1.18
diff -u -r1.18 canvas-primitives.c
--- canvas-primitives.c	1999/03/26 12:37:45	1.18
+++ canvas-primitives.c	1999/03/27 13:02:38
@@ -623,6 +623,62 @@
 }
 
 static void
+setup_curves (GnomeCanvasGroup *root)
+{
+	GnomeCanvasPoints *points;
+
+	/* x: 400..600 y: 150..300 */
+	points = gnome_canvas_points_new (5);
+	points->coords[0] = 550.0;
+	points->coords[1] = 170.0;
+	points->coords[2] = 450.0;
+	points->coords[3] = 170.0;
+	points->coords[4] = 400.0;
+	points->coords[5] = 230.0;
+	points->coords[6] = 450.0;
+	points->coords[7] = 270.0;
+	points->coords[8] = 550.0;
+	points->coords[9] = 270.0;
+	setup_item (gnome_canvas_item_new (root,
+					   gnome_canvas_line_get_type (),
+					   "points", points,
+					   "fill_color", "black",
+					   "width_units", 8.0,
+					   "first_arrowhead", TRUE,
+					   "last_arrowhead", TRUE,
+					   "arrow_shape_a", 8.0,
+					   "arrow_shape_b", 12.0,
+					   "arrow_shape_c", 4.0,
+					   "smooth", TRUE,
+					   NULL));
+	gnome_canvas_points_free (points);
+
+	points = gnome_canvas_points_new (5);
+	points->coords[0] = 550.0;
+	points->coords[1] = 170.0;
+	points->coords[2] = 450.0;
+	points->coords[3] = 170.0;
+	points->coords[4] = 400.0;
+	points->coords[5] = 230.0;
+	points->coords[6] = 450.0;
+	points->coords[7] = 270.0;
+	points->coords[8] = 550.0;
+	points->coords[9] = 270.0;
+	setup_item (gnome_canvas_item_new (root,
+					   gnome_canvas_line_get_type (),
+					   "points", points,
+					   "fill_color", "white",
+					   "width_units", 2.0,
+					   "first_arrowhead", TRUE,
+					   "last_arrowhead", TRUE,
+					   "arrow_shape_a", 8.0,
+					   "arrow_shape_b", 12.0,
+					   "arrow_shape_c", 4.0,
+					   NULL));
+	gnome_canvas_points_free (points);
+}
+
+static void
 setup_polygons (GnomeCanvasGroup *root)
 {
 	GnomeCanvasPoints *points;
@@ -780,6 +836,7 @@
 	setup_texts (root);
 	setup_images (root, aa);
 	setup_lines (root);
+	setup_curves (root);
 	setup_polygons (root);
 	setup_widgets (root);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]