Clone in a terminal:
Commit 5a8d176
Johan Mattsson - 2013-03-04T14:21:08+00:00
5a8d176b07e20bed20ad55e71dab42b54cbfd87ajohan.mattsson.m@gmail.com

Convert cubic Bezier curves to TrueType outlines

Changed files (4)

Diff

diff --git a/libbirdfont/OpenFontFormat/GlyfData.vala b/libbirdfont/OpenFontFormat/GlyfData.valaindex c104be7..2e59ac4 100644--- a/libbirdfont/OpenFontFormat/GlyfData.vala+++ b/libbirdfont/OpenFontFormat/GlyfData.vala@@ -120,8 +120,6 @@ class GlyfData : GLib.Object { 		nflags = 0; 		 		foreach (Path p in paths) {-			p = p.get_quadratic_points ();-			 			foreach (EditPoint e in p.points) { 				flags.append (Coordinate.ON_PATH); 				nflags++;diff --git a/libbirdfont/Path.vala b/libbirdfont/Path.valaindex f06eb09..b4b6601 100644--- a/libbirdfont/Path.vala+++ b/libbirdfont/Path.vala@@ -985,53 +985,97 @@ public class Path { 	public Path get_quadratic_points () { 		EditPoint middle = new EditPoint (); 		unowned List<EditPoint> e;-		EditPointHandle eh; 		EditPointHandle last; 		EditPoint first; 		 		quadratic_path = copy ();-		-		last = quadratic_path.points.last ().data.get_right_handle ();-		if (last.type == PointType.QUADRATIC) {-			first = quadratic_path.points.first ().data;-			quadratic_path.points.append (first);-		}-		quadratic_path.close ();-/*				-		if (quadratic_path.points.length () < 2) {-			return quadratic_path;-		} -		// split all curves in as many regions as we need-		split_cubic_in_parts (quadratic_path);	+		// split all cubic curves in smaller sections	+		for (int i = 0; quadratic_path.split_cubic_curves (this); i++) {+			if (i == 5) {+				warning ("Too many points in converted path.");+				break;+			}+		}  		// estimate quatdratic form 		middle.prev = quadratic_path.points.last (); 		middle.next = quadratic_path.points.first ();--		convert_to_quadratic (quadratic_path, middle);+		+		if (middle.get_right_handle ().type == PointType.CUBIC) {+			convert_to_quadratic (quadratic_path, middle);+		} 		 		e = (!) quadratic_path.points.first (); 		while (e != quadratic_path.points.last ().prev) { 			middle.prev = e; 			middle.next = e.next; 			-			convert_to_quadratic (quadratic_path, middle);	+			if (middle.get_right_handle ().type == PointType.CUBIC) {+				convert_to_quadratic (quadratic_path, middle);+			}  			e = (!) e.next; 		}-		-		eh = ((!)quadratic_path.points.last ().prev).data.get_left_handle ();-		eh.set_point_type (PointType.NONE);-		eh.length = 0; -		eh = ((!)quadratic_path.points.last ().prev).data.get_right_handle ();-		eh.set_point_type (PointType.CUBIC);-		eh.length *= 1.6;-*/+		last = quadratic_path.points.last ().data.get_right_handle ();+		if (last.type == PointType.QUADRATIC) {+			first = quadratic_path.points.first ().data;+			quadratic_path.points.append (first);+		}+		quadratic_path.close ();+		 		return quadratic_path; 	}+	+	private bool split (Path cubic, EditPoint start, EditPoint stop) {+		double curve_x, curve_y, cx, cy, qx, qy, nx, ny, distance;+				+		estimate_quadratic (start, stop, out curve_x, out curve_y);+	+		qx = quadratic_bezier_path (0.75, start.x, curve_x, stop.x);+		qy = quadratic_bezier_path (0.75, start.y, curve_y, stop.y);++		cx = bezier_path (0.75, start.x, start.get_right_handle ().x (), stop.get_left_handle ().x (), stop.x);+		cy = bezier_path (0.75, start.y, start.get_right_handle ().y (), stop.get_left_handle ().y (), stop.y);++		distance = Math.sqrt (Math.pow (cx - qx, 2) + Math.pow (cy - qy, 2));++		nx = bezier_path (0.5, start.x, start.get_right_handle ().x (), stop.get_left_handle ().x (), stop.x);+		ny = bezier_path (0.5, start.y, start.get_right_handle ().y (), stop.get_left_handle ().y (), stop.y);++		if (Math.fabs (distance) > 0.01) {+			EditPoint new_edit_point = new EditPoint (nx, ny, PointType.CUBIC); +			new_edit_point.next = start.get_next ();+			new_edit_point.prev = start.get_next ().data.get_prev ();+			+			insert_new_point_on_path (new_edit_point);+			create_list ();++			return true;	+		}+		+		return false;+	}+	+	private bool split_cubic_curves (Path cubic) requires (points.length () > 2) {+		EditPoint start = points.last ().data;+		int i = 0;+		bool n = false;+		+		foreach (EditPoint stop in points) {+			if (start.get_right_handle ().type == PointType.CUBIC) {+				if (split (cubic, start, stop)) {+					n = true;+				}+			}+			start = stop;			+		}+		+		return n;+	}+	 	void convert_to_quadratic (Path cubic_path, EditPoint middle) { 		double curve_x, curve_y;	 		EditPointHandle eh;@@ -1046,7 +1090,7 @@ public class Path { 		eh.length = 0; 		 		eh = start.get_right_handle ();-		eh.set_point_type (PointType.CUBIC);+		eh.set_point_type (PointType.QUADRATIC); 		eh.move_to_coordinate (curve_x, curve_y); 	} @@ -1109,12 +1153,10 @@ public class Path { 		EditPoint start; 		EditPoint stop; 		PointType rt = middle.get_right_handle ().type;-		-		/* // FIXME: DELETE-		if (rt == PointType.QUADRATIC || rt == PointType.LINE_CUBIC || rt == PointType.LINE_QUADRATIC) {-			return false;++		if (rt != PointType.CUBIC) {+			warning ("Expecting cubic path"); 		}-		*/ 		 		start = middle.get_prev ().data; 		stop = middle.get_next ().data;diff --git a/libbirdfont/TestCases.vala b/libbirdfont/TestCases.valaindex 06317cf..926bec9 100644--- a/libbirdfont/TestCases.vala+++ b/libbirdfont/TestCases.vala@@ -531,27 +531,6 @@ class TestCases { 		 		EditPoint e0, e1, e2, e3; 		-		g = MainWindow.get_current_glyph ();-		-		// split_all_cubic_in_half-		foreach (Path gp in g.path_list) {-			gqp_points = gp.copy ();-			gqp_points.split_cubic_in_parts (gqp_points);-			gqp_points.move (50, 0);-			qpl.append (gqp_points);-		}-		-		// convert to quadratic points-		foreach (Path gp in g.path_list) {-			gqp = gp.get_quadratic_points ();-			gqp.move (100, 0);-			qpl.append (gqp);-		}--		foreach (Path gp in qpl) {-			g.add_path (gp);-		}- 		Tool.test_open_next_glyph (); 		 		g = MainWindow.get_current_glyph ();diff --git a/scripts/bavala.py b/scripts/bavala.pyindex cd315d5..7735ed0 100644--- a/scripts/bavala.py+++ b/scripts/bavala.py@@ -57,8 +57,8 @@ class Vala(object):         self.c = get_sources_path (src, '*.c') # copy regular c sources         self.cc = [join(build + '/' + src, f) for f in get_sources_name (src, '*.c') ]         self.cc += [join(build + '/' + src, f.replace('.vala', '.c')) for f in get_sources_name (src, '*.vala')]-        self.obj = [f.replace('.c', '.o') for f in get_sources_name (src, '*.c')]-        self.obj += [join(build, f.replace('.vala', '.o')) for f in get_sources_name (src, '*.vala')]+        self.obj = [self.build + '/' + self.src + '/' + f.replace('.c', '.o') for f in get_sources_name (src, '*.c')]+        self.obj += [self.build + '/' + self.src + '/' +  f.replace('.vala', '.o') for f in get_sources_name (src, '*.vala')]                  if library:             self.header = join(build, library) + '.h'

Contact

Email: johan.mattsson.m@gmail.com
Mastodon: typo.social/@birdfont
GitHub: johanmattssonm
LinkedIn: johan-mattsson-2ab324112