Clone in a terminal:
Commit a0571c6
Johan Mattsson - 2014-03-19T17:48:57+00:00
a0571c63a915f6725e267b7b948d1fb47d9766c7johan.mattsson.m@gmail.com

Stroke ends

Changed files (4)

Diff

diff --git a/libbirdfont/DrawingTools.vala b/libbirdfont/DrawingTools.valaindex b21eb2c..4345a11 100644--- a/libbirdfont/DrawingTools.vala+++ b/libbirdfont/DrawingTools.vala@@ -76,8 +76,11 @@ public class DrawingTools : ToolCollection  { 		draw_tools.add_tool (resize_tool);  		Tool stroke_tool = new StrokeTool ("stroke"); // create outline from path-		draw_tools.add_tool (stroke_tool); +		if (BirdFont.has_argument ("--test")) {+			draw_tools.add_tool (stroke_tool);+		}+		 		TrackTool track_tool = new TrackTool ("track"); // draw outline on free hand 		draw_tools.add_tool (track_tool); 		@@ -133,7 +136,9 @@ public class DrawingTools : ToolCollection  { 			} 		}); 		-		draw_tool_modifiers.add_tool (object_stroke);	+		if (BirdFont.has_argument ("--test")) {+			draw_tool_modifiers.add_tool (object_stroke);+		}  		// tie edit point handles 		Tool tie_handles = new Tool ("tie_point", t_("Tie curve handles for the selected edit point"), 'w');diff --git a/libbirdfont/PointSelection.vala b/libbirdfont/PointSelection.valaindex bb44854..d7b663e 100644--- a/libbirdfont/PointSelection.vala+++ b/libbirdfont/PointSelection.vala@@ -47,6 +47,16 @@ public class PointSelection : GLib.Object { 		return_val_if_fail (path.points.length () > 0, false); 		return path.points.first ().data == point; 	}++	/** @return true if this point is the last point in the path. */+	public bool is_last () {+		return_val_if_fail (path.points.length () > 0, false);+		return path.points.last ().data == point;+	}+	+	public bool is_endpoint () {+		return is_first () || is_last ();+	} }  }diff --git a/libbirdfont/StrokeTool.vala b/libbirdfont/StrokeTool.valaindex 40e0314..c0b4099 100644--- a/libbirdfont/StrokeTool.vala+++ b/libbirdfont/StrokeTool.vala@@ -28,7 +28,6 @@ public class StrokeTool : Tool { 	public static void set_stroke_for_selected_paths (double width) { 		Glyph g = MainWindow.get_current_glyph (); 		-		warning ("set_stroke_for_selected_paths"); 		foreach (Path p in g.active_paths) { 			p.set_stroke (width); 		}@@ -79,7 +78,7 @@ public class StrokeTool : Tool { 		} else if (p.is_open ()) { 			outline = create_stroke (p, thickness); 			counter = create_stroke (p, -1 * thickness);-			merged = merge_strokes (outline, counter);+			merged = merge_strokes (p, outline, counter, thickness); 			 			if (p.is_clockwise ()) { 				merged.force_direction (Direction.CLOCKWISE);@@ -98,37 +97,72 @@ public class StrokeTool : Tool { 	 	/** Create one stroke from the outline and counter stroke and close the  	 * open endings.+	 * +	 * @param path the path to create stroke for+	 * @param stroke for the outline of path+	 * @param stroke for the counter path 	 */-	static Path merge_strokes (Path stroke, Path counter) {+	static Path merge_strokes (Path path, Path stroke, Path counter, double thickness) { 		Path merged;--		if (stroke.points.length () < 3) {+		EditPoint corner1, corner2;+		EditPoint corner3, corner4;+		EditPoint new_corner1, new_corner2;+		EditPoint end;+		double angle;+		+		if (path.points.length () < 2) {+			warning ("Missing points.");+			return stroke;+		}+		+		if (stroke.points.length () < 4) { 			warning ("Missing points."); 			return stroke; 		} -		if (counter.points.length () < 3) {+		if (counter.points.length () < 4) { 			warning ("Missing points."); 			return stroke; 		}-						-		counter.reverse (); 		-		counter.points.remove_link (counter.points.first ());-		counter.points.remove_link (counter.points.last ());+		// end of stroke+		end = path.get_last_point ();+		corner1 = stroke.get_last_point ();+		angle = end.get_left_handle ().angle;+		corner1.x = end.x + cos (angle - PI / 2) * 2 * thickness;+		corner1.y = end.y + sin (angle - PI / 2) * 2 * thickness;		++		corner2 = counter.get_last_point ();+		corner2.x = end.x + cos (angle + PI / 2) * 2 * thickness;+		corner2.y = end.y + sin (angle + PI / 2) * 2 * thickness;++		// the other end+		end = path.get_first_point ();+		corner3 = stroke.get_first_point ();+		angle = end.get_right_handle ().angle;+		corner3.x = end.x + cos (angle + PI / 2) * 2 * thickness;+		corner3.y = end.y + sin (angle + PI / 2) * 2 * thickness;		++		corner4 = counter.get_first_point ();+		corner4.x = end.x + cos (angle - PI / 2) * 2 * thickness;+		corner4.y = end.y + sin (angle - PI / 2) * 2 * thickness;+		+		corner1.get_right_handle ().convert_to_line ();+		corner2.get_left_handle ().convert_to_line ();+		corner3.get_right_handle ().convert_to_line ();+		corner4.get_left_handle ().convert_to_line ();+				+		counter.reverse (); +		// Append the other part of the stroke 		merged = stroke.copy ();--		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);+		corner2 = merged.points.last ().data;+		+		merged.create_list (); 		merged.close (); 		merged.recalculate_linear_handles ();-		+								 		return merged; 	} 	@@ -141,9 +175,7 @@ public class StrokeTool : Tool { 		if (new_path.points.length () >= 2) { 			stroked = change_stroke_width (new_path, thickness); -			if (p.is_open ()) {-				remove_end_corner (stroked);-			} else {+			if (!p.is_open ()) { 				stroked.reverse (); 				stroked.close (); 			}@@ -156,19 +188,6 @@ public class StrokeTool : Tool { 		return stroked; 	} -	static void remove_end_corner (Path stroked) {-		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 tangents (Path p) { 		Path pn = p; 		for (int i = 0; i < 3; i++) {@@ -255,10 +274,6 @@ public class StrokeTool : Tool { 			path.create_list (); 		} 		-		while (path.points.length () > 0 && path.points.last ().data.type == PointType.HIDDEN) {-			path.delete_last_point ();-		}-		 		path.create_list (); 		 		return path;@@ -275,7 +290,8 @@ public class StrokeTool : Tool { 		uint k; 		uint npoints; 		double distance_to_counter, distance_to_path;-								+		PointSelection ps;+						 		clockwise = new_path.is_clockwise (); 		 		end_point = true;@@ -290,9 +306,9 @@ public class StrokeTool : Tool { 		foreach (EditPoint e in new_path.points) { 			ep = e.copy (); 			-			//get_new_position (e, clockwise, thickness, out nx, out ny);-			get_new_position_delta (e, clockwise, thickness, out dnx, out dny);-			get_new_position_delta (e, clockwise, thickness, out counter_dnx, out counter_dny);+			ps = new PointSelection (e, new_path);+			get_new_position_delta (ps, clockwise, thickness, out dnx, out dny);+			get_new_position_delta (ps, clockwise, thickness, out counter_dnx, out counter_dny); 				 			end_point = (k == 0 || k == npoints - 1); 			k++;@@ -300,38 +316,47 @@ public class StrokeTool : Tool { 			px = ep.x; 			py = ep.y; 			-			if (ep.type != PointType.HIDDEN) {+			if (!end_point) { 				ep.x += dnx; 				ep.y += dny;-			} else {+			}+			+			if (ep.type == PointType.HIDDEN) { 				break; 			} 			 			nx = ep.x; 			ny = ep.y; 			-			space_left = get_space_difference (e, e.get_prev ().data, thickness, clockwise);-			space_right = get_space_difference (e, e.get_next ().data, thickness, clockwise);+			space_left = get_space_difference (new_path, e, e.get_prev ().data, thickness, clockwise);+			space_right = get_space_difference (new_path, e, e.get_next ().data, thickness, clockwise); 		 			distance_to_counter = Path.distance (nx, px + counter_dnx, ny, py + counter_dny); 			distance_to_path = Path.distance (px, nx, py, ny); 			-			//print (@"$k:  $distance_to_path < $thickness\n");-			//print (@"$k  space_left + space_right  $(space_left + space_right)  $space_left + $space_right\n");-			-			if (distance_to_path >= fabs (2 * thickness) - 0.1) {-				ep.get_left_handle ().length += space_left / 3; -				ep.get_right_handle ().length += space_right / 3;-				stroked.add_point (ep);-			} else if (distance_to_path < fabs (2 * thickness) && (space_left + space_right) > 0) {-				add_corner_nodes (stroked, e, clockwise, thickness, end_point, nx, ny);-			} else if (distance_to_path < fabs (2 * thickness) && (space_left + space_right) < 0) {-				corner_position (e, clockwise, thickness, stroked);+			if (new_path.is_open () && end_point) {+				// open end point+				stroked.add (e.x, e.y);  			} else {-				ep.get_left_handle ().length += space_left / 3; -				ep.get_right_handle ().length += space_right / 3;-				stroked.add_point (ep);-				warning ("Stroke might become distorted");+				if (distance_to_path >= fabs (2 * thickness) - 0.1) {+					// smooth curve+					ep.get_left_handle ().length += space_left / 3; +					ep.get_right_handle ().length += space_right / 3;+					stroked.add_point (ep);+				} else if (distance_to_path < fabs (2 * thickness) && (space_left + space_right) > 0) {+					// sharp corner+					add_corner_nodes (new_path, stroked, e, clockwise, thickness, end_point, nx, ny);+				} else if (distance_to_path < fabs (2 * thickness) && (space_left + space_right) < 0) {+					if (!new_path.is_open () || (new_path.is_open () && !ps.is_endpoint ())) {+						// wide corner+						corner_position (e, clockwise, thickness, stroked);+					}+				} else {+					ep.get_left_handle ().length += space_left / 3; +					ep.get_right_handle ().length += space_right / 3;+					stroked.add_point (ep);+					warning ("Stroke might become distorted");+				} 			} 		} 	@@ -405,11 +430,12 @@ public class StrokeTool : Tool { 	}  	/** Sharp corner that need two extra points to be built. */-	public static void add_corner_nodes (Path stroked, EditPoint e, bool clockwise, double thickness, bool end_point, double nx, double ny) {+	public static void add_corner_nodes (Path path, Path stroked, EditPoint e, bool clockwise, double thickness, bool end_point, double nx, double ny) { 		double middle_x, middle_y; 		double corner_thickness_left, corner_thickness_right; 		double middle_point_position; 		EditPoint corner1, corner2, corner3, swap_corner;+		PointSelection ps; 		 		// add new points in order to preserve the stroke 		corner1 = e.copy ();@@ -438,25 +464,32 @@ public class StrokeTool : Tool {  		// fill the gap 		// FIXME: this should move the point not create a new point-		corner_position (e, clockwise, thickness, stroked);+		if (!path.is_open () || (path.is_open () && !end_point)) {+			corner_position (e, clockwise, thickness, stroked);+		}  	} -	public static void get_new_position (EditPoint e, bool clockwise, double thickness, out double strokex, out double strokey) {+	public static void get_new_position (PointSelection ps, bool clockwise, double thickness, out double strokex, out double strokey) { 		double sx, sy;-		get_new_position_delta (e, clockwise, thickness, out sx, out sy);-		strokex = sx + e.x;-		strokey = sy + e.y;	+		get_new_position_delta (ps, clockwise, thickness, out sx, out sy);+		strokex = sx + ps.point.x;+		strokey = sy + ps.point.y;	 	} -	static void get_new_position_delta (EditPoint e, bool clockwise, double thickness, out double strokex, out double strokey) {+	static void get_new_position_delta (PointSelection ps, bool clockwise, double thickness, out double strokex, out double strokey) { 			double ra, la; 			double avg_angle; 			double angle; 			 			double m, n, o, p; 			double ldnx, ldny;-						-			e.recalculate_linear_handles ();+			+			bool end_node = ps.is_first () || ps.is_last ();+			EditPoint e = ps.point;+			+			if (!end_node) {+				e.recalculate_linear_handles ();+			} 			 			ra = e.get_right_handle ().angle; 			la = e.get_left_handle ().angle;@@ -477,17 +510,22 @@ public class StrokeTool : Tool {  			ldnx = m + o; 			ldny = n + p;-			-			strokex = ldnx;-			strokey = ldny;++			if (end_node) {+				strokex = 0;+				strokey = 0;+			} else {+				strokex = ldnx;+				strokey = ldny;+			} 	} 	-	static double get_space_difference (EditPoint ep0, EditPoint ep1, double stroke, bool clockwise) {+	static double get_space_difference (Path p, EditPoint ep0, EditPoint ep1, double stroke, bool clockwise) { 		double p0x, p0y, p1x, p1y; 		double d1, d2; 		-		get_new_position (ep0, clockwise, stroke, out p0x, out p0y);-		get_new_position (ep1, clockwise, stroke, out p1x, out p1y);+		get_new_position (new PointSelection (ep0, p), clockwise, stroke, out p0x, out p0y);+		get_new_position (new PointSelection (ep1, p), clockwise, stroke, out p1x, out p1y); 		 		d1 = Path.distance (ep0.x, ep1.x, ep0.y, ep1.y); 		d2 = Path.distance (p0x, p1x, p0y, p1y);diff --git a/libbirdfont/TrackTool.vala b/libbirdfont/TrackTool.valaindex ce10911..d27b8bc 100644--- a/libbirdfont/TrackTool.vala+++ b/libbirdfont/TrackTool.vala@@ -153,7 +153,6 @@ public class TrackTool : Tool { 		string w = SpinButton.convert_to_string (width); 		Preferences.set ("free_hand_stroke_width", w); 		stroke_width = width;-		warning (@"W: $width\n"); 	}  	void add_endpoint_and_merge (int x, int y) {@@ -162,6 +161,7 @@ public class TrackTool : Tool { 			PointSelection? open_path = get_path_with_end_point (x, y); 			PointSelection joined_path; 			EditPoint ep;+			 			glyph = MainWindow.get_current_glyph (); 			 			if (glyph.path_list.length () == 0) {@@ -191,17 +191,11 @@ public class TrackTool : Tool { 				add_corner (x, y); 			} -			 			if (p.points.length () == 0) { 				warning ("No point."); 				return; 			}-			-			ep = p.get_first_point ();-			ep.process_tied_handle ();	-			ep.set_tie_handle (false);-			ep.recalculate_linear_handles ();-			+ 			p.create_list (); 			 			if (glyph.path_list.length () < 2) {@@ -222,7 +216,7 @@ public class TrackTool : Tool { 			} else { 				p.force_direction (Direction.CLOCKWISE); 			}-							+					 			glyph.update_view (); 	} @@ -478,7 +472,9 @@ public class TrackTool : Tool { 		px = Glyph.reverse_path_coordinate_x (nx); 		py = Glyph.reverse_path_coordinate_y (ny); 		average = PenTool.add_new_edit_point (px, py).point;-		average.set_tie_handle (true);+		+		// tie handles for all points except for the end points+		average.set_tie_handle (p.points.length () > 1);  		 		if (unlikely (p.points.length () == 0)) { 			warning ("No points.");@@ -486,8 +482,10 @@ public class TrackTool : Tool { 		} 		 		if (average.prev != null && average.get_prev ().data.tie_handles) {-			PenTool.convert_point_to_line (average.get_prev ().data, true);-			average.get_prev ().data.process_tied_handle ();+			if (p.points.length () > 2) {+				PenTool.convert_point_to_line (average.get_prev ().data, true);+				average.get_prev ().data.process_tied_handle ();+			} 		}  		added_points = 0;

Contact

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