Clone in a terminal:
Commit 1fe0b77
Johan Mattsson - 2015-04-03T06:51:37+00:00
1fe0b777c2750797fa380596dbbf0e8fa310d058johan.mattsson.m@gmail.com

Split path before creating stroke

Changed files (3)

Diff

diff --git a/libbirdfont/Line.vala b/libbirdfont/Line.valaindex 4ce9dbd..113f158 100644--- a/libbirdfont/Line.vala+++ b/libbirdfont/Line.vala@@ -16,7 +16,7 @@ using Cairo;  namespace BirdFont { -/** Help line */+/** Guide */ public class Line : GLib.Object { 	public static const bool VERTICAL = true; 	public static const bool HORIZONTAL = false;diff --git a/libbirdfont/PenTool.vala b/libbirdfont/PenTool.valaindex 65804d1..a6ff78e 100644--- a/libbirdfont/PenTool.vala+++ b/libbirdfont/PenTool.vala@@ -1004,6 +1004,88 @@ public class PenTool : Tool { 		return m;	 	} 	+	public static Path merge_open_paths (Path path1, Path path2) {+		Path union, merge;+		EditPoint first_point;+		+		return_if_fail (path1.points.size > 1);+		return_if_fail (path2.points.size > 1);++		union = path1.copy ();+		merge = path2.copy ();++		merge.points.get (0).set_tie_handle (false);+		merge.points.get (0).set_reflective_handles (false);+		+		merge.points.get (merge.points.size - 1).set_tie_handle (false);+		merge.points.get (merge.points.size - 1).set_reflective_handles (false);+						+		union.points.get (union.points.size - 1).set_tie_handle (false);+		union.points.get (union.points.size - 1).set_reflective_handles (false);++		union.points.get (0).set_tie_handle (false);+		union.points.get (0).set_reflective_handles (false);+				+		first_point = merge.get_first_point ();+		+		if (union.get_last_point ().get_left_handle ().is_curve ()) {+			first_point.get_left_handle ().convert_to_curve ();+		} else {+			first_point.get_left_handle ().convert_to_line ();+		}+		+		first_point.get_left_handle ().move_to_coordinate_internal (+			union.get_last_point ().get_left_handle ().x,+			union.get_last_point ().get_left_handle ().y);++		union.delete_last_point ();+		+		union.append_path (merge);+		+		return union;+	}+	+	public static void close_path (Path path) {+		Path? p;+		EditPoint first_point;+		bool last_segment_is_line;+		bool first_segment_is_line;+		+		return_if_fail (path.points.size > 1);++		last_segment_is_line = path.get_last_point ().get_left_handle ().is_line ();+		first_segment_is_line = path.get_first_point ().get_right_handle ().is_line ();+		+		// TODO: set point type+		path.points.get (0).left_handle.move_to_coordinate (+			path.points.get (path.points.size - 1).left_handle.x,+			path.points.get (path.points.size - 1).left_handle.y);+			+		path.points.get (0).left_handle.type = +			path.points.get (path.points.size - 1).left_handle.type;++		path.points.get (0).recalculate_linear_handles ();+		path.points.get (path.points.size - 1).recalculate_linear_handles ();+		+		// force the connected handle to move+		path.points.get (0).set_position (+			path.points.get (0).x, path.points.get (0).y);+	+		path.points.remove_at (path.points.size - 1);+		+		path.close ();++		if (last_segment_is_line) {+			path.get_first_point ().get_left_handle ().convert_to_line ();+			path.get_first_point ().recalculate_linear_handles ();+		}++		if (first_segment_is_line) {+			path.get_first_point ().get_right_handle ().convert_to_line ();+			path.get_first_point ().recalculate_linear_handles ();+		}+	}	+	 	private static void join_paths (double x, double y) { 		Glyph glyph = MainWindow.get_current_glyph (); 		Path? p;@@ -1024,8 +1106,8 @@ public class PenTool : Tool { 			warning ("No path to join."); 			return; 		}+		 		path = (!) p;- 		if (!path.is_open ()) { 			warning ("Path is closed."); 			return;@@ -1053,56 +1135,19 @@ public class PenTool : Tool { 		if (is_endpoint ((!) active_edit_point) 			&& is_close_to_point (path.points.get (0), px, py)) { 			-			last_segment_is_line = path.get_last_point ().get_left_handle ().is_line ();-			first_segment_is_line = path.get_first_point ().get_right_handle ().is_line ();-			-			// TODO: set point type-			path.points.get (0).left_handle.move_to_coordinate (-				path.points.get (path.points.size - 1).left_handle.x,-				path.points.get (path.points.size - 1).left_handle.y);-				-			path.points.get (0).left_handle.type = -				path.points.get (path.points.size - 1).left_handle.type;--			path.points.get (0).recalculate_linear_handles ();-			path.points.get (path.points.size - 1).recalculate_linear_handles ();-			-			// force the connected handle to move-			path.points.get (0).set_position (-				path.points.get (0).x, path.points.get (0).y);-		-			path.points.remove_at (path.points.size - 1);-			-			path.close ();+			close_path (path); 			glyph.close_path ();--			if (last_segment_is_line) {-				path.get_first_point ().get_left_handle ().convert_to_line ();-				path.get_first_point ().recalculate_linear_handles ();-			}--			if (first_segment_is_line) {-				path.get_first_point ().get_right_handle ().convert_to_line ();-				path.get_first_point ().recalculate_linear_handles ();-			}+			force_direction (); 			- 			force_direction ();- 			if (direction_changed) { 				path.reverse (); 				update_selection (); 			} 			 			remove_all_selected_points ();- 			return; 		} 		-		union = new Path ();-		foreach (EditPoint ep in path.points) {-			union.add_point (ep.copy ());-		}-				 		foreach (Path merge in glyph.path_list) { 			// don't join path with itself here 			if (path == merge) {@@ -1123,35 +1168,9 @@ public class PenTool : Tool { 			return_if_fail (merge.points.size > 0);  			if (is_close_to_point (merge.points.get (0), px, py)) {-				merge.points.get (0).set_tie_handle (false);-				merge.points.get (0).set_reflective_handles (false);-				-				merge.points.get (merge.points.size - 1).set_tie_handle (false);-				merge.points.get (merge.points.size - 1).set_reflective_handles (false);-								-				path.points.get (path.points.size - 1).set_tie_handle (false);-				path.points.get (path.points.size - 1).set_reflective_handles (false);+				union = merge_open_paths (path, merge);  -				path.points.get (0).set_tie_handle (false);-				path.points.get (0).set_reflective_handles (false);-				-				second_path = merge.copy ();-				-				first_point = second_path.get_first_point ();-				-				if (union.get_last_point ().get_left_handle ().is_curve ()) {-					first_point.get_left_handle ().convert_to_curve ();-				} else {-					first_point.get_left_handle ().convert_to_line ();-				}-				-				first_point.get_left_handle ().move_to_coordinate_internal (union.get_last_point ().get_left_handle ().x, union.get_last_point ().get_left_handle ().y);--				union.delete_last_point ();-				-				union.append_path (second_path); 				glyph.add_path (union);-				 				glyph.delete_path (path); 				glyph.delete_path (merge); 				glyph.clear_active_paths ();diff --git a/libbirdfont/StrokeTool.vala b/libbirdfont/StrokeTool.valaindex 246a790..5ef0a42 100644--- a/libbirdfont/StrokeTool.vala+++ b/libbirdfont/StrokeTool.vala@@ -79,7 +79,17 @@ public class StrokeTool : Tool { 		return pl;	 	} 	-	public static PathList get_stroke_outline (Path p, double thickness) {+	public static PathList get_stroke_outline (Path path, double thickness) {+		PathList pl = new PathList ();+		+		foreach (Path p in get_parts (path).paths) {+			pl.append (get_strokes (p, thickness));+		}+		+		return pl;+	}+	+	public static PathList get_strokes (Path p, double thickness) { 		Path counter, outline; 		Path merged; 		PathList paths = new PathList ();@@ -90,7 +100,8 @@ public class StrokeTool : Tool { 			outline.close (); 			 			parts = remove_intersections (outline, thickness, p);-			+			parts = merge (parts);+					 			foreach (Path sp in parts.paths) { 				paths.add (sp); 				sp.update_region_boundaries ();@@ -112,19 +123,18 @@ public class StrokeTool : Tool { 			} 			 			parts = remove_intersections (outline, thickness, p);-			 			foreach (Path sp in parts.paths) { 				paths.add (sp); 				sp.update_region_boundaries (); 			}--			parts = remove_intersections (counter, thickness, p); 			+			parts = remove_intersections (counter, thickness, p); 			foreach (Path sp in parts.paths) { 				paths.add (sp); 				sp.update_region_boundaries (); 			}-		} else if (p.is_open ()) {+			+		} else if (p.is_open ()) { // FIXME: this can create many parts 			outline = create_stroke (p, thickness); 			counter = create_stroke (p, -1 * thickness); 			merged = merge_strokes (p, outline, counter, thickness);@@ -136,6 +146,7 @@ public class StrokeTool : Tool { 			}  			parts = remove_intersections (merged, thickness, p);+			parts = merge (parts); 			 			foreach (Path sp in parts.paths) { 				paths.add (sp);@@ -329,7 +340,7 @@ public class StrokeTool : Tool {  	static PathList remove_intersections (Path path, double thickness, Path original) { 		PathList parts;-		+ 		parts = get_parts (path); 		delete_intersection_parts (original, parts, thickness); 		@@ -370,7 +381,7 @@ public class StrokeTool : Tool { 	/** Split one path at intersection points in two parts. */ 	static PathList split (Path path) { 		PathList pl;-		int i = 0;+		int i;  		if (!has_intersection_points (path)) { 			add_self_intersection_points (path);@@ -378,13 +389,7 @@ public class StrokeTool : Tool { 			warning ("points already created."); 		} 		-		foreach (EditPoint p in path.points) {-			if ((p.flags & EditPoint.INTERSECTION) > 0) {-				p.deleted = true;-				i++;-				// FIXME: delete p.color = new Color (1, 1, 0, 1);-			} -		}+		i = mark_intersection_as_deleted (path); 		 		if (!(i == 0 || i == 2)) { 			warning (@"Split should only create two parts, $i points will be deleted.");@@ -641,6 +646,7 @@ public class StrokeTool : Tool { 		}		 	} 	+	/** @return true if the part is inside of the stroke of the path */ 	static bool is_stroke (Path original, Path part, double stroke_width) { 		double stroke_size = fabs (stroke_width); 		bool stroke = false;@@ -663,6 +669,89 @@ public class StrokeTool : Tool { 		 		return stroke; 	}+	+	static PathList merge (PathList pl) {+		Path merged;+		+		foreach (Path p1 in pl.paths) {+			foreach (Path p2 in pl.paths) {+				if (merge_path (p1, p2, out merged)) {+					//pl.paths.remove (p1);+					//pl.paths.remove (p2);+					pl.add (merged);+					return pl;+				}+			}+		}+		+		return pl;+	}++	static int mark_intersection_as_deleted (Path path) {+		int i = 0;+		+		foreach (EditPoint p in path.points) {+			if ((p.flags & EditPoint.INTERSECTION) > 0) {+				p.deleted = true;+				i++;+				// FIXME: delete p.color = new Color (1, 1, 0, 1);+			} +		}+		+		return i;+	}++	/** @return true if the two paths can be merged. */+	static bool merge_path (Path path1, Path path2, out Path merged) {+		PathList pl1, pl2;+		Path p1, p2;+		int i;+		+		merged = new Path ();+		+		if (add_intersection_points (path1, path2)) {+			i = mark_intersection_as_deleted (path1);+			return_if_fail (i == 1);++			i = mark_intersection_as_deleted (path2);+			return_if_fail (i == 1);+			+			pl1 = get_remaining_points (path1.copy ());+			pl2 = get_remaining_points (path2.copy ());+			+			return_if_fail (pl1.paths.size == 1);+			return_if_fail (pl2.paths.size == 1);+			+			p1 = pl1.paths.get (0);+			p2 = pl2.paths.get (0);+			+			merged = PenTool.merge_open_paths (p1, p2);+			+			return true;+		}+		+		return false;+	}++	static bool add_intersection_points (Path path1, Path path2) {+		bool intersection = false;++		path1.all_segments ((ep1, ep2) => {+			double ix, iy;+			EditPoint p1, p2;+			+			if (segment_intersects (path2, ep1, ep2, out ix, out iy, out p1, out p2)) {				+				add_intersection (path1, ep1, ep2, ix, iy);+				add_intersection (path2, p1, p2, ix, iy); +				intersection = true;+				return false;+			}+			+			return true;+		});+		+		return intersection;+	} }  }

Contact

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