Clone in a terminal:
Commit d5305e3
Johan Mattsson - 2012-08-28T00:18:04+00:00
d5305e3d6ae72c19985401bbd7ee031e13e55640johan.mattsson.m@gmail.com

merge paths

Changed files (12)

Diff

diff --git a/src/Argument.vala b/src/Argument.valaindex 50e210e..e967b27 100644--- a/src/Argument.vala+++ b/src/Argument.vala@@ -60,7 +60,7 @@ class Argument : GLib.Object { 			} 			 			// valid parameter-			if (a == "--autosave" || a == "--exit" || a == "--slow" || a == "--help" || a == "--test" || a == "--fatal-warning") {+			if (a == "--autosave" || a == "--exit" || a == "--slow" || a == "--help" || a == "--test" || a == "--fatal-warning" || a == "--show-coordinates") { 				prev = a; 				i++; 				continue;@@ -180,6 +180,8 @@ class Argument : GLib.Object { 		switch (p.get_char (1)) { 			case 'a':  				return "--autosave";+			case 'c':+				return "--show-coordinates"; 			case 'e':  				return "--exit"; 			case 'f': @@ -231,6 +233,7 @@ class Argument : GLib.Object { 		print_padded ("-h, --help", "show this message"); 		print_padded ("-s, --slow", "sleep between each command in test suite"); 		print_padded ("-t, --test [TEST]", "run test case");+		print_padded ("-c  --show-coordinates", "show coordinate in glyph view"); 		 		stdout.printf ("\n"); 	}diff --git a/src/ExportTool.vala b/src/ExportTool.valaindex 130164f..bb0df89 100644--- a/src/ExportTool.vala+++ b/src/ExportTool.vala@@ -383,16 +383,6 @@ os.put_string (""" 		ta.show_text (@"Wrote $file_name"); 		return true; 	}-	-	public override bool test () {-		this.yield ();-		return true;-	}--	public void test_view_result () {-		test ();-		view_result ();-	} }  }diff --git a/src/Glyph.vala b/src/Glyph.valaindex 69f31c3..a24a998 100644--- a/src/Glyph.vala+++ b/src/Glyph.vala@@ -93,6 +93,9 @@ class Glyph : FontDisplay {  	public List<Kerning> kerning = new List<Kerning> (); +	double motion_x = 0;+	double motion_y = 0;+	 	public Glyph (string name, unichar unichar_code = 0) { 		this.name = name; 		this.unichar_code = unichar_code;@@ -198,7 +201,7 @@ class Glyph : FontDisplay { 			if (p.ymax > y2) y2 = p.ymax; 		} 	}-+	 	/** @return centrum pixel for x coordinates. */ 	public static double xc () { 		return MainWindow.get_current_glyph ().allocation.width / 2.0;@@ -532,7 +535,12 @@ class Glyph : FontDisplay { 		 		t = MainWindow.get_toolbox ().get_current_tool (); 		t.move_action (t, (int) e.x, (int) e.y);-		++		if (Supplement.show_coordinates) {+			motion_x = e.x * ivz () - xc () + view_offset_x;+			motion_y = yc () - e.y * ivz () - view_offset_y;+		}+	 		help_line_event (e);	 	} 	@@ -1350,6 +1358,14 @@ class Glyph : FontDisplay { 		}		 	} 	+	private void draw_coordinate (Context cr) {+		cr.set_source_rgba (0.5, 0.5, 0.5, 1);+		cr.set_font_size (12);+		cr.move_to (0, 10);+		cr.show_text (@"($motion_x, $motion_y)");+		cr.stroke ();		+	}+	 	private void draw_path (Context cr) { 		double left, baseline; 		@@ -1395,14 +1411,11 @@ class Glyph : FontDisplay { 	} 	 	private void draw_help_lines (Context cr) {-		-		// lines  		foreach (Line line in get_all_help_lines ()) { 			cr.save (); 			line.draw (cr, allocation); 			cr.restore (); 		}-		 	} 	 	public override void draw (Allocation allocation, Context cr) {@@ -1420,6 +1433,10 @@ class Glyph : FontDisplay { 		draw_background_color (cr, 1); 		cr.restore (); +		if (Supplement.show_coordinates) {+			draw_coordinate (cmp);+		}+ 		if (show_help_lines) { 			cmp.save (); 			cmp.scale (view_zoom, view_zoom);diff --git a/src/IntersectionList.vala b/src/IntersectionList.valaindex 2d15631..f83a4e9 100644--- a/src/IntersectionList.vala+++ b/src/IntersectionList.vala@@ -25,7 +25,8 @@ class IntersectionList { 	public void add (Intersection i) { 		double d; 		Intersection l;-				+		bool close = false;+			 		if (points.length () == 0) { 			points.append (i); 			return;@@ -35,20 +36,34 @@ class IntersectionList { 			return; 		} 	-		l = ((!) points.last ()).data;-		d = Math.fabs (Math.sqrt (Math.pow (i.x - l.x, 2) + Math.pow (i.y - l.y, 2)));+		for (unowned List<Intersection> pl = points.first (); ; pl = pl.next) {+			l = pl.data;+			d = Math.fabs (Math.sqrt (Math.pow (i.x - l.x, 2) + Math.pow (i.y - l.y, 2))); -		if (l.distance >= i.distance) {-			points.remove_link (points.last ());+			if (l.distance >= i.distance) {+				close = true;+				+				if (d < 0.3) {+					points.remove_link (points.last ());+					points.append (i);+					return;+				}+			}+			+			if (pl == points.last ()) {+				break;+			}+		}+		+		if (!close) { 			points.append (i);-			return; 		}--		if (d < 0.3) {-			return;+	}+	+	public void clear () {+		while (points.length () > 0) {+			points.remove_link (points.first ()); 		}--		points.append (i); 	} 	 	public void remove_point (EditPoint e) {@@ -70,15 +85,19 @@ class IntersectionList { 	} 	 	bool has_point (Intersection i) {+		return has_point_at (i.x, i.y);+	}++	bool has_point_at (double x, double y) { 		foreach (Intersection n in points) {-			if (i.x == n.x && i.y == n.y) {+			if (x == n.x && y == n.y) { 				return true; 			} 		} 		 		return false; 	}-	+		 	public int get_point_index (EditPoint e) { 		int i = 0; 		foreach (Intersection n in points) {@@ -105,13 +124,14 @@ class IntersectionList { 	} 	 	public Intersection? get_intersection (EditPoint e) {+		Intersection? p = null; 		foreach (Intersection n in points) { 			if (n.editpoint_a == e || n.editpoint_b == e) {-				return n;+				assert (p == null);+				p = n; 			} 		}-		-		return null;+		return p; 	} 	 	public void append (IntersectionList i) {@@ -133,6 +153,7 @@ class IntersectionList { 			return il; 		} 		+		// find crossing paths 		a_start = p1.points.first (); 		for (int i = 0; i < p1.points.length (); i++) { 			@@ -150,27 +171,15 @@ class IntersectionList { 				} else { 					b_stop = b_start.data.get_next (); 				}-				-				//if (probably_intersecting (a_start.data, a_stop.data, b_start.data, b_stop.data)) {-					il.append (find_intersections (a_start.data, a_stop.data, b_start.data, b_stop.data));-				//}-				++				il.append (find_intersections (a_start.data, a_stop.data, b_start.data, b_stop.data));+ 				b_start = b_stop; 			} 			 			a_start = a_stop;-		} -/*-		foreach (Intersection inter in il.points) {-			e = new EditPoint ();-			p1.get_closest_point_on_path (e, inter.x, inter.y);-			inter.editpoint_a = e;--			e = new EditPoint ();-			p2.get_closest_point_on_path (e, inter.x, inter.y);-			inter.editpoint_b = e;-		}		-		*/+		}+		 		return il; 	} @@ -189,7 +198,7 @@ class IntersectionList { 				double d = Math.fabs (Math.sqrt (Math.pow (ax - bx, 2) + Math.pow (ay - by, 2))); 				 				if (d < 0.2) {-					il.add (new Intersection (ax, ay, 0));+					il.add (new Intersection (ax, ay, d)); 				} 				 				if (d < mind) mind = d;diff --git a/src/OverView.vala b/src/OverView.valaindex 8f6660d..b5df38c 100644--- a/src/OverView.vala+++ b/src/OverView.vala@@ -333,11 +333,6 @@ class OverView : FontDisplay { 				character_string = glyph_range.get_char ((uint32) index); 			} 			-			if (character_string == "") {-				warning (@"Got null character as name for glyph. Index: $index");-				// break;-			}-			 			cr.save (); 			draw_thumbnail (cr, character_string, x, y); 			cr.restore ();diff --git a/src/Path.vala b/src/Path.valaindex 0c7cc5c..b0a3b9f 100644--- a/src/Path.vala+++ b/src/Path.vala@@ -386,7 +386,7 @@ class Path { 				 				next = ((!)ed).data; 				-				if (is_over (ep.x, ep.y)) {+				if (is_over_coordinate (ep.x, ep.y)) { 					union.reverse (); 					return false; 				}@@ -742,37 +742,80 @@ class Path { 	} 	 	public bool is_over_coordinate (double x, double y) {+		return is_over_coordinate_var (x, y, 0.1);+	}+	+	public double distance (double ax, double bx, double ay, double by) {+		return Math.fabs (Math.sqrt (Math.pow (ax - bx, 2) + Math.pow (ay - by, 2)));+	}+	+	/** Variable precision */+	public bool is_over_coordinate_var (double x, double y, double precision) { 		List<EditPoint> ycoordinates = new List<EditPoint> (); 		double last = 0;-				-		if (!is_over_boundry (x, y)) {+		bool on_edge = false;+		double last_x = 0;+		+		if (points.length () == 0) {+			return false;+		}+		+		if (!is_over_boundry_precision (x, y, precision)) { 			return false; 		} +		foreach (EditPoint e in points) {+			if (distance (e.x, x, e.y, y) < precision) {+				return true;+			}+		}+ 		all_of_path ((cx, cy, ct) => {-			if (Math.fabs (cx - x) < 0.2 && Math.fabs (last - cy) > 1) {+			double distance = Math.fabs (Math.sqrt (Math.pow (cx - x, 2) + Math.pow (cy - y, 2)));+			+			if (distance < precision) {+				on_edge = true;+				return false;+			}+			+			if (Math.fabs (cx - x) < precision && Math.fabs (last - cy) > 1) { 				ycoordinates.append (new EditPoint (cx, cy)); 				last = cy; 			}+			+			last_x = cx; 			return true; 		}); +		if (on_edge) {+			return true;+		}+ 		ycoordinates.sort ((a, b) => { 			return (a.y < b.y) ? 1 : -1; 		});--		return_val_if_fail (ycoordinates.length () >= 2, true); 		 		if (unlikely (ycoordinates.length () % 2 != 0)) { 			warning (@"not an even number of coordinates ($(ycoordinates.length ()))");-		}+			stderr.printf (@"(ymin <= y <= ymax) && (xmin <= x <= xmax);\n");+			stderr.printf (@"($ymin <= $y <= $ymax) && ($xmin <= $x <= $xmax);\n");+		+			stderr.printf ("ycoordinates:\n");+			foreach (EditPoint e in ycoordinates) {+				stderr.printf (@"$(e.y)\n");+			} +			ycoordinates.append (ycoordinates.last ().data.copy ());+			+			return true;+		}+		 		for (unowned List<EditPoint> e = ycoordinates.first (); true; e = e.next) {-			if (y < e.data.y) {+			if (y <= e.data.y + precision) { 				return_if_fail ((void*) e.next != null); 				e = e.next; -				if (y > e.data.y) {+				if (y >= e.data.y - precision) { 					return true; 				} 			}@@ -785,12 +828,24 @@ class Path { 		return false; 	} 	+	public bool is_over_boundry_precision (double x, double y, double p) {+		if (unlikely (ymin == double.MAX)) {+			warning ("no bounding box");+		}+		+		return (ymin - p <= y <= ymax + p) && (xmin - p <= x <= xmax + p);+	}+	 	public bool is_over_boundry (double x, double y) {+		if (unlikely (ymin == double.MAX)) {+			warning ("bounding box is not calculated, run update_region_boundries first.");+		}+ 		return (ymin <= y <= ymax) && (xmin <= x <= xmax); 	}  	public bool has_overlapping_boundry (Path p) {-		return !(xmax < p.xmin || ymax < p.ymin) || (xmin > p.xmax || ymin > p.ymax);+		return !(xmax <= p.xmin || ymax <= p.ymin) || (xmin >= p.xmax || ymin >= p.ymax); 	} 	 	public void add (double x, double y) {@@ -1570,11 +1625,7 @@ class Path { 		bool done; 		PathList path_list; 		-		done = try_merge (p1.copy(), p0.copy(), out path_list);-		-		if (!done) {-			done = try_merge (p0.copy(), p1.copy(), out path_list);-		}+		done = try_merge (p0.copy(), p1.copy(), out path_list); 		 		if (!done) { 			warning ("failed to merge paths");@@ -1585,7 +1636,7 @@ class Path { 	 	private static bool try_merge (Path p0, Path p1, out PathList path_list) { 		EditPoint e;-		IntersectionList il = IntersectionList.create_intersection_list (p0, p1);+		IntersectionList il; 		 		EditPoint ex; 		EditPoint ix;@@ -1599,7 +1650,11 @@ class Path { 		bool over; 		Path np; 		Path np_counter;-				+		+		unowned List<Path> pi;+		+		il = IntersectionList.create_intersection_list (p0, p1);+		 		path_list = new PathList (); 		 		if (p0 == p1) {@@ -1607,6 +1662,8 @@ class Path { 		} 		 		// add editpoints points on intersections +		p0.update_region_boundries ();+		p1.update_region_boundries (); 		foreach (Intersection inter in il.points) { 			e = new EditPoint (); 			p0.get_closest_point_on_path (e, inter.x, inter.y);@@ -1621,72 +1678,239 @@ class Path { 			p1.get_closest_point_on_path (e, inter.x, inter.y); 			inter.editpoint_b = e; 			+			inter.editpoint_b.x = inter.editpoint_a.x;+			inter.editpoint_b.y = inter.editpoint_a.y;+			 			e = inter.editpoint_b; 			if (!p1.has_edit_point (e)) { 				p1.insert_new_point_on_path (e); 			}+		}+			+		if (il.points.length () < 2) {+			return false;+		}+		+		//path_list.paths.append (p0);+		//path_list.paths.append (p1);+		//return false;+		+		// get all parts+		foreach (Intersection inter in il.points) {+			p0.set_new_start (inter.editpoint_a);+			get_merge_part (il, p0, p1, out np);+			path_list.paths.append (np);+		}+		+		foreach (Path pp in path_list.paths) {+			pp.update_region_boundries ();+		} +		// remove duplicate paths+		for (i = 0; i < path_list.paths.length (); i++) {+			pi = path_list.paths.nth (i);+			+			if (is_duplicated (path_list, pi.data)) {+				path_list.paths.remove_link (pi);+				--i;			+			} 		} 		-		if (il.points.length () == 0) {-			return false;+		// remova paths contained in other paths+		for (i = 0; i < path_list.paths.length (); i++) {+			pi = path_list.paths.nth (i);+			+			if (pi.data.is_clockwise () && is_clasped (path_list, pi.data)) {+				path_list.paths.remove_link (pi);+				i--;+			} 		} 		-		// begin outside intersection-		ex = p0.points.first ().data;-		prev = p0.points.first ().data;-		for (i = 0; i < p0.points.length (); i++) {-			ex = prev.get_next ().data;+		return true;+	}+	+	private static bool is_duplicated (PathList pl, Path p) {+		bool duplicate = false;+		foreach (Path pd in pl.paths) {+			if (pd == p) {+				continue;+			} 			-			if (i != 0 && !p1.is_over_coordinate (ex.x, ex.y) && !p1.is_over_coordinate (prev.x, prev.y) && !il.has_edit_point (prev) && !il.has_edit_point (ex)) {-				p0.set_new_start (ex);-				break;+			if (is_duplicated_path (pd, p)) {+				duplicate = true; 			}+		}+		+		return duplicate;+	}+	+	private static bool is_duplicated_path (Path p0, Path p1) {+		bool eq;+		+		assert (p1 != p0);	+		+		foreach (EditPoint ep in p0.points) {+			eq = false; 			-			prev = ex;+			foreach (EditPoint e in p1.points) {+				eq = (Math.fabs (ep.x - e.x) < 0.04 && Math.fabs (ep.y - e.y) < 0.04);+				+				if (eq) {+					break;+				}+			}+			+			if (eq) {+				continue;+			} else {+				return false;+			} 		}--		if (i == p0.points.length ()) {-			warning ("no point outside path.");+		+		return true;+	}+	+	private static bool is_clasped (PathList pl, Path p) {+		foreach (Path o in pl.paths) {+			if (o == p) {+				continue;+			}+			+			if (is_clasped_path (o, p)) {+				return true;+			} 		}+				+		return false;+	} -		print (@"il.points.length (): $(il.points.length ())\n");--		//path_list.paths.append (p0);-		//path_list.paths.append (p1);-		//return false;-		-		// create a new path -		if (!create_merged_path (il, p0, p1, out np)) {-			return false;+	private static bool is_clasped_path (Path outside, Path inside) {+		bool i = true;+		foreach (EditPoint e in inside.points) {+			if (!outside.is_over_coordinate_var (e.x, e.y, 0.5)) { // high tolerance since point may be off curve in both paths+				i = false;+			} 		}+		return i;+	}+	+	private static bool get_merge_part (IntersectionList il, Path p0, Path p1, out Path new_path) {+		EditPoint ex;+		EditPoint ix;+		EditPoint en;+		uint offset_i = 0;+		uint offset_j;+		uint len_i;+		int i, j;+		uint len_j;+		bool over;+		Path np = new Path ();+		Intersection s = new Intersection (0, 0, 1); 		-		path_list.paths.append (np);+		ex = p0.points.last ().data;+		ix = p0.points.last ().data;+		len_i = p0.points.length (); 		-		if (!np.is_clockwise ()) {-			warning ("Outline is counter clockwise after merge");-			return false;-		}+		for (i = 0; i < p0.points.length (); i++) {+			ex = p0.points.nth ((i + offset_i) % len_i).data; -		// find counter path if we have more intersections-		if (il.points.length () > 0) { -			ex = p0.points.first ().data;-			p0.set_new_start (il.points.first ().data.editpoint_a);+			if (ex == p0.points.first ().data && i != 0) {	+				s = (!) il.get_intersection (ex);	+				break;+			} -			if (!create_merged_path (il, p0, p1, out np_counter)) {-				warning ("Failed to merge counter");+			// add new point for path a+			if (np.has_edit_point (ex)) {+				// SPLIT+				warning ("Merged path need split");+				np.close ();+				new_path = np;+				+				return false;+			} else {+				en = ex.copy ();+				np.add_point (en);+				en.recalculate_linear_handles (); 			} 			-			path_list.paths.append (np_counter);+			// swap paths+			if (il.has_edit_point (ex)) {+				s = (!) il.get_intersection (ex); 			-			if (np_counter.is_clockwise ()) {-				warning ("Counter is clockwise after merge");-				return false;+				en.type = PointType.CURVE;+				en.right_handle.type = PointType.CURVE;+				en.right_handle.angle  = s.editpoint_b.right_handle.angle;+				en.right_handle.length = s.editpoint_b.right_handle.length;+							+				// read until we find ex+				for (j = 0; j < p1.points.length (); j++) {+					ix = p1.points.nth (j).data;+					+					if (ix == s.editpoint_b) {+						break;+					}+				}+				+				offset_j = j + 1;+				len_j = p1.points.length ();+				for (j = 0; j < p1.points.length (); j++) {+					+					ix = p1.points.nth ((j + offset_j) % len_j).data;+					+					// add+					if (np.has_edit_point (ix)) {+						// SPLIT+						warning ("Merged path need split");+						np.close ();+						new_path = np;+						+						break;+					} else {+						en = ix.copy ();+						np.add_point (en);+						ix.recalculate_linear_handles ();+					}+					+					if (il.has_edit_point (ix)) {+						s = (!) il.get_intersection (ix);+						break;+					}+				}++				en.type = PointType.CURVE;+				en.right_handle.type = PointType.CURVE;+				en.right_handle.angle  = s.editpoint_a.right_handle.angle;+				en.right_handle.length = s.editpoint_a.right_handle.length;+								+				if (j == p0.points.length ()) {+					np.close ();+					new_path = np;+					return true;+				}++				// skip to next intersection+				int k;+				for (k = 0; k < p0.points.length (); k++) {+					ix = p0.points.nth (k).data; ++					if (ix == s.editpoint_a) {+						break;+					}+				}+				+				if (k == p0.points.length ()) {+					new_path = np;+					return true;+				}+				+				offset_i = 0;+				i = k; 			}-			 		}++		new_path = np; 		-		return true;+		return true;	 	} 	 	private static bool create_merged_path (IntersectionList il, Path p0, Path p1, out Path new_path) {@@ -1716,6 +1940,9 @@ class Path { 			if (np.has_edit_point (ex)) { 				// SPLIT 				warning ("Merged path need split");+				np.close ();+				new_path = np;+				return false; 			} else { 				np.add_point (ex); 				ex.recalculate_linear_handles ();@@ -1752,6 +1979,9 @@ class Path { 					if (np.has_edit_point (ix)) { 						// SPLIT 						warning ("Merged path need split");+						np.close ();+						new_path = np;+						return false; 					} else { 						np.add_point (ix); 						ix.recalculate_linear_handles ();diff --git a/src/PenTool.vala b/src/PenTool.valaindex 20507ff..0802a8e 100644--- a/src/PenTool.vala+++ b/src/PenTool.vala@@ -586,6 +586,7 @@ class PenTool : Tool { 		 		// merge it 		+		 		this.yield (); 		 		return true;diff --git a/src/Supplement.vala b/src/Supplement.valaindex 5b85790..6312f09 100644--- a/src/Supplement.vala+++ b/src/Supplement.vala@@ -22,6 +22,8 @@ namespace Supplement { class Supplement {
 	public static Argument args;
 	public static bool experimental;
+	public static bool show_coordinates;
+	public static bool fatal_wanings;
 
 	static Font current_font;
 
@@ -105,6 +107,8 @@ class Supplement { 		stdout.printf ("birdfont version %s\n", VERSION);		
 
 		experimental = args.has_argument ("--test");
+		show_coordinates = args.has_argument ("--show-coordinates");
+		fatal_wanings = has_argument ("--fatal-warning");
 
 		Preferences preferences = new Preferences ();
 		preferences.load ();
@@ -124,7 +128,7 @@ class Supplement { 		MainWindow window = new MainWindow ("Birdfont");
 		window.show_all ();
 
-		if (has_argument ("--fatal-warning")) {
+		if (fatal_wanings) {
 			LogLevelFlags levels = LogLevelFlags.LEVEL_ERROR | LogLevelFlags.LEVEL_CRITICAL | LogLevelFlags.LEVEL_WARNING;
 			Log.set_handler (null, levels, fatal_warning);
 		}
diff --git a/src/TestCases.vala b/src/TestCases.valaindex 8459f3d..7a5123d 100644--- a/src/TestCases.vala+++ b/src/TestCases.vala@@ -35,10 +35,85 @@ class TestCases { 		add (test_coordinates, "Coordinates"); 		add (test_drawing, "Pen tool"); 		add (test_delete_points, "Delete edit points");-		add (test_view_result, "View result in web browser"); 		add (test_save_backup, "Save backup"); 		add (test_convert_to_quadratic_bezier_path, "Convert to quadratic path"); 		add (test_notdef, "Notdef");+		add (test_merge, "Merge");+		add (test_over_path, "Over path");+	}++	public static void test_over_path () {+		Glyph g;+		Path p = new Path ();+		Path p2 = new Path ();+		Tool pen_tool;+		+		pen_tool = MainWindow.get_toolbox ().get_tool ("pen_tool");+		pen_tool.test_select_action ();+		Tool.test_open_next_glyph ();+		+		g = MainWindow.get_current_glyph ();++		pen_tool.test_click_action (1, 10, 10);+		pen_tool.test_click_action (1, 10, 10);+		pen_tool.test_click_action (1, 100, 10);+		pen_tool.test_click_action (1, 100, 100);+		pen_tool.test_click_action (1, 10, 100);+		pen_tool.test_click_action (3, 0, 0);++		warn_if_fail (g.active_paths.length () == 0);++		g.select_path (50, 50);+		+		warn_if_fail (g.active_paths.length () == 1);+		+		p.add (-10, 10);+		p.add (10, 10);+		p.add (10, -10);+		p.add (-10, -10);+		p.update_region_boundries ();+		p.close ();+		g.add_path (p);++		if (!p.is_over_coordinate (0, 0)) {+			warning ("Coordinate 0, 0 is not in path.");+		}+		+		if (!p.is_over_coordinate (-10, 10)) {+			warning ("Corner corrdinate -10, 10 is not in path.");+		}+		+		warn_if_fail (!p.is_over_coordinate (-20, -20));		+	}++	public static void test_merge () {+		Glyph g;+		Path p = new Path ();+		Path p2 = new Path ();+		+		Tool.test_open_next_glyph ();+		g = MainWindow.get_current_glyph ();+				+		p.add (-10, 10);+		p.add (10, 10);+		p.add (10, -10);+		p.add (-10, -10);+		p.close ();+		g.add_path (p);++		p2.add (10, 10);+		p2.add (10, -10);		+		p2.add (20, -10);+		p2.add (20, 10);+		p2.reverse ();+		p2.close ();+		g.add_path (p2);+		+		g.add_active_path (p);+		g.add_active_path (p);+		+		g.add_active_path (p);+		g.merge_all	(); 	}  	public static void test_notdef () {@@ -349,11 +424,6 @@ class TestCases { 		tool.test_coordinates ();		 	} -	public static void test_view_result () {-		ExportTool tool = (ExportTool) MainWindow.get_toolbox ().get_tool ("export");-		tool.test_view_result ();-	}- 	public static void test_reverse_random_paths () { 		PenTool tool = (PenTool) MainWindow.get_toolbox ().get_tool ("pen_tool"); 		tool.test_reverse_random_triangles ();		diff --git a/src/TestSupplement.vala b/src/TestSupplement.valaindex d31ff7d..716a197 100644--- a/src/TestSupplement.vala+++ b/src/TestSupplement.vala@@ -134,6 +134,8 @@ class TestSupplement : GLib.Object { 		stderr.printf ("%s\n\n", message);	
 		
 		get_singleton ().has_failed = true;
+		
+		assert (!Supplement.fatal_wanings);
 	}
 
 	public static void @continue () {
diff --git a/src/Tool.vala b/src/Tool.valaindex a2d1291..34acd52 100644--- a/src/Tool.vala+++ b/src/Tool.vala@@ -265,9 +265,11 @@ class Tool : GLib.Object {  	public static void test_open_next_glyph () { 		Tool.yield ();+		Glyph g; 		OverView o = MainWindow.get_overview (); 		 		MainWindow.get_tab_bar ().select_overview ();+		MainWindow.get_toolbox ().select_tool_by_name ("utf_8"); 		 		o.select_next_glyph (); 		Tool.yield ();diff --git a/src/Toolbox.vala b/src/Toolbox.valaindex fe2820d..f27bd5a 100644--- a/src/Toolbox.vala+++ b/src/Toolbox.vala@@ -146,10 +146,8 @@ class Toolbox : DrawingArea { 		draw_tool_modifiers.add_tool (erase_tool);	 				 		// path tools-		if (Supplement.experimental) {-			Tool union_paths_tool = new MergeTool ("union_paths");-			path_tool_modifiers.add_tool (union_paths_tool);-		}+		Tool union_paths_tool = new MergeTool ("union_paths");+		path_tool_modifiers.add_tool (union_paths_tool); 		 		Tool reverse_path_tool = new Tool ("reverse_path", "Create counter from outline", 'r'); 		reverse_path_tool.select_action.connect((self) => {

Contact

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