Clone in a terminal:
Commit 448aa3e
Johan Mattsson - 2014-03-17T17:10:35+00:00
448aa3e3fd52a864f124fd32f6fd646478865ecajohan.mattsson.m@gmail.com

Speed optimization of tangent point function

Changed files (8)

Diff

diff --git a/libbirdfont/DrawingTools.vala b/libbirdfont/DrawingTools.valaindex 1c8f48a..3f54ffc 100644--- a/libbirdfont/DrawingTools.vala+++ b/libbirdfont/DrawingTools.vala@@ -126,6 +126,10 @@ public class DrawingTools : ToolCollection  { 			if (track_tool.is_selected ()) { 				track_tool.set_stroke_width (object_stroke.get_value ()); 			}+			+			if (pen_tool.is_selected ()) {+				pen_tool.set_stroke_width (object_stroke.get_value ());+			} 		}); 		 		draw_tool_modifiers.add_tool (object_stroke);	diff --git a/libbirdfont/EditPoint.vala b/libbirdfont/EditPoint.valaindex d340afc..334719a 100644--- a/libbirdfont/EditPoint.vala+++ b/libbirdfont/EditPoint.vala@@ -389,6 +389,23 @@ public class EditPoint { 		return (!) next; 	} 	+	public unowned List<EditPoint>? get_link_item () {+		+		if (unlikely (prev == null && next == null)) {+			warning ("Need prev or next, create a list first.");+		}+		+		if (prev != null) {+			return ((!) prev).data.get_next ();+		}+		+		if (next != null) {+			return ((!) next).data.get_prev ();+		}+		+		return null;	+	}+	 	public unowned List<EditPoint> get_list () { 		return get_next ().first (); 	}diff --git a/libbirdfont/FileTab.vala b/libbirdfont/FileTab.valaindex ffb25ea..7e2c2a2 100644--- a/libbirdfont/FileTab.vala+++ b/libbirdfont/FileTab.vala@@ -24,7 +24,7 @@ public class FileTab : FontDisplay { 	double top = 60; 	WidgetAllocation allocation = new WidgetAllocation (); 	List<Font> recent_fonts = new List<Font> ();-	List<string> backups = new List<string> ();+	List<string> backups = new List<string> (); // FIXME: use ref counted object 	 	public signal void open_file (); 	@@ -160,7 +160,8 @@ public class FileTab : FontDisplay { 		}  		if (is_null (backups)) {-			warning ("No backups");+			// FIXME:+			// warning ("No backups"); 			return; 		} diff --git a/libbirdfont/Glyph.vala b/libbirdfont/Glyph.valaindex 10412aa..05fbe10 100644--- a/libbirdfont/Glyph.vala+++ b/libbirdfont/Glyph.vala@@ -962,7 +962,7 @@ public class Glyph : FontDisplay { 		} else { 			np = new Path (); 			path_list.append (np);-			np.add (xt, yt);+			np.add (xt, yt);			 		}	  		clear_active_paths ();@@ -1083,14 +1083,11 @@ public class Glyph : FontDisplay { 				p.close (); 			} 		}-		-		// FIXME: delete-		// clear_active_paths ();++		print ("CLOSE\n"); // FIXME: DELETE 		 		redraw_area (0, 0, allocation.width, allocation.height);-		 		open = false;-		 		return r; 	} @@ -1616,7 +1613,9 @@ public class Glyph : FontDisplay { 		return img; 	} -	/** Split curve in two parts and add a new point in between. */+	/** Split curve in two parts and add a new point in between.+	 * @return the new point+	 */ 	public void insert_new_point_on_path (double x, double y) { 		double min, distance; 		Path? p = null;diff --git a/libbirdfont/Path.vala b/libbirdfont/Path.valaindex 0c7f4ac..72745fe 100644--- a/libbirdfont/Path.vala+++ b/libbirdfont/Path.vala@@ -1341,7 +1341,6 @@ public class Path { 			return true; 		}); -		// this is a point on a line		 		if (right == PointType.LINE_QUADRATIC && left == PointType.LINE_QUADRATIC) { 			ep.get_right_handle ().set_point_type (PointType.LINE_QUADRATIC); 			ep.get_left_handle ().set_point_type (PointType.LINE_QUADRATIC);@@ -1438,6 +1437,11 @@ public class Path { 		EditPoint next; 		double step = 0; +		if (points.length () == 0) {+			warning ("Empty path.");+			return;+		}+ 		if (points.length () == 1) { 			edit_point.x = i.data.x; 			edit_point.y = i.data.y;@@ -1446,7 +1450,6 @@ public class Path { 			edit_point.next = i; 			 			exit = true;-			 			return; 		} 		@@ -1493,6 +1496,10 @@ public class Path { 			}); 		} +		if (previous_point == null && is_open ()) {+			previous_point = points.last ();+		}+		 		if (previous_point == null) { 			warning (@"previous_point == null, points.length (): $(points.length ())"); 			return;@@ -1616,7 +1623,7 @@ public class Path { 		}	 	} -	private void all_segments (SegmentIterator iter) {+	public void all_segments (SegmentIterator iter) { 		unowned List<EditPoint> i, next; 		 		if (points.length () < 2) {@@ -1644,6 +1651,7 @@ public class Path { 		}); 	} +	// FIXME: DELETE 	public void all_vectors (VectorIterator iter, int steps = -1) { 		all_segments ((start, stop) => { 			all_of (start, stop, (x, y, s) => {diff --git a/libbirdfont/PenTool.vala b/libbirdfont/PenTool.valaindex adea3df..603e324 100644--- a/libbirdfont/PenTool.vala+++ b/libbirdfont/PenTool.vala@@ -70,6 +70,8 @@ public class PenTool : Tool {  	static List<Path> clockwise; 	static List<Path> counter_clockwise;+	+	static double path_stroke_width = 0; 			 	public PenTool (string name) { 		string click_to_add_points;@@ -233,6 +235,12 @@ public class PenTool : Tool { 		}); 	} +	public void set_stroke_width (double width) {+		string w = SpinButton.convert_to_string (width);+		Preferences.set ("pen_tool_stroke_width", w);+		path_stroke_width = width;+	}+	 	/** @return true after the initial delay.*/ 	public static bool isResponding (int px, int py) { 		double d;@@ -1087,6 +1095,7 @@ public class PenTool : Tool { 	public static PointSelection add_new_edit_point (int x, int y) { 		Glyph glyph; 		PointSelection new_point;+		 		glyph = MainWindow.get_current_glyph (); 		 		new_point = glyph.add_new_edit_point (x, y);@@ -1098,6 +1107,8 @@ public class PenTool : Tool { 		set_point_type (selected_point); 		set_default_handle_positions (); 		+		new_point.path.set_stroke (path_stroke_width);+		 		return new_point; 	} diff --git a/libbirdfont/StrokeTool.vala b/libbirdfont/StrokeTool.valaindex 6c25b76..14be4f6 100644--- a/libbirdfont/StrokeTool.vala+++ b/libbirdfont/StrokeTool.vala@@ -51,49 +51,163 @@ public class StrokeTool : Tool { 	} 	 	public static Path get_stroke (Path p, double thickness) {+		Path counter, outline, merged;+		+		if (!p.is_open ()) {+			merged = create_stroke (p, thickness);+		} else {+			outline = create_stroke (p, thickness);+			counter = create_stroke (p, -1 * thickness);+			merged = merge_strokes (outline, counter);+		}+		+		return merged;+	}+	+	/** Create one stroke from the outline and counter stroke and close the +	 * open endings.+	 */+	static Path merge_strokes (Path stroke, Path counter) {+		Glyph g;+		Path merged = stroke.copy ();++		if (stroke.points.length () < 3) {+			warning ("Missing points.");+			return merged;+		}++		if (counter.points.length () < 3) {+			warning ("Missing points.");+			return merged;+		}+						+		counter.reverse ();+		+		counter.get_last_point ().get_right_handle ().convert_to_line ();+		counter.get_first_point ().get_left_handle ().convert_to_line ();++		merged.get_last_point ().get_right_handle ().convert_to_line ();+		merged.get_first_point ().get_left_handle ().convert_to_line ();+				+		merged.append_path (counter);+		merged.close ();+		merged.recalculate_linear_handles ();+		+		return merged;+	}+	+	static Path create_stroke (Path p, double thickness) { 		Path new_path; 		Path stroked;  		new_path = add_tangent_points (p);-		stroked = change_stroke_width (new_path, thickness);-				-		stroked.reverse (); 		-		if (p.is_open ()) {-			remove_end_corner (stroked);+		if (new_path.points.length () >= 2) {+			stroked = change_stroke_width (new_path, thickness);++			if (p.is_open ()) {+				remove_end_corner (stroked);+			} else {+				stroked.reverse ();+				stroked.close ();+			} 		} else {-			stroked.close ();+			// TODO: create stroke for path with one point+			stroked = new Path (); 		} 		 		return stroked; 	}  	static void remove_end_corner (Path stroked) {-		if (stroked.points.length () < 2) {-			warning ("points < 2");+		if (stroked.points.length () < 4) {+			warning ("points < 4"); 			return; 		} 		 		stroked.points.remove_link (stroked.points.last ()); 		stroked.points.remove_link (stroked.points.last ());+		+		//stroked.points.remove_link (stroked.points.first ());+		stroked.points.remove_link (stroked.points.first ()); 	}  	static Path add_tangent_points (Path p) {-		Path new_path = p.copy ();+		Path path = p.copy (); 		int steps = 4;-				-		p.all_of_path ((x, y, step) => {-				EditPoint ep = new EditPoint ();-				-				if (step != 0 && step != 1) {-					new_path.get_closest_point_on_path (ep, x, y);-					new_path.insert_new_point_on_path (ep);-				}+		List<EditPoint> new_points = new List<EditPoint> ();+		+		EditPoint nep;+		EditPoint? previous = null;+		+		path.all_segments ((start, stop) => {+			EditPoint? prev = null;+			Path.all_of (start, stop, (x, y, step) => {+					EditPoint ep = new EditPoint ();++					if (0 < step < 1) {+						//new_path.get_closest_point_on_path (ep, x, y);+						ep.set_position (x, y);+						+						// Stop processing when the first hidden point is found.+						if (start.type == PointType.HIDDEN || stop.type == PointType.HIDDEN) {+							return false;+						}+						+						return_val_if_fail (prev != null, false);++						ep.prev = ((!) prev).get_link_item ();+						ep.next = start.get_next ();+						+						if (unlikely (ep.next == null || ep.prev == null)) {+							warning ("No points on segment.");+							return false;+						}++						new_points.append (ep);+					}+					+					if (step <= 0) {+						prev = start;+						new_points.append (start);+					} else if (step >= 1) {+						prev = stop;+						new_points.append (stop);+					} else {+						prev = ep;+					}+					+					return true;+				}, steps); 				 				return true;-			}, steps);+			});++		while (new_points.length () > 0) {+			nep = new_points.first ().data;+			+			if (previous != null) {+				nep.prev = ((!) previous).get_link_item ();+			} 			-		return new_path;+			if (!path.has_point (nep)) {+				path.insert_new_point_on_path (nep);+				return_if_fail (nep.prev != null);+			}+			+			previous = nep;++			new_points.remove_link (new_points.first ());+			path.create_list ();+		}+		+		while (path.points.length () > 0 && path.points.last ().data.type == PointType.HIDDEN) {+			path.delete_last_point ();+		}+		+		path.create_list ();+		+		return path; 	}  	/** Shrink or expand the outline. */@@ -118,19 +232,24 @@ public class StrokeTool : Tool { 		k = 0; 		npoints = new_path.points.length (); 		-		foreach (EditPoint e in new_path.points) {	+		if (npoints < 2) {+			warning ("npoints < 2");+			return new_path;+		}+		+		foreach (EditPoint e in new_path.points) { 			ep = e.copy (); 			 			get_new_position (e, clockwise, thickness, out nx, out ny);  			end_point = (k == 0 || k == npoints - 1); 			k++;--			if (k == 0) {-				-			} else {+			+			if (ep.type != PointType.HIDDEN) { 				ep.x = nx; 				ep.y = ny;+			} else {+				break; 			} 			 			if (e.is_corner ()) {@@ -139,7 +258,7 @@ public class StrokeTool : Tool { 				stroked.add_point (corner1); 				 				corner2 = e.copy ();-				stroked.get_closest_point_on_path (corner2, nx, ny);+				stroked.get_closest_point_on_path (corner2, nx, ny); // FIXME: optimize  				if (end_point) { 					swap_corner = corner1;diff --git a/libbirdfont/TrackTool.vala b/libbirdfont/TrackTool.valaindex 5f2f8f1..372ba49 100644--- a/libbirdfont/TrackTool.vala+++ b/libbirdfont/TrackTool.vala@@ -69,7 +69,9 @@ public class TrackTool : Tool { 				 				if (join_paths) { 					ps = get_path_with_end_point (x, y);-					return_if_fail (ps != null);+					if (unlikely (ps == null)) {+						warning ("No end point.");+					} 					end_point = (!) ps; 					if (end_point.is_first ()) { 						end_point.path.reverse ();@@ -214,7 +216,7 @@ public class TrackTool : Tool { 			glyph.update_view (); 	} -	public static Path merge_paths (Path a, PointSelection b) {+	private static Path merge_paths (Path a, PointSelection b) { 		Glyph g; 		Path merged = a.copy (); 

Contact

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