Clone in a terminal:
Commit bb5c3f9
Johan Mattsson - 2013-02-09T19:16:59+00:00
bb5c3f9986b5e23b7a3b7ae1e7c52da1d5c26a4cjohan.mattsson.m@gmail.com

quadratic control points

Changed files (10)

Diff

diff --git a/libbirdfont/EditPoint.vala b/libbirdfont/EditPoint.valaindex 24ae2d0..a75b80a 100644--- a/libbirdfont/EditPoint.vala+++ b/libbirdfont/EditPoint.vala@@ -24,6 +24,7 @@ public enum PointType { 	NORMAL, 	LINE, 	CURVE,+	QUADRATIC, 	DOUBLE_CURVE, 	END, 	FLOATINGdiff --git a/libbirdfont/EditPointHandle.vala b/libbirdfont/EditPointHandle.valaindex 13d3a51..8a6b322 100644--- a/libbirdfont/EditPointHandle.vala+++ b/libbirdfont/EditPointHandle.vala@@ -111,7 +111,7 @@ public class EditPointHandle  { 		 		return p; 	}-	+ 	public void move_to_coordinate (double x, double y) { 		double a, b, c; diff --git a/libbirdfont/Font.vala b/libbirdfont/Font.valaindex 521334b..3c16e43 100644--- a/libbirdfont/Font.vala+++ b/libbirdfont/Font.vala@@ -1378,7 +1378,8 @@ public class Font : GLib.Object { 		bool r;  		if (unlikely (unicode.index_of ("U+") != 0)) {-			warning ("All unicode values must begin with U+");+			warning (@"All unicode values must begin with U+ ($unicode");+			return '\0'; 		} 		 		while (r = unicode.get_next_char (ref index, out c)) {diff --git a/libbirdfont/Glyph.vala b/libbirdfont/Glyph.valaindex 2db088d..be7c71f 100644--- a/libbirdfont/Glyph.vala+++ b/libbirdfont/Glyph.vala@@ -1275,8 +1275,6 @@ public class Glyph : FontDisplay { 	 	public void draw_path (Context cr) { 		double left, baseline;--		// plot_outline (cr); 			 		baseline = get_line ("baseline").pos; 		left = get_line ("left").pos;diff --git a/libbirdfont/ImportSvg.vala b/libbirdfont/ImportSvg.valaindex 86bdc4e..153ad0c 100644--- a/libbirdfont/ImportSvg.vala+++ b/libbirdfont/ImportSvg.vala@@ -168,13 +168,18 @@ public class ImportSvg { 		data = data.replace ("V", " V "); 		data = data.replace ("l", " l "); 		data = data.replace ("L", " L ");+		data = data.replace ("q", " q ");+		data = data.replace ("Q", " Q ");		 		data = data.replace ("c", " c "); 		data = data.replace ("C", " C ");+		data = data.replace ("t", " t ");+		data = data.replace ("T", " T "); 		data = data.replace ("s", " s "); 		data = data.replace ("S", " S "); 		data = data.replace ("zM", " z M "); 		data = data.replace ("zm", " z m "); 		data = data.replace ("z", " z ");+		data = data.replace ("Z", " Z "); 		data = data.replace ("-", " -"); 		data = data.replace ("e -", "e-"); // minus can be either separator or a negative exponent 		data = data.replace ("\t", " ");@@ -348,7 +353,7 @@ public class ImportSvg { 					py = cy;					 				}	 			}-			+						 			if (c[i] == "c") { 				while (is_point (c[i + 1])) { 					command[ci++] = "C";@@ -406,7 +411,10 @@ public class ImportSvg { 					} else { 						cy = -parse_double (c[++i]); 					}-					++					px2 = cx;+					py2 = cy;+										 					p[pi++] = cx; 					p[pi++] = cy; 					@@ -437,6 +445,135 @@ public class ImportSvg { 				}	 			} +			// quadratic+			if (c[i] == "q") {+				while (is_point (c[i + 1])) {+					command[ci++] = "Q";+					+					cx = px + parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = py + parse_double (c[++i]);+					} else {+						cy = py + -parse_double (c[++i]);+					}+					+					p[pi++] = cx;+					p[pi++] = cy;+					+					px2 = cx;+					py2 = cy;+										+					cx = px + parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = py + parse_double (c[++i]);+					} else {+						cy = py + -parse_double (c[++i]);+					}+					+					p[pi++] = cx;+					p[pi++] = cy;+					+					px = cx;+					py = cy;+				}+			}+			+			if (c[i] == "Q") {++				while (is_point (c[i + 1])) {+					command[ci++] = "Q";+					+					cx = parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = parse_double (c[++i]);+					} else {+						cy = -parse_double (c[++i]);+					}+					+					p[pi++] = cx;+					p[pi++] = cy;++					px2 = cx;+					py2 = cy;+										+					cx = parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = parse_double (c[++i]);+					} else {+						cy = -parse_double (c[++i]);+					}+					+					p[pi++] = cx;+					p[pi++] = cy;+					+					px = cx;+					py = cy;			+				}	+			}++			if (c[i] == "t") {+				while (is_point (c[i + 1])) {+					command[ci++] = "Q";+					+					// the first point is the reflection+					cx = 2 * px - px2;+					cy = 2 * py - py2; // if (svg_glyph) ?+					+					p[pi++] = cx;+					p[pi++] = cy;++					px2 = cx;+					py2 = cy;+										+					cx = px + parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = py + parse_double (c[++i]);+					} else {+						cy = py + -parse_double (c[++i]);+					}+					+					px = cx;+					py = cy;+					+					p[pi++] = px;+					p[pi++] = py;+				}+			}++			if (c[i] == "T") {+				while (is_point (c[i + 1])) {+					command[ci++] = "Q";+					+					// the reflection+					cx = 2 * px - px2;+					cy = 2 * py - py2; // if (svg_glyph) ?+					p[pi++] = cx;+					p[pi++] = cy;++					px2 = cx;+					py2 = cy;+					+					cx = parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = parse_double (c[++i]);+					} else {+						cy = -parse_double (c[++i]);+					}+					+					px = cx;+					py = cy;+					+					p[pi++] = px;+					p[pi++] = py;					+				}+			}+ 			if (c[i] == "s") { 				while (is_point (c[i + 1])) { 					command[ci++] = "C";@@ -529,13 +666,17 @@ public class ImportSvg {  		Path path = new Path (); 		-		// move+		// move and resize 		if (svg_glyph) {+			// resize all points+			for (int i = 0; i < pi; i++) {+				p[i] *= units;+			}+			+			// move only y  			for (int i = 0; i < pi; i += 2) {-				p[i] *= units; 						// TODO: test it. 				p[i] += glyph.left_limit;-				//p[i+1] += font.top_position;-				p[i+1] -= font.base_line; 	// FIXME: is the font at the baseline?+				p[i+1] -= font.base_line; 			} 		} else { 			for (int i = 0; i < pi; i += 2) {@@ -563,7 +704,31 @@ public class ImportSvg { 			if (command[i] == "L") { 				path.add (p[ic++], p[ic++]); 			}-						+			+			if (command[i] == "Q") {+				x0 = p[ic++];+				y0 = p[ic++];+				x1 = p[ic++];+				y1 = p[ic++];++				if (is_null (path.points.last ().data)) {+					warning ("Paths must begin with M");+					return;+				}+				+				ep1 = path.points.last ().data;+				ep1.recalculate_linear_handles ();+				ep1.get_right_handle ().type = PointType.QUADRATIC;+				ep1.get_right_handle ().move_to_coordinate (x0, y0);	++				path.add (x1, y1);++				ep2 = path.points.last ().data;+				ep2.recalculate_linear_handles ();+				ep2.get_left_handle ().type = PointType.QUADRATIC;+				ep2.get_left_handle ().move_to_coordinate (x0, y0);				+			}+					 			if (command[i] == "C") { 				x0 = p[ic++]; 				y0 = p[ic++];diff --git a/libbirdfont/Path.vala b/libbirdfont/Path.valaindex 37bccdf..e7e4863 100644--- a/libbirdfont/Path.vala+++ b/libbirdfont/Path.vala@@ -210,7 +210,11 @@ public class Path { 		 		cr.line_to (xa, ya); // this point makes sense only if it is the first or last position, the other points are meaning less don't export them -		cr.curve_to (xb, yb, xc, yc, xd, yd);+		if (en.get_right_handle ().type == PointType.QUADRATIC) {+			cr.curve_to ((xa + 2 * xb) / 3, (ya + 2 * yb) / 3, (xd + 2 * xb) / 3, (yd + 2 * yb) / 3, xd, yd);		+		} else {+			cr.curve_to (xb, yb, xc, yc, xd, yd);+		} 	} 	 	/** Curve relative to window center. */@@ -299,7 +303,7 @@ public class Path { 			draw_img_center (cr, img_right, e.get_right_handle ().x (), e.get_right_handle ().y ()); 		} 		-		if (!(is_open () && e == points.first ().data)) {+		if (!(is_open () && e == points.first ().data) && e.get_left_handle ().type != PointType.QUADRATIC) { 			draw_line (handle_left, e, cr, 0.15); 			draw_img_center (cr, img_left, e.get_left_handle ().x (), e.get_left_handle ().y ()); 		}@@ -966,7 +970,7 @@ public class Path { 		eh.length = 0;  		eh = ((!)quadratic_path.points.last ().prev).data.get_right_handle ();-		eh.set_point_type (PointType.CURVE);+		eh.set_point_type (PointType.QUADRATIC); 		eh.length *= 1.6;  		return quadratic_path;@@ -986,7 +990,7 @@ public class Path { 		eh.length = 0; 		 		eh = start.get_right_handle ();-		eh.set_point_type (PointType.CURVE);+		eh.set_point_type (PointType.QUADRATIC); 		eh.move_to_coordinate (curve_x, curve_y); 	} diff --git a/libbirdfont/PenTool.vala b/libbirdfont/PenTool.valaindex 05b578d..7a2752a 100644--- a/libbirdfont/PenTool.vala+++ b/libbirdfont/PenTool.vala@@ -171,14 +171,16 @@ public class PenTool : Tool { 		 		// move curve handles 		if (move_selected_handle) {+			if (selected_handle.type == PointType.LINE) {+				selected_handle.set_point_type (PointType.CURVE); // TODO: quadratic+			}+				 			if (GridTool.is_visible ()) { 				coordinate_x = Glyph.path_coordinate_x (x); 				coordinate_y = Glyph.path_coordinate_y (y); 				GridTool.tie_coordinate (ref coordinate_x, ref coordinate_y);-				selected_handle.set_point_type (PointType.CURVE); 				selected_handle.move_to_coordinate (coordinate_x, coordinate_y); 			} else {-				selected_handle.set_point_type (PointType.CURVE); 				selected_handle.move_delta ((x - last_point_x) * precision, (y - last_point_y) * precision); 			} 			diff --git a/libbirdfont/Svg.vala b/libbirdfont/Svg.valaindex 34d5c17..7811e10 100644--- a/libbirdfont/Svg.vala+++ b/libbirdfont/Svg.vala@@ -78,13 +78,19 @@ class Svg { 	}  	private static void add_abs_next (EditPoint start, EditPoint end, StringBuilder svg, Glyph g, bool do_glyph) {+		if (end.get_left_handle ().type == PointType.QUADRATIC) {+			add_quadratic_abs_path (end, start, svg, g, do_glyph);+		}+		 		if (start.right_handle.type == PointType.LINE && end.left_handle.type == PointType.LINE) { 			add_abs_line_to (end, start, svg, g, do_glyph);-		} else if (end.get_left_handle ().type == PointType.NONE) {-			add_quadratic_abs_path (end, start, svg, g, do_glyph);-		} else {+		} else if (end.get_left_handle ().type == PointType.CURVE) { 			add_cubic_abs_path (end, start, svg, g, do_glyph); 		}++		if (end.get_left_handle ().type == PointType.NONE) {+			warning ("No point type.");+		} 	}  	private static void add_abs_start (EditPoint ep, StringBuilder svg, Glyph g, bool to_glyph) {		@@ -142,6 +148,8 @@ class Svg {  		double center_x = Glyph.xc (); 		double center_y = Glyph.yc ();++		// FIXME xc or xd, right or left handle?: 		 		// cubic path 		if (!to_glyph) {@@ -150,8 +158,8 @@ class Svg { 			svg.append_printf ("%s ", round (xb - center_x - left)); 			svg.append_printf ("%s ", round (yb - center_y - baseline + height)); 			-			svg.append_printf ("%s ", round (xc - center_x - left));-			svg.append_printf ("%s ", round (yc - center_y - baseline + height));+			svg.append_printf ("%s ", round (xd - center_x - left));+			svg.append_printf ("%s ", round (yd - center_y - baseline + height));  		} else {		 			svg.append_printf ("Q");@@ -159,8 +167,8 @@ class Svg { 			svg.append_printf ("%s ", round (xb - center_x - left)); 			svg.append_printf ("%s ", round (-yb + center_y + baseline)); 			-			svg.append_printf ("%s ", round (xc - center_x - left));-			svg.append_printf ("%s ", round (-yc + center_y + baseline));	+			svg.append_printf ("%s ", round (xd - center_x - left));+			svg.append_printf ("%s ", round (-yd + center_y + baseline));	 		} 	} 			@@ -207,13 +215,16 @@ class Svg { 	public static void draw_svg_path (Context cr, string svg, double x, double y) { 		double x1, x2, x3; 		double y1, y2, y3;-+		double px, py; 		string[] d = svg.split (" ");  		if (d.length == 0) { 			return; 		} 		+		px = 0;+		py = 0;+		 		cr.save ();  		cr.set_line_width (1);@@ -227,13 +238,16 @@ class Svg { 			 			// trim off leading white space	 			while (d[i].index_of (" ") == 0) { -				d[i] = d[i].substring (1);+				d[i] = d[i].substring (1); // FIXME: maybe no ascii 			} 			 			if (d[i].index_of ("L") == 0) { 				x1 = double.parse (d[i].substring (1)) + x; 				y1 = -double.parse (d[i+1]) + y; 				cr.line_to (x1, y1);+				+				px = x1;+				py = y1;			 				continue; 			} @@ -243,8 +257,11 @@ class Svg {  				x2 = double.parse (d[i+2]) + x; 				y2 = -double.parse (d[i+3]) + y;-																-				cr.curve_to (x1, y1, x2, y2, x2, y2);+											+				cr.curve_to ((px + 2 * x1) / 3, (py + 2 * y1) / 3, (x2 + 2 * x1) / 3, (y2 + 2 * y1) / 3, x2, y2);+				+				px = x2;+				py = y2; 				continue; 			} 			@@ -259,6 +276,9 @@ class Svg { 				y3 = -double.parse (d[i+5]) + y; 																 				cr.curve_to (x1, y1, x2, y2, x3, y3);+				+				px = x3;+				py = y3; 				continue; 			} @@ -267,6 +287,9 @@ class Svg { 				y1 = -double.parse (d[i+1]) + y; 				 				cr.move_to (x1, y1);++				px = x1;+				py = y1; 				continue; 			} 								@@ -277,6 +300,9 @@ class Svg { 				y1 = -double.parse (d[i+1]) + y; 				 				cr.move_to (x1, y1);++				px = x1;+				py = y1; 				continue; 			} diff --git a/libbirdfont/SvgFont.vala b/libbirdfont/SvgFont.valaindex 81b099a..6ff140f 100644--- a/libbirdfont/SvgFont.vala+++ b/libbirdfont/SvgFont.vala@@ -22,7 +22,8 @@ namespace Supplement { class SvgFont : GLib.Object { 	Font font; 	double units = 1;-		+	double font_advance = 0;+	 	public SvgFont (Font f) { 		this.font = f; 	}@@ -43,16 +44,13 @@ class SvgFont : GLib.Object { 	} 	 	void parse_svg_font (Xml.Node* node) {-		print ("parse_svg_font" + node->name + "\n"); 		for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {-			print (iter->name + "\n");-			 			if (iter->name == "defs") { 				parse_svg_font (iter); 			} 			 			if (iter->name == "font") {-				parse_font_name (iter);+				parse_font_tag (iter); 				parse_svg_font (iter); 			} @@ -73,6 +71,8 @@ class SvgFont : GLib.Object { 	void parse_hkern (Xml.Node* node) { 		string left = ""; 		string right = "";+		string left_name = "";+		string right_name = ""; 		double kerning = 0; 		unichar l, r; 		StringBuilder sl, sr;@@ -83,8 +83,6 @@ class SvgFont : GLib.Object { 			attr_name = prop->name; 			attr_content = prop->children->content; 			-			print (attr_name + "\n");-			 			// left 			if (attr_name == "u1") { 				left = attr_content;@@ -94,29 +92,37 @@ class SvgFont : GLib.Object { 			if (attr_name == "u2") { 				right = attr_content; 			}++			if (attr_name == "g1") {+				left_name = attr_content;+			} 			+			if (attr_name == "g2") {+				right_name = attr_content;+			}+				 			// kerning 			if (attr_name == "k") { 				kerning = double.parse (attr_content); 			}-			-			// TODO: ranges and sequences for u1 & u2 + g1 & g2 		} 		-		print ("L " + left + "\n");-		-		l = get_unichar (left);-		r = get_unichar (right);-		-		sl = new StringBuilder ();-		sl.append_unichar (l);-		-		print ("L " + sl.str + "\n"); 		-		sr = new StringBuilder ();-		sr.append_unichar (r);-		-		font.set_kerning (sl.str, sr.str, -kerning);+		// TODO: ranges and sequences for u1 & u2 + g1 & g2+		foreach (string lk in left.split (",")) {+			foreach (string rk in right.split (",")) {+				l = get_unichar (lk);+				r = get_unichar (rk);+				+				sl = new StringBuilder ();+				sl.append_unichar (l);+				+				sr = new StringBuilder ();+				sr.append_unichar (r);+				+				font.set_kerning (sl.str, sr.str, -kerning);				+			}+		} 	}  	void parse_font_limits (Xml.Node* node) {@@ -149,7 +155,7 @@ class SvgFont : GLib.Object { 		font.top_limit = top_limit; 	} 	-	void parse_font_name (Xml.Node* node) {+	void parse_font_tag (Xml.Node* node) { 		string attr_name = ""; 		string attr_content; 		@@ -157,6 +163,10 @@ class SvgFont : GLib.Object { 			attr_name = prop->name; 			attr_content = prop->children->content; 			+			if (attr_name == "horiz-adv-x") {+				font_advance = double.parse (attr_content);+			}+						 			if (attr_name == "id") { 				font.set_name (attr_content); 			}@@ -170,6 +180,10 @@ class SvgFont : GLib.Object { 		string v = val; 		unichar unicode_value; 		+		if (val == "&") {+			return '&';+		}+		 		// TODO: parse ligatures 		if (v.has_prefix ("&")) { 			// parse hex value@@ -192,7 +206,7 @@ class SvgFont : GLib.Object { 		string glyph_name = ""; 		string svg = ""; 		Glyph glyph;-		double advance = 100;+		double advance = font_advance;  		for (Xml.Attr* prop = node->properties; prop != null; prop = prop->next) { 			attr_name = prop->name;@@ -200,10 +214,7 @@ class SvgFont : GLib.Object {  			if (attr_name == "unicode") { 				unicode_value = get_unichar (attr_content);-				-				if (glyph_name == "") {-					glyph_name = attr_content;-				}+				glyph_name = attr_content; 			} 			 			// svg data@@ -212,12 +223,14 @@ class SvgFont : GLib.Object { 			} 			 			if (attr_name == "glyph-name") {-				glyph_name = attr_content;+				// use glyph value as name until ligatures is properly implemented+				if (glyph_name == "") {+					glyph_name = attr_content;+				} 			}  			if (attr_name == "horiz-adv-x") { 				advance = double.parse (attr_content);-				print (@"horiz-adv-x $advance\n"); 			} 		} 		diff --git a/libbirdfont/TestCases.vala b/libbirdfont/TestCases.valaindex 4fdc3ab..718af10 100644--- a/libbirdfont/TestCases.vala+++ b/libbirdfont/TestCases.vala@@ -45,6 +45,15 @@ class TestCases { 		add (test_spin_button, "Spin button"); 		add (test_inkscape_import, "Inkscape import"); 		add (test_illustrator_import, "Illustrator import");+		add (test_parse_quadratic_paths, "Quadratic paths");+	}++	public static void test_parse_quadratic_paths () {+		Glyph g;+		Tool.test_open_next_glyph ();+		g = MainWindow.get_current_glyph ();+		ImportSvg.parse_svg_data ("M20,300 Q400,50 600,300 T1000,300Q1200 50 1400 300Q1600 50 1800 600 L 1800 700 L 200 700 z", g);+		Toolbox.select_tool_by_name ("full_glyph"); 	}  	public static void test_illustrator_import () {

Contact

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